diff options
Diffstat (limited to 'pyload/plugins/crypter')
72 files changed, 3231 insertions, 0 deletions
diff --git a/pyload/plugins/crypter/BitshareComFolder.py b/pyload/plugins/crypter/BitshareComFolder.py new file mode 100644 index 000000000..cfb6fc1a0 --- /dev/null +++ b/pyload/plugins/crypter/BitshareComFolder.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + + +class BitshareComFolder(SimpleCrypter): + __name__ = "BitshareComFolder" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'http://(?:www\.)?bitshare\.com/\?d=\w+' + + __description__ = """Bitshare.com folder decrypter plugin""" + __author_name__ = "stickell" + __author_mail__ = "l.stickell@yahoo.it" + + LINK_PATTERN = r'<a href="(http://bitshare.com/files/.+)">.+</a></td>' + TITLE_PATTERN = r'View public folder "(?P<title>.+)"</h1>' diff --git a/pyload/plugins/crypter/C1neonCom.py b/pyload/plugins/crypter/C1neonCom.py new file mode 100644 index 000000000..2d1e91ef6 --- /dev/null +++ b/pyload/plugins/crypter/C1neonCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.DeadCrypter import DeadCrypter + + +class C1neonCom(DeadCrypter): + __name__ = "C1neonCom" + __type__ = "crypter" + __version__ = "0.05" + + __pattern__ = r'http://(?:www\.)?c1neon.com/.*?' + + __description__ = """C1neon.com decrypter plugin""" + __author_name__ = "godofdream" + __author_mail__ = "soilfiction@gmail.com" diff --git a/pyload/plugins/crypter/ChipDe.py b/pyload/plugins/crypter/ChipDe.py new file mode 100644 index 000000000..fe91b69ce --- /dev/null +++ b/pyload/plugins/crypter/ChipDe.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- + +import re +from pyload.plugins.base.Crypter import Crypter + + +class ChipDe(Crypter): + __name__ = "ChipDe" + __type__ = "crypter" + __version__ = "0.1" + + __pattern__ = r'http://(?:www\.)?chip.de/video/.*\.html' + + __description__ = """Chip.de decrypter plugin""" + __author_name__ = "4Christopher" + __author_mail__ = "4Christopher@gmx.de" + + + def decrypt(self, pyfile): + self.html = self.load(pyfile.url) + try: + f = re.search(r'"(http://video.chip.de/\d+?/.*)"', self.html) + except: + self.fail('Failed to find the URL') + else: + self.urls = [f.group(1)] + self.logDebug("The file URL is %s" % self.urls[0]) diff --git a/pyload/plugins/crypter/CrockoComFolder.py b/pyload/plugins/crypter/CrockoComFolder.py new file mode 100644 index 000000000..200b3333e --- /dev/null +++ b/pyload/plugins/crypter/CrockoComFolder.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + + +class CrockoComFolder(SimpleCrypter): + __name__ = "CrockoComFolder" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'http://(?:www\.)?crocko.com/f/.*' + + __description__ = """Crocko.com folder decrypter plugin""" + __author_name__ = "zoidberg" + __author_mail__ = "zoidberg@mujmail.cz" + + LINK_PATTERN = r'<td class="last"><a href="([^"]+)">download</a>' diff --git a/pyload/plugins/crypter/CryptItCom.py b/pyload/plugins/crypter/CryptItCom.py new file mode 100644 index 000000000..3de00847e --- /dev/null +++ b/pyload/plugins/crypter/CryptItCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.DeadCrypter import DeadCrypter + + +class CryptItCom(DeadCrypter): + __name__ = "CryptItCom" + __type__ = "crypter" + __version__ = "0.11" + + __pattern__ = r'http://(?:www\.)?crypt-it\.com/(s|e|d|c)/[\w]+' + + __description__ = """Crypt-it.com decrypter plugin""" + __author_name__ = "jeix" + __author_mail__ = "jeix@hasnomail.de" diff --git a/pyload/plugins/crypter/CzshareComFolder.py b/pyload/plugins/crypter/CzshareComFolder.py new file mode 100644 index 000000000..2191a04b3 --- /dev/null +++ b/pyload/plugins/crypter/CzshareComFolder.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- + +import re +from pyload.plugins.base.Crypter import Crypter + + +class CzshareComFolder(Crypter): + __name__ = "CzshareComFolder" + __type__ = "crypter" + __version__ = "0.2" + + __pattern__ = r'http://(?:www\.)?(czshare|sdilej)\.(com|cz)/folders/.*' + + __description__ = """Czshare.com folder decrypter plugin, now Sdilej.cz""" + __author_name__ = "zoidberg" + __author_mail__ = "zoidberg@mujmail.cz" + + FOLDER_PATTERN = r'<tr class="subdirectory">\s*<td>\s*<table>(.*?)</table>' + LINK_PATTERN = r'<td class="col2"><a href="([^"]+)">info</a></td>' + + + def decrypt(self, pyfile): + html = self.load(pyfile.url) + + m = re.search(self.FOLDER_PATTERN, html, re.DOTALL) + if m is None: + self.fail("Parse error (FOLDER)") + + self.urls.extend(re.findall(self.LINK_PATTERN, m.group(1))) + if not self.urls: + self.fail('Could not extract any links') diff --git a/pyload/plugins/crypter/DDLMusicOrg.py b/pyload/plugins/crypter/DDLMusicOrg.py new file mode 100644 index 000000000..8c944c306 --- /dev/null +++ b/pyload/plugins/crypter/DDLMusicOrg.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- + +import re + +from time import sleep + +from pyload.plugins.base.Crypter import Crypter + + +class DDLMusicOrg(Crypter): + __name__ = "DDLMusicOrg" + __type__ = "crypter" + __version__ = "0.3" + + __pattern__ = r'http://(?:www\.)?ddl-music\.org/captcha/ddlm_cr\d\.php\?\d+\?\d+' + + __description__ = """Ddl-music.org decrypter plugin""" + __author_name__ = "mkaay" + __author_mail__ = "mkaay@mkaay.de" + + + def setup(self): + self.multiDL = False + + def decrypt(self, pyfile): + html = self.load(pyfile.url, cookies=True) + + if re.search(r"Wer dies nicht rechnen kann", html) is not None: + self.offline() + + math = re.search(r"(\d+) ([\+-]) (\d+) =\s+<inp", self.html) + id = re.search(r"name=\"id\" value=\"(\d+)\"", self.html).group(1) + linknr = re.search(r"name=\"linknr\" value=\"(\d+)\"", self.html).group(1) + + solve = "" + if math.group(2) == "+": + solve = int(math.group(1)) + int(math.group(3)) + else: + solve = int(math.group(1)) - int(math.group(3)) + sleep(3) + htmlwithlink = self.load(pyfile.url, cookies=True, + post={"calc%s" % linknr: solve, "send%s" % linknr: "Send", "id": id, + "linknr": linknr}) + m = re.search(r"<form id=\"ff\" action=\"(.*?)\" method=\"post\">", htmlwithlink) + if m: + self.urls = [m.group(1)] + else: + self.retry() diff --git a/pyload/plugins/crypter/DailymotionBatch.py b/pyload/plugins/crypter/DailymotionBatch.py new file mode 100644 index 000000000..73a0ceed5 --- /dev/null +++ b/pyload/plugins/crypter/DailymotionBatch.py @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- + +import re + +from urlparse import urljoin + +from pyload.utils import json_loads +from pyload.plugins.base.Crypter import Crypter +from pyload.utils import safe_join + + +class DailymotionBatch(Crypter): + __name__ = "DailymotionBatch" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'https?://(?:www\.)?dailymotion\.com/((playlists/)?(?P<TYPE>playlist|user)/)?(?P<ID>[\w^_]+)(?(TYPE)|#)' + + __description__ = """Dailymotion.com channel & playlist decrypter""" + __author_name__ = "Walter Purcaro" + __author_mail__ = "vuolter@gmail.com" + + + def api_response(self, ref, req=None): + url = urljoin("https://api.dailymotion.com/", ref) + page = self.load(url, get=req) + return json_loads(page) + + def getPlaylistInfo(self, id): + ref = "playlist/" + id + req = {"fields": "name,owner.screenname"} + playlist = self.api_response(ref, req) + + if "error" in playlist: + return + + name = playlist['name'] + owner = playlist['owner.screenname'] + return name, owner + + def _getPlaylists(self, user_id, page=1): + ref = "user/%s/playlists" % user_id + req = {"fields": "id", "page": page, "limit": 100} + user = self.api_response(ref, req) + + if "error" in user: + return + + for playlist in user['list']: + yield playlist['id'] + + if user['has_more']: + for item in self._getPlaylists(user_id, page + 1): + yield item + + def getPlaylists(self, user_id): + return [(id,) + self.getPlaylistInfo(id) for id in self._getPlaylists(user_id)] + + def _getVideos(self, id, page=1): + ref = "playlist/%s/videos" % id + req = {"fields": "url", "page": page, "limit": 100} + playlist = self.api_response(ref, req) + + if "error" in playlist: + return + + for video in playlist['list']: + yield video['url'] + + if playlist['has_more']: + for item in self._getVideos(id, page + 1): + yield item + + def getVideos(self, playlist_id): + return list(self._getVideos(playlist_id))[::-1] + + def decrypt(self, pyfile): + m = re.match(self.__pattern__, pyfile.url) + m_id = m.group("ID") + m_type = m.group("TYPE") + + if m_type == "playlist": + self.logDebug("Url recognized as Playlist") + p_info = self.getPlaylistInfo(m_id) + playlists = [(m_id,) + p_info] if p_info else None + else: + self.logDebug("Url recognized as Channel") + playlists = self.getPlaylists(m_id) + self.logDebug("%s playlist\s found on channel \"%s\"" % (len(playlists), m_id)) + + if not playlists: + self.fail("No playlist available") + + for p_id, p_name, p_owner in playlists: + p_videos = self.getVideos(p_id) + p_folder = safe_join(self.config['general']['download_folder'], p_owner, p_name) + self.logDebug("%s video\s found on playlist \"%s\"" % (len(p_videos), p_name)) + self.packages.append((p_name, p_videos, p_folder)) #: folder is NOT recognized by pyload 0.4.9! diff --git a/pyload/plugins/crypter/DataHuFolder.py b/pyload/plugins/crypter/DataHuFolder.py new file mode 100644 index 000000000..aafcf0def --- /dev/null +++ b/pyload/plugins/crypter/DataHuFolder.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + + +class DataHuFolder(SimpleCrypter): + __name__ = "DataHuFolder" + __type__ = "crypter" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?data.hu/dir/\w+' + + __description__ = """Data.hu folder decrypter plugin""" + __author_name__ = ("crash", "stickell") + __author_mail__ = "l.stickell@yahoo.it" + + LINK_PATTERN = r"<a href='(http://data\.hu/get/.+)' target='_blank'>\1</a>" + TITLE_PATTERN = ur'<title>(?P<title>.+) Let\xf6lt\xe9se</title>' + + + def decrypt(self, pyfile): + self.html = self.load(pyfile.url, decode=True) + + if u'K\xe9rlek add meg a jelsz\xf3t' in self.html: # Password protected + password = self.getPassword() + if password is '': + self.fail("No password specified, please set right password on Add package form and retry") + self.logDebug("The folder is password protected', 'Using password: " + password) + self.html = self.load(pyfile.url, post={'mappa_pass': password}, decode=True) + if u'Hib\xe1s jelsz\xf3' in self.html: # Wrong password + self.fail("Incorrect password, please set right password on Add package form and retry") + + package_name, folder_name = self.getPackageNameAndFolder() + + package_links = re.findall(self.LINK_PATTERN, self.html) + self.logDebug("Package has %d links" % len(package_links)) + + if package_links: + self.packages = [(package_name, package_links, folder_name)] + else: + self.fail('Could not extract any links') diff --git a/pyload/plugins/crypter/DdlstorageComFolder.py b/pyload/plugins/crypter/DdlstorageComFolder.py new file mode 100644 index 000000000..7469610f1 --- /dev/null +++ b/pyload/plugins/crypter/DdlstorageComFolder.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.DeadCrypter import DeadCrypter, create_getInfo + + +class DdlstorageComFolder(DeadCrypter): + __name__ = "DdlstorageComFolder" + __type__ = "crypter" + __version__ = "0.03" + + __pattern__ = r'https?://(?:www\.)?ddlstorage\.com/folder/\w+' + + __description__ = """DDLStorage.com folder decrypter plugin""" + __author_name__ = ("godofdream", "stickell") + __author_mail__ = ("soilfiction@gmail.com", "l.stickell@yahoo.it") + + +getInfo = create_getInfo(SpeedLoadOrg) diff --git a/pyload/plugins/crypter/DepositfilesComFolder.py b/pyload/plugins/crypter/DepositfilesComFolder.py new file mode 100644 index 000000000..e308305ae --- /dev/null +++ b/pyload/plugins/crypter/DepositfilesComFolder.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + + +class DepositfilesComFolder(SimpleCrypter): + __name__ = "DepositfilesComFolder" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'http://(?:www\.)?depositfiles.com/folders/\w+' + + __description__ = """Depositfiles.com folder decrypter plugin""" + __author_name__ = "zoidberg" + __author_mail__ = "zoidberg@mujmail.cz" + + LINK_PATTERN = r'<div class="progressName"[^>]*>\s*<a href="([^"]+)" title="[^"]*" target="_blank">' diff --git a/pyload/plugins/crypter/Dereferer.py b/pyload/plugins/crypter/Dereferer.py new file mode 100644 index 000000000..90288fb59 --- /dev/null +++ b/pyload/plugins/crypter/Dereferer.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- + +import re + +from urllib import unquote + +from pyload.plugins.base.Crypter import Crypter + + +class Dereferer(Crypter): + __name__ = "Dereferer" + __type__ = "crypter" + __version__ = "0.1" + + __pattern__ = r'https?://([^/]+)/.*?(?P<url>(ht|f)tps?(://|%3A%2F%2F).*)' + + __description__ = """Crypter for dereferers""" + __author_name__ = "zoidberg" + __author_mail__ = "zoidberg@mujmail.cz" + + + def decrypt(self, pyfile): + link = re.match(self.__pattern__, pyfile.url).group('url') + self.urls = [unquote(link).rstrip('+')] diff --git a/pyload/plugins/crypter/DlProtectCom.py b/pyload/plugins/crypter/DlProtectCom.py new file mode 100644 index 000000000..2c9e282be --- /dev/null +++ b/pyload/plugins/crypter/DlProtectCom.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- + +import re + +from base64 import urlsafe_b64encode +from time import time + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + + +class DlProtectCom(SimpleCrypter): + __name__ = "DlProtectCom" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'http://(?:www\.)?dl-protect\.com/((en|fr)/)?(?P<ID>\w+)' + + __description__ = """Dl-protect.com decrypter plugin""" + __author_name__ = "Walter Purcaro" + __author_mail__ = "vuolter@gmail.com" + + OFFLINE_PATTERN = r'>Unfortunately, the link you are looking for is not found' + + + def getLinks(self): + # Direct link with redirect + if not re.match(r"http://(?:www\.)?dl-protect\.com", self.req.http.lastEffectiveURL): + return [self.req.http.lastEffectiveURL] + + #id = re.match(self.__pattern__, self.pyfile.url).group("ID") + key = re.search(r'name="id_key" value="(.+?)"', self.html).group(1) + + post_req = {"id_key": key, "submitform": ""} + + if self.OFFLINE_PATTERN in self.html: + self.offline() + elif ">Please click on continue to see the content" in self.html: + post_req.update({"submitform": "Continue"}) + else: + mstime = int(round(time() * 1000)) + b64time = "_" + urlsafe_b64encode(str(mstime)).replace("=", "%3D") + + post_req.update({"i": b64time, "submitform": "Decrypt+link"}) + + if ">Password :" in self.html: + post_req['pwd'] = self.getPassword() + + if ">Security Code" in self.html: + captcha_id = re.search(r'/captcha\.php\?uid=(.+?)"', self.html).group(1) + captcha_url = "http://www.dl-protect.com/captcha.php?uid=" + captcha_id + captcha_code = self.decryptCaptcha(captcha_url, imgtype="gif") + + post_req['secure'] = captcha_code + + self.html = self.load(self.pyfile.url, post=post_req) + + for errmsg in (">The password is incorrect", ">The security code is incorrect"): + if errmsg in self.html: + self.fail(errmsg[1:]) + + pattern = r'<a href="([^/].+?)" target="_blank">' + return re.findall(pattern, self.html) diff --git a/pyload/plugins/crypter/DontKnowMe.py b/pyload/plugins/crypter/DontKnowMe.py new file mode 100644 index 000000000..5d048994e --- /dev/null +++ b/pyload/plugins/crypter/DontKnowMe.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +import re + +from urllib import unquote + +from pyload.plugins.base.Crypter import Crypter + + +class DontKnowMe(Crypter): + __name__ = "DontKnowMe" + __type__ = "crypter" + __version__ = "0.1" + + __pattern__ = r'http://(?:www\.)?dontknow.me/at/\?.+$' + + __description__ = """DontKnow.me decrypter plugin""" + __author_name__ = "selaux" + __author_mail__ = None + + LINK_PATTERN = r'http://dontknow.me/at/\?(.+)$' + + + def decrypt(self, pyfile): + link = re.findall(self.LINK_PATTERN, pyfile.url)[0] + self.urls = [unquote(link)] diff --git a/pyload/plugins/crypter/DuckCryptInfo.py b/pyload/plugins/crypter/DuckCryptInfo.py new file mode 100644 index 000000000..7f25b9ae6 --- /dev/null +++ b/pyload/plugins/crypter/DuckCryptInfo.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- + +import re + +from BeautifulSoup import BeautifulSoup + +from pyload.plugins.base.Crypter import Crypter + + +class DuckCryptInfo(Crypter): + __name__ = "DuckCryptInfo" + __type__ = "crypter" + __version__ = "0.02" + + __pattern__ = r'http://(?:www\.)?duckcrypt.info/(folder|wait|link)/(\w+)/?(\w*)' + + __description__ = """DuckCrypt.info decrypter plugin""" + __author_name__ = "godofdream" + __author_mail__ = "soilfiction@gmail.com" + + TIMER_PATTERN = r'<span id="timer">(.*)</span>' + + + def decrypt(self, pyfile): + url = pyfile.url + + m = re.match(self.__pattern__, url) + if m is None: + self.fail('Weird error in link') + if str(m.group(1)) == "link": + self.handleLink(url) + else: + self.handleFolder(m) + + def handleFolder(self, m): + src = self.load("http://duckcrypt.info/ajax/auth.php?hash=" + str(m.group(2))) + m = re.match(self.__pattern__, src) + self.logDebug("Redirectet to " + str(m.group(0))) + src = self.load(str(m.group(0))) + soup = BeautifulSoup(src) + cryptlinks = soup.findAll("div", attrs={"class": "folderbox"}) + self.logDebug("Redirectet to " + str(cryptlinks)) + if not cryptlinks: + self.fail('no links m - (Plugin out of date?)') + for clink in cryptlinks: + if clink.find("a"): + self.handleLink(clink.find("a")['href']) + + def handleLink(self, url): + src = self.load(url) + soup = BeautifulSoup(src) + self.urls = [soup.find("iframe")['src']] + if not self.urls: + self.logDebug("No link found - (Plugin out of date?)") diff --git a/pyload/plugins/crypter/DuploadOrgFolder.py b/pyload/plugins/crypter/DuploadOrgFolder.py new file mode 100644 index 000000000..ca76cff75 --- /dev/null +++ b/pyload/plugins/crypter/DuploadOrgFolder.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + + +class DuploadOrgFolder(SimpleCrypter): + __name__ = "DuploadOrgFolder" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'http://(?:www\.)?dupload\.org/folder/\d+/' + + __description__ = """Dupload.org folder decrypter plugin""" + __author_name__ = "stickell" + __author_mail__ = "l.stickell@yahoo.it" + + LINK_PATTERN = r'<td style="[^"]+"><a href="(http://[^"]+)" target="_blank">[^<]+</a></td>' diff --git a/pyload/plugins/crypter/EasybytezComFolder.py b/pyload/plugins/crypter/EasybytezComFolder.py new file mode 100644 index 000000000..c9575db96 --- /dev/null +++ b/pyload/plugins/crypter/EasybytezComFolder.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + + +class EasybytezComFolder(SimpleCrypter): + __name__ = "EasybytezComFolder" + __type__ = "crypter" + __version__ = "0.07" + + __pattern__ = r'http://(?:www\.)?easybytez\.com/users/(?P<ID>\d+/\d+)' + + __description__ = """Easybytez.com decrypter plugin""" + __author_name__ = "stickell" + __author_mail__ = "l.stickell@yahoo.it" + + + URL_REPLACEMENTS = [(__pattern__, r"http://www.easybytez.com/users/\g<ID>?per_page=10000")] + + LINK_PATTERN = r'<td><a href="(http://www\.easybytez\.com/\w+)" target="_blank">.+(?:</a>)?</td>' + TITLE_PATTERN = r'<Title>Files of \d+: (?P<title>.+) folder</Title>' + + LOGIN_ACCOUNT = True diff --git a/pyload/plugins/crypter/EmbeduploadCom.py b/pyload/plugins/crypter/EmbeduploadCom.py new file mode 100644 index 000000000..0200d4468 --- /dev/null +++ b/pyload/plugins/crypter/EmbeduploadCom.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- + +import re +from pyload.plugins.base.Crypter import Crypter +from pyload.network.HTTPRequest import BadHeader + + +class EmbeduploadCom(Crypter): + __name__ = "EmbeduploadCom" + __type__ = "crypter" + __version__ = "0.02" + + __pattern__ = r'http://(?:www\.)?embedupload.com/\?d=.*' + __config__ = [("preferedHoster", "str", "Prefered hoster list (bar-separated) ", "embedupload"), + ("ignoredHoster", "str", "Ignored hoster list (bar-separated) ", "")] + + __description__ = """EmbedUpload.com decrypter plugin""" + __author_name__ = "zoidberg" + __author_mail__ = "zoidberg@mujmail.cz" + + LINK_PATTERN = r'<div id="([^"]+)"[^>]*>\s*<a href="([^"]+)" target="_blank" (?:class="DownloadNow"|style="color:red")>' + + + def decrypt(self, pyfile): + self.html = self.load(pyfile.url, decode=True) + tmp_links = [] + + m = re.findall(self.LINK_PATTERN, self.html) + if m: + prefered_set = set(self.getConfig("preferedHoster").split('|')) + prefered_set = map(lambda s: s.lower().split('.')[0], prefered_set) + print "PF", prefered_set + tmp_links.extend([x[1] for x in m if x[0] in prefered_set]) + self.urls = self.getLocation(tmp_links) + + if not self.urls: + ignored_set = set(self.getConfig("ignoredHoster").split('|')) + ignored_set = map(lambda s: s.lower().split('.')[0], ignored_set) + print "IG", ignored_set + tmp_links.extend([x[1] for x in m if x[0] not in ignored_set]) + self.urls = self.getLocation(tmp_links) + + if not self.urls: + self.fail('Could not extract any links') + + def getLocation(self, tmp_links): + new_links = [] + for link in tmp_links: + try: + header = self.load(link, just_header=True) + if "location" in header: + new_links.append(header['location']) + except BadHeader: + pass + return new_links diff --git a/pyload/plugins/crypter/FilebeerInfoFolder.py b/pyload/plugins/crypter/FilebeerInfoFolder.py new file mode 100644 index 000000000..ee577a865 --- /dev/null +++ b/pyload/plugins/crypter/FilebeerInfoFolder.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.DeadCrypter import DeadCrypter + + +class FilebeerInfoFolder(DeadCrypter): + __name__ = "FilebeerInfoFolder" + __type__ = "crypter" + __version__ = "0.02" + + __pattern__ = r'http://(?:www\.)?filebeer\.info/(\d+~f).*' + + __description__ = """Filebeer.info folder decrypter plugin""" + __author_name__ = "zoidberg" + __author_mail__ = "zoidberg@mujmail.cz" diff --git a/pyload/plugins/crypter/FilecloudIoFolder.py b/pyload/plugins/crypter/FilecloudIoFolder.py new file mode 100644 index 000000000..577dd43a3 --- /dev/null +++ b/pyload/plugins/crypter/FilecloudIoFolder.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + + +class FilecloudIoFolder(SimpleCrypter): + __name__ = "FilecloudIoFolder" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'https?://(?:www\.)?(filecloud\.io|ifile\.it)/_\w+' + + __description__ = """Filecloud.io folder decrypter plugin""" + __author_name__ = "Walter Purcaro" + __author_mail__ = "vuolter@gmail.com" + + LINK_PATTERN = r'href="(http://filecloud.io/\w+)" title' + TITLE_PATTERN = r'>(?P<title>.+?) - filecloud.io<' diff --git a/pyload/plugins/crypter/FilefactoryComFolder.py b/pyload/plugins/crypter/FilefactoryComFolder.py new file mode 100644 index 000000000..c624b4fc5 --- /dev/null +++ b/pyload/plugins/crypter/FilefactoryComFolder.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + + +class FilefactoryComFolder(SimpleCrypter): + __name__ = "FilefactoryComFolder" + __type__ = "crypter" + __version__ = "0.2" + + __pattern__ = r'https?://(?:www\.)?filefactory\.com/(?:f|folder)/\w+' + + __description__ = """Filefactory.com folder decrypter plugin""" + __author_name__ = "stickell" + __author_mail__ = "l.stickell@yahoo.it" + + LINK_PATTERN = r'<td><a href="([^"]+)">' + TITLE_PATTERN = r'<h1>Files in <span>(?P<title>.+)</span></h1>' + PAGES_PATTERN = r'data-paginator-totalPages="(?P<pages>\d+)"' + + COOKIES = [('.filefactory.com', 'locale', 'en_US.utf8')] + + + def loadPage(self, page_n): + return self.load(self.pyfile.url, get={'page': page_n}) diff --git a/pyload/plugins/crypter/FilerNetFolder.py b/pyload/plugins/crypter/FilerNetFolder.py new file mode 100644 index 000000000..4acb7e165 --- /dev/null +++ b/pyload/plugins/crypter/FilerNetFolder.py @@ -0,0 +1,22 @@ +import re + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + + +class FilerNetFolder(SimpleCrypter): + __name__ = "FilerNetFolder" + __type__ = "crypter" + __version__ = "0.3" + + __pattern__ = r'https?://filer\.net/folder/\w{16}' + + __description__ = """Filer.net decrypter plugin""" + __author_name_ = ("nath_schwarz", "stickell") + __author_mail_ = ("nathan.notwhite@gmail.com", "l.stickell@yahoo.it") + + LINK_PATTERN = r'href="(/get/\w{16})">(?!<)' + TITLE_PATTERN = r'<h3>(?P<title>.+) - <small' + + + def getLinks(self): + return ['http://filer.net%s' % link for link in re.findall(self.LINK_PATTERN, self.html)] diff --git a/pyload/plugins/crypter/FileserveComFolder.py b/pyload/plugins/crypter/FileserveComFolder.py new file mode 100644 index 000000000..0a6232603 --- /dev/null +++ b/pyload/plugins/crypter/FileserveComFolder.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugins.base.Crypter import Crypter + + +class FileserveComFolder(Crypter): + __name__ = "FileserveComFolder" + __type__ = "crypter" + __version__ = "0.11" + + __pattern__ = r'http://(?:www\.)?fileserve.com/list/\w+' + + __description__ = """FileServe.com folder decrypter plugin""" + __author_name__ = "fionnc" + __author_mail__ = "fionnc@gmail.com" + + FOLDER_PATTERN = r'<table class="file_list">(.*?)</table>' + LINK_PATTERN = r'<a href="([^"]+)" class="sheet_icon wbold">' + + + def decrypt(self, pyfile): + html = self.load(pyfile.url) + + new_links = [] + + folder = re.search(self.FOLDER_PATTERN, html, re.DOTALL) + if folder is None: + self.fail("Parse error (FOLDER)") + + new_links.extend(re.findall(self.LINK_PATTERN, folder.group(1))) + + if new_links: + self.urls = [map(lambda s: "http://fileserve.com%s" % s, new_links)] + else: + self.fail('Could not extract any links') diff --git a/pyload/plugins/crypter/FilestubeCom.py b/pyload/plugins/crypter/FilestubeCom.py new file mode 100644 index 000000000..fc80762d1 --- /dev/null +++ b/pyload/plugins/crypter/FilestubeCom.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + + +class FilestubeCom(SimpleCrypter): + __name__ = "FilestubeCom" + __type__ = "crypter" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?filestube\.(?:com|to)/\w+' + + __description__ = """Filestube.com decrypter plugin""" + __author_name__ = "stickell" + __author_mail__ = "l.stickell@yahoo.it" + + LINK_PATTERN = r'<a class=\"file-link-main(?: noref)?\" [^>]* href=\"(http://[^\"]+)' + TITLE_PATTERN = r'<h1\s*> (?P<title>.+) download\s*</h1>' diff --git a/pyload/plugins/crypter/FiletramCom.py b/pyload/plugins/crypter/FiletramCom.py new file mode 100644 index 000000000..6620adc12 --- /dev/null +++ b/pyload/plugins/crypter/FiletramCom.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + + +class FiletramCom(SimpleCrypter): + __name__ = "FiletramCom" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'http://(?:www\.)?filetram.com/[^/]+/.+' + + __description__ = """Filetram.com decrypter plugin""" + __author_name__ = ("igel", "stickell") + __author_mail__ = ("igelkun@myopera.com", "l.stickell@yahoo.it") + + LINK_PATTERN = r'\s+(http://.+)' + TITLE_PATTERN = r'<title>(?P<title>[^<]+) - Free Download[^<]*</title>' diff --git a/pyload/plugins/crypter/FiredriveComFolder.py b/pyload/plugins/crypter/FiredriveComFolder.py new file mode 100644 index 000000000..072a548a2 --- /dev/null +++ b/pyload/plugins/crypter/FiredriveComFolder.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + + +class FiredriveComFolder(SimpleCrypter): + __name__ = "FiredriveComFolder" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'https?://(?:www\.)?(firedrive|putlocker)\.com/share/.+' + + __description__ = """Firedrive.com folder decrypter plugin""" + __author_name__ = "Walter Purcaro" + __author_mail__ = "vuolter@gmail.com" + + LINK_PATTERN = r'<div class="pf_item pf_(file|folder).+?public=\'(.+?)\'' + TITLE_PATTERN = r'>Shared Folder "(?P<title>.+)" | Firedrive<' + OFFLINE_PATTERN = r'class="sad_face_image"|>No such page here.<' + TEMP_OFFLINE_PATTERN = r'>(File Temporarily Unavailable|Server Error. Try again later)' + + + def getLinks(self): + return map(lambda x: "http://www.firedrive.com/%s/%s" % + ("share" if x[0] == "folder" else "file", x[1]), + re.findall(self.LINK_PATTERN, self.html)) diff --git a/pyload/plugins/crypter/FourChanOrg.py b/pyload/plugins/crypter/FourChanOrg.py new file mode 100644 index 000000000..4762f5d1d --- /dev/null +++ b/pyload/plugins/crypter/FourChanOrg.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# +# Based on 4chandl by Roland Beermann (https://gist.github.com/enkore/3492599) + +import re + +from pyload.plugins.base.Crypter import Crypter + + +class FourChanOrg(Crypter): + __name__ = "FourChanOrg" + __type__ = "crypter" + __version__ = "0.3" + + __pattern__ = r'http://(?:www\.)?boards\.4chan.org/\w+/res/(\d+)' + + __description__ = """4chan.org folder decrypter plugin""" + __author_name__ = None + __author_mail__ = None + + + def decrypt(self, pyfile): + pagehtml = self.load(pyfile.url) + images = set(re.findall(r'(images\.4chan\.org/[^/]*/src/[^"<]*)', pagehtml)) + self.urls = ["http://" + image for image in images] diff --git a/pyload/plugins/crypter/FreakhareComFolder.py b/pyload/plugins/crypter/FreakhareComFolder.py new file mode 100644 index 000000000..fca1b26a1 --- /dev/null +++ b/pyload/plugins/crypter/FreakhareComFolder.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + + +class FreakhareComFolder(SimpleCrypter): + __name__ = "FreakhareComFolder" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'http://(?:www\.)?freakshare\.com/folder/.+' + + __description__ = """Freakhare.com folder decrypter plugin""" + __author_name__ = "stickell" + __author_mail__ = "l.stickell@yahoo.it" + + LINK_PATTERN = r'<a href="(http://freakshare.com/files/[^"]+)" target="_blank">' + TITLE_PATTERN = r'Folder:</b> (?P<title>.+)' + PAGES_PATTERN = r'Pages: +(?P<pages>\d+)' + + + def loadPage(self, page_n): + if not hasattr(self, 'f_id') and not hasattr(self, 'f_md5'): + m = re.search(r'http://freakshare.com/\?x=folder&f_id=(\d+)&f_md5=(\w+)', self.html) + if m: + self.f_id = m.group(1) + self.f_md5 = m.group(2) + return self.load('http://freakshare.com/', get={'x': 'folder', + 'f_id': self.f_id, + 'f_md5': self.f_md5, + 'entrys': '20', + 'page': page_n - 1, + 'order': ''}, decode=True) diff --git a/pyload/plugins/crypter/FreetexthostCom.py b/pyload/plugins/crypter/FreetexthostCom.py new file mode 100644 index 000000000..e56d638f0 --- /dev/null +++ b/pyload/plugins/crypter/FreetexthostCom.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + + +class FreetexthostCom(SimpleCrypter): + __name__ = "FreetexthostCom" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'http://(?:www\.)?freetexthost\.com/\w+' + + __description__ = """Freetexthost.com decrypter plugin""" + __author_name__ = "stickell" + __author_mail__ = "l.stickell@yahoo.it" + + + def getLinks(self): + m = re.search(r'<div id="contentsinner">\s*(.+)<div class="viewcount">', self.html, re.DOTALL) + if m is None: + self.fail('Unable to extract links | Plugin may be out-of-date') + links = m.group(1) + return links.strip().split("<br />\r\n") diff --git a/pyload/plugins/crypter/FshareVnFolder.py b/pyload/plugins/crypter/FshareVnFolder.py new file mode 100644 index 000000000..1706d97e0 --- /dev/null +++ b/pyload/plugins/crypter/FshareVnFolder.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + + +class FshareVnFolder(SimpleCrypter): + __name__ = "FshareVnFolder" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'http://(?:www\.)?fshare.vn/folder/.*' + + __description__ = """Fshare.vn folder decrypter plugin""" + __author_name__ = "zoidberg" + __author_mail__ = "zoidberg@mujmail.cz" + + LINK_PATTERN = r'<li class="w_80pc"><a href="([^"]+)" target="_blank">' diff --git a/pyload/plugins/crypter/GooGl.py b/pyload/plugins/crypter/GooGl.py new file mode 100644 index 000000000..0e89c5bad --- /dev/null +++ b/pyload/plugins/crypter/GooGl.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.base.Crypter import Crypter +from pyload.utils import json_loads + + +class GooGl(Crypter): + __name__ = "GooGl" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'https?://(?:www\.)?goo\.gl/\w+' + + __description__ = """Goo.gl decrypter plugin""" + __author_name__ = "stickell" + __author_mail__ = "l.stickell@yahoo.it" + + API_URL = "https://www.googleapis.com/urlshortener/v1/url" + + + def decrypt(self, pyfile): + rep = self.load(self.API_URL, get={'shortUrl': pyfile.url}) + self.logDebug("JSON data: " + rep) + rep = json_loads(rep) + + if 'longUrl' in rep: + self.urls = [rep['longUrl']] + else: + self.fail('Unable to expand shortened link') diff --git a/pyload/plugins/crypter/HoerbuchIn.py b/pyload/plugins/crypter/HoerbuchIn.py new file mode 100644 index 000000000..572472f5a --- /dev/null +++ b/pyload/plugins/crypter/HoerbuchIn.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- + +import re + +from BeautifulSoup import BeautifulSoup, BeautifulStoneSoup + +from pyload.plugins.base.Crypter import Crypter + + +class HoerbuchIn(Crypter): + __name__ = "HoerbuchIn" + __type__ = "crypter" + __version__ = "0.6" + + __pattern__ = r'http://(?:www\.)?hoerbuch\.in/(wp/horbucher/\d+/.+/|tp/out.php\?.+|protection/folder_\d+\.html)' + + __description__ = """Hoerbuch.in decrypter plugin""" + __author_name__ = ("spoob", "mkaay") + __author_mail__ = ("spoob@pyload.org", "mkaay@mkaay.de") + + article = re.compile("http://(?:www\.)?hoerbuch\.in/wp/horbucher/\d+/.+/") + protection = re.compile("http://(?:www\.)?hoerbuch\.in/protection/folder_\d+.html") + + + def decrypt(self, pyfile): + self.pyfile = pyfile + + if self.article.match(pyfile.url): + src = self.load(pyfile.url) + soup = BeautifulSoup(src, convertEntities=BeautifulStoneSoup.HTML_ENTITIES) + + abookname = soup.find("a", attrs={"rel": "bookmark"}).text + for a in soup.findAll("a", attrs={"href": self.protection}): + package = "%s (%s)" % (abookname, a.previousSibling.previousSibling.text[:-1]) + links = self.decryptFolder(a['href']) + + self.packages.append((package, links, package)) + else: + self.urls = self.decryptFolder(pyfile.url) + + def decryptFolder(self, url): + m = self.protection.search(url) + if m is None: + self.fail("Bad URL") + url = m.group(0) + + self.pyfile.url = url + src = self.load(url, post={"viewed": "adpg"}) + + links = [] + pattern = re.compile("http://www\.hoerbuch\.in/protection/(\w+)/(.*?)\"") + for hoster, lid in pattern.findall(src): + self.req.lastURL = url + self.load("http://www.hoerbuch.in/protection/%s/%s" % (hoster, lid)) + links.append(self.req.lastEffectiveURL) + + return links diff --git a/pyload/plugins/crypter/HotfileFolderCom.py b/pyload/plugins/crypter/HotfileFolderCom.py new file mode 100644 index 000000000..4f144cc52 --- /dev/null +++ b/pyload/plugins/crypter/HotfileFolderCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.DeadCrypter import DeadCrypter + + +class HotfileFolderCom(DeadCrypter): + __name__ = "HotfileFolderCom" + __type__ = "crypter" + __version__ = "0.3" + + __pattern__ = r'https?://(?:www\.)?hotfile\.com/list/\w+/\w+' + + __description__ = """Hotfile.com folder decrypter plugin""" + __author_name__ = "RaNaN" + __author_mail__ = "RaNaN@pyload.org" diff --git a/pyload/plugins/crypter/ILoadTo.py b/pyload/plugins/crypter/ILoadTo.py new file mode 100644 index 000000000..16f813926 --- /dev/null +++ b/pyload/plugins/crypter/ILoadTo.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.DeadCrypter import DeadCrypter + + +class ILoadTo(DeadCrypter): + __name__ = "ILoadTo" + __type__ = "crypter" + __version__ = "0.11" + + __pattern__ = r'http://(?:www\.)?iload\.to/go/\d+-[\w\.-]+/' + + __description__ = """Iload.to decrypter plugin""" + __author_name__ = "hzpz" + __author_mail__ = None diff --git a/pyload/plugins/crypter/ImgurComAlbum.py b/pyload/plugins/crypter/ImgurComAlbum.py new file mode 100644 index 000000000..5e8be3a5d --- /dev/null +++ b/pyload/plugins/crypter/ImgurComAlbum.py @@ -0,0 +1,24 @@ +import re + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter +from pyload.utils import uniqify + + +class ImgurComAlbum(SimpleCrypter): + __name__ = "ImgurComAlbum" + __type__ = "crypter" + __version__ = "0.4" + + __pattern__ = r'https?://(?:www\.|m\.)?imgur\.com/(a|gallery|)/?\w{5,7}' + + __description__ = """Imgur.com decrypter plugin""" + __author_name_ = "nath_schwarz" + __author_mail_ = "nathan.notwhite@gmail.com" + + TITLE_PATTERN = r'(?P<title>.+) - Imgur' + LINK_PATTERN = r'i\.imgur\.com/\w{7}s?\.(?:jpeg|jpg|png|gif|apng)' + + + def getLinks(self): + f = lambda url: "http://" + re.sub(r'(\w{7})s\.', r'\1.', url) + return uniqify(map(f, re.findall(self.LINK_PATTERN, self.html))) diff --git a/pyload/plugins/crypter/LetitbitNetFolder.py b/pyload/plugins/crypter/LetitbitNetFolder.py new file mode 100644 index 000000000..b5a48a949 --- /dev/null +++ b/pyload/plugins/crypter/LetitbitNetFolder.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- + +import re +from pyload.plugins.base.Crypter import Crypter + + +class LetitbitNetFolder(Crypter): + __name__ = "LetitbitNetFolder" + __type__ = "crypter" + __version__ = "0.1" + + __pattern__ = r'http://(?:www\.)?letitbit.net/folder/\w+' + + __description__ = """Letitbit.net folder decrypter plugin""" + __author_name__ = ("DHMH", "z00nx") + __author_mail__ = ("webmaster@pcProfil.de", "z00nx0@gmail.com") + + FOLDER_PATTERN = r'<table>(.*)</table>' + LINK_PATTERN = r'<a href="([^"]+)" target="_blank">' + + + def decrypt(self, pyfile): + html = self.load(pyfile.url) + + folder = re.search(self.FOLDER_PATTERN, html, re.DOTALL) + if folder is None: + self.fail("Parse error (FOLDER)") + + self.urls.extend(re.findall(self.LINK_PATTERN, folder.group(0))) + + if not self.urls: + self.fail('Could not extract any links') diff --git a/pyload/plugins/crypter/LinkSaveIn.py b/pyload/plugins/crypter/LinkSaveIn.py new file mode 100644 index 000000000..f5c28e28e --- /dev/null +++ b/pyload/plugins/crypter/LinkSaveIn.py @@ -0,0 +1,241 @@ +# -*- coding: utf-8 -*- +# +# * cnl2 and web links are skipped if JS is not available (instead of failing the package) +# * only best available link source is used (priority: cnl2>rsdf>ccf>dlc>web + +import base64 +import binascii +import re + +from Crypto.Cipher import AES + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter +from pyload.utils import html_unescape + + +class LinkSaveIn(SimpleCrypter): + __name__ = "LinkSaveIn" + __type__ = "crypter" + __version__ = "2.02" + + __pattern__ = r'http://(?:www\.)?linksave.in/(?P<id>\w+)$' + + __description__ = """LinkSave.in decrypter plugin""" + __author_name__ = "fragonib" + __author_mail__ = "fragonib[AT]yahoo[DOT]es" + + + COOKIES = [(".linksave.in", "Linksave_Language", "english")] + + # Constants + _JK_KEY_ = "jk" + _CRYPTED_KEY_ = "crypted" + + + def setup(self): + self.html = None + self.fileid = None + self.captcha = False + self.package = None + self.preferred_sources = ["cnl2", "rsdf", "ccf", "dlc", "web"] + + + def decrypt(self, pyfile): + # Init + self.package = pyfile.package() + self.fileid = re.match(self.__pattern__, pyfile.url).group('id') + + # Request package + self.html = self.load(pyfile.url) + if not self.isOnline(): + self.offline() + + # Check for protection + if self.isPasswordProtected(): + self.unlockPasswordProtection() + self.handleErrors() + + if self.isCaptchaProtected(): + self.captcha = True + self.unlockCaptchaProtection() + self.handleErrors() + + # Get package name and folder + (package_name, folder_name) = self.getPackageInfo() + + # Extract package links + package_links = [] + for type_ in self.preferred_sources: + package_links.extend(self.handleLinkSource(type_)) + if package_links: # use only first source which provides links + break + package_links = set(package_links) + + # Pack + if package_links: + self.packages = [(package_name, package_links, folder_name)] + else: + self.fail('Could not extract any links') + + + def isOnline(self): + if "<big>Error 404 - Folder not found!</big>" in self.html: + self.logDebug("File not found") + return False + return True + + + def isPasswordProtected(self): + if re.search(r'''<input.*?type="password"''', self.html): + self.logDebug("Links are password protected") + return True + + + def isCaptchaProtected(self): + if "<b>Captcha:</b>" in self.html: + self.logDebug("Links are captcha protected") + return True + return False + + + def unlockPasswordProtection(self): + password = self.getPassword() + self.logDebug("Submitting password [%s] for protected links" % password) + post = {"id": self.fileid, "besucherpasswort": password, 'login': 'submit'} + self.html = self.load(self.pyfile.url, post=post) + + + def unlockCaptchaProtection(self): + captcha_hash = re.search(r'name="hash" value="([^"]+)', self.html).group(1) + captcha_url = re.search(r'src=".(/captcha/cap.php\?hsh=[^"]+)', self.html).group(1) + captcha_code = self.decryptCaptcha("http://linksave.in" + captcha_url, forceUser=True) + self.html = self.load(self.pyfile.url, post={"id": self.fileid, "hash": captcha_hash, "code": captcha_code}) + + + def getPackageInfo(self): + name = self.pyfile.package().name + folder = self.pyfile.package().folder + self.logDebug("Defaulting to pyfile name [%s] and folder [%s] for package" % (name, folder)) + return name, folder + + + def handleErrors(self): + if "The visitorpassword you have entered is wrong" in self.html: + self.logDebug("Incorrect password, please set right password on 'Edit package' form and retry") + self.fail("Incorrect password, please set right password on 'Edit package' form and retry") + + if self.captcha: + if "Wrong code. Please retry" in self.html: + self.logDebug("Invalid captcha, retrying") + self.invalidCaptcha() + self.retry() + else: + self.correctCaptcha() + + + def handleLinkSource(self, type_): + if type_ == "cnl2": + return self.handleCNL2() + elif type_ in ("rsdf", "ccf", "dlc"): + return self.handleContainer(type_) + elif type_ == "web": + return self.handleWebLinks() + else: + self.fail('unknown source type "%s" (this is probably a bug)' % type_) + + + def handleWebLinks(self): + package_links = [] + self.logDebug("Search for Web links") + if not self.js: + self.logDebug("No JS -> skip Web links") + else: + #@TODO: Gather paginated web links + pattern = r'<a href="http://linksave\.in/(\w{43})"' + ids = re.findall(pattern, self.html) + self.logDebug("Decrypting %d Web links" % len(ids)) + for i, weblink_id in enumerate(ids): + try: + webLink = "http://linksave.in/%s" % weblink_id + self.logDebug("Decrypting Web link %d, %s" % (i + 1, webLink)) + fwLink = "http://linksave.in/fw-%s" % weblink_id + response = self.load(fwLink) + jscode = re.findall(r'<script type="text/javascript">(.*)</script>', response)[-1] + jseval = self.js.eval("document = { write: function(e) { return e; } }; %s" % jscode) + dlLink = re.search(r'http://linksave\.in/dl-\w+', jseval).group(0) + self.logDebug("JsEngine returns value [%s] for redirection link" % dlLink) + response = self.load(dlLink) + link = html_unescape(re.search(r'<iframe src="(.+?)"', response).group(1)) + package_links.append(link) + except Exception, detail: + self.logDebug("Error decrypting Web link %s, %s" % (webLink, detail)) + return package_links + + + def handleContainer(self, type_): + package_links = [] + type_ = type_.lower() + self.logDebug("Seach for %s Container links" % type_.upper()) + if not type_.isalnum(): # check to prevent broken re-pattern (cnl2,rsdf,ccf,dlc,web are all alpha-numeric) + self.fail('unknown container type "%s" (this is probably a bug)' % type_) + pattern = r"\('%s_link'\).href=unescape\('(.*?\.%s)'\)" % (type_, type_) + containersLinks = re.findall(pattern, self.html) + self.logDebug("Found %d %s Container links" % (len(containersLinks), type_.upper())) + for containerLink in containersLinks: + link = "http://linksave.in/%s" % html_unescape(containerLink) + package_links.append(link) + return package_links + + + def handleCNL2(self): + package_links = [] + self.logDebug("Search for CNL2 links") + if not self.js: + self.logDebug("No JS -> skip CNL2 links") + elif 'cnl2_load' in self.html: + try: + (vcrypted, vjk) = self._getCipherParams() + for (crypted, jk) in zip(vcrypted, vjk): + package_links.extend(self._getLinks(crypted, jk)) + except: + self.fail("Unable to decrypt CNL2 links") + return package_links + + + def _getCipherParams(self): + # Get jk + jk_re = r'<INPUT.*?NAME="%s".*?VALUE="(.*?)"' % LinkSaveIn._JK_KEY_ + vjk = re.findall(jk_re, self.html) + + # Get crypted + crypted_re = r'<INPUT.*?NAME="%s".*?VALUE="(.*?)"' % LinkSaveIn._CRYPTED_KEY_ + vcrypted = re.findall(crypted_re, self.html) + + # Log and return + self.logDebug("Detected %d crypted blocks" % len(vcrypted)) + return vcrypted, vjk + + + def _getLinks(self, crypted, jk): + # Get key + jreturn = self.js.eval("%s f()" % jk) + self.logDebug("JsEngine returns value [%s]" % jreturn) + key = binascii.unhexlify(jreturn) + + # Decode crypted + crypted = base64.standard_b64decode(crypted) + + # Decrypt + Key = key + IV = key + obj = AES.new(Key, AES.MODE_CBC, IV) + text = obj.decrypt(crypted) + + # Extract links + text = text.replace("\x00", "").replace("\r", "") + links = text.split("\n") + links = filter(lambda x: x != "", links) + + # Log and return + self.logDebug("Package has %d links" % len(links)) + return links diff --git a/pyload/plugins/crypter/LinkdecrypterCom.py b/pyload/plugins/crypter/LinkdecrypterCom.py new file mode 100644 index 000000000..d2c24b753 --- /dev/null +++ b/pyload/plugins/crypter/LinkdecrypterCom.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- + +import re +from pyload.plugins.base.Crypter import Crypter + + +class LinkdecrypterCom(Crypter): + __name__ = "LinkdecrypterCom" + __type__ = "crypter" + __version__ = "0.27" + + __pattern__ = None + + __description__ = """Linkdecrypter.com""" + __author_name__ = ("zoidberg", "flowlee") + __author_mail__ = ("zoidberg@mujmail.cz", "") + + TEXTAREA_PATTERN = r'<textarea name="links" wrap="off" readonly="1" class="caja_des">(.+)</textarea>' + PASSWORD_PATTERN = r'<input type="text" name="password"' + CAPTCHA_PATTERN = r'<img class="captcha" src="(.+?)"(.*?)>' + REDIR_PATTERN = r'<i>(Click <a href="./">here</a> if your browser does not redirect you).</i>' + + + def decrypt(self, pyfile): + + self.passwords = self.getPassword().splitlines() + + # API not working anymore + self.urls = self.decryptHTML() + if not self.urls: + self.fail('Could not extract any links') + + def decryptAPI(self): + + get_dict = {"t": "link", "url": self.pyfile.url, "lcache": "1"} + self.html = self.load('http://linkdecrypter.com/api', get=get_dict) + if self.html.startswith('http://'): + return self.html.splitlines() + + if self.html == 'INTERRUPTION(PASSWORD)': + for get_dict['pass'] in self.passwords: + self.html = self.load('http://linkdecrypter.com/api', get=get_dict) + if self.html.startswith('http://'): + return self.html.splitlines() + + self.logError("API", self.html) + if self.html == 'INTERRUPTION(PASSWORD)': + self.fail("No or incorrect password") + + return None + + def decryptHTML(self): + + retries = 5 + + post_dict = {"link_cache": "on", "pro_links": self.pyfile.url, "modo_links": "text"} + self.html = self.load('http://linkdecrypter.com/', post=post_dict, cookies=True, decode=True) + + while self.passwords or retries: + m = re.search(self.TEXTAREA_PATTERN, self.html, flags=re.DOTALL) + if m: + return [x for x in m.group(1).splitlines() if '[LINK-ERROR]' not in x] + + m = re.search(self.CAPTCHA_PATTERN, self.html) + if m: + captcha_url = 'http://linkdecrypter.com/' + m.group(1) + result_type = "positional" if "getPos" in m.group(2) else "textual" + + m = re.search(r"<p><i><b>([^<]+)</b></i></p>", self.html) + msg = m.group(1) if m else "" + self.logInfo("Captcha protected link", result_type, msg) + + captcha = self.decryptCaptcha(captcha_url, result_type=result_type) + if result_type == "positional": + captcha = "%d|%d" % captcha + self.html = self.load('http://linkdecrypter.com/', post={"captcha": captcha}, decode=True) + retries -= 1 + + elif self.PASSWORD_PATTERN in self.html: + if self.passwords: + password = self.passwords.pop(0) + self.logInfo("Password protected link, trying " + password) + self.html = self.load('http://linkdecrypter.com/', post={'password': password}, decode=True) + else: + self.fail("No or incorrect password") + + else: + retries -= 1 + self.html = self.load('http://linkdecrypter.com/', cookies=True, decode=True) + + return None diff --git a/pyload/plugins/crypter/LixIn.py b/pyload/plugins/crypter/LixIn.py new file mode 100644 index 000000000..831f35c22 --- /dev/null +++ b/pyload/plugins/crypter/LixIn.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugins.base.Crypter import Crypter + + +class LixIn(Crypter): + __name__ = "LixIn" + __type__ = "crypter" + __version__ = "0.22" + + __pattern__ = r'http://(?:www\.)?lix\.in/(?P<ID>.+)' + + __description__ = """Lix.in decrypter plugin""" + __author_name__ = "spoob" + __author_mail__ = "spoob@pyload.org" + + CAPTCHA_PATTERN = r'<img src="(?P<image>captcha_img.php\?.*?)"' + SUBMIT_PATTERN = r"value='continue.*?'" + LINK_PATTERN = r'name="ifram" src="(?P<link>.*?)"' + + + def decrypt(self, pyfile): + url = pyfile.url + + m = re.match(self.__pattern__, url) + if m is None: + self.fail("couldn't identify file id") + + id = m.group("ID") + self.logDebug("File id is %s" % id) + + self.html = self.load(url, decode=True) + + m = re.search(self.SUBMIT_PATTERN, self.html) + if m is None: + self.fail("link doesn't seem valid") + + m = re.search(self.CAPTCHA_PATTERN, self.html) + if m: + for _ in xrange(5): + m = re.search(self.CAPTCHA_PATTERN, self.html) + if m: + self.logDebug("Trying captcha") + captcharesult = self.decryptCaptcha("http://lix.in/" + m.group("image")) + self.html = self.load(url, decode=True, + post={"capt": captcharesult, "submit": "submit", "tiny": id}) + else: + self.logDebug("No captcha/captcha solved") + else: + self.html = self.load(url, decode=True, post={"submit": "submit", "tiny": id}) + + m = re.search(self.LINK_PATTERN, self.html) + if m is None: + self.fail("can't find destination url") + else: + self.urls = [m.group("link")] + self.logDebug("Found link %s, adding to package" % self.urls[0]) diff --git a/pyload/plugins/crypter/LofCc.py b/pyload/plugins/crypter/LofCc.py new file mode 100644 index 000000000..6c91a55ec --- /dev/null +++ b/pyload/plugins/crypter/LofCc.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.DeadCrypter import DeadCrypter + + +class LofCc(DeadCrypter): + __name__ = "LofCc" + __type__ = "crypter" + __version__ = "0.21" + + __pattern__ = r'http://(?:www\.)?lof.cc/(.*)' + + __description__ = """Lof.cc decrypter plugin""" + __author_name__ = "mkaay" + __author_mail__ = "mkaay@mkaay.de" diff --git a/pyload/plugins/crypter/MBLinkInfo.py b/pyload/plugins/crypter/MBLinkInfo.py new file mode 100644 index 000000000..8516ff6e4 --- /dev/null +++ b/pyload/plugins/crypter/MBLinkInfo.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.DeadCrypter import DeadCrypter + + +class MBLinkInfo(DeadCrypter): + __name__ = "MBLinkInfo" + __type__ = "crypter" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?mblink\.info/?\?id=(\d+)' + + __description__ = """MBLink.info decrypter plugin""" + __author_name__ = ("Gummibaer", "stickell") + __author_mail__ = ("Gummibaer@wiki-bierkiste.de", "l.stickell@yahoo.it") diff --git a/pyload/plugins/crypter/MediafireComFolder.py b/pyload/plugins/crypter/MediafireComFolder.py new file mode 100644 index 000000000..d8785a7cf --- /dev/null +++ b/pyload/plugins/crypter/MediafireComFolder.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- + +import re +from pyload.plugins.base.Crypter import Crypter +from pyload.plugins.hoster.MediafireCom import checkHTMLHeader +from pyload.utils import json_loads + + +class MediafireComFolder(Crypter): + __name__ = "MediafireComFolder" + __type__ = "crypter" + __version__ = "0.14" + + __pattern__ = r'http://(?:www\.)?mediafire\.com/(folder/|\?sharekey=|\?\w{13}($|[/#]))' + + __description__ = """Mediafire.com folder decrypter plugin""" + __author_name__ = "zoidberg" + __author_mail__ = "zoidberg@mujmail.cz" + + FOLDER_KEY_PATTERN = r"var afI= '(\w+)';" + FILE_URL_PATTERN = r'<meta property="og:url" content="http://www.mediafire.com/\?(\w+)"/>' + + + def decrypt(self, pyfile): + url, result = checkHTMLHeader(pyfile.url) + self.logDebug("Location (%d): %s" % (result, url)) + + if result == 0: + # load and parse html + html = self.load(pyfile.url) + m = re.search(self.FILE_URL_PATTERN, html) + if m: + # file page + self.urls.append("http://www.mediafire.com/file/%s" % m.group(1)) + else: + # folder page + m = re.search(self.FOLDER_KEY_PATTERN, html) + if m: + folder_key = m.group(1) + self.logDebug("FOLDER KEY: %s" % folder_key) + + json_resp = json_loads(self.load( + "http://www.mediafire.com/api/folder/get_info.php?folder_key=%s&response_format=json&version=1" % folder_key)) + #self.logInfo(json_resp) + if json_resp['response']['result'] == "Success": + for link in json_resp['response']['folder_info']['files']: + self.urls.append("http://www.mediafire.com/file/%s" % link['quickkey']) + else: + self.fail(json_resp['response']['message']) + elif result == 1: + self.offline() + else: + self.urls.append(url) + + if not self.urls: + self.fail('Could not extract any links') diff --git a/pyload/plugins/crypter/Movie2kTo.py b/pyload/plugins/crypter/Movie2kTo.py new file mode 100644 index 000000000..b6a554758 --- /dev/null +++ b/pyload/plugins/crypter/Movie2kTo.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.DeadCrypter import DeadCrypter + + +class Movie2kTo(DeadCrypter): + __name__ = "Movie2kTo" + __type__ = "crypter" + __version__ = "0.51" + + __pattern__ = r'http://(?:www\.)?movie2k\.to/(.*)\.html' + + __description__ = """Movie2k.to decrypter plugin""" + __author_name__ = "4Christopher" + __author_mail__ = "4Christopher@gmx.de" diff --git a/pyload/plugins/crypter/MultiUpOrg.py b/pyload/plugins/crypter/MultiUpOrg.py new file mode 100644 index 000000000..96553a09a --- /dev/null +++ b/pyload/plugins/crypter/MultiUpOrg.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- + +import re +from urlparse import urljoin + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + + +class MultiUpOrg(SimpleCrypter): + __name__ = "MultiUpOrg" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'http://(?:www\.)?multiup\.org/(en|fr)/(?P<TYPE>project|download|miror)/\w+(/\w+)?' + + __description__ = """MultiUp.org crypter plugin""" + __author_name__ = "Walter Purcaro" + __author_mail__ = "vuolter@gmail.com" + + TITLE_PATTERN = r'<title>.*(Project|Projet|ownload|élécharger) (?P<title>.+?) (\(|- )' + + + def getLinks(self): + m_type = re.match(self.__pattern__, self.pyfile.url).group("TYPE") + + if m_type == "project": + pattern = r'\n(http://www\.multiup\.org/(?:en|fr)/download/.*)' + else: + pattern = r'style="width:97%;text-align:left".*\n.*href="(.*)"' + if m_type == "download": + dl_pattern = r'href="(.*)">.*\n.*<h5>DOWNLOAD</h5>' + miror_page = urljoin("http://www.multiup.org", re.search(dl_pattern, self.html).group(1)) + self.html = self.load(miror_page) + + return re.findall(pattern, self.html) diff --git a/pyload/plugins/crypter/MultiloadCz.py b/pyload/plugins/crypter/MultiloadCz.py new file mode 100644 index 000000000..37d0a1663 --- /dev/null +++ b/pyload/plugins/crypter/MultiloadCz.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- + +import re +from pyload.plugins.base.Crypter import Crypter + + +class MultiloadCz(Crypter): + __name__ = "MultiloadCz" + __type__ = "crypter" + __version__ = "0.4" + + __pattern__ = r'http://(?:[^/]*\.)?multiload.cz/(stahnout|slozka)/.*' + __config__ = [("usedHoster", "str", "Prefered hoster list (bar-separated) ", ""), + ("ignoredHoster", "str", "Ignored hoster list (bar-separated) ", "")] + + __description__ = """Multiload.cz decrypter plugin""" + __author_name__ = "zoidberg" + __author_mail__ = "zoidberg@mujmail.cz" + + FOLDER_PATTERN = r'<form action="" method="get"><textarea[^>]*>([^>]*)</textarea></form>' + LINK_PATTERN = r'<p class="manager-server"><strong>([^<]+)</strong></p><p class="manager-linky"><a href="([^"]+)">' + + + def decrypt(self, pyfile): + self.html = self.load(pyfile.url, decode=True) + + if re.match(self.__pattern__, pyfile.url).group(1) == "slozka": + m = re.search(self.FOLDER_PATTERN, self.html) + if m: + self.urls.extend(m.group(1).split()) + else: + m = re.findall(self.LINK_PATTERN, self.html) + if m: + prefered_set = set(self.getConfig("usedHoster").split('|')) + self.urls.extend([x[1] for x in m if x[0] in prefered_set]) + + if not self.urls: + ignored_set = set(self.getConfig("ignoredHoster").split('|')) + self.urls.extend([x[1] for x in m if x[0] not in ignored_set]) + + if not self.urls: + self.fail('Could not extract any links') diff --git a/pyload/plugins/crypter/MultiuploadCom.py b/pyload/plugins/crypter/MultiuploadCom.py new file mode 100644 index 000000000..148d76b8f --- /dev/null +++ b/pyload/plugins/crypter/MultiuploadCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.DeadCrypter import DeadCrypter + + +class MultiuploadCom(DeadCrypter): + __name__ = "MultiuploadCom" + __type__ = "crypter" + __version__ = "0.02" + + __pattern__ = r'http://(?:www\.)?multiupload\.(com|nl)/\w+' + + __description__ = """MultiUpload.com decrypter plugin""" + __author_name__ = "zoidberg" + __author_mail__ = "zoidberg@mujmail.cz" diff --git a/pyload/plugins/crypter/NCryptIn.py b/pyload/plugins/crypter/NCryptIn.py new file mode 100644 index 000000000..3289bddad --- /dev/null +++ b/pyload/plugins/crypter/NCryptIn.py @@ -0,0 +1,303 @@ +# -*- coding: utf-8 -*- + +import base64 +import binascii +import re + +from Crypto.Cipher import AES + +from pyload.plugins.base.Crypter import Crypter +from pyload.plugins.internal.CaptchaService import ReCaptcha + + +class NCryptIn(Crypter): + __name__ = "NCryptIn" + __type__ = "crypter" + __version__ = "1.32" + + __pattern__ = r'http://(?:www\.)?ncrypt.in/(?P<type>folder|link|frame)-([^/\?]+)' + + __description__ = """NCrypt.in decrypter plugin""" + __author_name__ = ("fragonib", "stickell") + __author_mail__ = ("fragonib[AT]yahoo[DOT]es", "l.stickell@yahoo.it") + + JK_KEY = "jk" + CRYPTED_KEY = "crypted" + + NAME_PATTERN = r'<meta name="description" content="(?P<N>[^"]+)"' + + + def setup(self): + self.package = None + self.html = None + self.cleanedHtml = None + self.links_source_order = ["cnl2", "rsdf", "ccf", "dlc", "web"] + self.protection_type = None + + def decrypt(self, pyfile): + # Init + self.package = pyfile.package() + package_links = [] + package_name = self.package.name + folder_name = self.package.folder + + # Deal with single links + if self.isSingleLink(): + package_links.extend(self.handleSingleLink()) + + # Deal with folders + else: + + # Request folder home + self.html = self.requestFolderHome() + self.cleanedHtml = self.removeHtmlCrap(self.html) + if not self.isOnline(): + self.offline() + + # Check for folder protection + if self.isProtected(): + self.html = self.unlockProtection() + self.cleanedHtml = self.removeHtmlCrap(self.html) + self.handleErrors() + + # Prepare package name and folder + (package_name, folder_name) = self.getPackageInfo() + + # Extract package links + for link_source_type in self.links_source_order: + package_links.extend(self.handleLinkSource(link_source_type)) + if package_links: # use only first source which provides links + break + package_links = set(package_links) + + # Pack and return links + if not package_links: + self.fail('Could not extract any links') + self.packages = [(package_name, package_links, folder_name)] + + def isSingleLink(self): + link_type = re.match(self.__pattern__, self.pyfile.url).group('type') + return link_type in ("link", "frame") + + def requestFolderHome(self): + return self.load(self.pyfile.url, decode=True) + + def removeHtmlCrap(self, content): + patterns = (r'(type="hidden".*?(name=".*?")?.*?value=".*?")', + r'display:none;">(.*?)</(div|span)>', + r'<div\s+class="jdownloader"(.*?)</div>', + r'<table class="global">(.*?)</table>', + r'<iframe\s+style="display:none(.*?)</iframe>') + for pattern in patterns: + rexpr = re.compile(pattern, re.DOTALL) + content = re.sub(rexpr, "", content) + return content + + def isOnline(self): + if "Your folder does not exist" in self.cleanedHtml: + self.logDebug("File not m") + return False + return True + + def isProtected(self): + form = re.search(r'<form.*?name.*?protected.*?>(.*?)</form>', self.cleanedHtml, re.DOTALL) + if form is not None: + content = form.group(1) + for keyword in ("password", "captcha"): + if keyword in content: + self.protection_type = keyword + self.logDebug("Links are %s protected" % self.protection_type) + return True + return False + + def getPackageInfo(self): + m = re.search(self.NAME_PATTERN, self.html) + if m: + name = folder = m.group('N').strip() + self.logDebug("Found name [%s] and folder [%s] in package info" % (name, folder)) + else: + name = self.package.name + folder = self.package.folder + self.logDebug("Package info not m, defaulting to pyfile name [%s] and folder [%s]" % (name, folder)) + return name, folder + + def unlockProtection(self): + + postData = {} + + form = re.search(r'<form name="protected"(.*?)</form>', self.cleanedHtml, re.DOTALL).group(1) + + # Submit package password + if "password" in form: + password = self.getPassword() + self.logDebug("Submitting password [%s] for protected links" % password) + postData['password'] = password + + # Resolve anicaptcha + if "anicaptcha" in form: + self.logDebug("Captcha protected") + captchaUri = re.search(r'src="(/temp/anicaptcha/[^"]+)', form).group(1) + captcha = self.decryptCaptcha("http://ncrypt.in" + captchaUri) + self.logDebug("Captcha resolved [%s]" % captcha) + postData['captcha'] = captcha + + # Resolve recaptcha + if "recaptcha" in form: + self.logDebug("ReCaptcha protected") + captcha_key = re.search(r'\?k=(.*?)"', form).group(1) + self.logDebug("Resolving ReCaptcha with key [%s]" % captcha_key) + recaptcha = ReCaptcha(self) + challenge, code = recaptcha.challenge(captcha_key) + postData['recaptcha_challenge_field'] = challenge + postData['recaptcha_response_field'] = code + + # Resolve circlecaptcha + if "circlecaptcha" in form: + self.logDebug("CircleCaptcha protected") + captcha_img_url = "http://ncrypt.in/classes/captcha/circlecaptcha.php" + coords = self.decryptCaptcha(captcha_img_url, forceUser=True, imgtype="png", result_type='positional') + self.logDebug("Captcha resolved, coords [%s]" % coords) + postData['circle.x'] = coords[0] + postData['circle.y'] = coords[1] + + # Unlock protection + postData['submit_protected'] = 'Continue to folder' + return self.load(self.pyfile.url, post=postData, decode=True) + + def handleErrors(self): + if self.protection_type == "password": + if "This password is invalid!" in self.cleanedHtml: + self.logDebug("Incorrect password, please set right password on 'Edit package' form and retry") + self.fail("Incorrect password, please set right password on 'Edit package' form and retry") + + if self.protection_type == "captcha": + if "The securitycheck was wrong!" in self.cleanedHtml: + self.logDebug("Invalid captcha, retrying") + self.invalidCaptcha() + self.retry() + else: + self.correctCaptcha() + + def handleLinkSource(self, link_source_type): + # Check for JS engine + require_js_engine = link_source_type in ("cnl2", "rsdf", "ccf", "dlc") + if require_js_engine and not self.js: + self.logDebug("No JS engine available, skip %s links" % link_source_type) + return [] + + # Select suitable handler + if link_source_type == 'single': + return self.handleSingleLink() + if link_source_type == 'cnl2': + return self.handleCNL2() + elif link_source_type in ("rsdf", "ccf", "dlc"): + return self.handleContainer(link_source_type) + elif link_source_type == "web": + return self.handleWebLinks() + else: + self.fail('unknown source type "%s" (this is probably a bug)' % link_source_type) + + def handleSingleLink(self): + + self.logDebug("Handling Single link") + package_links = [] + + # Decrypt single link + decrypted_link = self.decryptLink(self.pyfile.url) + if decrypted_link: + package_links.append(decrypted_link) + + return package_links + + def handleCNL2(self): + + self.logDebug("Handling CNL2 links") + package_links = [] + + if 'cnl2_output' in self.cleanedHtml: + try: + (vcrypted, vjk) = self._getCipherParams() + for (crypted, jk) in zip(vcrypted, vjk): + package_links.extend(self._getLinks(crypted, jk)) + except: + self.fail("Unable to decrypt CNL2 links") + + return package_links + + def handleContainers(self): + + self.logDebug("Handling Container links") + package_links = [] + + pattern = r"/container/(rsdf|dlc|ccf)/([a-z0-9]+)" + containersLinks = re.findall(pattern, self.html) + self.logDebug("Decrypting %d Container links" % len(containersLinks)) + for containerLink in containersLinks: + link = "http://ncrypt.in/container/%s/%s.%s" % (containerLink[0], containerLink[1], containerLink[0]) + package_links.append(link) + + return package_links + + def handleWebLinks(self): + + self.logDebug("Handling Web links") + pattern = r"(http://ncrypt\.in/link-.*?=)" + links = re.findall(pattern, self.html) + + package_links = [] + self.logDebug("Decrypting %d Web links" % len(links)) + for i, link in enumerate(links): + self.logDebug("Decrypting Web link %d, %s" % (i + 1, link)) + decrypted_link = self.decrypt(link) + if decrypted_link: + package_links.append(decrypted_link) + + return package_links + + def decryptLink(self, link): + try: + url = link.replace("link-", "frame-") + link = self.load(url, just_header=True)['location'] + return link + except Exception, detail: + self.logDebug("Error decrypting link %s, %s" % (link, detail)) + + def _getCipherParams(self): + + pattern = r'<input.*?name="%s".*?value="(.*?)"' + + # Get jk + jk_re = pattern % NCryptIn.JK_KEY + vjk = re.findall(jk_re, self.html) + + # Get crypted + crypted_re = pattern % NCryptIn.CRYPTED_KEY + vcrypted = re.findall(crypted_re, self.html) + + # Log and return + self.logDebug("Detected %d crypted blocks" % len(vcrypted)) + return vcrypted, vjk + + def _getLinks(self, crypted, jk): + # Get key + jreturn = self.js.eval("%s f()" % jk) + self.logDebug("JsEngine returns value [%s]" % jreturn) + key = binascii.unhexlify(jreturn) + + # Decode crypted + crypted = base64.standard_b64decode(crypted) + + # Decrypt + Key = key + IV = key + obj = AES.new(Key, AES.MODE_CBC, IV) + text = obj.decrypt(crypted) + + # Extract links + text = text.replace("\x00", "").replace("\r", "") + links = text.split("\n") + links = filter(lambda x: x != "", links) + + # Log and return + self.logDebug("Block has %d links" % len(links)) + return links diff --git a/pyload/plugins/crypter/NetfolderIn.py b/pyload/plugins/crypter/NetfolderIn.py new file mode 100644 index 000000000..858755e5c --- /dev/null +++ b/pyload/plugins/crypter/NetfolderIn.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + + +class NetfolderIn(SimpleCrypter): + __name__ = "NetfolderIn" + __type__ = "crypter" + __version__ = "0.6" + + __pattern__ = r'http://(?:www\.)?netfolder.in/((?P<id1>\w+)/\w+|folder.php\?folder_id=(?P<id2>\w+))' + + __description__ = """NetFolder.in decrypter plugin""" + __author_name__ = ("RaNaN", "fragonib") + __author_mail__ = ("RaNaN@pyload.org", "fragonib[AT]yahoo[DOT]es") + + TITLE_PATTERN = r'<div class="Text">Inhalt des Ordners <span(.*)>(?P<title>.+)</span></div>' + + + def decrypt(self, pyfile): + # Request package + self.html = self.load(pyfile.url) + + # Check for password protection + if self.isPasswordProtected(): + self.html = self.submitPassword() + if not self.html: + self.fail("Incorrect password, please set right password on Add package form and retry") + + # Get package name and folder + (package_name, folder_name) = self.getPackageNameAndFolder() + + # Get package links + package_links = self.getLinks() + + # Set package + self.packages = [(package_name, package_links, folder_name)] + + def isPasswordProtected(self): + if '<input type="password" name="password"' in self.html: + self.logDebug("Links are password protected") + return True + return False + + def submitPassword(self): + # Gather data + try: + m = re.match(self.__pattern__, self.pyfile.url) + id = max(m.group('id1'), m.group('id2')) + except AttributeError: + self.logDebug("Unable to get package id from url [%s]" % self.pyfile.url) + return + url = "http://netfolder.in/folder.php?folder_id=" + id + password = self.getPassword() + + # Submit package password + post = {'password': password, 'save': 'Absenden'} + self.logDebug("Submitting password [%s] for protected links with id [%s]" % (password, id)) + html = self.load(url, {}, post) + + # Check for invalid password + if '<div class="InPage_Error">' in html: + self.logDebug("Incorrect password, please set right password on Edit package form and retry") + return None + + return html + + def getLinks(self): + links = re.search(r'name="list" value="(.*?)"', self.html).group(1).split(",") + self.logDebug("Package has %d links" % len(links)) + return links diff --git a/pyload/plugins/crypter/NosvideoCom.py b/pyload/plugins/crypter/NosvideoCom.py new file mode 100644 index 000000000..e1c9e2c55 --- /dev/null +++ b/pyload/plugins/crypter/NosvideoCom.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + + +class NosvideoCom(SimpleCrypter): + __name__ = "NosvideoCom" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'http://(?:www\.)?nosvideo\.com/\?v=\w+' + + __description__ = """Nosvideo.com decrypter plugin""" + __author_name__ = "igel" + __author_mail__ = "igelkun@myopera.com" + + LINK_PATTERN = r'href="(http://(?:w{3}\.)?nosupload.com/\?d=\w+)"' + TITLE_PATTERN = r'<[tT]itle>Watch (?P<title>.+)</[tT]itle>' diff --git a/pyload/plugins/crypter/OneKhDe.py b/pyload/plugins/crypter/OneKhDe.py new file mode 100644 index 000000000..b39504628 --- /dev/null +++ b/pyload/plugins/crypter/OneKhDe.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.utils import html_unescape +from pyload.plugins.base.Crypter import Crypter + + +class OneKhDe(Crypter): + __name__ = "OneKhDe" + __type__ = "crypter" + __version__ = "0.1" + + __pattern__ = r'http://(?:www\.)?1kh.de/f/' + + __description__ = """1kh.de decrypter plugin""" + __author_name__ = "spoob" + __author_mail__ = "spoob@pyload.org" + + + def __init__(self, parent): + Crypter.__init__(self, parent) + self.parent = parent + self.html = None + + def file_exists(self): + """ returns True or False + """ + return True + + def proceed(self, url, location): + url = self.parent.url + self.html = self.load(url) + link_ids = re.findall(r"<a id=\"DownloadLink_(\d*)\" href=\"http://1kh.de/", self.html) + for id in link_ids: + new_link = html_unescape(re.search("width=\"100%\" src=\"(.*)\"></iframe>", self.load("http://1kh.de/l/" + id)).group(1)) + self.urls.append(new_link) diff --git a/pyload/plugins/crypter/OronComFolder.py b/pyload/plugins/crypter/OronComFolder.py new file mode 100644 index 000000000..9b5fb3959 --- /dev/null +++ b/pyload/plugins/crypter/OronComFolder.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.DeadCrypter import DeadCrypter + + +class OronComFolder(DeadCrypter): + __name__ = "OronComFolder" + __type__ = "crypter" + __version__ = "0.11" + + __pattern__ = r'http://(?:www\.)?oron.com/folder/\w+' + + __description__ = """Oron.com folder decrypter plugin""" + __author_name__ = "DHMH" + __author_mail__ = "webmaster@pcProfil.de" diff --git a/pyload/plugins/crypter/PastebinCom.py b/pyload/plugins/crypter/PastebinCom.py new file mode 100644 index 000000000..8e394ac3a --- /dev/null +++ b/pyload/plugins/crypter/PastebinCom.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + + +class PastebinCom(SimpleCrypter): + __name__ = "PastebinCom" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'http://(?:www\.)?pastebin\.com/\w+' + + __description__ = """Pastebin.com decrypter plugin""" + __author_name__ = "stickell" + __author_mail__ = "l.stickell@yahoo.it" + + LINK_PATTERN = r'<div class="de\d+">(https?://[^ <]+)(?:[^<]*)</div>' + TITLE_PATTERN = r'<div class="paste_box_line1" title="(?P<title>[^"]+)">' diff --git a/pyload/plugins/crypter/QuickshareCzFolder.py b/pyload/plugins/crypter/QuickshareCzFolder.py new file mode 100644 index 000000000..1e4adec2c --- /dev/null +++ b/pyload/plugins/crypter/QuickshareCzFolder.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- + +import re +from pyload.plugins.base.Crypter import Crypter + + +class QuickshareCzFolder(Crypter): + __name__ = "QuickshareCzFolder" + __type__ = "crypter" + __version__ = "0.1" + + __pattern__ = r'http://(?:www\.)?quickshare.cz/slozka-\d+.*' + + __description__ = """Quickshare.cz folder decrypter plugin""" + __author_name__ = "zoidberg" + __author_mail__ = "zoidberg@mujmail.cz" + + FOLDER_PATTERN = r'<textarea[^>]*>(.*?)</textarea>' + LINK_PATTERN = r'(http://www.quickshare.cz/\S+)' + + + def decrypt(self, pyfile): + html = self.load(pyfile.url) + + m = re.search(self.FOLDER_PATTERN, html, re.DOTALL) + if m is None: + self.fail("Parse error (FOLDER)") + self.urls.extend(re.findall(self.LINK_PATTERN, m.group(1))) + + if not self.urls: + self.fail('Could not extract any links') diff --git a/pyload/plugins/crypter/RSLayerCom.py b/pyload/plugins/crypter/RSLayerCom.py new file mode 100644 index 000000000..ded550a50 --- /dev/null +++ b/pyload/plugins/crypter/RSLayerCom.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.DeadCrypter import DeadCrypter + + +class RSLayerCom(DeadCrypter): + __name__ = "RSLayerCom" + __type__ = "crypter" + __version__ = "0.21" + + __pattern__ = r'http://(?:www\.)?rs-layer.com/directory-' + + __description__ = """RS-Layer.com decrypter plugin""" + __author_name__ = "hzpz" + __author_mail__ = None diff --git a/pyload/plugins/crypter/RelinkUs.py b/pyload/plugins/crypter/RelinkUs.py new file mode 100644 index 000000000..2c48f2078 --- /dev/null +++ b/pyload/plugins/crypter/RelinkUs.py @@ -0,0 +1,263 @@ +# -*- coding: utf-8 -*- + +import base64 +import binascii +import re +import os + +from Crypto.Cipher import AES +from pyload.plugins.base.Crypter import Crypter + + +class RelinkUs(Crypter): + __name__ = "RelinkUs" + __type__ = "crypter" + __version__ = "3.0" + + __pattern__ = r'http://(?:www\.)?relink.us/(f/|((view|go).php\?id=))(?P<id>.+)' + + __description__ = """Relink.us decrypter plugin""" + __author_name__ = "fragonib" + __author_mail__ = "fragonib[AT]yahoo[DOT]es" + + # Constants + PREFERRED_LINK_SOURCES = ["cnl2", "dlc", "web"] + + OFFLINE_TOKEN = r'<title>Tattooside' + PASSWORD_TOKEN = r'container_password\.php' + PASSWORD_ERROR_ROKEN = r'You have entered an incorrect password' + PASSWORD_SUBMIT_URL = r'http://www\.relink\.us/container_password\.php' + CAPTCHA_TOKEN = r'container_captcha\.php' + CAPTCHA_ERROR_ROKEN = r'You have solved the captcha wrong' + CAPTCHA_IMG_URL = r'http://www\.relink\.us/core/captcha/circlecaptcha\.php' + CAPTCHA_SUBMIT_URL = r'http://www\.relink\.us/container_captcha\.php' + FILE_TITLE_REGEX = r'<th>Title</th><td><i>(.*)</i></td></tr>' + FILE_NOTITLE = r'No title' + + CNL2_FORM_REGEX = r'<form id="cnl_form-(.*?)</form>' + CNL2_FORMINPUT_REGEX = r'<input.*?name="%s".*?value="(.*?)"' + CNL2_JK_KEY = "jk" + CNL2_CRYPTED_KEY = "crypted" + DLC_LINK_REGEX = r'<a href=".*?" class="dlc_button" target="_blank">' + DLC_DOWNLOAD_URL = r'http://www\.relink\.us/download\.php' + WEB_FORWARD_REGEX = r"getFile\('(?P<link>.+)'\)" + WEB_FORWARD_URL = r'http://www\.relink\.us/frame\.php' + WEB_LINK_REGEX = r'<iframe name="Container" height="100%" frameborder="no" width="100%" src="(?P<link>.+)"></iframe>' + + + def setup(self): + self.fileid = None + self.package = None + self.password = None + self.html = None + self.captcha = False + + def decrypt(self, pyfile): + # Init + self.initPackage(pyfile) + + # Request package + self.requestPackage() + + # Check for online + if not self.isOnline(): + self.offline() + + # Check for protection + if self.isPasswordProtected(): + self.unlockPasswordProtection() + self.handleErrors() + + if self.isCaptchaProtected(): + self.captcha = True + self.unlockCaptchaProtection() + self.handleErrors() + + # Get package name and folder + (package_name, folder_name) = self.getPackageInfo() + + # Extract package links + package_links = [] + for sources in self.PREFERRED_LINK_SOURCES: + package_links.extend(self.handleLinkSource(sources)) + if package_links: # use only first source which provides links + break + package_links = set(package_links) + + # Pack + if package_links: + self.packages = [(package_name, package_links, folder_name)] + else: + self.fail('Could not extract any links') + + def initPackage(self, pyfile): + self.fileid = re.match(self.__pattern__, pyfile.url).group('id') + self.package = pyfile.package() + self.password = self.getPassword() + + def requestPackage(self): + self.html = self.load(self.pyfile.url, decode=True) + + def isOnline(self): + if self.OFFLINE_TOKEN in self.html: + self.logDebug("File not found") + return False + return True + + def isPasswordProtected(self): + if self.PASSWORD_TOKEN in self.html: + self.logDebug("Links are password protected") + return True + + def isCaptchaProtected(self): + if self.CAPTCHA_TOKEN in self.html: + self.logDebug("Links are captcha protected") + return True + return False + + def unlockPasswordProtection(self): + self.logDebug("Submitting password [%s] for protected links" % self.password) + passwd_url = self.PASSWORD_SUBMIT_URL + "?id=%s" % self.fileid + passwd_data = {'id': self.fileid, 'password': self.password, 'pw': 'submit'} + self.html = self.load(passwd_url, post=passwd_data, decode=True) + + def unlockCaptchaProtection(self): + self.logDebug("Request user positional captcha resolving") + captcha_img_url = self.CAPTCHA_IMG_URL + "?id=%s" % self.fileid + coords = self.decryptCaptcha(captcha_img_url, forceUser=True, imgtype="png", result_type='positional') + self.logDebug("Captcha resolved, coords [%s]" % coords) + captcha_post_url = self.CAPTCHA_SUBMIT_URL + "?id=%s" % self.fileid + captcha_post_data = {'button.x': coords[0], 'button.y': coords[1], 'captcha': 'submit'} + self.html = self.load(captcha_post_url, post=captcha_post_data, decode=True) + + def getPackageInfo(self): + name = folder = None + + # Try to get info from web + m = re.search(self.FILE_TITLE_REGEX, self.html) + if m is not None: + title = m.group(1).strip() + if not self.FILE_NOTITLE in title: + name = folder = title + self.logDebug("Found name [%s] and folder [%s] in package info" % (name, folder)) + + # Fallback to defaults + if not name or not folder: + name = self.package.name + folder = self.package.folder + self.logDebug("Package info not found, defaulting to pyfile name [%s] and folder [%s]" % (name, folder)) + + # Return package info + return name, folder + + def handleErrors(self): + if self.PASSWORD_ERROR_ROKEN in self.html: + msg = "Incorrect password, please set right password on 'Edit package' form and retry" + self.logDebug(msg) + self.fail(msg) + + if self.captcha: + if self.CAPTCHA_ERROR_ROKEN in self.html: + self.logDebug("Invalid captcha, retrying") + self.invalidCaptcha() + self.retry() + else: + self.correctCaptcha() + + def handleLinkSource(self, source): + if source == 'cnl2': + return self.handleCNL2Links() + elif source == 'dlc': + return self.handleDLCLinks() + elif source == 'web': + return self.handleWEBLinks() + else: + self.fail('Unknown source [%s] (this is probably a bug)' % source) + + def handleCNL2Links(self): + self.logDebug("Search for CNL2 links") + package_links = [] + m = re.search(self.CNL2_FORM_REGEX, self.html, re.DOTALL) + if m is not None: + cnl2_form = m.group(1) + try: + (vcrypted, vjk) = self._getCipherParams(cnl2_form) + for (crypted, jk) in zip(vcrypted, vjk): + package_links.extend(self._getLinks(crypted, jk)) + except: + self.logDebug("Unable to decrypt CNL2 links") + return package_links + + def handleDLCLinks(self): + self.logDebug("Search for DLC links") + package_links = [] + m = re.search(self.DLC_LINK_REGEX, self.html) + if m is not None: + container_url = self.DLC_DOWNLOAD_URL + "?id=%s&dlc=1" % self.fileid + self.logDebug("Downloading DLC container link [%s]" % container_url) + try: + dlc = self.load(container_url) + dlc_filename = self.fileid + ".dlc" + dlc_filepath = os.path.join(self.config['general']['download_folder'], dlc_filename) + f = open(dlc_filepath, "wb") + f.write(dlc) + f.close() + package_links.append(dlc_filepath) + except: + self.logDebug("Unable to download DLC container") + return package_links + + def handleWEBLinks(self): + self.logDebug("Search for WEB links") + package_links = [] + fw_params = re.findall(self.WEB_FORWARD_REGEX, self.html) + self.logDebug("Decrypting %d Web links" % len(fw_params)) + for index, fw_param in enumerate(fw_params): + try: + fw_url = self.WEB_FORWARD_URL + "?%s" % fw_param + self.logDebug("Decrypting Web link %d, %s" % (index + 1, fw_url)) + fw_response = self.load(fw_url, decode=True) + dl_link = re.search(self.WEB_LINK_REGEX, fw_response).group('link') + package_links.append(dl_link) + except Exception, detail: + self.logDebug("Error decrypting Web link %s, %s" % (index, detail)) + self.setWait(4) + self.wait() + return package_links + + def _getCipherParams(self, cnl2_form): + # Get jk + jk_re = self.CNL2_FORMINPUT_REGEX % self.CNL2_JK_KEY + vjk = re.findall(jk_re, cnl2_form, re.IGNORECASE) + + # Get crypted + crypted_re = self.CNL2_FORMINPUT_REGEX % RelinkUs.CNL2_CRYPTED_KEY + vcrypted = re.findall(crypted_re, cnl2_form, re.IGNORECASE) + + # Log and return + self.logDebug("Detected %d crypted blocks" % len(vcrypted)) + return vcrypted, vjk + + def _getLinks(self, crypted, jk): + # Get key + jreturn = self.js.eval("%s f()" % jk) + self.logDebug("JsEngine returns value [%s]" % jreturn) + key = binascii.unhexlify(jreturn) + + # Decode crypted + crypted = base64.standard_b64decode(crypted) + + # Decrypt + Key = key + IV = key + obj = AES.new(Key, AES.MODE_CBC, IV) + text = obj.decrypt(crypted) + + # Extract links + text = text.replace("\x00", "").replace("\r", "") + links = text.split("\n") + links = filter(lambda x: x != "", links) + + # Log and return + self.logDebug("Package has %d links" % len(links)) + return links diff --git a/pyload/plugins/crypter/SafelinkingNet.py b/pyload/plugins/crypter/SafelinkingNet.py new file mode 100644 index 000000000..4129efca3 --- /dev/null +++ b/pyload/plugins/crypter/SafelinkingNet.py @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- + +import re + +from pycurl import FOLLOWLOCATION + +from BeautifulSoup import BeautifulSoup + +from pyload.utils import json_loads +from pyload.plugins.base.Crypter import Crypter +from pyload.plugins.internal.CaptchaService import SolveMedia + + +class SafelinkingNet(Crypter): + __name__ = "SafelinkingNet" + __type__ = "crypter" + __version__ = "0.1" + + __pattern__ = r'https?://(?:www\.)?safelinking.net/([pd])/\w+' + + __description__ = """Safelinking.net decrypter plugin""" + __author_name__ = "quareevo" + __author_mail__ = "quareevo@arcor.de" + + SOLVEMEDIA_PATTERN = "solvemediaApiKey = '([\w\.\-_]+)';" + + + def decrypt(self, pyfile): + url = pyfile.url + if re.match(self.__pattern__, url).group(1) == "d": + self.req.http.c.setopt(FOLLOWLOCATION, 0) + self.load(url) + m = re.search("^Location: (.+)$", self.req.http.header, re.MULTILINE) + if m: + self.urls = [m.group(1)] + else: + self.fail("Couldn't find forwarded Link") + + else: + password = "" + postData = {"post-protect": "1"} + + self.html = self.load(url) + + if "link-password" in self.html: + password = pyfile.package().password + postData['link-password'] = password + + if "altcaptcha" in self.html: + for _ in xrange(5): + m = re.search(self.SOLVEMEDIA_PATTERN, self.html) + if m: + captchaKey = m.group(1) + captcha = SolveMedia(self) + captchaProvider = "Solvemedia" + else: + self.fail("Error parsing captcha") + + challenge, response = captcha.challenge(captchaKey) + postData['adcopy_challenge'] = challenge + postData['adcopy_response'] = response + + self.html = self.load(url, post=postData) + if "The password you entered was incorrect" in self.html: + self.fail("Incorrect Password") + if not "The CAPTCHA code you entered was wrong" in self.html: + break + + pyfile.package().password = "" + soup = BeautifulSoup(self.html) + scripts = soup.findAll("script") + for s in scripts: + if "d_links" in s.text: + break + m = re.search('d_links":(\[.*?\])', s.text) + if m: + linkDict = json_loads(m.group(1)) + for link in linkDict: + if not "http://" in link['full']: + self.urls.append("https://safelinking.net/d/" + link['full']) + else: + self.urls.append(link['full']) diff --git a/pyload/plugins/crypter/SecuredIn.py b/pyload/plugins/crypter/SecuredIn.py new file mode 100644 index 000000000..fc2667586 --- /dev/null +++ b/pyload/plugins/crypter/SecuredIn.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.DeadCrypter import DeadCrypter + + +class SecuredIn(DeadCrypter): + __name__ = "SecuredIn" + __type__ = "crypter" + __version__ = "0.21" + + __pattern__ = r'http://(?:www\.)?secured\.in/download-[\d]+-[\w]{8}\.html' + + __description__ = """Secured.in decrypter plugin""" + __author_name__ = "mkaay" + __author_mail__ = "mkaay@mkaay.de" diff --git a/pyload/plugins/crypter/ShareLinksBiz.py b/pyload/plugins/crypter/ShareLinksBiz.py new file mode 100644 index 000000000..75c3db302 --- /dev/null +++ b/pyload/plugins/crypter/ShareLinksBiz.py @@ -0,0 +1,269 @@ +# -*- coding: utf-8 -*- + +import base64 +import binascii +import re + +from Crypto.Cipher import AES +from pyload.plugins.base.Crypter import Crypter + + +class ShareLinksBiz(Crypter): + __name__ = "ShareLinksBiz" + __type__ = "crypter" + __version__ = "1.13" + + __pattern__ = r'http://(?:www\.)?(share-links|s2l)\.biz/(?P<ID>_?\w+)' + + __description__ = """Share-Links.biz decrypter plugin""" + __author_name__ = "fragonib" + __author_mail__ = "fragonib[AT]yahoo[DOT]es" + + + def setup(self): + self.baseUrl = None + self.fileId = None + self.package = None + self.html = None + self.captcha = False + + def decrypt(self, pyfile): + # Init + self.initFile(pyfile) + + # Request package + url = self.baseUrl + '/' + self.fileId + self.html = self.load(url, decode=True) + + # Unblock server (load all images) + self.unblockServer() + + # Check for protection + if self.isPasswordProtected(): + self.unlockPasswordProtection() + self.handleErrors() + + if self.isCaptchaProtected(): + self.captcha = True + self.unlockCaptchaProtection() + self.handleErrors() + + # Extract package links + package_links = [] + package_links.extend(self.handleWebLinks()) + package_links.extend(self.handleContainers()) + package_links.extend(self.handleCNL2()) + package_links = set(package_links) + + # Get package info + package_name, package_folder = self.getPackageInfo() + + # Pack + self.packages = [(package_name, package_links, package_folder)] + + def initFile(self, pyfile): + url = pyfile.url + if 's2l.biz' in url: + url = self.load(url, just_header=True)['location'] + self.baseUrl = "http://www.%s.biz" % re.match(self.__pattern__, url).group(1) + self.fileId = re.match(self.__pattern__, url).group('ID') + self.package = pyfile.package() + + def isOnline(self): + if "No usable content was found" in self.html: + self.logDebug("File not found") + return False + return True + + def isPasswordProtected(self): + if re.search(r'''<form.*?id="passwordForm".*?>''', self.html): + self.logDebug("Links are protected") + return True + return False + + def isCaptchaProtected(self): + if '<map id="captchamap"' in self.html: + self.logDebug("Links are captcha protected") + return True + return False + + def unblockServer(self): + imgs = re.findall(r"(/template/images/.*?\.gif)", self.html) + for img in imgs: + self.load(self.baseUrl + img) + + def unlockPasswordProtection(self): + password = self.getPassword() + self.logDebug("Submitting password [%s] for protected links" % password) + post = {"password": password, 'login': 'Submit form'} + url = self.baseUrl + '/' + self.fileId + self.html = self.load(url, post=post, decode=True) + + def unlockCaptchaProtection(self): + # Get captcha map + captchaMap = self._getCaptchaMap() + self.logDebug("Captcha map with [%d] positions" % len(captchaMap.keys())) + + # Request user for captcha coords + m = re.search(r'<img src="/captcha.gif\?d=(.*?)&PHPSESSID=(.*?)&legend=1"', self.html) + captchaUrl = self.baseUrl + '/captcha.gif?d=%s&PHPSESSID=%s' % (m.group(1), m.group(2)) + self.logDebug("Waiting user for correct position") + coords = self.decryptCaptcha(captchaUrl, forceUser=True, imgtype="gif", result_type='positional') + self.logDebug("Captcha resolved, coords [%s]" % coords) + + # Resolve captcha + href = self._resolveCoords(coords, captchaMap) + if href is None: + self.logDebug("Invalid captcha resolving, retrying") + self.invalidCaptcha() + self.setWait(5, False) + self.wait() + self.retry() + url = self.baseUrl + href + self.html = self.load(url, decode=True) + + def _getCaptchaMap(self): + mapp = {} + for m in re.finditer(r'<area shape="rect" coords="(.*?)" href="(.*?)"', self.html): + rect = eval('(' + m.group(1) + ')') + href = m.group(2) + mapp[rect] = href + return mapp + + def _resolveCoords(self, coords, captchaMap): + x, y = coords + for rect, href in captchaMap.items(): + x1, y1, x2, y2 = rect + if (x >= x1 and x <= x2) and (y >= y1 and y <= y2): + return href + + def handleErrors(self): + if "The inserted password was wrong" in self.html: + self.logDebug("Incorrect password, please set right password on 'Edit package' form and retry") + self.fail("Incorrect password, please set right password on 'Edit package' form and retry") + + if self.captcha: + if "Your choice was wrong" in self.html: + self.logDebug("Invalid captcha, retrying") + self.invalidCaptcha() + self.setWait(5) + self.wait() + self.retry() + else: + self.correctCaptcha() + + def getPackageInfo(self): + name = folder = None + + # Extract from web package header + title_re = r'<h2><img.*?/>(.*)</h2>' + m = re.search(title_re, self.html, re.DOTALL) + if m is not None: + title = m.group(1).strip() + if 'unnamed' not in title: + name = folder = title + self.logDebug("Found name [%s] and folder [%s] in package info" % (name, folder)) + + # Fallback to defaults + if not name or not folder: + name = self.package.name + folder = self.package.folder + self.logDebug("Package info not found, defaulting to pyfile name [%s] and folder [%s]" % (name, folder)) + + # Return package info + return name, folder + + def handleWebLinks(self): + package_links = [] + self.logDebug("Handling Web links") + + #@TODO: Gather paginated web links + pattern = r"javascript:_get\('(.*?)', \d+, ''\)" + ids = re.findall(pattern, self.html) + self.logDebug("Decrypting %d Web links" % len(ids)) + for i, ID in enumerate(ids): + try: + self.logDebug("Decrypting Web link %d, [%s]" % (i + 1, ID)) + dwLink = self.baseUrl + "/get/lnk/" + ID + response = self.load(dwLink) + code = re.search(r'frm/(\d+)', response).group(1) + fwLink = self.baseUrl + "/get/frm/" + code + response = self.load(fwLink) + jscode = re.search(r'<script language="javascript">\s*eval\((.*)\)\s*</script>', response, + re.DOTALL).group(1) + jscode = self.js.eval("f = %s" % jscode) + jslauncher = "window=''; parent={frames:{Main:{location:{href:''}}},location:''}; %s; parent.frames.Main.location.href" + dlLink = self.js.eval(jslauncher % jscode) + self.logDebug("JsEngine returns value [%s] for redirection link" % dlLink) + package_links.append(dlLink) + except Exception, detail: + self.logDebug("Error decrypting Web link [%s], %s" % (ID, detail)) + return package_links + + def handleContainers(self): + package_links = [] + self.logDebug("Handling Container links") + + pattern = r"javascript:_get\('(.*?)', 0, '(rsdf|ccf|dlc)'\)" + containersLinks = re.findall(pattern, self.html) + self.logDebug("Decrypting %d Container links" % len(containersLinks)) + for containerLink in containersLinks: + link = "%s/get/%s/%s" % (self.baseUrl, containerLink[1], containerLink[0]) + package_links.append(link) + return package_links + + def handleCNL2(self): + package_links = [] + self.logDebug("Handling CNL2 links") + + if '/lib/cnl2/ClicknLoad.swf' in self.html: + try: + (crypted, jk) = self._getCipherParams() + package_links.extend(self._getLinks(crypted, jk)) + except: + self.fail("Unable to decrypt CNL2 links") + return package_links + + def _getCipherParams(self): + # Request CNL2 + code = re.search(r'ClicknLoad.swf\?code=(.*?)"', self.html).group(1) + url = "%s/get/cnl2/%s" % (self.baseUrl, code) + response = self.load(url) + params = response.split(";;") + + # Get jk + strlist = list(base64.standard_b64decode(params[1])) + strlist.reverse() + jk = ''.join(strlist) + + # Get crypted + strlist = list(base64.standard_b64decode(params[2])) + strlist.reverse() + crypted = ''.join(strlist) + + # Log and return + return crypted, jk + + def _getLinks(self, crypted, jk): + # Get key + jreturn = self.js.eval("%s f()" % jk) + self.logDebug("JsEngine returns value [%s]" % jreturn) + key = binascii.unhexlify(jreturn) + + # Decode crypted + crypted = base64.standard_b64decode(crypted) + + # Decrypt + Key = key + IV = key + obj = AES.new(Key, AES.MODE_CBC, IV) + text = obj.decrypt(crypted) + + # Extract links + text = text.replace("\x00", "").replace("\r", "") + links = text.split("\n") + links = filter(lambda x: x != "", links) + + # Log and return + self.logDebug("Block has %d links" % len(links)) + return links diff --git a/pyload/plugins/crypter/ShareRapidComFolder.py b/pyload/plugins/crypter/ShareRapidComFolder.py new file mode 100644 index 000000000..c8e95be1c --- /dev/null +++ b/pyload/plugins/crypter/ShareRapidComFolder.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + + +class ShareRapidComFolder(SimpleCrypter): + __name__ = "ShareRapidComFolder" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'http://(?:www\.)?((share(-?rapid\.(biz|com|cz|info|eu|net|org|pl|sk)|-(central|credit|free|net)\.cz|-ms\.net)|(s-?rapid|rapids)\.(cz|sk))|(e-stahuj|mediatack|premium-rapidshare|rapidshare-premium|qiuck)\.cz|kadzet\.com|stahuj-zdarma\.eu|strelci\.net|universal-share\.com)/(slozka/.+)' + + __description__ = """Share-Rapid.com folder decrypter plugin""" + __author_name__ = "zoidberg" + __author_mail__ = "zoidberg@mujmail.cz" + + LINK_PATTERN = r'<td class="soubor"[^>]*><a href="([^"]+)">' diff --git a/pyload/plugins/crypter/SpeedLoadOrgFolder.py b/pyload/plugins/crypter/SpeedLoadOrgFolder.py new file mode 100644 index 000000000..fff119a93 --- /dev/null +++ b/pyload/plugins/crypter/SpeedLoadOrgFolder.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.DeadCrypter import DeadCrypter + + +class SpeedLoadOrgFolder(DeadCrypter): + __name__ = "SpeedLoadOrgFolder" + __type__ = "crypter" + __version__ = "0.3" + + __pattern__ = r'http://(?:www\.)?speedload\.org/(\d+~f$|folder/\d+/)' + + __description__ = """Speedload decrypter plugin""" + __author_name__ = "stickell" + __author_mail__ = "l.stickell@yahoo.it" diff --git a/pyload/plugins/crypter/StealthTo.py b/pyload/plugins/crypter/StealthTo.py new file mode 100644 index 000000000..24489a1b3 --- /dev/null +++ b/pyload/plugins/crypter/StealthTo.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.DeadCrypter import DeadCrypter + + +class StealthTo(DeadCrypter): + __name__ = "StealthTo" + __type__ = "crypter" + __version__ = "0.2" + + __pattern__ = r'http://(?:www\.)?stealth\.to/folder/.+' + + __description__ = """Stealth.to decrypter plugin""" + __author_name__ = "spoob" + __author_mail__ = "spoob@pyload.org" diff --git a/pyload/plugins/crypter/TnyCz.py b/pyload/plugins/crypter/TnyCz.py new file mode 100644 index 000000000..879941ba4 --- /dev/null +++ b/pyload/plugins/crypter/TnyCz.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + +import re + + +class TnyCz(SimpleCrypter): + __name__ = "TnyCz" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'http://(?:www\.)?tny\.cz/\w+' + + __description__ = """Tny.cz decrypter plugin""" + __author_name__ = "Walter Purcaro" + __author_mail__ = "vuolter@gmail.com" + + TITLE_PATTERN = r'<title>(?P<title>.+) - .+</title>' + + + def getLinks(self): + m = re.search(r'<a id=\'save_paste\' href="(.+save\.php\?hash=.+)">', self.html) + return re.findall(".+", self.load(m.group(1), decode=True)) if m else None diff --git a/pyload/plugins/crypter/TrailerzoneInfo.py b/pyload/plugins/crypter/TrailerzoneInfo.py new file mode 100644 index 000000000..7be3beef0 --- /dev/null +++ b/pyload/plugins/crypter/TrailerzoneInfo.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.DeadCrypter import DeadCrypter + + +class TrailerzoneInfo(DeadCrypter): + __name__ = "TrailerzoneInfo" + __type__ = "crypter" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?trailerzone.info/.*?' + + __description__ = """TrailerZone.info decrypter plugin""" + __author_name__ = "godofdream" + __author_mail__ = "soilfiction@gmail.com" diff --git a/pyload/plugins/crypter/TurbobitNetFolder.py b/pyload/plugins/crypter/TurbobitNetFolder.py new file mode 100644 index 000000000..c7786b7be --- /dev/null +++ b/pyload/plugins/crypter/TurbobitNetFolder.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter +from pyload.utils import json_loads + + +class TurbobitNetFolder(SimpleCrypter): + __name__ = "TurbobitNetFolder" + __type__ = "crypter" + __version__ = "0.03" + + __pattern__ = r'http://(?:www\.)?turbobit\.net/download/folder/(?P<ID>\w+)' + + __description__ = """Turbobit.net folder decrypter plugin""" + __author_name__ = ("stickell", "Walter Purcaro") + __author_mail__ = ("l.stickell@yahoo.it", "vuolter@gmail.com") + + TITLE_PATTERN = r"src='/js/lib/grid/icon/folder.png'> <span>(?P<title>.+?)</span>" + + + def _getLinks(self, id, page=1): + gridFile = self.load("http://turbobit.net/downloadfolder/gridFile", + get={"rootId": id, "rows": 200, "page": page}, decode=True) + grid = json_loads(gridFile) + + if grid['rows']: + for i in grid['rows']: + yield i['id'] + for id in self._getLinks(id, page + 1): + yield id + else: + return + + def getLinks(self): + id = re.match(self.__pattern__, self.pyfile.url).group("ID") + fixurl = lambda id: "http://turbobit.net/%s.html" % id + return map(fixurl, self._getLinks(id)) diff --git a/pyload/plugins/crypter/TusfilesNetFolder.py b/pyload/plugins/crypter/TusfilesNetFolder.py new file mode 100644 index 000000000..f4f1c7723 --- /dev/null +++ b/pyload/plugins/crypter/TusfilesNetFolder.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- + +import math +import re +from urlparse import urljoin + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + + +class TusfilesNetFolder(SimpleCrypter): + __name__ = "TusfilesNetFolder" + __type__ = "crypter" + __version__ = "0.02" + + __pattern__ = r'https?://(?:www\.)?tusfiles\.net/go/(?P<ID>\w+)/?' + + __description__ = """Tusfiles.net folder decrypter plugin""" + __author_name__ = ("Walter Purcaro", "stickell") + __author_mail__ = ("vuolter@gmail.com", "l.stickell@yahoo.it") + + LINK_PATTERN = r'<TD align=left><a href="(.*?)">' + TITLE_PATTERN = r'<Title>.*?\: (?P<title>.+) folder</Title>' + PAGES_PATTERN = r'>\((?P<pages>\d+) \w+\)<' + + URL_REPLACEMENTS = [(__pattern__, r'https://www.tusfiles.net/go/\g<ID>/')] + + + def loadPage(self, page_n): + return self.load(urljoin(self.pyfile.url, str(page_n)), decode=True) + + def handleMultiPages(self): + pages = re.search(self.PAGES_PATTERN, self.html) + if pages: + pages = int(math.ceil(int(pages.group('pages')) / 25.0)) + else: + return + + for p in xrange(2, pages + 1): + self.html = self.loadPage(p) + self.package_links += self.getLinks() diff --git a/pyload/plugins/crypter/UlozToFolder.py b/pyload/plugins/crypter/UlozToFolder.py new file mode 100644 index 000000000..5d302f58f --- /dev/null +++ b/pyload/plugins/crypter/UlozToFolder.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- + +import re +from pyload.plugins.base.Crypter import Crypter + + +class UlozToFolder(Crypter): + __name__ = "UlozToFolder" + __type__ = "crypter" + __version__ = "0.2" + + __pattern__ = r'http://(?:www\.)?(uloz\.to|ulozto\.(cz|sk|net)|bagruj.cz|zachowajto.pl)/(m|soubory)/.*' + + __description__ = """Uloz.to folder decrypter plugin""" + __author_name__ = "zoidberg" + __author_mail__ = "zoidberg@mujmail.cz" + + FOLDER_PATTERN = r'<ul class="profile_files">(.*?)</ul>' + LINK_PATTERN = r'<br /><a href="/([^"]+)">[^<]+</a>' + NEXT_PAGE_PATTERN = r'<a class="next " href="/([^"]+)"> </a>' + + + def decrypt(self, pyfile): + html = self.load(pyfile.url) + + new_links = [] + for i in xrange(1, 100): + self.logInfo("Fetching links from page %i" % i) + m = re.search(self.FOLDER_PATTERN, html, re.DOTALL) + if m is None: + self.fail("Parse error (FOLDER)") + + new_links.extend(re.findall(self.LINK_PATTERN, m.group(1))) + m = re.search(self.NEXT_PAGE_PATTERN, html) + if m: + html = self.load("http://ulozto.net/" + m.group(1)) + else: + break + else: + self.logInfo("Limit of 99 pages reached, aborting") + + if new_links: + self.urls = [map(lambda s: "http://ulozto.net/%s" % s, new_links)] + else: + self.fail('Could not extract any links') diff --git a/pyload/plugins/crypter/UploadableChFolder.py b/pyload/plugins/crypter/UploadableChFolder.py new file mode 100644 index 000000000..acc56580c --- /dev/null +++ b/pyload/plugins/crypter/UploadableChFolder.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + + +class UploadableChFolder(SimpleCrypter): + __name__ = "UploadableChFolder" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = r'http://(?:www\.)?uploadable\.ch/list/\w+' + + __description__ = """Uploadable.ch folder decrypter plugin""" + __author_name__ = ("guidobelix", "Walter Purcaro") + __author_mail__ = ("guidobelix@hotmail.it", "vuolter@gmail.com") + + + LINK_PATTERN = r'"(.+?)" class="icon_zipfile">' + TITLE_PATTERN = r'<div class="folder"><span> </span>(?P<title>.+?)</div>' + OFFLINE_PATTERN = r'We are sorry... The URL you entered cannot be found on the server.' + TEMP_OFFLINE_PATTERN = r'<div class="icon_err">' diff --git a/pyload/plugins/crypter/UploadedToFolder.py b/pyload/plugins/crypter/UploadedToFolder.py new file mode 100644 index 000000000..5ba34d8b5 --- /dev/null +++ b/pyload/plugins/crypter/UploadedToFolder.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugins.internal.SimpleCrypter import SimpleCrypter + + +class UploadedToFolder(SimpleCrypter): + __name__ = "UploadedToFolder" + __type__ = "crypter" + __version__ = "0.3" + + __pattern__ = r'http://(?:www\.)?(uploaded|ul)\.(to|net)/(f|folder|list)/(?P<id>\w+)' + + __description__ = """UploadedTo decrypter plugin""" + __author_name__ = "stickell" + __author_mail__ = "l.stickell@yahoo.it" + + PLAIN_PATTERN = r'<small class="date"><a href="(?P<plain>[\w/]+)" onclick=' + TITLE_PATTERN = r'<title>(?P<title>[^<]+)</title>' + + + def decrypt(self, pyfile): + self.html = self.load(pyfile.url) + + package_name, folder_name = self.getPackageNameAndFolder() + + m = re.search(self.PLAIN_PATTERN, self.html) + if m: + plain_link = 'http://uploaded.net/' + m.group('plain') + else: + self.fail('Parse error - Unable to find plain url list') + + self.html = self.load(plain_link) + package_links = self.html.split('\n')[:-1] + self.logDebug("Package has %d links" % len(package_links)) + + self.packages = [(package_name, package_links, folder_name)] diff --git a/pyload/plugins/crypter/WiiReloadedOrg.py b/pyload/plugins/crypter/WiiReloadedOrg.py new file mode 100644 index 000000000..7dfe574ab --- /dev/null +++ b/pyload/plugins/crypter/WiiReloadedOrg.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.internal.DeadCrypter import DeadCrypter + + +class WiiReloadedOrg(DeadCrypter): + __name__ = "WiiReloadedOrg" + __type__ = "crypter" + __version__ = "0.11" + + __pattern__ = r'http://(?:www\.)?wii-reloaded\.org/protect/get\.php\?i=.+' + + __description__ = """Wii-Reloaded.org decrypter plugin""" + __author_name__ = "hzpz" + __author_mail__ = None diff --git a/pyload/plugins/crypter/XupPl.py b/pyload/plugins/crypter/XupPl.py new file mode 100644 index 000000000..9a5f99e5a --- /dev/null +++ b/pyload/plugins/crypter/XupPl.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.base.Crypter import Crypter + + +class XupPl(Crypter): + __name__ = "XupPl" + __type__ = "crypter" + __version__ = "0.1" + + __pattern__ = r'https?://(?:[^/]*\.)?xup\.pl/.*' + + __description__ = """Xup.pl decrypter plugin""" + __author_name__ = "z00nx" + __author_mail__ = "z00nx0@gmail.com" + + + def decrypt(self, pyfile): + header = self.load(pyfile.url, just_header=True) + if 'location' in header: + self.urls = [header['location']] + else: + self.fail('Unable to find link') diff --git a/pyload/plugins/crypter/YoutubeBatch.py b/pyload/plugins/crypter/YoutubeBatch.py new file mode 100644 index 000000000..5ed0a7abf --- /dev/null +++ b/pyload/plugins/crypter/YoutubeBatch.py @@ -0,0 +1,138 @@ +# -*- coding: utf-8 -*- + +import re + +from urlparse import urljoin + +from pyload.utils import json_loads +from pyload.plugins.base.Crypter import Crypter +from pyload.utils import safe_join + +API_URL = "AIzaSyCKnWLNlkX-L4oD1aEzqqhRw1zczeD6_k0" + + +class YoutubeBatch(Crypter): + __name__ = "YoutubeBatch" + __type__ = "crypter" + __version__ = "1.00" + + __pattern__ = r'https?://(?:www\.|m\.)?youtube\.com/(?P<TYPE>user|playlist|view_play_list)(/|.*?[?&](?:list|p)=)(?P<ID>[\w-]+)' + __config__ = [("likes", "bool", "Grab user (channel) liked videos", False), + ("favorites", "bool", "Grab user (channel) favorite videos", False), + ("uploads", "bool", "Grab channel unplaylisted videos", True)] + + __description__ = """Youtube.com channel & playlist decrypter plugin""" + __author_name__ = "Walter Purcaro" + __author_mail__ = "vuolter@gmail.com" + + + def api_response(self, ref, req): + req.update({"key": API_KEY}) + url = urljoin("https://www.googleapis.com/youtube/v3/", ref) + page = self.load(url, get=req) + return json_loads(page) + + def getChannel(self, user): + channels = self.api_response("channels", {"part": "id,snippet,contentDetails", "forUsername": user, "maxResults": "50"}) + if channels['items']: + channel = channels['items'][0] + return {"id": channel['id'], + "title": channel['snippet']['title'], + "relatedPlaylists": channel['contentDetails']['relatedPlaylists'], + "user": user} # One lone channel for user? + + def getPlaylist(self, p_id): + playlists = self.api_response("playlists", {"part": "snippet", "id": p_id}) + if playlists['items']: + playlist = playlists['items'][0] + return {"id": p_id, + "title": playlist['snippet']['title'], + "channelId": playlist['snippet']['channelId'], + "channelTitle": playlist['snippet']['channelTitle']} + + def _getPlaylists(self, id, token=None): + req = {"part": "id", "maxResults": "50", "channelId": id} + if token: + req.update({"pageToken": token}) + + playlists = self.api_response("playlists", req) + + for playlist in playlists['items']: + yield playlist['id'] + + if "nextPageToken" in playlists: + for item in self._getPlaylists(id, playlists['nextPageToken']): + yield item + + def getPlaylists(self, ch_id): + return map(self.getPlaylist, self._getPlaylists(ch_id)) + + def _getVideosId(self, id, token=None): + req = {"part": "contentDetails", "maxResults": "50", "playlistId": id} + if token: + req.update({"pageToken": token}) + + playlist = self.api_response("playlistItems", req) + + for item in playlist['items']: + yield item['contentDetails']['videoId'] + + if "nextPageToken" in playlist: + for item in self._getVideosId(id, playlist['nextPageToken']): + yield item + + def getVideosId(self, p_id): + return list(self._getVideosId(p_id)) + + def decrypt(self, pyfile): + m = re.match(self.__pattern__, pyfile.url) + m_id = m.group("ID") + m_type = m.group("TYPE") + + if m_type == "user": + self.logDebug("Url recognized as Channel") + user = m_id + channel = self.getChannel(user) + + if channel: + playlists = self.getPlaylists(channel['id']) + self.logDebug("%s playlist\s found on channel \"%s\"" % (len(playlists), channel['title'])) + + relatedplaylist = {p_name: self.getPlaylist(p_id) for p_name, p_id in channel['relatedPlaylists'].iteritems()} + self.logDebug("Channel's related playlists found = %s" % relatedplaylist.keys()) + + relatedplaylist['uploads']['title'] = "Unplaylisted videos" + relatedplaylist['uploads']['checkDups'] = True #: checkDups flag + + for p_name, p_data in relatedplaylist.iteritems(): + if self.getConfig(p_name): + p_data['title'] += " of " + user + playlists.append(p_data) + else: + playlists = [] + else: + self.logDebug("Url recognized as Playlist") + playlists = [self.getPlaylist(m_id)] + + if not playlists: + self.fail("No playlist available") + + addedvideos = [] + urlize = lambda x: "https://www.youtube.com/watch?v=" + x + for p in playlists: + p_name = p['title'] + p_videos = self.getVideosId(p['id']) + p_folder = safe_join(self.config['general']['download_folder'], p['channelTitle'], p_name) + self.logDebug("%s video\s found on playlist \"%s\"" % (len(p_videos), p_name)) + + if not p_videos: + continue + elif "checkDups" in p: + p_urls = [urlize(v_id) for v_id in p_videos if v_id not in addedvideos] + self.logDebug("%s video\s available on playlist \"%s\" after duplicates cleanup" % (len(p_urls), p_name)) + else: + p_urls = map(urlize, p_videos) + + self.packages.append((p_name, p_urls, p_folder)) #: folder is NOT recognized by pyload 0.4.9! + + addedvideos.extend(p_videos) diff --git a/pyload/plugins/crypter/__init__.py b/pyload/plugins/crypter/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/pyload/plugins/crypter/__init__.py |