diff options
Diffstat (limited to 'module/plugins/internal')
| -rw-r--r-- | module/plugins/internal/CaptchaService.py | 49 | ||||
| -rw-r--r-- | module/plugins/internal/DeadCrypter.py | 6 | ||||
| -rw-r--r-- | module/plugins/internal/DeadHoster.py | 6 | ||||
| -rw-r--r-- | module/plugins/internal/MultiHook.py | 214 | ||||
| -rw-r--r-- | module/plugins/internal/MultiHoster.py | 46 | ||||
| -rw-r--r-- | module/plugins/internal/SimpleCrypter.py | 22 | ||||
| -rw-r--r-- | module/plugins/internal/SimpleDereferer.py | 6 | ||||
| -rw-r--r-- | module/plugins/internal/SimpleHoster.py | 104 | ||||
| -rw-r--r-- | module/plugins/internal/XFSAccount.py | 12 | ||||
| -rw-r--r-- | module/plugins/internal/XFSCrypter.py | 1 | ||||
| -rw-r--r-- | module/plugins/internal/XFSHoster.py | 28 | 
11 files changed, 298 insertions, 196 deletions
diff --git a/module/plugins/internal/CaptchaService.py b/module/plugins/internal/CaptchaService.py index 965799e8e..b429fd6e0 100644 --- a/module/plugins/internal/CaptchaService.py +++ b/module/plugins/internal/CaptchaService.py @@ -2,6 +2,7 @@  import re +from base64 import urlsafe_b64encode  from random import random  from module.common.json_layer import json_loads @@ -54,14 +55,14 @@ class CaptchaService:  class ReCaptcha(CaptchaService):      __name__    = "ReCaptcha" -    __version__ = "0.08" +    __version__ = "0.09"      __description__ = """ReCaptcha captcha service plugin"""      __license__     = "GPLv3"      __authors__     = [("pyLoad Team", "admin@pyload.org")] -    KEY_PATTERN      = r'recaptcha(?:/api|\.net)/(?:challenge|noscript)\?k=([\w-]+)' +    KEY_PATTERN      = r'(?:class="g-recaptcha"\s+data-sitekey="|recaptcha(?:/api|\.net)/(?:challenge|noscript)\?k=)([\w-]+)'      KEY_AJAX_PATTERN = r'Recaptcha\.create\s*\(\s*["\']([\w-]+)' @@ -84,7 +85,7 @@ class ReCaptcha(CaptchaService):              return None -    def challenge(self, key=None): +    def challenge(self, key=None, userverify=False):          if not key:              if self.detect_key():                  key = self.key @@ -97,14 +98,30 @@ class ReCaptcha(CaptchaService):          try:              challenge = re.search("challenge : '(.+?)',", html).group(1)              server    = re.search("server : '(.+?)',", html).group(1) -        except: + +        except AttributeError:              errmsg = _("ReCaptcha challenge pattern not found")              self.plugin.fail(errmsg) -            raise ValueError(errmsg) +            raise AttributeError(errmsg)          self.plugin.logDebug("ReCaptcha challenge: %s" % challenge) -        return challenge, self.result(server, challenge) +        response = challenge, self.result(server, challenge) + +        return self.userverify(*response) if userverify else response + + +    def userverify(self, challenge, result): +        response = self.plugin.req.load("https://www.google.com/recaptcha/api2/userverify", +                                        post={'c'       : challenge, +                                              'response': urlsafe_b64encode('{"response":"%s"}' % result)}) +        try: +            return re.search(r'"uvresp","(.+?)"', response).group(1) + +        except AttributeError: +            errmsg = _("ReCaptcha userverify response not found") +            self.plugin.fail(errmsg) +            raise AttributeError(errmsg)      def result(self, server, challenge): @@ -167,10 +184,11 @@ class AdsCaptcha(CaptchaService):          try:              challenge = re.search("challenge: '(.+?)',", html).group(1)              server    = re.search("server: '(.+?)',", html).group(1) -        except: + +        except AttributeError:              errmsg = _("AdsCaptcha challenge pattern not found")              self.plugin.fail(errmsg) -            raise ValueError(errmsg) +            raise AttributeError(errmsg)          self.plugin.logDebug("AdsCaptcha challenge: %s" % challenge) @@ -214,10 +232,11 @@ class SolveMedia(CaptchaService):              challenge = re.search(r'<input type=hidden name="adcopy_challenge" id="adcopy_challenge" value="([^"]+)">',                                    html).group(1)              server    = "http://api.solvemedia.com/papi/media" -        except: + +        except AttributeError:              errmsg = _("SolveMedia challenge pattern not found")              self.plugin.fail(errmsg) -            raise ValueError(errmsg) +            raise AttributeError(errmsg)          self.plugin.logDebug("SolveMedia challenge: %s" % challenge) @@ -286,10 +305,11 @@ class AdYouLike(CaptchaService):                                           'callback': callback})          try:              challenge = json_loads(re.search(callback + r'\s*\((.+?)\)', html).group(1)) -        except: + +        except AttributeError:              errmsg = _("AdYouLike challenge pattern not found")              self.plugin.fail(errmsg) -            raise ValueError(errmsg) +            raise AttributeError(errmsg)          self.plugin.logDebug("AdYouLike challenge: %s" % challenge) @@ -316,10 +336,11 @@ class AdYouLike(CaptchaService):          try:              instructions_visual = challenge['translations'][server['all']['lang']]['instructions_visual']              result = re.search(u'«(.+?)»', instructions_visual).group(1).strip() -        except: + +        except AttributeError:              errmsg = _("AdYouLike result not found")              self.plugin.fail(errmsg) -            raise ValueError(errmsg) +            raise AttributeError(errmsg)          result = {'_ayl_captcha_engine' : "adyoulike",                    '_ayl_env'            : server['all']['env'], diff --git a/module/plugins/internal/DeadCrypter.py b/module/plugins/internal/DeadCrypter.py index 07c5c3881..0fa23eef3 100644 --- a/module/plugins/internal/DeadCrypter.py +++ b/module/plugins/internal/DeadCrypter.py @@ -20,8 +20,10 @@ class DeadCrypter(_Crypter):      @classmethod -    def getInfo(cls, url="", html=""): -        return {'name': urlparse(unquote(url)).path.split('/')[-1] or _("Unknown"), 'size': 0, 'status': 1, 'url': url} +    def apiInfo(cls, url="", get={}, post={}): +        api = super(DeadCrypter, self).apiInfo(url, get, post) +        api['status'] = 1 +        return api      def setup(self): diff --git a/module/plugins/internal/DeadHoster.py b/module/plugins/internal/DeadHoster.py index 6f3252f70..cc7adf4df 100644 --- a/module/plugins/internal/DeadHoster.py +++ b/module/plugins/internal/DeadHoster.py @@ -20,8 +20,10 @@ class DeadHoster(_Hoster):      @classmethod -    def getInfo(cls, url="", html=""): -        return {'name': urlparse(unquote(url)).path.split('/')[-1] or _("Unknown"), 'size': 0, 'status': 1, 'url': url} +    def apiInfo(cls, url="", get={}, post={}): +        api = super(DeadHoster, self).apiInfo(url, get, post) +        api['status'] = 1 +        return api      def setup(self): diff --git a/module/plugins/internal/MultiHook.py b/module/plugins/internal/MultiHook.py index ea9f32673..a3b266679 100644 --- a/module/plugins/internal/MultiHook.py +++ b/module/plugins/internal/MultiHook.py @@ -2,19 +2,24 @@  import re +from time import sleep +  from module.plugins.Hook import Hook -from module.utils import remove_chars +from module.utils import decode, remove_chars  class MultiHook(Hook):      __name__    = "MultiHook"      __type__    = "hook" -    __version__ = "0.29" +    __version__ = "0.35" -    __config__ = [("mode"        , "all;listed;unlisted", "Use for plugins (if supported)"               , "all"), -                  ("pluginlist"  , "str"                , "Plugin list (comma separated)"                , ""   ), -                  ("revertfailed", "bool"               , "Revert to standard download if download fails", False), -                  ("interval"    , "int"                , "Reload interval in hours (0 to disable)"      , 12   )] +    __config__ = [("pluginmode"    , "all;listed;unlisted", "Use for plugins"                     , "all"), +                  ("pluginlist"    , "str"                , "Plugin list (comma separated)"       , ""   ), +                  ("revertfailed"  , "bool"               , "Revert to standard download if fails", True ), +                  ("retry"         , "int"                , "Number of retries before revert"     , 10   ), +                  ("retryinterval" , "int"                , "Retry interval in minutes"           , 1    ), +                  ("reload"        , "bool"               , "Reload plugin list"                  , True ), +                  ("reloadinterval", "int"                , "Reload interval in hours"            , 12   )]      __description__ = """Hook plugin for multi hoster/crypter"""      __license__     = "GPLv3" @@ -22,49 +27,78 @@ class MultiHook(Hook):                         ("Walter Purcaro", "vuolter@gmail.com")] -    MIN_INTERVAL = 12 * 60 * 60  #: reload plugins every 12h - -    PLUGIN_REPLACEMENTS = [("1fichier.com"   , "onefichier.com"), -                           ("2shared.com"    , "twoshared.com" ), -                           ("4shared.com"    , "fourshared.com"), -                           ("cloudnator.com" , "shragle.com"   ), -                           ("easy-share.com" , "crocko.com"    ), -                           ("fileparadox.com", "fileparadox.in"), -                           ("freakshare.net" , "freakshare.com"), -                           ("hellshare.com"  , "hellshare.cz"  ), -                           ("ifile.it"       , "filecloud.io"  ), -                           ("nowdownload.ch" , "nowdownload.sx"), -                           ("nowvideo.co"    , "nowvideo.sx"   ), -                           ("putlocker.com"  , "firedrive.com" ), -                           ("share-rapid.cz" , "multishare.cz" ), -                           ("sharerapid.cz"  , "multishare.cz" ), -                           ("ul.to"          , "uploaded.to"   ), -                           ("uploaded.net"   , "uploaded.to"   )] +    MIN_INTERVAL = 1 * 60 * 60 + +    DOMAIN_REPLACEMENTS = [(r'180upload\.com'  , "hundredeightyupload.com"), +                           (r'1fichier\.com'   , "onefichier.com"         ), +                           (r'2shared\.com'    , "twoshared.com"          ), +                           (r'4shared\.com'    , "fourshared.com"         ), +                           (r'bayfiles\.net'   , "bayfiles.com"           ), +                           (r'cloudnator\.com' , "shragle.com"            ), +                           (r'dfiles\.eu'      , "depositfiles.com"       ), +                           (r'easy-share\.com' , "crocko.com"             ), +                           (r'freakshare\.net' , "freakshare.com"         ), +                           (r'hellshare\.com'  , "hellshare.cz"           ), +                           (r'ifile\.it'       , "filecloud.io"           ), +                           (r'nowdownload\.\w+', "nowdownload.sx"         ), +                           (r'nowvideo\.\w+'   , "nowvideo.sx"            ), +                           (r'putlocker\.com'  , "firedrive.com"          ), +                           (r'share-?rapid\.cz', "multishare.cz"          ), +                           (r'ul\.to'          , "uploaded.to"            ), +                           (r'uploaded\.net'   , "uploaded.to"            ), +                           (r'uploadhero\.co'  , "uploadhero.com"         ), +                           (r'zshares\.net'    , "zshare.net"             ), +                           (r'\d+.+'           , "X\0"                    )]      def setup(self): -        self.account       = None -        self.type          = self.core.pluginManager.findPlugin(self.__name__)[1] or "hoster"          self.plugins       = []          self.supported     = []          self.new_supported = [] +        self.account      = None +        self.pluginclass  = None +        self.pluginmodule = None +        self.pluginname   = None +        self.plugintype   = None + +        self._initPlugin() -    def coreReady(self): -        self.account = self.core.accountManager.getAccountPlugin(self.__name__) + +    def _initPlugin(self): +        plugin, type = self.core.pluginManager.findPlugin(self.__name__) + +        if not plugin: +            self.logWarning("Hook plugin will be deactivated due missing plugin reference") +            self.setConfig('activated', False) +        else: +            self.pluginname   = self.__name__ +            self.plugintype   = type +            self.pluginmodule = self.core.pluginManager.loadModule(type, self.__name__) +            self.pluginclass  = getattr(self.pluginmodule, self.__name__) + + +    def _loadAccount(self): +        self.account = self.core.accountManager.getAccountPlugin(self.pluginname)          if self.account and not self.account.canUse():              self.account = None -        if not self.account: -            self.logWarning("MultiHook will be deactivated due missing account reference") +        if not self.account and hasattr(self.pluginclass, "LOGIN_ACCOUNT") and self.pluginclass.LOGIN_ACCOUNT: +            self.logWarning("Hook plugin will be deactivated due missing account reference")              self.setConfig('activated', False) +    def coreReady(self): +        self._loadAccount() + +      def getURL(self, *args, **kwargs):  #@TODO: Remove in 0.4.10          """ see HTTPRequest for argument list """          h = pyreq.getHTTPRequest(timeout=120)          try: +            if not 'decode' in kwargs: +                kwargs['decode'] = True              rep = h.load(*args, **kwargs)          finally:              h.close() @@ -81,40 +115,50 @@ class MultiHook(Hook):              return default -    def pluginCached(self): -        if not self.plugins: +    def pluginsCached(self): +        if self.plugins: +            return self.plugins +             +        for _i in xrange(3):              try: -                pluginset = self.pluginSet(self.getHosters() if self.type == "hoster" else self.getCrypters()) +                pluginset = self._pluginSet(self.getHosters() if self.plugintype == "hoster" else self.getCrypters()) +                          except Exception, e: -                self.logError(e) -                return [] +                self.logError(e, "Waiting 1 minute and retry") +                sleep(60) +             +            else: +                break +        else: +            return list() -            try: -                configmode = self.getConfig("mode", 'all') -                if configmode in ("listed", "unlisted"): -                    pluginlist = self.getConfig("pluginlist", '').replace('|', ',').replace(';', ',').split(',') -                    configset  = self.pluginSet(pluginlist) +        try: +            configmode = self.getConfig("pluginmode", 'all') +            if configmode in ("listed", "unlisted"): +                pluginlist = self.getConfig("pluginlist", '').replace('|', ',').replace(';', ',').split(',') +                configset  = self._pluginSet(pluginlist) -                    if configmode == "listed": -                        pluginset &= configset -                    else: -                        pluginset -= configset +                if configmode == "listed": +                    pluginset &= configset +                else: +                    pluginset -= configset -            except Exception, e: -                self.logError(e) +        except Exception, e: +            self.logError(e) -            self.plugins = list(pluginset) +        self.plugins = list(pluginset)          return self.plugins -    def pluginSet(self, plugins): -        plugins = set((str(x).strip().lower() for x in plugins)) +    def _pluginSet(self, plugins): +        plugins = set((decode(x).strip().lower() for x in plugins if '.' in x)) -        for rep in self.PLUGIN_REPLACEMENTS: -            if rep[0] in plugins: -                plugins.remove(rep[0]) -                plugins.add(rep[1]) +        for rf, rt in self.DOMAIN_REPLACEMENTS: +            regex = re.compile(rf) +            for p in filter(lambda x: regex.match(x), plugins): +                plugins.remove(p) +                plugins.add(re.sub(rf, rt, p))          plugins.discard('') @@ -139,9 +183,7 @@ class MultiHook(Hook):      def periodical(self):          """reload plugin list periodically""" -        self.interval = max(self.getConfig("interval", 0), self.MIN_INTERVAL) - -        self.logInfo(_("Reloading supported %s list") % self.type) +        self.logInfo(_("Reloading supported %s list") % self.plugintype)          old_supported = self.supported @@ -158,18 +200,24 @@ class MultiHook(Hook):              for plugin in old_supported:                  self.unloadPlugin(plugin) +        if self.getConfig("reload", True): +            self.interval = max(self.getConfig("reloadinterval", 12), self.MIN_INTERVAL) +        else: +            self.core.scheduler.removeJob(self.cb) +            self.cb = None +      def overridePlugins(self):          excludedList = [] -        if self.type == "hoster": +        if self.plugintype == "hoster":              pluginMap    = dict((name.lower(), name) for name in self.core.pluginManager.hosterPlugins.iterkeys())              accountList  = [account.type.lower() for account in self.core.api.getAccounts(False) if account.valid and account.premium]          else:              pluginMap    = {}              accountList  = [name[::-1].replace("Folder"[::-1], "", 1).lower()[::-1] for name in self.core.pluginManager.crypterPlugins.iterkeys()] -        for plugin in self.pluginCached(): +        for plugin in self.pluginsCached():              name = remove_chars(plugin, "-.")              if name in accountList: @@ -181,42 +229,39 @@ class MultiHook(Hook):                      self.new_supported.append(plugin)          if not self.supported and not self.new_supported: -            self.logError(_("No %s loaded") % self.type) +            self.logError(_("No %s loaded") % self.plugintype)              return -        module = self.core.pluginManager.getPlugin(self.__name__) -        klass  = getattr(module, self.__name__) -          # inject plugin plugin -        self.logDebug("Overwritten %ss: %s" % (self.type, ", ".join(sorted(self.supported)))) +        self.logDebug("Overwritten %ss: %s" % (self.plugintype, ", ".join(sorted(self.supported))))          for plugin in self.supported: -            hdict = self.core.pluginManager.plugins[self.type][plugin] -            hdict['new_module'] = module -            hdict['new_name']   = self.__name__ +            hdict = self.core.pluginManager.plugins[self.plugintype][plugin] +            hdict['new_module'] = self.pluginmodule +            hdict['new_name']   = self.pluginname          if excludedList: -            self.logInfo(_("%ss not overwritten: %s") % (self.type.capitalize(), ", ".join(sorted(excludedList)))) +            self.logInfo(_("%ss not overwritten: %s") % (self.plugintype.capitalize(), ", ".join(sorted(excludedList))))          if self.new_supported:              plugins = sorted(self.new_supported) -            self.logDebug("New %ss: %s" % (self.type, ", ".join(plugins))) +            self.logDebug("New %ss: %s" % (self.plugintype, ", ".join(plugins)))              # create new regexp -            regexp = r'.*(%s).*' % "|".join([x.replace(".", "\.") for x in plugins]) -            if hasattr(klass, "__pattern__") and isinstance(klass.__pattern__, basestring) and '://' in klass.__pattern__: -                regexp = r'%s|%s' % (klass.__pattern__, regexp) +            regexp = r'.*(?P<DOMAIN>%s).*' % "|".join([x.replace(".", "\.") for x in plugins]) +            if hasattr(self.pluginclass, "__pattern__") and isinstance(self.pluginclass.__pattern__, basestring) and '://' in self.pluginclass.__pattern__: +                regexp = r'%s|%s' % (self.pluginclass.__pattern__, regexp)              self.logDebug("Regexp: %s" % regexp) -            hdict = self.core.pluginManager.plugins[self.type][self.__name__] +            hdict = self.core.pluginManager.plugins[self.plugintype][self.pluginname]              hdict['pattern'] = regexp              hdict['re']      = re.compile(regexp)      def unloadPlugin(self, plugin): -        hdict = self.core.pluginManager.plugins[self.type][plugin] +        hdict = self.core.pluginManager.plugins[self.plugintype][plugin]          if "module" in hdict:              del hdict['module'] @@ -231,18 +276,29 @@ class MultiHook(Hook):              self.unloadPlugin(plugin)          # reset pattern -        klass = getattr(self.core.pluginManager.getPlugin(self.__name__), self.__name__) -        hdict = self.core.pluginManager.plugins[self.type][self.__name__] +        hdict = self.core.pluginManager.plugins[self.plugintype][self.pluginname] -        hdict['pattern'] = getattr(klass, "__pattern__", r'^unmatchable$') +        hdict['pattern'] = getattr(self.pluginclass, "__pattern__", r'^unmatchable$')          hdict['re']      = re.compile(hdict['pattern'])      def downloadFailed(self, pyfile):          """remove plugin override if download fails but not if file is offline/temp.offline""" -        if pyfile.hasStatus("failed") and self.getConfig("revertfailed", True): -            hdict = self.core.pluginManager.plugins[self.type][pyfile.pluginname] -            if "new_name" in hdict and hdict['new_name'] == self.__name__: +        if pyfile.status != 8 or not self.getConfig("revertfailed", True): +            return + +        hdict = self.core.pluginManager.plugins[self.plugintype][pyfile.pluginname] +        if "new_name" in hdict and hdict['new_name'] == self.pluginname: +            if pyfile.error == "MultiHook":                  self.logDebug("Unload MultiHook", pyfile.pluginname, hdict)                  self.unloadPlugin(pyfile.pluginname)                  pyfile.setStatus("queued") +            else: +                retries   = max(self.getConfig("retry", 10), 0) +                wait_time = max(self.getConfig("retryinterval", 1), 0) + +                if 0 < retries > pyfile.plugin.retries: +                    pyfile.setCustomStatus("MultiHook", "queued") +                    pyfile.plugin.retries += 1 +                    pyfile.plugin.setWait(wait_time) +                    pyfile.plugin.wait() diff --git a/module/plugins/internal/MultiHoster.py b/module/plugins/internal/MultiHoster.py index 60320399a..8ca4d427f 100644 --- a/module/plugins/internal/MultiHoster.py +++ b/module/plugins/internal/MultiHoster.py @@ -8,7 +8,7 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, r  class MultiHoster(SimpleHoster):      __name__    = "MultiHoster"      __type__    = "hoster" -    __version__ = "0.29" +    __version__ = "0.32"      __pattern__ = r'^unmatchable$' @@ -17,12 +17,14 @@ class MultiHoster(SimpleHoster):      __authors__     = [("Walter Purcaro", "vuolter@gmail.com")] +    CHECK_TRAFFIC = True      LOGIN_ACCOUNT = True      def setup(self): -        self.chunkLimit = 1 -        self.multiDL    = self.premium +        self.chunkLimit     = 1 +        self.multiDL        = bool(self.account) +        self.resumeDownload = self.premium      def prepare(self): @@ -50,20 +52,8 @@ class MultiHoster(SimpleHoster):      def process(self, pyfile):          self.prepare() -        try: -            module = self.core.pluginManager.hosterPlugins[self.__name__]['module'] -            klass  = getattr(module, self.__name__) - -            self.logDebug("File info (BEFORE): %s" % self.info) -            self.info.update(klass.getInfo(self.pyfile.url, self.html)) -            self.logDebug("File info (AFTER): %s"  % self.info) - -        except Exception: -            self.checkNameSize() - -        else: -            self.checkNameSize(getinfo=False) -            self.checkStatus(getinfo=False) +        if self.__pattern__ != r'^unmatchable$' and re.match(self.__pattern__, pyfile.url): +            self.checkInfo()          if self.directDL:              self.logDebug("Looking for direct download link...") @@ -71,24 +61,34 @@ class MultiHoster(SimpleHoster):          if not self.link and not self.lastDownload:              self.preload() -            self.checkInfo() + +            self.checkErrors() +            self.checkStatus(getinfo=False)              if self.premium and (not self.CHECK_TRAFFIC or self.checkTrafficLeft()):                  self.logDebug("Handled as premium download") -                self.handlePremium() -            else: +                self.handlePremium(pyfile) + +            elif not self.LOGIN_ACCOUNT or (not self.CHECK_TRAFFIC or self.checkTrafficLeft()):                  self.logDebug("Handled as free download") -                self.handleFree() +                self.handleFree(pyfile)          self.downloadLink(self.link)          self.checkFile() -    def handlePremium(self, pyfile=None): +    #@TODO: Remove in 0.4.10 +    def downloadLink(self, link): +        if link and isinstance(link, basestring): +            self.correctCaptcha() +            self.download(link, disposition=True) + + +    def handlePremium(self, pyfile):          return self.handleFree(pyfile) -    def handleFree(self, pyfile=None): +    def handleFree(self, pyfile):          if self.premium:              raise NotImplementedError          else: diff --git a/module/plugins/internal/SimpleCrypter.py b/module/plugins/internal/SimpleCrypter.py index bfc473801..43b1347fd 100644 --- a/module/plugins/internal/SimpleCrypter.py +++ b/module/plugins/internal/SimpleCrypter.py @@ -12,7 +12,7 @@ from module.utils import fixup  class SimpleCrypter(Crypter, SimpleHoster):      __name__    = "SimpleCrypter"      __type__    = "crypter" -    __version__ = "0.37" +    __version__ = "0.38"      __pattern__ = r'^unmatchable$'      __config__  = [("use_subfolder", "bool", "Save package to subfolder", True),  #: Overrides core.config['general']['folder_per_package'] @@ -82,6 +82,8 @@ class SimpleCrypter(Crypter, SimpleHoster):      def prepare(self): +        self.pyfile.error = ""  #@TODO: Remove in 0.4.10 +          self.info  = {}          self.links = []  #@TODO: Move to hoster class in 0.4.10 @@ -120,27 +122,28 @@ class SimpleCrypter(Crypter, SimpleHoster):      def checkNameSize(self, getinfo=True): -        if getinfo: +        if not self.info or getinfo:              self.logDebug("File info (BEFORE): %s" % self.info)              self.info.update(self.getInfo(self.pyfile.url, self.html))              self.logDebug("File info (AFTER): %s"  % self.info)          try: -            name = self.info['name']              url  = self.info['url'] - +            name = self.info['name']              if name and name != url:                  self.pyfile.name = name -            else: -                self.pyfile.name = self.info['name'] = urlparse(name).path.split('/')[-1]          except Exception:              pass -        folder = self.info['folder'] = self.pyfile.name +        try: +            folder = self.info['folder'] = self.pyfile.name + +        except Exception: +            pass          self.logDebug("File name: %s"   % self.pyfile.name, -                      "File folder: %s" % folder) +                      "File folder: %s" % self.pyfile.name)      def getLinks(self): @@ -153,8 +156,7 @@ class SimpleCrypter(Crypter, SimpleHoster):      def handlePages(self, pyfile):          try: -            m = re.search(self.PAGES_PATTERN, self.html) -            pages = int(m.group(1)) +            pages = int(re.search(self.PAGES_PATTERN, self.html).group(1))          except:              pages = 1 diff --git a/module/plugins/internal/SimpleDereferer.py b/module/plugins/internal/SimpleDereferer.py index 04d63658e..53b80f827 100644 --- a/module/plugins/internal/SimpleDereferer.py +++ b/module/plugins/internal/SimpleDereferer.py @@ -5,13 +5,13 @@ import re  from urllib import unquote  from module.plugins.Crypter import Crypter -from module.plugins.internal.SimpleHoster import _isDirectLink, set_cookies +from module.plugins.internal.SimpleHoster import directLink, set_cookies  class SimpleDereferer(Crypter):      __name__    = "SimpleDereferer"      __type__    = "crypter" -    __version__ = "0.02" +    __version__ = "0.03"      __pattern__ = r'^unmatchable$'      __config__  = [("use_subfolder", "bool", "Save package to subfolder", True), @@ -45,7 +45,7 @@ class SimpleDereferer(Crypter):      def decrypt(self, pyfile): -        link = _isDirectLink(pyfile.url) +        link = directLink(self, pyfile.url)          if not link:              try: diff --git a/module/plugins/internal/SimpleHoster.py b/module/plugins/internal/SimpleHoster.py index c87a6160f..5a32ac943 100644 --- a/module/plugins/internal/SimpleHoster.py +++ b/module/plugins/internal/SimpleHoster.py @@ -10,6 +10,7 @@ from urlparse import urljoin, urlparse  from module.PyFile import statusMap as _statusMap  from module.network.CookieJar import CookieJar +from module.network.HTTPRequest import BadHeader  from module.network.RequestFactory import getURL  from module.plugins.Hoster import Hoster  from module.plugins.Plugin import Fail @@ -126,7 +127,7 @@ def timestamp():  #@TODO: Move to hoster class in 0.4.10 -def _isDirectLink(self, url, resumable=False): +def directLink(self, url, resumable=False):      link = ""      for i in xrange(5 if resumable else 1): @@ -182,7 +183,7 @@ def secondsToMidnight(gmt=0):  class SimpleHoster(Hoster):      __name__    = "SimpleHoster"      __type__    = "hoster" -    __version__ = "0.90" +    __version__ = "0.94"      __pattern__ = r'^unmatchable$' @@ -244,31 +245,46 @@ class SimpleHoster(Hoster):      CHECK_TRAFFIC = False  #: Set to True to force checking traffic left for premium account      DIRECT_LINK   = None   #: Set to True to looking for direct link (as defined in handleDirect method), set to None to do it if self.account is True else False      MULTI_HOSTER  = False  #: Set to True to leech other hoster link (as defined in handleMulti method) +    LOGIN_ACCOUNT = False  #: Set to True to require account login + +    directLink = directLink  #@TODO: Remove in 0.4.10      @classmethod -    def parseInfos(cls, urls): +    def parseInfos(cls, urls):  #@TODO: Built-in in 0.4.10 core, then remove from plugins          for url in urls:              url = replace_patterns(url, cls.FILE_URL_REPLACEMENTS if hasattr(cls, "FILE_URL_REPLACEMENTS") else cls.URL_REPLACEMENTS)  #@TODO: Remove FILE_URL_REPLACEMENTS check in 0.4.10              yield cls.getInfo(url)      @classmethod +    def apiInfo(cls, url="", get={}, post={}): +        url = unquote(url) +        return {'name'  : (urlparse(url).path.split('/')[-1] +                           or urlparse(url).query.split('=', 1)[::-1][0].split('&', 1)[0] +                           or _("Unknown")), +                'size'  : 0, +                'status': 3 if url else 8, +                'url'   : url} + + +    @classmethod      def getInfo(cls, url="", html=""): -        info   = {'name': urlparse(unquote(url)).path.split('/')[-1] or _("Unknown"), 'size': 0, 'status': 3, 'url': url} +        info   = cls.apiInfo(url)          online = False          try: -            info['pattern'] = re.match(cls.__pattern__, url).groupdict()  #: pattern groups will be saved here, please save api stuff to info['api'] +            info['pattern'] = re.match(cls.__pattern__, url).groupdict()  #: pattern groups will be saved here +          except Exception: -            pass +            info['pattern'] = {}          if not html:              if not url:                  info['error']  = "missing url"                  info['status'] = 1 -            else: +            elif info['status'] is 3:                  try:                      html = getURL(url, cookies=cls.COOKIES, decode=not cls.TEXT_ENCODING) @@ -312,7 +328,7 @@ class SimpleHoster(Hoster):                      else:                          online = True -        if 'pattern' in info and not info['pattern']: +        if not info['pattern']:              info.pop('pattern', None)          if online: @@ -343,11 +359,16 @@ class SimpleHoster(Hoster):      def prepare(self): +        self.pyfile.error = ""  #@TODO: Remove in 0.4.10 +          self.info      = {}          self.link      = ""     #@TODO: Move to hoster class in 0.4.10          self.directDL  = False  #@TODO: Move to hoster class in 0.4.10          self.multihost = False  #@TODO: Move to hoster class in 0.4.10 +        if self.LOGIN_ACCOUNT and not self.account: +            self.fail(_("Required account not found")) +          self.req.setOption("timeout", 120)          if isinstance(self.COOKIES, list): @@ -397,11 +418,11 @@ class SimpleHoster(Hoster):              if self.premium and (not self.CHECK_TRAFFIC or self.checkTrafficLeft()):                  self.logDebug("Handled as premium download") -                self.handlePremium() +                self.handlePremium(pyfile) -            else: +            elif not self.LOGIN_ACCOUNT or (not self.CHECK_TRAFFIC or self.checkTrafficLeft()):                  self.logDebug("Handled as free download") -                self.handleFree() +                self.handleFree(pyfile)          self.downloadLink(self.link)          self.checkFile() @@ -410,7 +431,7 @@ class SimpleHoster(Hoster):      def downloadLink(self, link):          if link and isinstance(link, basestring):              self.correctCaptcha() -            self.download(link, disposition=True) +            self.download(link, disposition=False)  #@TODO: Set `disposition=True` in 0.4.10      def checkFile(self): @@ -420,15 +441,12 @@ class SimpleHoster(Hoster):          elif not self.lastDownload or not exists(fs_encode(self.lastDownload)):              self.lastDownload = "" - -            errmsg = _("No file downloaded") -            if 'error' in self.info: -                self.fail(errmsg, self.info['error']) -            else: -                self.fail(errmsg) +            self.fail(self.pyfile.error or _("No file downloaded"))          else: -            rules = {'empty file': re.compile(r"^$")} +            rules = {'empty file': re.compile(r'\A\Z'), +                     'html file' : re.compile(r'\A\s*<!DOCTYPE html'), +                     'html error': re.compile(r'\A\s*(<.+>)?\d{3}(\Z|\s+)')}              if hasattr(self, 'ERROR_PATTERN'):                  rules['error'] = re.compile(self.ERROR_PATTERN) @@ -444,6 +462,10 @@ class SimpleHoster(Hoster):      def checkErrors(self): +        if not self.html: +            self.logWarning(_("No html code to check")) +            return +          if hasattr(self, 'PREMIUM_ONLY_PATTERN') and self.premium and re.search(self.PREMIUM_ONLY_PATTERN, self.html):              self.fail(_("Link require a premium account to be handled")) @@ -465,42 +487,44 @@ class SimpleHoster(Hoster):      def checkStatus(self, getinfo=True): -        if getinfo: +        if not self.info or getinfo:              self.logDebug("File info (BEFORE): %s" % self.info)              self.info.update(self.getInfo(self.pyfile.url, self.html)) -        if 'status' not in self.info: -            return +        try: +            status = self.info['status'] -        status = self.info['status'] +            if status is 1: +                self.offline() -        if status is 1: -            self.offline() +            elif status is 6: +                self.tempOffline() -        elif status is 6: -            self.tempOffline() +            elif status is 8: +                self.fail() -        elif status is not 2: +        finally:              self.logDebug("File status: %s" % statusMap[status],                            "File info: %s"   % self.info)      def checkNameSize(self, getinfo=True): -        if getinfo: +        if not self.info or getinfo:              self.logDebug("File info (BEFORE): %s" % self.info)              self.info.update(self.getInfo(self.pyfile.url, self.html))              self.logDebug("File info (AFTER): %s"  % self.info)          try: -            name = self.info['name'] -            size = self.info['size']              url  = self.info['url'] - +            name = self.info['name']              if name and name != url:                  self.pyfile.name = name -            else: -                self.pyfile.name = name = self.info['name'] = urlparse(name).path.split('/')[-1] +        except Exception: +            pass + +        try: +            size = self.info['size']              if size > 0:                  self.pyfile.size = size @@ -529,7 +553,7 @@ class SimpleHoster(Hoster):      def handleDirect(self, pyfile): -        link = _isDirectLink(self, pyfile.url, self.resumeDownload) +        link = self.directLink(pyfile.url, self.resumeDownload)          if link:              self.logInfo(_("Direct download link detected")) @@ -543,9 +567,9 @@ class SimpleHoster(Hoster):          pass -    def handleFree(self, pyfile=None): +    def handleFree(self, pyfile):          if not hasattr(self, 'LINK_FREE_PATTERN'): -            self.fail(_("Free download not implemented")) +            self.logError(_("Free download not implemented"))          try:              m = re.search(self.LINK_FREE_PATTERN, self.html) @@ -558,9 +582,11 @@ class SimpleHoster(Hoster):              self.fail(e) -    def handlePremium(self, pyfile=None): +    def handlePremium(self, pyfile):          if not hasattr(self, 'LINK_PREMIUM_PATTERN'): -            self.fail(_("Premium download not implemented")) +            self.logError(_("Premium download not implemented")) +            self.logDebug("Handled as free download") +            self.handleFree(pyfile)          try:              m = re.search(self.LINK_PREMIUM_PATTERN, self.html) diff --git a/module/plugins/internal/XFSAccount.py b/module/plugins/internal/XFSAccount.py index 2784ecd0b..c350729ac 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.33" +    __version__ = "0.35"      __description__ = """XFileSharing account plugin"""      __license__     = "GPLv3" @@ -35,7 +35,7 @@ class XFSAccount(Account):      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'>\s*(Incorrect Login or Password|Error<)' +    LOGIN_FAIL_PATTERN = r'Incorrect Login or Password|account was banned|Error<'      def __init__(self, manager, accounts):  #@TODO: remove in 0.4.10 @@ -48,7 +48,7 @@ class XFSAccount(Account):              self.logError(_("Missing HOSTER_DOMAIN"))          if not self.HOSTER_URL: -            self.HOSTER_URL = "http://www.%s/" % self.HOSTER_DOMAIN or "" +            self.HOSTER_URL = "http://www.%s/" % (self.HOSTER_DOMAIN or "")      def loadAccountInfo(self, user, req): @@ -76,10 +76,10 @@ class XFSAccount(Account):                  self.logDebug("Valid until: %s" % validuntil)                  if validuntil > mktime(gmtime()): -                    premium = True +                    premium     = True                      trafficleft = -1                  else: -                    premium = False +                    premium    = False                      validuntil = None  #: registered account type (not premium)          else:              self.logDebug("VALID_UNTIL_PATTERN not found") @@ -143,7 +143,7 @@ class XFSAccount(Account):          if isinstance(self.COOKIES, list):              set_cookies(req.cj, self.COOKIES) -        url = urljoin(self.HOSTER_URL, "login.html") +        url  = urljoin(self.HOSTER_URL, "login.html")          html = req.load(url, decode=True)          action, inputs = parseHtmlForm('name="FL"', html) diff --git a/module/plugins/internal/XFSCrypter.py b/module/plugins/internal/XFSCrypter.py index 4b57dab90..3cb837aac 100644 --- a/module/plugins/internal/XFSCrypter.py +++ b/module/plugins/internal/XFSCrypter.py @@ -16,7 +16,6 @@ class XFSCrypter(SimpleCrypter):      HOSTER_DOMAIN = None -    HOSTER_NAME = None      URL_REPLACEMENTS = [(r'&?per_page=\d+', ""), (r'[?/&]+$', ""), (r'(.+/[^?]+)$', r'\1?'), (r'$', r'&per_page=10000')] diff --git a/module/plugins/internal/XFSHoster.py b/module/plugins/internal/XFSHoster.py index e15504d16..b32f5978f 100644 --- a/module/plugins/internal/XFSHoster.py +++ b/module/plugins/internal/XFSHoster.py @@ -15,7 +15,7 @@ from module.utils import html_unescape  class XFSHoster(SimpleHoster):      __name__    = "XFSHoster"      __type__    = "hoster" -    __version__ = "0.34" +    __version__ = "0.35"      __pattern__ = r'^unmatchable$' @@ -27,7 +27,6 @@ class XFSHoster(SimpleHoster):      HOSTER_DOMAIN = None -    HOSTER_NAME   = None      TEXT_ENCODING = False      COOKIES       = [(HOSTER_DOMAIN, "lang", "english")] @@ -66,9 +65,6 @@ class XFSHoster(SimpleHoster):          if not self.HOSTER_DOMAIN:              self.fail(_("Missing HOSTER_DOMAIN")) -        if not self.HOSTER_NAME: -            self.HOSTER_NAME = "".join([str.capitalize() for str in self.HOSTER_DOMAIN.split('.')]) -          if not self.LINK_PATTERN:              pattern = r'(https?://(www\.)?([^/]*?%s|\d+\.\d+\.\d+\.\d+)(\:\d+)?(/d/|(/files)?/\d+/\w+/).+?)["\'<]'              self.LINK_PATTERN = pattern % self.HOSTER_DOMAIN.replace('.', '\.') @@ -82,14 +78,12 @@ class XFSHoster(SimpleHoster):              self.directDL = bool(self.premium) -    def handleFree(self, pyfile=None): -        link = self.getDownloadLink() - -        if link: +    def downloadLink(self, link): +        if link and isinstance(link, basestring):              if self.captcha:                  self.correctCaptcha() -            self.download(link, ref=True, cookies=True, disposition=True) +            self.download(link, ref=True, cookies=True, disposition=False)  #@TODO: Set `disposition=True` in 0.4.10          elif self.errmsg:              if 'captcha' in self.errmsg: @@ -101,11 +95,7 @@ class XFSHoster(SimpleHoster):              self.fail(_("Download link not found")) -    def handlePremium(self, pyfile=None): -        return self.handleFree(pyfile) - - -    def getDownloadLink(self): +    def handleFree(self, pyfile):          for i in xrange(1, 6):              self.logDebug("Getting download link: #%d" % i) @@ -119,7 +109,7 @@ class XFSHoster(SimpleHoster):              self.req.http.c.setopt(FOLLOWLOCATION, 0) -            self.html = self.load(self.pyfile.url, post=data, ref=True, decode=True) +            self.html = self.load(pyfile.url, post=data, ref=True, decode=True)              self.req.http.c.setopt(FOLLOWLOCATION, 1) @@ -136,7 +126,11 @@ class XFSHoster(SimpleHoster):          self.errmsg = None -        return m.group(1).strip()  #@TODO: Remove .strip() in 0.4.10 +        self.link = m.group(1).strip()  #@TODO: Remove .strip() in 0.4.10 + + +    def handlePremium(self, pyfile): +        return self.handleFree(pyfile)      def handleMulti(self, pyfile):  | 
