diff options
author | Walter Purcaro <vuolter@gmail.com> | 2014-12-02 00:08:42 +0100 |
---|---|---|
committer | Walter Purcaro <vuolter@gmail.com> | 2014-12-02 00:08:42 +0100 |
commit | 2a8d0af88b07e62eeb316a8dfbb7cd8d7dbfdcac (patch) | |
tree | 4324ec7c224724156ee9897e8689135f85e2e804 /module/plugins | |
parent | Merge pull request #920 from chris-19/stable (diff) | |
parent | [SimpleHoster] Force _isDirectLink to old style (diff) | |
download | pyload-2a8d0af88b07e62eeb316a8dfbb7cd8d7dbfdcac.tar.xz |
Merge branch 'stable-next' into stable
Diffstat (limited to 'module/plugins')
30 files changed, 342 insertions, 325 deletions
diff --git a/module/plugins/accounts/EasybytezCom.py b/module/plugins/accounts/EasybytezCom.py index 0afd93d3b..93d3e2c19 100644 --- a/module/plugins/accounts/EasybytezCom.py +++ b/module/plugins/accounts/EasybytezCom.py @@ -8,7 +8,7 @@ from module.plugins.internal.XFSAccount import XFSAccount class EasybytezCom(XFSAccount): __name__ = "EasybytezCom" __type__ = "account" - __version__ = "0.11" + __version__ = "0.12" __description__ = """EasyBytez.com account plugin""" __license__ = "GPLv3" @@ -17,9 +17,3 @@ class EasybytezCom(XFSAccount): HOSTER_DOMAIN = "easybytez.com" - - - def loadAccountInfo(self, *args, **kwargs): - info = super(EasybytezCom, self).loadAccountInfo(*args, **kwargs) - info['leechtraffic'] = 26214400 - return info diff --git a/module/plugins/accounts/SafesharingEu.py b/module/plugins/accounts/SafesharingEu.py index a2b964cba..2e58d33b3 100644 --- a/module/plugins/accounts/SafesharingEu.py +++ b/module/plugins/accounts/SafesharingEu.py @@ -4,16 +4,13 @@ from module.plugins.internal.XFSAccount import XFSAccount class SafesharingEu(XFSAccount): - __name__ = "SafesharingEu" - __type__ = "account" + __name__ = "SafesharingEu" + __type__ = "account" __version__ = "0.02" __description__ = """Safesharing.eu account plugin""" - __license__ = "GPLv3" - __authors__ = [("guidobelix", "guidobelix@hotmail.it")] + __license__ = "GPLv3" + __authors__ = [("guidobelix", "guidobelix@hotmail.it")] HOSTER_DOMAIN = "safesharing.eu" - - VALID_UNTIL_PATTERN = r'> Premium.[Aa]ccount expire:(.+?)</div>' - TRAFFIC_LEFT_PATTERN = r'> Traffic available today:\s*?(?P<S>[\d.,]+)\s*?(?:(?P<U>[\w^_]+)\s*)?</div>' diff --git a/module/plugins/hooks/Captcha9kw.py b/module/plugins/hooks/Captcha9kw.py index 38b39b2af..ead8aec9a 100755 --- a/module/plugins/hooks/Captcha9kw.py +++ b/module/plugins/hooks/Captcha9kw.py @@ -56,7 +56,7 @@ class Captcha9kw(Hook): if res.isdigit(): self.logInfo(_("%s credits left") % res) - credits = self.info["credits"] = int(res) + credits = self.info['credits'] = int(res) return credits else: self.logError(res) diff --git a/module/plugins/hooks/Checksum.py b/module/plugins/hooks/Checksum.py index b746fce5f..eeda2d849 100644 --- a/module/plugins/hooks/Checksum.py +++ b/module/plugins/hooks/Checksum.py @@ -81,10 +81,15 @@ class Checksum(Hook): a) if known, the exact filesize in bytes (e.g. "size": 123456789) b) hexadecimal hash string with algorithm name as key (e.g. "md5": "d76505d0869f9f928a17d42d66326307") """ - if hasattr(pyfile.plugin, "check_data") and (isinstance(pyfile.plugin.check_data, dict)): + if hasattr(pyfile.plugin, "check_data") and isinstance(pyfile.plugin.check_data, dict): data = pyfile.plugin.check_data.copy() - elif hasattr(pyfile.plugin, "api_data") and (isinstance(pyfile.plugin.api_data, dict)): + + elif hasattr(pyfile.plugin, "api_data") and isinstance(pyfile.plugin.api_data, dict): data = pyfile.plugin.api_data.copy() + + # elif hasattr(pyfile.plugin, "info") and isinstance(pyfile.plugin.info, dict): + # data = pyfile.plugin.info.copy() + else: return diff --git a/module/plugins/hooks/UpdateManager.py b/module/plugins/hooks/UpdateManager.py index 3fda0b5e8..9c26cf5d9 100644 --- a/module/plugins/hooks/UpdateManager.py +++ b/module/plugins/hooks/UpdateManager.py @@ -14,13 +14,14 @@ from module.utils import save_join class UpdateManager(Hook): __name__ = "UpdateManager" __type__ = "hook" - __version__ = "0.39" + __version__ = "0.40" - __config__ = [("activated", "bool", "Activated", True), - ("mode", "pyLoad + plugins;plugins only", "Check updates for", "pyLoad + plugins"), - ("interval", "int", "Check interval in hours", 8), - ("reloadplugins", "bool", "Monitor plugins for code changes (debug mode only)", True), - ("nodebugupdate", "bool", "Don't check for updates in debug mode", True)] + __config__ = [("activated" , "bool" , "Activated" , True ), + ("mode" , "pyLoad + plugins;plugins only", "Check updates for" , "pyLoad + plugins"), + ("interval" , "int" , "Check interval in hours" , 8 ), + ("autorestart" , "bool" , "Automatically restart pyLoad when required" , True ), + ("reloadplugins", "bool" , "Monitor plugins for code changes in debug mode", True ), + ("nodebugupdate", "bool" , "Don't check for updates in debug mode" , True )] __description__ = """ Check for updates """ __license__ = "GPLv3" @@ -123,7 +124,7 @@ class UpdateManager(Hook): status = self.update(onlyplugin=self.getConfig("mode") == "plugins only") - if status == 2: + if status is 2 and self.getConfig("autorestart"): self.core.api.restart() else: self.updating = False diff --git a/module/plugins/hoster/BasePlugin.py b/module/plugins/hoster/BasePlugin.py index 01a234d3b..0b1888e3b 100644 --- a/module/plugins/hoster/BasePlugin.py +++ b/module/plugins/hoster/BasePlugin.py @@ -3,7 +3,7 @@ import re from urllib import unquote -from urlparse import urlparse +from urlparse import urljoin, urlparse from module.network.HTTPRequest import BadHeader from module.plugins.internal.SimpleHoster import create_getInfo @@ -13,7 +13,7 @@ from module.plugins.Hoster import Hoster class BasePlugin(Hoster): __name__ = "BasePlugin" __type__ = "hoster" - __version__ = "0.24" + __version__ = "0.25" __pattern__ = r'^unmatchable$' @@ -25,7 +25,7 @@ class BasePlugin(Hoster): @classmethod def getInfo(cls, url="", html=""): #@TODO: Move to hoster class in 0.4.10 - return {'name': urlparse(url).path.split('/')[-1] or _("Unknown"), 'size': 0, 'status': 3 if url else 1, 'url': url or ""} + return {'name': urlparse(unquote(url)).path.split('/')[-1] or _("Unknown"), 'size': 0, 'status': 3 if url else 1, 'url': unquote(url) or ""} def setup(self): @@ -50,7 +50,7 @@ class BasePlugin(Hoster): self.offline() elif e.code in (401, 403): - self.logDebug("Auth required") + self.logDebug("Auth required", "Received HTTP status code: %d" % e.code) account = self.core.accountManager.getAccountPlugin('Http') servers = [x['login'] for x in account.getAllAccounts()] @@ -65,16 +65,16 @@ class BasePlugin(Hoster): self.req.addAuth(pwd.strip()) break else: - self.fail(_("Authorization required (username:password)")) + self.fail(_("Authorization required")) else: self.fail(e) else: break else: - self.fail(_("No file downloaded")) #@TODO: Move to hoster class (check if self.lastDownload) in 0.4.10 + self.fail(_("No file downloaded")) #@TODO: Move to hoster class in 0.4.10 - # if self.checkDownload({'empty': re.compile(r"^$")}) is "empty": - # self.fail(_("Empty file")) + if self.checkDownload({'empty': re.compile(r"^$")}) is "empty": #@TODO: Move to hoster in 0.4.10 + self.fail(_("Empty file")) def downloadFile(self, pyfile): @@ -85,7 +85,8 @@ class BasePlugin(Hoster): if 'location' not in header or not header['location']: if 'code' in header and header['code'] not in (200, 201, 203, 206): - self.fail(_("File not found"), _("HTTP status code: %d") % header['code']) + self.logDebug("Received HTTP status code: %d" % header['code']) + self.fail(_("File not found")) else: break @@ -93,17 +94,13 @@ class BasePlugin(Hoster): self.logDebug("Redirect #%d to: %s" % (i, location)) - base = re.match(r'https?://[^/]+', url).group(0) - - if location.startswith("http"): + if urlparse(location).scheme: url = location - - elif location.startswith("/"): - url = base + unquote(location) - else: - url = "%s/%s" % (base, unquote(location)) + p = urlparse(url) + base = "%s://%s" % (p.scheme, p.netloc) + url = urljoin(base, location) else: self.fail(_("Too many redirects")) - self.download(url, disposition=True) + self.download(unquote(url), disposition=True) diff --git a/module/plugins/hoster/DataHu.py b/module/plugins/hoster/DataHu.py index fd6a01135..74d631e7b 100644 --- a/module/plugins/hoster/DataHu.py +++ b/module/plugins/hoster/DataHu.py @@ -33,13 +33,10 @@ class DataHu(SimpleHoster): def handleFree(self): m = re.search(self.LINK_PATTERN, self.html) - if m: - url = m.group(1) - self.logDebug("Direct link: " + url) - else: + if m is None: self.error(_("LINK_PATTERN not found")) - self.download(url, disposition=True) + self.download(m.group(1), disposition=True) getInfo = create_getInfo(DataHu) diff --git a/module/plugins/hoster/DateiTo.py b/module/plugins/hoster/DateiTo.py index 9d51b5036..683c6b75d 100644 --- a/module/plugins/hoster/DateiTo.py +++ b/module/plugins/hoster/DateiTo.py @@ -9,7 +9,7 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo class DateiTo(SimpleHoster): __name__ = "DateiTo" __type__ = "hoster" - __version__ = "0.04" + __version__ = "0.05" __pattern__ = r'http://(?:www\.)?datei\.to/datei/(?P<ID>\w+)\.html' @@ -29,7 +29,7 @@ class DateiTo(SimpleHoster): def handleFree(self): url = 'http://datei.to/ajax/download.php' - data = {'P': 'I', 'ID': self.info['ID']} + data = {'P': 'I', 'ID': self.info['pattern']['ID']} recaptcha = ReCaptcha(self) for _i in xrange(10): diff --git a/module/plugins/hoster/FastshareCz.py b/module/plugins/hoster/FastshareCz.py index 1467a0909..14931f681 100644 --- a/module/plugins/hoster/FastshareCz.py +++ b/module/plugins/hoster/FastshareCz.py @@ -75,7 +75,6 @@ class FastshareCz(SimpleHoster): else: self.error(_("PREMIUM_URL_PATTERN not found")) - self.logDebug("PREMIUM URL: " + url) self.download(url, disposition=True) check = self.checkDownload({"credit": re.compile(self.CREDIT_PATTERN)}) diff --git a/module/plugins/hoster/FilecloudIo.py b/module/plugins/hoster/FilecloudIo.py index 819a7faf3..85ea3dae4 100644 --- a/module/plugins/hoster/FilecloudIo.py +++ b/module/plugins/hoster/FilecloudIo.py @@ -10,7 +10,7 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo class FilecloudIo(SimpleHoster): __name__ = "FilecloudIo" __type__ = "hoster" - __version__ = "0.04" + __version__ = "0.05" __pattern__ = r'http://(?:www\.)?(?:filecloud\.io|ifile\.it|mihd\.net)/(?P<ID>\w+).*' @@ -39,7 +39,7 @@ class FilecloudIo(SimpleHoster): def handleFree(self): - data = {"ukey": self.info['ID']} + data = {"ukey": self.info['pattern']['ID']} m = re.search(self.AB1_PATTERN, self.html) if m is None: @@ -94,7 +94,7 @@ class FilecloudIo(SimpleHoster): if res['dl']: self.html = self.load('http://filecloud.io/download.html') - m = re.search(self.LINK_PATTERN % self.info['ID'], self.html) + m = re.search(self.LINK_PATTERN % self.info['pattern']['ID'], self.html) if m is None: self.error(_("LINK_PATTERN not found")) @@ -109,7 +109,7 @@ class FilecloudIo(SimpleHoster): def handlePremium(self): akey = self.account.getAccountData(self.user)['akey'] - ukey = self.info['ID'] + ukey = self.info['pattern']['ID'] self.logDebug("Akey: %s | Ukey: %s" % (akey, ukey)) rep = self.load("http://api.filecloud.io/api-fetch_download_url.api", post={"akey": akey, "ukey": ukey}) diff --git a/module/plugins/hoster/FilepostCom.py b/module/plugins/hoster/FilepostCom.py index 314ad449c..db5ea20d3 100644 --- a/module/plugins/hoster/FilepostCom.py +++ b/module/plugins/hoster/FilepostCom.py @@ -12,9 +12,9 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo class FilepostCom(SimpleHoster): __name__ = "FilepostCom" __type__ = "hoster" - __version__ = "0.29" + __version__ = "0.30" - __pattern__ = r'https?://(?:www\.)?(?:filepost\.com/files|fp\.io)/([^/]+).*' + __pattern__ = r'https?://(?:www\.)?(?:filepost\.com/files|fp\.io)/(?P<ID>[^/]+)' __description__ = """Filepost.com hoster plugin""" __license__ = "GPLv3" @@ -30,9 +30,6 @@ class FilepostCom(SimpleHoster): def handleFree(self): - # Find token and captcha key - file_id = re.match(self.__pattern__, self.pyfile.url).group(1) - m = re.search(self.FLP_TOKEN_PATTERN, self.html) if m is None: self.error(_("Token")) @@ -45,13 +42,13 @@ class FilepostCom(SimpleHoster): # Get wait time get_dict = {'SID': self.req.cj.getCookie('SID'), 'JsHttpRequest': str(int(time() * 10000)) + '-xml'} - post_dict = {'action': 'set_download', 'token': flp_token, 'code': file_id} + post_dict = {'action': 'set_download', 'token': flp_token, 'code': self.info['pattern']['ID']} wait_time = int(self.getJsonResponse(get_dict, post_dict, 'wait_time')) if wait_time > 0: self.wait(wait_time) - post_dict = {"token": flp_token, "code": file_id, "file_pass": ''} + post_dict = {"token": flp_token, "code": self.info['pattern']['ID'], "file_pass": ''} if 'var is_pass_exists = true;' in self.html: # Solve password diff --git a/module/plugins/hoster/FilerNet.py b/module/plugins/hoster/FilerNet.py index c91729730..3bfafc675 100644 --- a/module/plugins/hoster/FilerNet.py +++ b/module/plugins/hoster/FilerNet.py @@ -92,7 +92,6 @@ class FilerNet(SimpleHoster): self.error(_("LINK_PATTERN not found")) dl = 'http://filer.net' + m.group(1) - self.logDebug("Direct link: " + dl) self.download(dl, disposition=True) diff --git a/module/plugins/hoster/Keep2shareCc.py b/module/plugins/hoster/Keep2shareCc.py index fd8a5524d..7ca29701a 100644 --- a/module/plugins/hoster/Keep2shareCc.py +++ b/module/plugins/hoster/Keep2shareCc.py @@ -2,16 +2,16 @@ import re -from urlparse import urlparse, urljoin +from urlparse import urljoin, urlparse from module.plugins.internal.CaptchaService import ReCaptcha -from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo +from module.plugins.internal.SimpleHoster import _isDirectLink, SimpleHoster, create_getInfo class Keep2shareCc(SimpleHoster): __name__ = "Keep2shareCc" __type__ = "hoster" - __version__ = "0.15" + __version__ = "0.16" __pattern__ = r'https?://(?:www\.)?(keep2share|k2s|keep2s)\.cc/file/(?P<ID>\w+)' @@ -21,75 +21,98 @@ class Keep2shareCc(SimpleHoster): ("Walter Purcaro", "vuolter@gmail.com")] + URL_REPLACEMENTS = [(__pattern__ + ".*", "http://k2s.cc/file/\g<ID>")] + + CONTENT_DISPOSITION = True + NAME_PATTERN = r'File: <span>(?P<N>.+)</span>' SIZE_PATTERN = r'Size: (?P<S>[^<]+)</div>' - OFFLINE_PATTERN = r'File not found or deleted|Sorry, this file is blocked or deleted|Error 404' - LINK_PATTERN = r'To download this file with slow speed, use <a href="([^"]+)">this link</a>' + OFFLINE_PATTERN = r'File not found or deleted|Sorry, this file is blocked or deleted|Error 404' + TEMP_OFFLINE_PATTERN = r'Downloading blocked due to' + + LINK_FREE_PATTERN = LINK_PREMIUM_PATTERN = r'"([^"]+url.html?file=.+?)"|window\.location\.href = \'(.+?)\';' + CAPTCHA_PATTERN = r'src="(/file/captcha\.html.+?)"' - WAIT_PATTERN = r'Please wait ([\d:]+) to download this file' - MULTIDL_ERROR = r'Free account does not allow to download more than one file at the same time' + WAIT_PATTERN = r'Please wait ([\d:]+) to download this file' + TEMP_ERROR_PATTERN = r'>\s*(Download count files exceed|Traffic limit exceed|Free account does not allow to download more than one file at the same time)' + ERROR_PATTERN = r'>\s*(Free user can\'t download large files|You no can access to this file|This download available only for premium users|This is private file)' - def handleFree(self): - self.sanitize_url() - self.html = self.load(self.pyfile.url) - self.fid = re.search(r'<input type="hidden" name="slow_id" value="([^"]+)">', self.html).group(1) + def checkErrors(self): + m = re.search(self.TEMP_ERROR_PATTERN, self.html) + if m: + self.info['error'] = m.group(1) + self.wantReconnect = True + self.retry(wait_time=30 * 60, reason=m.group(0)) + + m = re.search(self.ERROR_PATTERN, self.html) + if m: + e = self.info['error'] = m.group(1) + self.error(e) + + m = re.search(self.WAIT_PATTERN, self.html) + if m: + self.logDebug("Hoster told us to wait for %s" % m.group(1)) + + # string to time convert courtesy of https://stackoverflow.com/questions/10663720 + ftr = [3600, 60, 1] + wait_time = sum([a * b for a, b in zip(ftr, map(int, m.group(1).split(':')))]) + + self.wantReconnect = True + self.retry(wait_time=wait_time, reason="Please wait to download this file") + + self.info.pop('error', None) + + + def handleFree(self): + self.fid = re.search(r'<input type="hidden" name="slow_id" value="([^"]+)">', self.html).group(1) self.html = self.load(self.pyfile.url, post={'yt0': '', 'slow_id': self.fid}) - if ">Downloading is not possible" in self.html: - self.fail("Free user can't download large files") + self.checkErrors() - m = re.search(r"function download\(\){.*window\.location\.href = '([^']+)';", self.html, re.S) - if m: # Direct mode - self.startDownload(m.group(1)) - else: + m = re.search(self.LINK_FREE_PATTERN, self.html) + + if m is None: self.handleCaptcha() self.wait(30) self.html = self.load(self.pyfile.url, post={'uniqueId': self.fid, 'free': 1}) - m = re.search(self.WAIT_PATTERN, self.html) - if m: - self.logDebug("Hoster told us to wait for %s" % m.group(1)) - # string to time convert courtesy of https://stackoverflow.com/questions/10663720 - ftr = [3600, 60, 1] - wait_time = sum([a * b for a, b in zip(ftr, map(int, m.group(1).split(':')))]) - self.wait(wait_time, True) - self.retry() - - m = re.search(self.MULTIDL_ERROR, self.html) - if m: - # if someone is already downloading on our line, wait 30min and retry - self.logDebug("Already downloading, waiting for 30 minutes") - self.wait(30 * 60, True) - self.retry() + self.checkErrors() - m = re.search(self.LINK_PATTERN, self.html) + m = re.search(self.LINK_FREE_PATTERN, self.html) if m is None: - self.error(_("LINK_PATTERN not found")) - self.startDownload(m.group(1)) + self.error(_("LINK_FREE_PATTERN not found")) + + self.link = self._getDownloadLink(m.group(1)) + + + def handlePremium(self): + super(Keep2shareCc, self).handlePremium() + if self.link: + self.link = self._getDownloadLink(self.link) def handleCaptcha(self): recaptcha = ReCaptcha(self) for _i in xrange(5): - post_data = {'free': 1, + post_data = {'free' : 1, 'freeDownloadRequest': 1, - 'uniqueId': self.fid, - 'yt0': ''} + 'uniqueId' : self.fid, + 'yt0' : ''} m = re.search(self.CAPTCHA_PATTERN, self.html) if m: - captcha_url = urljoin(self.base_url, m.group(1)) + captcha_url = urljoin(self.base, m.group(1)) post_data['CaptchaForm[code]'] = self.decryptCaptcha(captcha_url) else: challenge, response = recaptcha.challenge() post_data.update({'recaptcha_challenge_field': challenge, - 'recaptcha_response_field': response}) + 'recaptcha_response_field' : response}) self.html = self.load(self.pyfile.url, post=post_data) @@ -102,17 +125,11 @@ class Keep2shareCc(SimpleHoster): self.fail(_("All captcha attempts failed")) - def startDownload(self, url): - d = urljoin(self.base_url, url) - self.download(d, disposition=True) - - - def sanitize_url(self): - header = self.load(self.pyfile.url, just_header=True) - if 'location' in header: - self.pyfile.url = header['location'] + def _getDownloadLink(self, url): p = urlparse(self.pyfile.url) - self.base_url = "%s://%s" % (p.scheme, p.hostname) + base = "%s://%s" % (p.scheme, p.netloc) + link = _isDirectLink(self, url, self.premium) + return urljoin(base, link) if link else "" getInfo = create_getInfo(Keep2shareCc) diff --git a/module/plugins/hoster/KingfilesNet.py b/module/plugins/hoster/KingfilesNet.py index ce34da38f..202ab4a77 100644 --- a/module/plugins/hoster/KingfilesNet.py +++ b/module/plugins/hoster/KingfilesNet.py @@ -9,7 +9,7 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo class KingfilesNet(SimpleHoster): __name__ = "KingfilesNet" __type__ = "hoster" - __version__ = "0.04" + __version__ = "0.05" __pattern__ = r'http://(?:www\.)?kingfiles\.net/(?P<ID>\w{12})' @@ -38,7 +38,7 @@ class KingfilesNet(SimpleHoster): # Click the free user button post_data = {'op': "download1", 'usr_login': "", - 'id': self.info['ID'], + 'id': self.info['pattern']['ID'], 'fname': self.pyfile.name, 'referer': "", 'method_free': "+"} @@ -57,7 +57,7 @@ class KingfilesNet(SimpleHoster): self.logDebug("rand = ", rand) post_data = {'op': "download2", - 'id': self.info['ID'], + 'id': self.info['pattern']['ID'], 'rand': rand, 'referer': self.pyfile.url, 'method_free': "+", diff --git a/module/plugins/hoster/LetitbitNet.py b/module/plugins/hoster/LetitbitNet.py index a1a812de4..ed8d4a39d 100644 --- a/module/plugins/hoster/LetitbitNet.py +++ b/module/plugins/hoster/LetitbitNet.py @@ -139,7 +139,4 @@ class LetitbitNet(SimpleHoster): if api_rep['status'] == 'FAIL': self.fail(api_rep['data']) - direct_link = api_rep['data'][0][0] - self.logDebug("Direct Link: " + direct_link) - - self.download(direct_link, disposition=True) + self.download(api_rep['data'][0][0], disposition=True) diff --git a/module/plugins/hoster/LuckyShareNet.py b/module/plugins/hoster/LuckyShareNet.py index aeab46d3d..2c33b57e7 100644 --- a/module/plugins/hoster/LuckyShareNet.py +++ b/module/plugins/hoster/LuckyShareNet.py @@ -11,7 +11,7 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo class LuckyShareNet(SimpleHoster): __name__ = "LuckyShareNet" __type__ = "hoster" - __version__ = "0.03" + __version__ = "0.04" __pattern__ = r'https?://(?:www\.)?luckyshare\.net/(?P<ID>\d{10,})' @@ -42,9 +42,7 @@ class LuckyShareNet(SimpleHoster): # TODO: There should be a filesize limit for free downloads # TODO: Some files could not be downloaded in free mode def handleFree(self): - file_id = re.match(self.__pattern__, self.pyfile.url).group('ID') - self.logDebug("File ID: " + file_id) - rep = self.load(r"http://luckyshare.net/download/request/type/time/file/" + file_id, decode=True) + rep = self.load(r"http://luckyshare.net/download/request/type/time/file/" + self.info['pattern']['ID'], decode=True) self.logDebug("JSON: " + rep) json = self.parseJson(rep) @@ -69,7 +67,6 @@ class LuckyShareNet(SimpleHoster): if not json['link']: self.fail(_("No Download url retrieved/all captcha attempts failed")) - self.logDebug("Direct URL: " + json['link']) self.download(json['link']) diff --git a/module/plugins/hoster/NowVideoAt.py b/module/plugins/hoster/NowVideoAt.py index c0b49c6f4..3d9b706d3 100644 --- a/module/plugins/hoster/NowVideoAt.py +++ b/module/plugins/hoster/NowVideoAt.py @@ -8,7 +8,7 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo class NowVideoAt(SimpleHoster): __name__ = "NowVideoAt" __type__ = "hoster" - __version__ = "0.06" + __version__ = "0.07" __pattern__ = r'http://(?:www\.)?nowvideo\.(at|ch|co|eu|sx)/(video|mobile/#/videos)/(?P<ID>\w+)' @@ -32,7 +32,7 @@ class NowVideoAt(SimpleHoster): def handleFree(self): - self.html = self.load("http://www.nowvideo.at/mobile/video.php", get={'id': self.info['ID']}) + self.html = self.load("http://www.nowvideo.at/mobile/video.php", get={'id': self.info['pattern']['ID']}) m = re.search(self.LINK_FREE_PATTERN, self.html) if m is None: diff --git a/module/plugins/hoster/OneFichierCom.py b/module/plugins/hoster/OneFichierCom.py index 7847a11e9..977d45b6f 100644 --- a/module/plugins/hoster/OneFichierCom.py +++ b/module/plugins/hoster/OneFichierCom.py @@ -8,7 +8,7 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo class OneFichierCom(SimpleHoster): __name__ = "OneFichierCom" __type__ = "hoster" - __version__ = "0.73" + __version__ = "0.74" __pattern__ = r'https?://(?:www\.)?(?:(?P<ID1>\w+)\.)?(?P<HOST>1fichier\.com|alterupload\.com|cjoint\.net|d(es)?fichiers\.com|dl4free\.com|megadl\.fr|mesfichiers\.org|piecejointe\.net|pjointe\.com|tenvoi\.com)(?:/\?(?P<ID2>\w+))?' @@ -46,7 +46,7 @@ class OneFichierCom(SimpleHoster): self.wait(wait_time, reconnect) self.retry(reason="You have to wait been each free download") - id = self.info['ID1'] or self.info['ID2'] + id = self.info['pattern']['ID1'] or self.info['pattern']['ID2'] url, inputs = self.parseHtmlForm('action="https://1fichier.com/\?%s' % id) if not url: diff --git a/module/plugins/hoster/PromptfileCom.py b/module/plugins/hoster/PromptfileCom.py index 22fea09ea..af38c4e15 100644 --- a/module/plugins/hoster/PromptfileCom.py +++ b/module/plugins/hoster/PromptfileCom.py @@ -38,9 +38,8 @@ class PromptfileCom(SimpleHoster): m = re.search(self.LINK_PATTERN, self.html) if m is None: self.error(_("LINK_PATTERN not found")) - direct = m.group(1) - self.logDebug("Found direct link: " + direct) - self.download(direct, disposition=True) + + self.download(m.group(1), disposition=True) getInfo = create_getInfo(PromptfileCom) diff --git a/module/plugins/hoster/SafesharingEu.py b/module/plugins/hoster/SafesharingEu.py index 92a0ff932..f0936b9e8 100644 --- a/module/plugins/hoster/SafesharingEu.py +++ b/module/plugins/hoster/SafesharingEu.py @@ -4,31 +4,20 @@ from module.plugins.internal.XFSHoster import XFSHoster, create_getInfo class SafesharingEu(XFSHoster): - __name__ = "SafesharingEu" - __type__ = "hoster" - __version__ = "0.04" + __name__ = "SafesharingEu" + __type__ = "hoster" + __version__ = "0.05" - __pattern__ = r'https?://(?:\w+\.)?safesharing.eu/\w+' + __pattern__ = r'https?://(?:www\.)?safesharing\.eu/\w{12}' __description__ = """Safesharing.eu hoster plugin""" - __license__ = "GPLv3" - __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de")] + __license__ = "GPLv3" + __authors__ = [("zapp-brannigan", "fuerst.reinje@web.de")] - HOSTER_DOMAIN = "safesharing.eu" - - FILE_NAME_PATTERN = r'Filename:</b></td><td nowrap>(?P<N>.*)</td></tr>' - FILE_SIZE_PATTERN = r'Size:</b></td><td>(?P<S>.*) (?P<U>[kKmMbB]*) <small>' - - FILE_ID_PATTERN = r'<input type="hidden" name="id" value="(.*)">' - OFFLINE_PATTERN = r'<b>File Not Found</b>' - TEMP_OFFLINE_PATTERN = r'This server is in maintenance mode' + HOSTER_DOMAIN = "safesharing.eu" WAIT_PATTERN = r'You have to wait (\d+) minutes' - COUNTDOWN_PATTERN = r'<br><span id="countdown_str">Wait <span id=".*">(\d+)</span> seconds</span>' - - RECAPTCHA_KEY_PATTERN = r'<script type="text/javascript" src="http://www.google.com/recaptcha/api/challenge\?k=(.*)"></script>' - RANDOM_STRING_PATTERN = r'<input type="hidden" name="rand" value="(.*)">' ERROR_PATTERN = r'(?:<div class="alert alert-danger">)(.+?)(?:</div>)' diff --git a/module/plugins/hoster/ShareonlineBiz.py b/module/plugins/hoster/ShareonlineBiz.py index 78a27558b..91fc989c9 100644 --- a/module/plugins/hoster/ShareonlineBiz.py +++ b/module/plugins/hoster/ShareonlineBiz.py @@ -3,43 +3,18 @@ import re from time import time +from urllib import unquote +from urlparse import urlparse from module.network.RequestFactory import getURL -from module.plugins.Hoster import Hoster -from module.plugins.Plugin import chunks from module.plugins.internal.CaptchaService import ReCaptcha +from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo -def getInfo(urls): - api_url_base = "http://api.share-online.biz/linkcheck.php" - - urls = [url.replace("https://", "http://") for url in urls] - - for chunk in chunks(urls, 90): - api_param_file = {"links": "\n".join(x.replace("http://www.share-online.biz/dl/", "").rstrip("/") for x in - chunk)} # api only supports old style links - html = getURL(api_url_base, post=api_param_file, decode=True) - result = [] - for i, res in enumerate(html.split("\n")): - if not res: - continue - fields = res.split(";") - - if fields[1] == "OK": - status = 2 - elif fields[1] in ("DELETED", "NOT FOUND"): - status = 1 - else: - status = 3 - - result.append((fields[2], int(fields[3]), status, chunk[i])) - yield result - - -class ShareonlineBiz(Hoster): +class ShareonlineBiz(SimpleHoster): __name__ = "ShareonlineBiz" __type__ = "hoster" - __version__ = "0.41" + __version__ = "0.42" __pattern__ = r'https?://(?:www\.)?(share-online\.biz|egoshare\.com)/(download\.php\?id=|dl/)(?P<ID>\w+)' @@ -51,110 +26,118 @@ class ShareonlineBiz(Hoster): ("Walter Purcaro", "vuolter@gmail.com")] - ERROR_INFO_PATTERN = r'<p class="b">Information:</p>\s*<div>\s*<strong>(.*?)</strong>' + URL_REPLACEMENTS = [(__pattern__ + ".*", "http://www.share-online.biz/dl/\g<ID>")] + ERROR_INFO_PATTERN = r'<p class="b">Information:</p>\s*<div>\s*<strong>(.*?)</strong>' - def setup(self): - self.file_id = re.match(self.__pattern__, self.pyfile.url).group("ID") - self.pyfile.url = "http://www.share-online.biz/dl/" + self.file_id - self.resumeDownload = self.premium - self.multiDL = False + @classmethod + def getInfo(cls, url="", html=""): + info = {'name': urlparse(unquote(url)).path.split('/')[-1] or _("Unknown"), 'size': 0, 'status': 3 if url else 1, 'url': url} - self.check_data = None + if url: + info.update(re.match(cls.__pattern__, url).groupdict()) + api_url = "http://api.share-online.biz/linkcheck.php?md5=1" + html = getURL(api_url, cookies=False, post={"links": self.info['pattern']['ID']}, decode=True) + field = html.split(";") - def process(self, pyfile): - if self.premium: - self.handlePremium() - else: - self.handleFree() + if field[1] is "OK": + info['fileid'] = field[0] + info['status'] = 2 + info['filename'] = field[2] + info['size'] = field[3] #: in bytes + info['md5'] = field[4].strip().lower().replace("\n\n", "") #: md5 - if self.api_data: - self.check_data = {"size": int(self.api_data['size']), "md5": self.api_data['md5']} + elif field[1] in ("DELETED", "NOT FOUND"): + info['status'] = 1 + return info - def loadAPIData(self): - api_url_base = "http://api.share-online.biz/linkcheck.php?md5=1" - api_param_file = {"links": self.file_id} #: api only supports old style links - html = self.load(api_url_base, cookies=False, post=api_param_file, decode=True) - - fields = html.split(";") - self.api_data = {"fileid": fields[0], - "status": fields[1]} - if not self.api_data['status'] == "OK": - self.offline() - else: - self.api_data['filename'] = fields[2] - self.api_data['size'] = fields[3] #: in bytes - self.api_data['md5'] = fields[4].strip().lower().replace("\n\n", "") #: md5 + def setup(self): + self.resumeDownload = self.premium + self.multiDL = False - def handleFree(self): - self.loadAPIData() - self.pyfile.name = self.api_data['filename'] - self.pyfile.size = int(self.api_data['size']) - - self.html = self.load(self.pyfile.url, cookies=True) #: refer, stuff - self.setWait(3) - self.wait() - - self.html = self.load("%s/free/" % self.pyfile.url, post={"dl_free": "1", "choice": "free"}, decode=True) - self.checkErrors() - - m = re.search(r'var wait=(\d+);', self.html) + def handleCaptcha(self): recaptcha = ReCaptcha(self) + for _i in xrange(5): - challenge, response = recaptcha.challenge("6LdatrsSAAAAAHZrB70txiV5p-8Iv8BtVxlTtjKX") + challenge, response = recaptcha.challenge() + + m = re.search(r'var wait=(\d+);', self.html) self.setWait(int(m.group(1)) if m else 30) + res = self.load("%s/free/captcha/%d" % (self.pyfile.url, int(time() * 1000)), - post={'dl_free': '1', + post={'dl_free' : "1", 'recaptcha_challenge_field': challenge, - 'recaptcha_response_field': response}) - + 'recaptcha_response_field' : response}) if not res == '0': self.correctCaptcha() - break + return res else: self.invalidCaptcha() else: self.invalidCaptcha() self.fail(_("No valid captcha solution received")) + + def handleFree(self): + self.html = self.load(self.pyfile.url, cookies=True) #: refer, stuff + + self.wait(3) + + self.html = self.load("%s/free/" % self.pyfile.url, post={"dl_free": "1", "choice": "free"}, decode=True) + + self.checkErrors() + + res = self.handleCaptcha() + download_url = res.decode("base64") + if not download_url.startswith("http://"): self.error(_("Wrong download url")) self.wait() + self.download(download_url) + + def checkFile(self): # check download check = self.checkDownload({ - "cookie": re.compile(r'<div id="dl_failure"'), - "fail": re.compile(r"<title>Share-Online") + 'empty' : re.compile(r"^$"), + 'cookie': re.compile(r'<div id="dl_failure"'), + 'fail' : re.compile(r"<title>Share-Online") }) - if check == "cookie": + + if check == "empty": + self.fail(_("Empty file")) + + elif check == "cookie": self.invalidCaptcha() - self.retry(5, 60, "Cookie failure") + self.retry(5, 60, _("Cookie failure")) + elif check == "fail": self.invalidCaptcha() - self.retry(5, 5 * 60, "Download failed") - else: - self.correctCaptcha() + self.retry(5, 5 * 60, _("Download failed")) def handlePremium(self): #: should be working better loading (account) api internally self.account.getAccountInfo(self.user, True) + html = self.load("http://api.share-online.biz/account.php", {"username": self.user, "password": self.account.accounts[self.user]['password'], - "act": "download", "lid": self.file_id}) + "act": "download", "lid": self.info['fileid']}) self.api_data = dlinfo = {} + for line in html.splitlines(): key, value = line.split(": ") dlinfo[key.lower()] = value self.logDebug(dlinfo) + if not dlinfo['status'] == "online": self.offline() else: @@ -162,6 +145,7 @@ class ShareonlineBiz(Hoster): self.pyfile.size = int(dlinfo['size']) dlLink = dlinfo['url'] + if dlLink == "server_under_maintenance": self.tempOffline() else: @@ -174,23 +158,29 @@ class ShareonlineBiz(Hoster): if m is None: return - err = m.group(1) + errmsg = m.group(1).lower() + try: - self.logError(err, re.search(self.ERROR_INFO_PATTERN, self.html).group(1)) + self.logError(errmsg, re.search(self.ERROR_INFO_PATTERN, self.html).group(1)) except: - self.logError(err, "Unknown error occurred") + self.logError("Unknown error occurred", errmsg) - if err == "invalid": + if errmsg is "invalid": self.fail(_("File not available")) - elif err in ("freelimit", "size", "proxy"): + + elif errmsg in ("freelimit", "size", "proxy"): self.fail(_("Premium account needed")) + + elif errmsg in ("expired", "server"): + self.retry(wait_time=600, reason=errmsg) + + elif 'slot' in errmsg: + self.wantReconnect = True + self.retry(24, 3600, errmsg) + else: - if err in 'server': - self.setWait(600, False) - elif err in 'expired': - self.setWait(30, False) - else: - self.setWait(300, True) + self.wantReconnect = True + self.retry(wait_time=60, reason=errmsg) + - self.wait() - self.retry(max_tries=25, reason=err) +getInfo = create_getInfo(ShareonlineBiz) diff --git a/module/plugins/hoster/TurbobitNet.py b/module/plugins/hoster/TurbobitNet.py index 7426ea35c..9d7dcc67b 100644 --- a/module/plugins/hoster/TurbobitNet.py +++ b/module/plugins/hoster/TurbobitNet.py @@ -17,7 +17,7 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, t class TurbobitNet(SimpleHoster): __name__ = "TurbobitNet" __type__ = "hoster" - __version__ = "0.15" + __version__ = "0.16" __pattern__ = r'http://(?:www\.)?turbobit\.net/(?:download/free/)?(?P<ID>\w+)' @@ -42,7 +42,7 @@ class TurbobitNet(SimpleHoster): def handleFree(self): - self.url = "http://turbobit.net/download/free/%s" % self.info['ID'] + self.url = "http://turbobit.net/download/free/%s" % self.info['pattern']['ID'] self.html = self.load(self.url, ref=True, decode=True) rtUpdate = self.getRtUpdate() @@ -130,7 +130,7 @@ class TurbobitNet(SimpleHoster): for b in [1, 3]: self.jscode = "var id = \'%s\';var b = %d;var inn = \'%s\';%sout" % ( - self.info['ID'], b, quote(fun), rtUpdate) + self.info['pattern']['ID'], b, quote(fun), rtUpdate) try: out = self.js.eval(self.jscode) diff --git a/module/plugins/hoster/UploadingCom.py b/module/plugins/hoster/UploadingCom.py index 2b11e3bf4..b163f2252 100644 --- a/module/plugins/hoster/UploadingCom.py +++ b/module/plugins/hoster/UploadingCom.py @@ -11,7 +11,7 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, t class UploadingCom(SimpleHoster): __name__ = "UploadingCom" __type__ = "hoster" - __version__ = "0.38" + __version__ = "0.39" __pattern__ = r'http://(?:www\.)?uploading\.com/files/(?:get/)?(?P<ID>\w+)' @@ -47,7 +47,7 @@ class UploadingCom(SimpleHoster): def handlePremium(self): postData = {'action': 'get_link', - 'code': self.info['ID'], + 'code': self.info['pattern']['ID'], 'pass': 'undefined'} self.html = self.load('http://uploading.com/files/get/?JsHttpRequest=%d-xml' % timestamp(), post=postData) @@ -70,7 +70,7 @@ class UploadingCom(SimpleHoster): self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With: XMLHttpRequest"]) self.req.http.lastURL = self.pyfile.url - res = json_loads(self.load(ajax_url, post={'action': 'second_page', 'code': self.info['ID']})) + res = json_loads(self.load(ajax_url, post={'action': 'second_page', 'code': self.info['pattern']['ID']})) if 'answer' in res and 'wait_time' in res['answer']: wait_time = int(res['answer']['wait_time']) @@ -79,7 +79,7 @@ class UploadingCom(SimpleHoster): else: self.error(_("No AJAX/WAIT")) - res = json_loads(self.load(ajax_url, post={'action': 'get_link', 'code': self.info['ID'], 'pass': 'false'})) + res = json_loads(self.load(ajax_url, post={'action': 'get_link', 'code': self.info['pattern']['ID'], 'pass': 'false'})) if 'answer' in res and 'link' in res['answer']: url = res['answer']['link'] diff --git a/module/plugins/hoster/WebshareCz.py b/module/plugins/hoster/WebshareCz.py index cd43de2bb..17aaff37c 100644 --- a/module/plugins/hoster/WebshareCz.py +++ b/module/plugins/hoster/WebshareCz.py @@ -35,13 +35,14 @@ class WebshareCz(SimpleHoster): def handleFree(self): api_data = self.load('https://webshare.cz/api/file_link/', post={'ident': self.fid}) + self.logDebug("API data: " + api_data) + m = re.search('<link>(.+)</link>', api_data) if m is None: self.error(_("Unable to detect direct link")) - direct = m.group(1) - self.logDebug("Direct link: " + direct) - self.download(direct, disposition=True) + + self.download(m.group(1), disposition=True) def getFileInfo(self): diff --git a/module/plugins/hoster/ZippyshareCom.py b/module/plugins/hoster/ZippyshareCom.py index 8bf5aa942..3edf3c5c1 100644 --- a/module/plugins/hoster/ZippyshareCom.py +++ b/module/plugins/hoster/ZippyshareCom.py @@ -2,8 +2,7 @@ import re -from os import path -from urllib import unquote +from os.path import join from urlparse import urljoin from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo @@ -12,7 +11,7 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo class ZippyshareCom(SimpleHoster): __name__ = "ZippyshareCom" __type__ = "hoster" - __version__ = "0.60" + __version__ = "0.62" __pattern__ = r'(?P<HOST>http://www\d{0,2}\.zippyshare\.com)/v(?:/|iew\.jsp.*key=)(?P<KEY>\d+)' @@ -40,12 +39,6 @@ class ZippyshareCom(SimpleHoster): self.download(url) - def getFileInfo(self): - info = super(ZippyshareCom, self).getFileInfo() - self.pyfile.name = info['name'] = unquote(info['name']) - return info - - def get_checksum(self): try: m = re.search(r'\+[ ]*\((\d+)[ ]*\%[ ]*(\d+)[ ]*\+[ ]*(\d+)[ ]*\%[ ]*(\d+)\)[ ]*\+', self.html) @@ -64,8 +57,8 @@ class ZippyshareCom(SimpleHoster): def get_link(self): checksum = self.get_checksum() - p_url = path.join("d", self.info['KEY'], str(checksum), self.pyfile.name) - dl_link = urljoin(self.info['HOST'], p_url) + p_url = join("d", self.info['pattern']['KEY'], str(checksum), self.pyfile.name) + dl_link = urljoin(self.info['pattern']['HOST'], p_url) return dl_link diff --git a/module/plugins/internal/DeadCrypter.py b/module/plugins/internal/DeadCrypter.py index c721c8390..07c5c3881 100644 --- a/module/plugins/internal/DeadCrypter.py +++ b/module/plugins/internal/DeadCrypter.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from urllib import unquote from urlparse import urlparse from module.plugins.internal.SimpleCrypter import create_getInfo @@ -9,7 +10,7 @@ from module.plugins.Crypter import Crypter as _Crypter class DeadCrypter(_Crypter): __name__ = "DeadCrypter" __type__ = "crypter" - __version__ = "0.03" + __version__ = "0.04" __pattern__ = r'^unmatchable$' @@ -20,7 +21,7 @@ class DeadCrypter(_Crypter): @classmethod def getInfo(cls, url="", html=""): - return {'name': urlparse(url).path.split('/')[-1] or _("Unknown"), 'size': 0, 'status': 1, 'url': url or ""} + return {'name': urlparse(unquote(url)).path.split('/')[-1] or _("Unknown"), 'size': 0, 'status': 1, 'url': url} def setup(self): diff --git a/module/plugins/internal/DeadHoster.py b/module/plugins/internal/DeadHoster.py index b85aea3f9..6f3252f70 100644 --- a/module/plugins/internal/DeadHoster.py +++ b/module/plugins/internal/DeadHoster.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from urllib import unquote from urlparse import urlparse from module.plugins.internal.SimpleHoster import create_getInfo @@ -9,7 +10,7 @@ from module.plugins.Hoster import Hoster as _Hoster class DeadHoster(_Hoster): __name__ = "DeadHoster" __type__ = "hoster" - __version__ = "0.13" + __version__ = "0.14" __pattern__ = r'^unmatchable$' @@ -20,7 +21,7 @@ class DeadHoster(_Hoster): @classmethod def getInfo(cls, url="", html=""): - return {'name': urlparse(url).path.split('/')[-1] or _("Unknown"), 'size': 0, 'status': 1, 'url': url or ""} + return {'name': urlparse(unquote(url)).path.split('/')[-1] or _("Unknown"), 'size': 0, 'status': 1, 'url': url} def setup(self): diff --git a/module/plugins/internal/SimpleHoster.py b/module/plugins/internal/SimpleHoster.py index 24a2fa6b0..ba718950d 100644 --- a/module/plugins/internal/SimpleHoster.py +++ b/module/plugins/internal/SimpleHoster.py @@ -3,7 +3,8 @@ import re from time import time -from urlparse import urlparse +from urllib import unquote +from urlparse import urljoin, urlparse from module.PyFile import statusMap as _statusMap from module.network.CookieJar import CookieJar @@ -32,7 +33,7 @@ def _error(self, reason, type): #@TODO: Remove in 0.4.10 def _wait(self, seconds, reconnect): if seconds: - self.setWait(seconds) + self.setWait(seconds + 1) if reconnect is not None: self.wantReconnect = reconnect @@ -113,25 +114,37 @@ def timestamp(): #@TODO: Move to hoster class in 0.4.10 -def _getDirectLink(self, url): +def _isDirectLink(self, url, resumable=True): header = self.load(url, ref=True, just_header=True, decode=True) - if not 'code' in header or header['code'] != 302: - return "" - if not 'location' in header or not header['location']: return "" - # if 'content-type' in header and "text/plain" not in header['content-type']: - # return "" + location = header['location'] + + resumable = False #@NOTE: Testing... + + if resumable: #: sometimes http code may be wrong... + if 'location' in self.load(location, ref=True, cookies=True, just_header=True, decode=True): + return "" + else: + if not 'code' in header or header['code'] != 302: + return "" + + if urlparse(location).scheme: + link = location + else: + p = urlparse(url) + base = "%s://%s" % (p.scheme, p.netloc) + link = urljoin(base, location) - return header['location'] + return link class SimpleHoster(Hoster): __name__ = "SimpleHoster" __type__ = "hoster" - __version__ = "0.67" + __version__ = "0.69" __pattern__ = r'^unmatchable$' @@ -153,6 +166,9 @@ class SimpleHoster(Hoster): SIZE_PATTERN: (optional) Size that will be checked for the file example: SIZE_PATTERN = r'(?P<S>file_size) (?P<U>size_unit)' + HASHSUM_PATTERN: (optional) Hash code and type of the file + example: HASHSUM_PATTERN = r'(?P<H>hash_code) (?P<T>MD5)' + OFFLINE_PATTERN: (optional) Check if the file is yet available online example: OFFLINE_PATTERN = r'File (deleted|not found)' @@ -188,9 +204,9 @@ class SimpleHoster(Hoster): TEXT_ENCODING = False #: Set to True or encoding name if encoding value in http header is not correct COOKIES = True #: or False or list of tuples [(domain, name, value)] FORCE_CHECK_TRAFFIC = False #: Set to True to force checking traffic left for premium account - CHECK_DIRECT_LINK = None #: when None self-set to True if self.account else False - MULTI_HOSTER = False #: Set to True to leech other hoster link - CONTENT_DISPOSITION = False #: Set to True to replace file name with content-disposition value in http header + CHECK_DIRECT_LINK = None #: Set to True to check for direct link, set to None to do it only if self.account is True + MULTI_HOSTER = False #: Set to True to leech other hoster link (according its multihoster hook if available) + CONTENT_DISPOSITION = False #: Set to True to replace file name with content-disposition value from http header @classmethod @@ -202,14 +218,32 @@ class SimpleHoster(Hoster): @classmethod def getInfo(cls, url="", html=""): - info = {'name': urlparse(url).path.split('/')[-1] or _("Unknown"), 'size': 0, 'status': 3 if url else 1, 'url': url or ""} + info = {'name': urlparse(unquote(url)).path.split('/')[-1] or _("Unknown"), 'size': 0, 'status': 3, 'url': url} if not html: - if url: - html = getURL(url, cookies=cls.COOKIES, decode=not cls.TEXT_ENCODING) - if isinstance(cls.TEXT_ENCODING, basestring): - html = unicode(html, cls.TEXT_ENCODING) - else: + try: + if not url: + info['error'] = "missing url" + info['status'] = 1 + raise + + try: + html = getURL(url, cookies=cls.COOKIES, decode=not cls.TEXT_ENCODING) + + if isinstance(cls.TEXT_ENCODING, basestring): + html = unicode(html, cls.TEXT_ENCODING) + + except BadHeader, e: + info['error'] = "%d: %s" % (e.code, e.content) + + if e.code is 404: + info['status'] = 1 + raise + + if e.code is 503: + info['status'] = 6 + raise + except: return info online = False @@ -225,19 +259,20 @@ class SimpleHoster(Hoster): else: try: - info.update(re.match(cls.__pattern__, url).groupdict()) + info['pattern'] = re.match(cls.__pattern__, url).groupdict() #: pattern groups will be saved here, please save api stuff to info['api'] except: pass for pattern in ("FILE_INFO_PATTERN", "INFO_PATTERN", "FILE_NAME_PATTERN", "NAME_PATTERN", - "FILE_SIZE_PATTERN", "SIZE_PATTERN"): #@TODO: Remove old patterns starting with "FILE_" in 0.4.10 + "FILE_SIZE_PATTERN", "SIZE_PATTERN", + "HASHSUM_PATTERN"): #@TODO: Remove old patterns starting with "FILE_" in 0.4.10 try: attr = getattr(cls, pattern) dict = re.search(attr, html).groupdict() - if all(True for k in dict if k not in info): - info.update(dict) + if all(True for k in dict if k not in info['pattern']): + info['pattern'].update(dict) except AttributeError: continue @@ -248,12 +283,12 @@ class SimpleHoster(Hoster): if online: info['status'] = 2 - if 'N' in info: - info['name'] = replace_patterns(info['N'].strip(), + if 'N' in info['pattern']: + info['name'] = replace_patterns(unquote(info['pattern']['N'].strip()), cls.FILE_NAME_REPLACEMENTS if hasattr(cls, "FILE_NAME_REPLACEMENTS") else cls.NAME_REPLACEMENTS) #@TODO: Remove FILE_NAME_REPLACEMENTS check in 0.4.10 - if 'S' in info: - size = replace_patterns(info['S'] + info['U'] if 'U' in info else info['S'], + if 'S' in info['pattern']: + size = replace_patterns(info['pattern']['S'] + info['pattern']['U'] if 'U' in info else info['pattern']['S'], cls.FILE_SIZE_REPLACEMENTS if hasattr(cls, "FILE_SIZE_REPLACEMENTS") else cls.SIZE_REPLACEMENTS) #@TODO: Remove FILE_SIZE_REPLACEMENTS check in 0.4.10 info['size'] = parseFileSize(size) @@ -261,6 +296,10 @@ class SimpleHoster(Hoster): unit = info['units'] if 'units' in info else None info['size'] = parseFileSize(info['size'], unit) + if 'H' in info['pattern']: + hashtype = info['pattern']['T'] if 'T' in info['pattern'] else "hash" + info[hashtype] = info['pattern']['H'] + return info @@ -348,15 +387,20 @@ class SimpleHoster(Hoster): if self.link: self.download(self.link, disposition=self.CONTENT_DISPOSITION) + self.checkFile() + + + def checkFile(self): + if self.checkDownload({'empty': re.compile(r"^$")}) is "empty": #@TODO: Move to hoster in 0.4.10 + self.fail(_("Empty file")) + def checkErrors(self): - if hasattr(self, 'WAIT_PATTERN'): - m = re.search(self.WAIT_PATTERN, self.html) + if hasattr(self, 'ERROR_PATTERN'): + m = re.search(self.ERROR_PATTERN, self.html) if m: - wait_time = sum([int(v) * {"hr": 3600, "hour": 3600, "min": 60, "sec": 1}[u.lower()] for v, u in - re.findall(r'(\d+)\s*(hr|hour|min|sec)', m, re.I)]) - self.wait(wait_time, False) - return + e = self.info['error'] = m.group(1) + self.error(e) if hasattr(self, 'PREMIUM_ONLY_PATTERN'): m = re.search(self.PREMIUM_ONLY_PATTERN, self.html) @@ -364,11 +408,13 @@ class SimpleHoster(Hoster): self.info['error'] = "premium-only" return - if hasattr(self, 'ERROR_PATTERN'): - m = re.search(self.ERROR_PATTERN, self.html) + if hasattr(self, 'WAIT_PATTERN'): + m = re.search(self.WAIT_PATTERN, self.html) if m: - e = self.info['error'] = m.group(1) - self.error(e) + wait_time = sum([int(v) * {"hr": 3600, "hour": 3600, "min": 60, "sec": 1}[u.lower()] for v, u in + re.findall(r'(\d+)\s*(hr|hour|min|sec)', m, re.I)]) + self.wait(wait_time, False) + return self.info.pop('error', None) @@ -430,7 +476,7 @@ class SimpleHoster(Hoster): def handleDirect(self): - link = _getDirectLink(self, self.pyfile.url) + link = _isDirectLink(self, self.pyfile.url, self.resumeDownload) if link: self.logInfo(_("Direct download link detected")) @@ -459,7 +505,7 @@ class SimpleHoster(Hoster): self.link = m.group(1) except Exception, e: - self.fail(str(e)) + self.fail(e) def handlePremium(self): @@ -474,7 +520,7 @@ class SimpleHoster(Hoster): self.link = m.group(1) except Exception, e: - self.fail(str(e)) + self.fail(e) def longWait(self, wait_time=None, max_tries=3): diff --git a/module/plugins/internal/XFSAccount.py b/module/plugins/internal/XFSAccount.py index 5a265c08a..2094b1480 100644 --- a/module/plugins/internal/XFSAccount.py +++ b/module/plugins/internal/XFSAccount.py @@ -12,7 +12,7 @@ from module.plugins.internal.SimpleHoster import parseHtmlForm, set_cookies class XFSAccount(Account): __name__ = "XFSAccount" __type__ = "account" - __version__ = "0.31" + __version__ = "0.32" __description__ = """XFileSharing account plugin""" __license__ = "GPLv3" @@ -27,15 +27,15 @@ class XFSAccount(Account): PREMIUM_PATTERN = r'\(Premium only\)' - VALID_UNTIL_PATTERN = r'>Premium.[Aa]ccount expire:.*?(\d{1,2} [\w^_]+ \d{4})' + VALID_UNTIL_PATTERN = r'Premium.[Aa]ccount expire:.*?(\d{1,2} [\w^_]+ \d{4})' - TRAFFIC_LEFT_PATTERN = r'>Traffic available today:.*?<b>\s*(?P<S>[\d.,]+|[Uu]nlimited)\s*(?:(?P<U>[\w^_]+)\s*)?</b>' + TRAFFIC_LEFT_PATTERN = r'Traffic available today:.*?<b>\s*(?P<S>[\d.,]+|[Uu]nlimited)\s*(?:(?P<U>[\w^_]+)\s*)?</b>' TRAFFIC_LEFT_UNIT = "MB" #: used only if no group <U> was found LEECH_TRAFFIC_PATTERN = r'Leech Traffic left:<b>.*?(?P<S>[\d.,]+|[Uu]nlimited)\s*(?:(?P<U>[\w^_]+)\s*)?</b>' LEECH_TRAFFIC_UNIT = "MB" #: used only if no group <U> was found - LOGIN_FAIL_PATTERN = r'>(Incorrect Login or Password|Error<)' + LOGIN_FAIL_PATTERN = r'>\s*(Incorrect Login or Password|Error<)' def __init__(self, manager, accounts): #@TODO: remove in 0.4.10 diff --git a/module/plugins/internal/XFSHoster.py b/module/plugins/internal/XFSHoster.py index 2aaf18b1a..c3db3f335 100644 --- a/module/plugins/internal/XFSHoster.py +++ b/module/plugins/internal/XFSHoster.py @@ -16,7 +16,7 @@ from module.utils import html_unescape class XFSHoster(SimpleHoster): __name__ = "XFSHoster" __type__ = "hoster" - __version__ = "0.26" + __version__ = "0.27" __pattern__ = r'^unmatchable$' @@ -35,7 +35,6 @@ class XFSHoster(SimpleHoster): CHECK_DIRECT_LINK = None MULTI_HOSTER = True #@NOTE: Should be default to False for safe, but I'm lazy... - INFO_PATTERN = r'<tr><td align=right><b>Filename:</b></td><td nowrap>(?P<N>[^<]+)</td></tr>\s*.*?<small>\((?P<S>[^<]+)\)</small>' NAME_PATTERN = r'(>Filename:</b></td><td nowrap>|name="fname" value="|<span class="name">)(?P<N>.+?)(\s*<|")' SIZE_PATTERN = r'(>Size:</b></td><td>|>File:.*>|<span class="size">)(?P<S>[\d.,]+)\s*(?P<U>[\w^_]+)' @@ -49,10 +48,10 @@ class XFSHoster(SimpleHoster): LEECH_LINK_PATTERN = r'<h2>Download Link</h2>\s*<textarea[^>]*>([^<]+)' LINK_PATTERN = None #: final download url pattern - CAPTCHA_PATTERN = r'(https?://[^"\']+?/captchas?/[^"\']+)' - CAPTCHA_DIV_PATTERN = r'>Enter code.*?<div.*?>(.+?)</div>' - RECAPTCHA_PATTERN = None - SOLVEMEDIA_PATTERN = None + CAPTCHA_PATTERN = r'(https?://[^"\']+?/captchas?/[^"\']+)' + CAPTCHA_BLOCK_PATTERN = r'>Enter code.*?<div.*?>(.+?)</div>' + RECAPTCHA_PATTERN = None + SOLVEMEDIA_PATTERN = None FORM_PATTERN = None FORM_INPUTS_MAP = None #: dict passed as input_names to parseHtmlForm @@ -234,10 +233,10 @@ class XFSHoster(SimpleHoster): retries = 3 else: delay = 1 * 60 * 60 - retries = 25 + retries = 24 - self.wait(delay, True) - self.retry(retries, reason=_("Download limit exceeded")) + self.wantReconnect = True + self.retry(retries, delay, _("Download limit exceeded")) elif 'countdown' in self.errmsg or 'Expired' in self.errmsg: self.retry(reason=_("Link expired")) @@ -249,6 +248,7 @@ class XFSHoster(SimpleHoster): self.fail(_("File too large for free download")) else: + self.wantReconnect = True self.retry(wait_time=60, reason=self.errmsg) if self.errmsg: @@ -311,7 +311,7 @@ class XFSHoster(SimpleHoster): inputs['code'] = self.decryptCaptcha(captcha_url) return 1 - m = re.search(self.CAPTCHA_DIV_PATTERN, self.html, re.S) + m = re.search(self.CAPTCHA_BLOCK_PATTERN, self.html, re.S) if m: captcha_div = m.group(1) numerals = re.findall(r'<span.*?padding-left\s*:\s*(\d+).*?>(\d)</span>', html_unescape(captcha_div)) |