summaryrefslogtreecommitdiffstats
path: root/module/plugins/internal
diff options
context:
space:
mode:
authorGravatar Sahil Shekhawat <sahilshekhawat01@gmail.com> 2015-01-11 14:54:48 +0100
committerGravatar Sahil Shekhawat <sahilshekhawat01@gmail.com> 2015-01-11 14:54:48 +0100
commitd2b60b5ceb369814a0de41c8b8744b5c4ed81523 (patch)
tree6619e01fc0e5f281e4d28678ec565860a86784ec /module/plugins/internal
parentupdated nitroflare.com's plugin (diff)
parentCode improvements (diff)
downloadpyload-d2b60b5ceb369814a0de41c8b8744b5c4ed81523.tar.xz
Merged with the updated nitroflare
Diffstat (limited to 'module/plugins/internal')
-rw-r--r--module/plugins/internal/CaptchaService.py49
-rw-r--r--module/plugins/internal/DeadCrypter.py6
-rw-r--r--module/plugins/internal/DeadHoster.py6
-rw-r--r--module/plugins/internal/MultiHook.py214
-rw-r--r--module/plugins/internal/MultiHoster.py46
-rw-r--r--module/plugins/internal/SimpleCrypter.py22
-rw-r--r--module/plugins/internal/SimpleDereferer.py6
-rw-r--r--module/plugins/internal/SimpleHoster.py104
-rw-r--r--module/plugins/internal/XFSAccount.py12
-rw-r--r--module/plugins/internal/XFSCrypter.py1
-rw-r--r--module/plugins/internal/XFSHoster.py28
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):