summaryrefslogtreecommitdiffstats
path: root/module/plugins/internal
diff options
context:
space:
mode:
Diffstat (limited to 'module/plugins/internal')
-rw-r--r--module/plugins/internal/SimpleHoster.py172
-rw-r--r--module/plugins/internal/UnRar.py4
-rw-r--r--module/plugins/internal/XFSPAccount.py79
3 files changed, 193 insertions, 62 deletions
diff --git a/module/plugins/internal/SimpleHoster.py b/module/plugins/internal/SimpleHoster.py
index 20263064a..5056b22b2 100644
--- a/module/plugins/internal/SimpleHoster.py
+++ b/module/plugins/internal/SimpleHoster.py
@@ -23,59 +23,97 @@ from time import time
from module.plugins.Hoster import Hoster
from module.utils import html_unescape, fixup, parseFileSize
from module.network.RequestFactory import getURL
+from module.network.CookieJar import CookieJar
-def reSub(string, ruleslist):
+def replace_patterns(string, ruleslist):
for r in ruleslist:
rf, rt = r
string = re.sub(rf, rt, string)
#self.logDebug(rf, rt, string)
return string
+def set_cookies(cj, cookies):
+ for cookie in cookies:
+ if isinstance(cookie, tuple) and len(cookie) == 3:
+ domain, name, value = cookie
+ cj.setCookie(domain, name, value)
+
def parseHtmlTagAttrValue(attr_name, tag):
m = re.search(r"%s\s*=\s*([\"']?)((?<=\")[^\"]+|(?<=')[^']+|[^\s\"'][^>\s]+)\1" % attr_name, tag)
- return m.group(2) if m else ''
-
-def parseFileInfo(self, url = '', html = '', infomode = False):
- if not html and hasattr(self, "html"): html = self.html
-
+ return m.group(2) if m else None
+
+def parseHtmlForm(attr_str, html):
+ inputs = {}
+ action = None
+ form = re.search(r"(?P<tag><form[^>]*%s[^>]*>)(?P<content>.*?)</(form|body|html)[^>]*>" % attr_str, html, re.S | re.I)
+ if form:
+ action = parseHtmlTagAttrValue("action", form.group('tag'))
+ for input in re.finditer(r'(<(input|textarea)[^>]*>)([^<]*(?=</\2)|)', form.group('content'), re.S | re.I):
+ name = parseHtmlTagAttrValue("name", input.group(1))
+ if name:
+ value = parseHtmlTagAttrValue("value", input.group(1))
+ if value is None:
+ inputs[name] = input.group(3) or ''
+ else:
+ inputs[name] = value
+
+ return action, inputs
+
+def parseFileInfo(self, url = '', html = ''):
info = {"name" : url, "size" : 0, "status" : 3}
- online = False
+
+ if hasattr(self, "pyfile"):
+ url = self.pyfile.url
if hasattr(self, "req") and self.req.http.code == '404':
info['status'] = 1
- elif hasattr(self, "FILE_OFFLINE_PATTERN") and re.search(self.FILE_OFFLINE_PATTERN, html):
- # File offline
- info['status'] = 1
else:
- for pattern in ("FILE_INFO_PATTERN", "FILE_NAME_PATTERN", "FILE_SIZE_PATTERN"):
+ if not html and hasattr(self, "html"): html = self.html
+ if isinstance(self.SH_BROKEN_ENCODING, (str, unicode)):
+ html = unicode(html, self.SH_BROKEN_ENCODING)
+ if hasattr(self, "html"): self.html = html
+
+ if hasattr(self, "FILE_OFFLINE_PATTERN") and re.search(self.FILE_OFFLINE_PATTERN, html):
+ # File offline
+ info['status'] = 1
+ else:
+ online = False
try:
- info = dict(info, **re.search(getattr(self, pattern), html).groupdict())
- online = True
- except AttributeError:
- continue
-
- if online:
- # File online, return name and size
- info['status'] = 2
- if 'N' in info:
- info['name'] = reSub(info['N'], self.FILE_NAME_REPLACEMENTS)
- if 'S' in info:
- size = reSub(info['S'] + info['U'] if 'U' in info else info['S'], self.FILE_SIZE_REPLACEMENTS)
- info['size'] = parseFileSize(size)
- elif isinstance(info['size'], (str, unicode)):
- if 'units' in info: info['size'] += info['units']
- info['size'] = parseFileSize(info['size'])
-
- if infomode:
- return info
- else:
- return info['name'], info['size'], info['status'], url
+ info.update(re.match(self.__pattern__, url).groupdict())
+ except:
+ pass
+
+ for pattern in ("FILE_INFO_PATTERN", "FILE_NAME_PATTERN", "FILE_SIZE_PATTERN"):
+ try:
+ info.update(re.search(getattr(self, pattern), html).groupdict())
+ online = True
+ except AttributeError:
+ continue
+
+ if online:
+ # File online, return name and size
+ info['status'] = 2
+ if 'N' in info:
+ info['name'] = replace_patterns(info['N'], self.FILE_NAME_REPLACEMENTS)
+ if 'S' in info:
+ size = replace_patterns(info['S'] + info['U'] if 'U' in info else info['S'], self.FILE_SIZE_REPLACEMENTS)
+ info['size'] = parseFileSize(size)
+ elif isinstance(info['size'], (str, unicode)):
+ if 'units' in info: info['size'] += info['units']
+ info['size'] = parseFileSize(info['size'])
+
+ if hasattr(self, "file_info"):
+ self.file_info = info
+
+ return info['name'], info['size'], info['status'], url
def create_getInfo(plugin):
def getInfo(urls):
for url in urls:
- file_info = parseFileInfo(plugin, url, getURL(reSub(url, plugin.FILE_URL_REPLACEMENTS), \
- decode = False if plugin.HTML_BROKEN_ENCODING else True))
+ cj = CookieJar(plugin.__name__)
+ if isinstance(plugin.SH_COOKIES, list): set_cookies(cj, plugin.SH_COOKIES)
+ file_info = parseFileInfo(plugin, url, getURL(replace_patterns(url, plugin.FILE_URL_REPLACEMENTS), \
+ decode = not plugin.SH_BROKEN_ENCODING, cookies = cj))
yield file_info
return getInfo
@@ -91,7 +129,7 @@ class PluginParseError(Exception):
class SimpleHoster(Hoster):
__name__ = "SimpleHoster"
- __version__ = "0.17"
+ __version__ = "0.25"
__pattern__ = None
__type__ = "hoster"
__description__ = """Base hoster plugin"""
@@ -110,16 +148,22 @@ class SimpleHoster(Hoster):
FILE_NAME_REPLACEMENTS = [("&#?\w+;", fixup)]
FILE_URL_REPLACEMENTS = []
- HTML_BROKEN_ENCODING = False
+ SH_BROKEN_ENCODING = False # Set to True or encoding name if encoding in http header is not correct
+ SH_COOKIES = True # or False or list of tuples [(domain, name, value)]
+ SH_CHECK_TRAFFIC = False # True = force check traffic left for a premium account
+
+ def init(self):
+ self.file_info = {}
def setup(self):
- self.resumeDownload = self.multiDL = True if self.account else False
+ self.resumeDownload = self.multiDL = True if self.premium else False
+ if isinstance(self.SH_COOKIES, list): set_cookies(self.req.cj, self.SH_COOKIES)
def process(self, pyfile):
- pyfile.url = reSub(pyfile.url, self.FILE_URL_REPLACEMENTS)
- self.html = self.load(pyfile.url, decode = False if self.HTML_BROKEN_ENCODING else True)
- self.file_info = self.getFileInfo()
- if self.premium:
+ pyfile.url = replace_patterns(pyfile.url, self.FILE_URL_REPLACEMENTS)
+ self.html = self.load(pyfile.url, decode = not self.SH_BROKEN_ENCODING, cookies = self.SH_COOKIES)
+ self.getFileInfo()
+ if self.premium and (not self.SH_CHECK_TRAFFIC or self.checkTrafficLeft()):
self.handlePremium()
else:
self.handleFree()
@@ -129,25 +173,26 @@ class SimpleHoster(Hoster):
if hasattr(self, "TEMP_OFFLINE_PATTERN") and re.search(self.TEMP_OFFLINE_PATTERN, self.html):
self.tempOffline()
- file_info = parseFileInfo(self, infomode = True)
- if file_info['status'] == 1:
+ name, size, status = parseFileInfo(self)[:3]
+
+ if status == 1:
self.offline()
- elif file_info['status'] != 2:
- self.logDebug(file_info)
+ elif status != 2:
+ self.logDebug(self.file_info)
self.parseError('File info')
- if file_info['name']:
- self.pyfile.name = file_info['name']
+ if name:
+ self.pyfile.name = name
else:
self.pyfile.name = html_unescape(urlparse(self.pyfile.url).path.split("/")[-1])
- if file_info['size']:
- self.pyfile.size = file_info['size']
+ if size:
+ self.pyfile.size = size
else:
self.logError("File size not parsed")
self.logDebug("FILE NAME: %s FILE SIZE: %s" % (self.pyfile.name, self.pyfile.size))
- return file_info
+ return self.file_info
def handleFree(self):
self.fail("Free download not implemented")
@@ -156,19 +201,24 @@ class SimpleHoster(Hoster):
self.fail("Premium download not implemented")
def parseError(self, msg):
- raise PluginParseError(msg)
+ raise PluginParseError(msg)
+
+ def longWait(self, wait_time = None, max_tries = 3):
+ if wait_time and isinstance(wait_time, (int, long, float)):
+ time_str = "%dh %dm" % divmod(wait_time / 60, 60)
+ else:
+ wait_time = 900
+ time_str = "(unknown time)"
+ max_tries = 100
+
+ self.logInfo("Download limit reached, reconnect or wait %s" % time_str)
+
+ self.setWait(wait_time, True)
+ self.wait()
+ self.retry(max_tries = max_tries, reason="Download limit reached")
def parseHtmlForm(self, attr_str):
- inputs = {}
- action = None
- form = re.search(r"(?P<tag><form[^>]*%s[^>]*>)(?P<content>.*?)</form[^>]*>" % attr_str, self.html, re.S)
- if form:
- action = parseHtmlTagAttrValue("action", form.group('tag'))
- for input in re.finditer(r'(<(?:input|textarea)[^>]*>)', form.group('content')):
- name = parseHtmlTagAttrValue("name", input.group(1))
- if name:
- inputs[name] = parseHtmlTagAttrValue("value", input.group(1))
- return action, inputs
+ return parseHtmlForm(attr_str, self.html)
def checkTrafficLeft(self):
traffic = self.account.getAccountInfo(self.user, True)["trafficleft"]
diff --git a/module/plugins/internal/UnRar.py b/module/plugins/internal/UnRar.py
index a315fbea3..53995a083 100644
--- a/module/plugins/internal/UnRar.py
+++ b/module/plugins/internal/UnRar.py
@@ -27,7 +27,7 @@ from module.plugins.internal.AbstractExtractor import AbtractExtractor, WrongPas
class UnRar(AbtractExtractor):
__name__ = "UnRar"
- __version__ = "0.1"
+ __version__ = "0.11"
# there are some more uncovered rar formats
re_splitfile = re.compile(r"(.*)\.part(\d+)\.rar$")
@@ -127,6 +127,8 @@ class UnRar(AbtractExtractor):
raise WrongPassword
if err.strip(): #raise error if anything is on stderr
raise ArchiveError(err.strip())
+ if p.returncode:
+ raise ArchiveError("Process terminated")
if not self.files:
self.password = password
diff --git a/module/plugins/internal/XFSPAccount.py b/module/plugins/internal/XFSPAccount.py
new file mode 100644
index 000000000..ad25ad2c8
--- /dev/null
+++ b/module/plugins/internal/XFSPAccount.py
@@ -0,0 +1,79 @@
+# -*- coding: utf-8 -*-
+
+"""
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+ @author: zoidberg
+"""
+
+import re
+from time import mktime, strptime
+from module.plugins.Account import Account
+from module.plugins.internal.SimpleHoster import parseHtmlForm
+from module.utils import parseFileSize
+
+class XFSPAccount(Account):
+ __name__ = "XFSPAccount"
+ __version__ = "0.05"
+ __type__ = "account"
+ __description__ = """XFileSharingPro account base"""
+ __author_name__ = ("zoidberg")
+ __author_mail__ = ("zoidberg@mujmail.cz")
+
+ MAIN_PAGE = None
+
+ VALID_UNTIL_PATTERN = r'>Premium account expire:</TD><TD><b>([^<]+)</b>'
+ TRAFFIC_LEFT_PATTERN = r'>Traffic available today:</TD><TD><b>([^<]+)</b>'
+
+ def loadAccountInfo(self, user, req):
+ html = req.load(self.MAIN_PAGE + "?op=my_account", decode = True)
+
+ validuntil = trafficleft = None
+ premium = True if '>Renew premium<' in html else False
+
+ found = re.search(self.VALID_UNTIL_PATTERN, html)
+ if found:
+ premium = True
+ trafficleft = -1
+ try:
+ self.logDebug(found.group(1))
+ validuntil = mktime(strptime(found.group(1), "%d %B %Y"))
+ except Exception, e:
+ self.logError(e)
+ else:
+ found = re.search(self.TRAFFIC_LEFT_PATTERN, html)
+ if found:
+ trafficleft = found.group(1)
+ if "Unlimited" in trafficleft:
+ premium = True
+ else:
+ trafficleft = parseFileSize(trafficleft) / 1024
+
+ return ({"validuntil": validuntil, "trafficleft": trafficleft, "premium": premium})
+
+ def login(self, user, data, req):
+ html = req.load('%slogin.html' % self.MAIN_PAGE, decode = True)
+
+ action, inputs = parseHtmlForm('name="FL"', html)
+ if not inputs:
+ inputs = {"op": "login",
+ "redirect": self.MAIN_PAGE}
+
+ inputs.update({"login": user,
+ "password": data['password']})
+
+ html = req.load(self.MAIN_PAGE, post = inputs, decode = True)
+
+ if 'Incorrect Login or Password' in html or '>Error<' in html:
+ self.wrongPassword() \ No newline at end of file