diff options
Diffstat (limited to 'module')
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)) | 
