summaryrefslogtreecommitdiffstats
path: root/pyload/plugins/internal
diff options
context:
space:
mode:
Diffstat (limited to 'pyload/plugins/internal')
-rw-r--r--pyload/plugins/internal/BasePlugin.py98
-rw-r--r--pyload/plugins/internal/DeadCrypter.py5
-rw-r--r--pyload/plugins/internal/DeadHoster.py5
-rw-r--r--pyload/plugins/internal/MultiHoster.py44
-rw-r--r--pyload/plugins/internal/SimpleHoster.py146
-rw-r--r--pyload/plugins/internal/UnRar.py14
-rw-r--r--pyload/plugins/internal/XFSAccount.py20
-rw-r--r--pyload/plugins/internal/XFSHoster.py22
8 files changed, 207 insertions, 147 deletions
diff --git a/pyload/plugins/internal/BasePlugin.py b/pyload/plugins/internal/BasePlugin.py
index f4abc1a15..a9d81d079 100644
--- a/pyload/plugins/internal/BasePlugin.py
+++ b/pyload/plugins/internal/BasePlugin.py
@@ -3,7 +3,7 @@
import re
from urllib import unquote
-from urlparse import urlparse
+from urlparse import urljoin, urlparse
from pyload.network.HTTPRequest import BadHeader
from pyload.plugins.internal.SimpleHoster import create_getInfo
@@ -13,7 +13,7 @@ from pyload.plugins.internal.Hoster import Hoster
class BasePlugin(Hoster):
__name__ = "BasePlugin"
__type__ = "hoster"
- __version__ = "0.23"
+ __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, '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):
@@ -38,69 +38,69 @@ class BasePlugin(Hoster):
pyfile.name = self.getInfo(pyfile.url)['name']
- if pyfile.url.startswith("http"):
- for _i in xrange(2):
- try:
- self.downloadFile(pyfile)
+ if not pyfile.url.startswith("http"):
+ self.fail(_("No plugin matched"))
+
+ for _i in xrange(5):
+ try:
+ self.downloadFile(pyfile)
- except BadHeader, e:
- if e.code is 404:
- self.offline()
+ except BadHeader, e:
+ if e.code is 404:
+ self.offline()
- elif e.code in (401, 403):
- self.logDebug("Auth required")
+ elif e.code in (401, 403):
+ 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()]
- server = urlparse(pyfile.url).netloc
+ account = self.core.accountManager.getAccountPlugin('Http')
+ servers = [x['login'] for x in account.getAllAccounts()]
+ server = urlparse(pyfile.url).netloc
- if server in servers:
- self.logDebug("Logging on to %s" % server)
- self.req.addAuth(account.accounts[server]['password'])
- else:
- for pwd in pyfile.package().password.splitlines():
- if ":" in pwd:
- self.req.addAuth(pwd.strip())
- break
- else:
- self.fail(_("Authorization required (username:password)"))
+ if server in servers:
+ self.logDebug("Logging on to %s" % server)
+ self.req.addAuth(account.accounts[server]['password'])
else:
- self.fail(e)
+ for pwd in self.getPassword().splitlines():
+ if ":" in pwd:
+ self.req.addAuth(pwd.strip())
+ break
+ else:
+ self.fail(_("Authorization required"))
else:
- break
+ self.fail(e)
else:
- self.fail(_("No file downloaded")) #@TODO: Move to hoster class (check if self.lastDownload) in 0.4.10
+ break
else:
- self.fail(_("No plugin matched"))
+ 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):
url = pyfile.url
- for _i in xrange(5):
- header = self.load(url, just_header=True)
-
- # self.load does not raise a BadHeader on 404 responses, do it here
- if 'code' in header and header['code'] == 404:
- raise BadHeader(404)
+ for i in xrange(1, 7): #@TODO: retrieve the pycurl.MAXREDIRS value set by req
+ header = self.load(url, ref=True, cookies=True, just_header=True, decode=True)
- if 'location' in header:
- self.logDebug("Location: " + header['location'])
-
- base = re.match(r'https?://[^/]+', url).group(0)
+ if 'location' not in header or not header['location']:
+ if 'code' in header and header['code'] not in (200, 201, 203, 206):
+ self.logDebug("Received HTTP status code: %d" % header['code'])
+ self.fail(_("File not found"))
+ else:
+ break
- if header['location'].startswith("http"):
- url = header['location']
+ location = header['location']
- elif header['location'].startswith("/"):
- url = base + unquote(header['location'])
+ self.logDebug("Redirect #%d to: %s" % (i, location))
- else:
- url = '%s/%s' % (base, unquote(header['location']))
+ if urlparse(location).scheme:
+ url = location
else:
- break
+ 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/pyload/plugins/internal/DeadCrypter.py b/pyload/plugins/internal/DeadCrypter.py
index 3510e1466..81b68e00a 100644
--- a/pyload/plugins/internal/DeadCrypter.py
+++ b/pyload/plugins/internal/DeadCrypter.py
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
+from urllib import unquote
from urlparse import urlparse
from pyload.plugins.internal.Crypter import Crypter as _Crypter
@@ -9,7 +10,7 @@ from pyload.plugins.internal.SimpleCrypter import create_getInfo
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/pyload/plugins/internal/DeadHoster.py b/pyload/plugins/internal/DeadHoster.py
index a7e5093d3..f066883c6 100644
--- a/pyload/plugins/internal/DeadHoster.py
+++ b/pyload/plugins/internal/DeadHoster.py
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
+from urllib import unquote
from urlparse import urlparse
from pyload.plugins.internal.Hoster import Hoster as _Hoster
@@ -9,7 +10,7 @@ from pyload.plugins.internal.SimpleHoster import create_getInfo
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/pyload/plugins/internal/MultiHoster.py b/pyload/plugins/internal/MultiHoster.py
index 4eb4a6f31..4d466d350 100644
--- a/pyload/plugins/internal/MultiHoster.py
+++ b/pyload/plugins/internal/MultiHoster.py
@@ -16,18 +16,21 @@ class MultiHoster(Addon):
__authors__ = [("pyLoad Team", "admin@pyload.org")]
- interval = 24 * 60 * 60 #: reload hosters daily
-
- HOSTER_REPLACEMENTS = [("2shared.com", "twoshared.com"), ("4shared.com", "fourshared.com"), ("cloudnator.com", "shragle.com"),
- ("ifile.it", "filecloud.io"), ("easy-share.com", "crocko.com"), ("freakshare.net", "freakshare.com"),
- ("hellshare.com", "hellshare.cz"), ("share-rapid.cz", "sharerapid.com"), ("sharerapid.cz", "sharerapid.com"),
- ("ul.to", "uploaded.to"), ("uploaded.net", "uploaded.to"), ("1fichier.com", "onefichier.com")]
+ interval = 12 * 60 * 60 #: reload hosters every 12h
+
+ HOSTER_REPLACEMENTS = [("1fichier.com", "onefichier.com"), ("2shared.com", "twoshared.com"),
+ ("4shared.com", "fourshared.com"), ("cloudnator.com", "shragle.com"),
+ ("easy-share.com", "crocko.com"), ("freakshare.net", "freakshare.com"),
+ ("hellshare.com", "hellshare.cz"), ("ifile.it", "filecloud.io"),
+ ("putlocker.com", "firedrive.com"), ("share-rapid.cz", "multishare.cz"),
+ ("sharerapid.cz", "multishare.cz"), ("ul.to", "uploaded.to"),
+ ("uploaded.net", "uploaded.to")]
HOSTER_EXCLUDED = []
def setup(self):
- self.hosters = []
- self.supported = []
+ self.hosters = []
+ self.supported = []
self.new_supported = []
@@ -110,8 +113,10 @@ class MultiHoster(Addon):
"""reload hoster list periodically"""
self.logInfo(_("Reloading supported hoster list"))
- old_supported = self.supported
- self.supported, self.new_supported, self.hosters = [], [], []
+ old_supported = self.supported
+ self.supported = []
+ self.new_supported = []
+ self.hosters = []
self.overridePlugins()
@@ -123,11 +128,8 @@ class MultiHoster(Addon):
def overridePlugins(self):
- pluginMap = {}
- for name in self.core.pluginManager.hosterPlugins.keys():
- pluginMap[name.lower()] = name
-
- accountList = [name.lower() for name, data in self.core.accountManager.accounts.iteritems() if data]
+ pluginMap = dict((name.lower(), name) for name in self.core.pluginManager.hosterPlugins.keys())
+ accountList = [name.lower() for name, data in self.core.accountManager.accounts.iteritems() if data]
excludedList = []
for hoster in self.getHosterCached():
@@ -146,14 +148,14 @@ class MultiHoster(Addon):
return
module = self.core.pluginManager.getPlugin(self.__type__, self.__name__)
- klass = getattr(module, self.__name__)
+ klass = getattr(module, self.__name__)
# inject plugin plugin
self.logDebug("Overwritten Hosters", ", ".join(sorted(self.supported)))
for hoster in self.supported:
dict = self.core.pluginManager.hosterPlugins[hoster]
dict['new_module'] = module
- dict['new_name'] = self.__name__
+ dict['new_name'] = self.__name__
if excludedList:
self.logInfo(_("The following hosters were not overwritten - account exists"), ", ".join(sorted(excludedList)))
@@ -162,7 +164,7 @@ class MultiHoster(Addon):
self.logDebug("New Hosters", ", ".join(sorted(self.new_supported)))
# create new regexp
- regexp = r'.*(%s).*' % "|".join([x.replace(".", "\\.") for x in self.new_supported])
+ regexp = r'.*(%s).*' % "|".join([x.replace(".", "\.") for x in self.new_supported])
if hasattr(klass, "__pattern__") and isinstance(klass.__pattern__, basestring) and '://' in klass.__pattern__:
regexp = r'%s|%s' % (klass.__pattern__, regexp)
@@ -170,7 +172,7 @@ class MultiHoster(Addon):
dict = self.core.pluginManager.hosterPlugins[self.__name__]
dict['pattern'] = regexp
- dict['re'] = re.compile(regexp)
+ dict['re'] = re.compile(regexp)
def unloadHoster(self, hoster):
@@ -190,9 +192,9 @@ class MultiHoster(Addon):
# reset pattern
klass = getattr(self.core.pluginManager.getPlugin(self.__type__, self.__name__), self.__name__)
- dict = self.core.pluginManager.hosterPlugins[self.__name__]
+ dict = self.core.pluginManager.hosterPlugins[self.__name__]
dict['pattern'] = getattr(klass, "__pattern__", r'^unmatchable$')
- dict['re'] = re.compile(dict['pattern'])
+ dict['re'] = re.compile(dict['pattern'])
def downloadFailed(self, pyfile):
diff --git a/pyload/plugins/internal/SimpleHoster.py b/pyload/plugins/internal/SimpleHoster.py
index 922361b30..ce1ddd2b6 100644
--- a/pyload/plugins/internal/SimpleHoster.py
+++ b/pyload/plugins/internal/SimpleHoster.py
@@ -3,9 +3,8 @@
import re
from time import time
-from urlparse import urlparse
-
-from pycurl import FOLLOWLOCATION
+from urllib import unquote
+from urlparse import urljoin, urlparse
from pyload.datatype.PyFile import statusMap as _statusMap
from pyload.network.CookieJar import CookieJar
@@ -91,22 +90,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 'location' in header or not header['location']:
return ""
- if header['code'] != 302 or 'content-type' not in header or header['content-type'] != "text/plain":
- 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.62"
+ __version__ = "0.71"
__pattern__ = r'^unmatchable$'
@@ -128,6 +142,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)'
@@ -163,9 +180,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
@@ -177,14 +194,32 @@ class SimpleHoster(Hoster):
@classmethod
def getInfo(cls, url="", html=""):
- info = {'name': urlparse(url).path.split('/')[-1] or _("Unknown"), 'size': 0, 'status': 3, '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
@@ -197,33 +232,43 @@ 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 Exception:
pass
- for pattern in ("INFO_PATTERN", "NAME_PATTERN", "SIZE_PATTERN"):
+ for pattern in ("INFO_PATTERN", "NAME_PATTERN", "SIZE_PATTERN", "HASHSUM_PATTERN"):
try:
attr = getattr(cls, pattern)
- info.update(re.search(attr, html).groupdict())
+ dict = re.search(attr, html).groupdict()
+
+ if all(True for k in dict if k not in info['pattern']):
+ info['pattern'].update(dict)
+
except AttributeError:
continue
+
else:
online = True
if online:
info['status'] = 2
- if 'N' in info:
- info['name'] = replace_patterns(info['N'].strip(), cls.NAME_REPLACEMENTS)
+ if 'N' in info['pattern']:
+ info['name'] = replace_patterns(unquote(info['pattern']['N'].strip()), cls.NAME_REPLACEMENTS)
- if 'S' in info:
- size = replace_patterns(info['S'] + info['U'] if 'U' in info else info['S'], cls.SIZE_REPLACEMENTS)
+ if 'S' in info['pattern']:
+ size = replace_patterns(info['pattern']['S'] + info['pattern']['U'] if 'U' in info else info['pattern']['S'],
+ cls.SIZE_REPLACEMENTS)
info['size'] = parseFileSize(size)
elif isinstance(info['size'], basestring):
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
@@ -243,8 +288,8 @@ class SimpleHoster(Hoster):
set_cookies(self.req.cj, self.COOKIES)
if (self.MULTI_HOSTER
- and self.__pattern__ != self.core.pluginManager.hosterPlugins[self.__name__]['pattern']
- and re.match(self.__pattern__, self.pyfile.url) is None):
+ and (self.__pattern__ != self.core.pluginManager.hosterPlugins[self.__name__]['pattern']
+ or re.match(self.__pattern__, self.pyfile.url) is None)):
self.logInfo("Multi hoster detected")
@@ -288,8 +333,7 @@ class SimpleHoster(Hoster):
premium_only = 'error' in self.info and self.info['error'] == "premium-only"
- info = self.getInfo(pyfile.url, self.html)
- self._updateInfo(info)
+ self._updateInfo(self.getInfo(pyfile.url, self.html))
self.checkNameSize()
@@ -308,18 +352,28 @@ class SimpleHoster(Hoster):
self.logDebug("Handled as free download")
self.handleFree()
- if self.link:
- self.download(self.link, disposition=self.CONTENT_DISPOSITION)
+ self.downloadLink(self.link)
+ self.checkFile()
+
+
+ def downloadLink(self, link):
+ if not link:
+ return
+
+ self.download(link, disposition=self.CONTENT_DISPOSITION)
+
+
+ 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
+ errmsg = self.info['error'] = m.group(1)
+ self.error(errmsg)
if hasattr(self, 'PREMIUM_ONLY_PATTERN'):
m = re.search(self.PREMIUM_ONLY_PATTERN, self.html)
@@ -327,11 +381,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)
@@ -381,7 +437,9 @@ class SimpleHoster(Hoster):
#: Deprecated
def getFileInfo(self):
- return self.checkInfo()
+ self.info = {}
+ self.checkInfo()
+ return self.info
def _updateInfo(self, info):
@@ -391,7 +449,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"))
@@ -420,7 +478,7 @@ class SimpleHoster(Hoster):
self.link = m.group(1)
except Exception, e:
- self.fail(str(e))
+ self.fail(e)
def handlePremium(self):
@@ -435,7 +493,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/pyload/plugins/internal/UnRar.py b/pyload/plugins/internal/UnRar.py
index ebfe53829..90216222b 100644
--- a/pyload/plugins/internal/UnRar.py
+++ b/pyload/plugins/internal/UnRar.py
@@ -22,7 +22,7 @@ def renice(pid, value):
class UnRar(AbtractExtractor):
__name__ = "UnRar"
- __version__ = "0.18"
+ __version__ = "0.19"
__description__ = """Rar extractor plugin"""
__license__ = "GPLv3"
@@ -32,12 +32,12 @@ class UnRar(AbtractExtractor):
CMD = "unrar"
# there are some more uncovered rar formats
- re_version = re.compile(r"(UNRAR 5[\d.]+(.*?)freeware)")
- re_splitfile = re.compile(r"(.*)\.part(\d+)\.rar$", re.I)
- re_partfiles = re.compile(r".*\.(rar|r\d+)", re.I)
- re_filelist = re.compile(r"(.+)\s+(\d+)\s+(\d+)\s+")
- re_filelist5 = re.compile(r"(.+)\s+(\d+)\s+\d\d-\d\d-\d\d\s+\d\d:\d\d\s+(.+)")
- re_wrongpwd = re.compile("(Corrupt file or wrong password|password incorrect)", re.I)
+ re_version = re.compile(r'UNRAR ([\w .]+?) freeware')
+ re_splitfile = re.compile(r'(.*)\.part(\d+)\.rar$', re.I)
+ re_partfiles = re.compile(r'.*\.(rar|r\d+)', re.I)
+ re_filelist = re.compile(r'(.+)\s+(\d+)\s+(\d+)\s+')
+ re_filelist5 = re.compile(r'(.+)\s+(\d+)\s+\d\d-\d\d-\d\d\s+\d\d:\d\d\s+(.+)')
+ re_wrongpwd = re.compile(r'(Corrupt file or wrong password|password incorrect)', re.I)
@staticmethod
diff --git a/pyload/plugins/internal/XFSAccount.py b/pyload/plugins/internal/XFSAccount.py
index 168c4f903..a330d2ff4 100644
--- a/pyload/plugins/internal/XFSAccount.py
+++ b/pyload/plugins/internal/XFSAccount.py
@@ -12,7 +12,7 @@ from pyload.plugins.internal.SimpleHoster import parseHtmlForm, set_cookies
class XFSAccount(Account):
__name__ = "XFSAccount"
__type__ = "account"
- __version__ = "0.30"
+ __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):
@@ -104,12 +104,12 @@ class XFSAccount(Account):
else:
self.logDebug("TRAFFIC_LEFT_PATTERN not found")
- m = re.finditer(self.LEECH_TRAFFIC_PATTERN, html)
- if m:
+ leech = [m.groupdict() for m in re.finditer(self.LEECH_TRAFFIC_PATTERN, html)]
+ if leech:
leechtraffic = 0
try:
- for leech in m:
- size = leech['S']
+ for traffic in leech:
+ size = traffic['S']
if "nlimited" in size:
leechtraffic = -1
@@ -117,8 +117,8 @@ class XFSAccount(Account):
validuntil = -1
break
else:
- if 'U' in leech:
- unit = leech['U']
+ if 'U' in traffic:
+ unit = traffic['U']
elif isinstance(self.LEECH_TRAFFIC_UNIT, basestring):
unit = self.LEECH_TRAFFIC_UNIT
else:
diff --git a/pyload/plugins/internal/XFSHoster.py b/pyload/plugins/internal/XFSHoster.py
index 061012059..a4e7339c5 100644
--- a/pyload/plugins/internal/XFSHoster.py
+++ b/pyload/plugins/internal/XFSHoster.py
@@ -16,7 +16,7 @@ from pyload.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:
@@ -256,8 +256,6 @@ class XFSHoster(SimpleHoster):
else:
self.info.pop('error', None)
- return self.errmsg
-
def getPostParameters(self):
if self.FORM_PATTERN or self.FORM_INPUTS_MAP:
@@ -311,7 +309,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))