summaryrefslogtreecommitdiffstats
path: root/module/plugins/internal
diff options
context:
space:
mode:
authorGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2013-03-24 17:16:34 +0100
committerGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2013-03-24 17:16:34 +0100
commit3ae2fbb170ad0f2bfe1ebf7f59e76d3645861f0a (patch)
treeb01e2c881aaf744aaab0af613a7a26e7129f2028 /module/plugins/internal
parententer captchas on webui (diff)
parentRapidgator: fixed bug #47 (diff)
downloadpyload-3ae2fbb170ad0f2bfe1ebf7f59e76d3645861f0a.tar.xz
Merge remote-tracking branch 'origin/stable'
Conflicts: module/plugins/accounts/FilesonicCom.py module/plugins/accounts/OronCom.py module/plugins/accounts/ShareonlineBiz.py module/plugins/addons/UpdateManager.py module/plugins/crypter/FilesonicComFolder.py module/plugins/hoster/BezvadataCz.py module/plugins/hoster/EuroshareEu.py module/plugins/hoster/FilesonicCom.py module/plugins/hoster/MegauploadCom.py module/plugins/hoster/Premium4Me.py module/plugins/hoster/YoutubeCom.py module/plugins/internal/MultiHoster.py module/utils.py
Diffstat (limited to 'module/plugins/internal')
-rw-r--r--module/plugins/internal/CaptchaService.py77
-rw-r--r--module/plugins/internal/SimpleCrypter.py49
-rw-r--r--module/plugins/internal/SimpleHoster.py98
-rw-r--r--module/plugins/internal/XFSPAccount.py2
4 files changed, 174 insertions, 52 deletions
diff --git a/module/plugins/internal/CaptchaService.py b/module/plugins/internal/CaptchaService.py
new file mode 100644
index 000000000..b912436a7
--- /dev/null
+++ b/module/plugins/internal/CaptchaService.py
@@ -0,0 +1,77 @@
+# -*- 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
+
+class CaptchaService():
+ __version__ = "0.02"
+
+ def __init__(self, plugin):
+ self.plugin = plugin
+
+class ReCaptcha():
+ def __init__(self, plugin):
+ self.plugin = plugin
+
+ def challenge(self, id):
+ js = self.plugin.req.load("http://www.google.com/recaptcha/api/challenge", get={"k":id}, cookies=True)
+
+ try:
+ challenge = re.search("challenge : '(.*?)',", js).group(1)
+ server = re.search("server : '(.*?)',", js).group(1)
+ except:
+ self.plugin.fail("recaptcha error")
+ result = self.result(server,challenge)
+
+ return challenge, result
+
+ def result(self, server, challenge):
+ return self.plugin.decryptCaptcha("%simage"%server, get={"c":challenge}, cookies=True, forceUser=True, imgtype="jpg")
+
+class AdsCaptcha(CaptchaService):
+ def challenge(self, src):
+ js = self.plugin.req.load(src, cookies=True)
+
+ try:
+ challenge = re.search("challenge: '(.*?)',", js).group(1)
+ server = re.search("server: '(.*?)',", js).group(1)
+ except:
+ self.plugin.fail("adscaptcha error")
+ result = self.result(server,challenge)
+
+ return challenge, result
+
+ def result(self, server, challenge):
+ return self.plugin.decryptCaptcha("%sChallenge.aspx" % server, get={"cid": challenge, "dummy": random()}, cookies=True, imgtype="jpg")
+
+class SolveMedia(CaptchaService):
+ def __init__(self,plugin):
+ self.plugin = plugin
+
+ def challenge(self, src):
+ html = self.plugin.req.load("http://api.solvemedia.com/papi/challenge.noscript?k=%s" % src, cookies=True)
+ try:
+ challenge = re.search(r'<input type=hidden name="adcopy_challenge" id="adcopy_challenge" value="([^"]+)">', html).group(1)
+ except:
+ self.plugin.fail("solvmedia error")
+ result = self.result(challenge)
+
+ return challenge, result
+
+ def result(self,challenge):
+ return self.plugin.decryptCaptcha("http://api.solvemedia.com/papi/media?c=%s" % challenge,imgtype="gif") \ No newline at end of file
diff --git a/module/plugins/internal/SimpleCrypter.py b/module/plugins/internal/SimpleCrypter.py
index 69798bc0a..b8942c724 100644
--- a/module/plugins/internal/SimpleCrypter.py
+++ b/module/plugins/internal/SimpleCrypter.py
@@ -13,32 +13,53 @@
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
"""
-from re import findall
+import re
from module.plugins.Crypter import Crypter
class SimpleCrypter(Crypter):
__name__ = "SimpleCrypter"
- __version__ = "0.01"
+ __version__ = "0.03"
__pattern__ = None
__type__ = "crypter"
__description__ = """Base crypter plugin"""
- __author_name__ = ("zoidberg")
- __author_mail__ = ("zoidberg@mujmail.cz")
+ __author_name__ = ("stickell", "zoidberg")
+ __author_mail__ = ("l.stickell@yahoo.it", "zoidberg@mujmail.cz")
+ """
+ These patterns should be defined by each hoster:
+
+ LINK_PATTERN: group(1) must be a download link
+ example: <div class="link"><a href="(http://speedload.org/\w+)
+
+ TITLE_PATTERN: (optional) the group defined by 'title' should be the title
+ example: <title>Files of: (?P<title>[^<]+) folder</title>
+ """
- def init(self):
- self.url = self.pyfile.url
-
def decrypt(self, pyfile):
- self.html = self.load(self.url)
+ self.html = self.load(pyfile.url)
- new_links = []
- new_links.extend(findall(self.LINK_PATTERN, self.html))
+ package_name, folder_name = self.getPackageNameAndFolder()
- if new_links:
- self.core.files.addLinks(new_links, self.pyfile.package().id)
+ package_links = re.findall(self.LINK_PATTERN, self.html)
+ self.logDebug('Package has %d links' % len(package_links))
+
+ if package_links:
+ self.packages = [(package_name, package_links, folder_name)]
else:
- self.fail('Could not extract any links') \ No newline at end of file
+ self.fail('Could not extract any links')
+
+ def getPackageNameAndFolder(self):
+ if hasattr(self, 'TITLE_PATTERN'):
+ m = re.search(self.TITLE_PATTERN, self.html)
+ if m:
+ name = folder = m.group('title')
+ self.logDebug("Found name [%s] and folder [%s] in package info" % (name, folder))
+ return name, folder
+
+ name = self.pyfile.package().name
+ folder = self.pyfile.package().folder
+ self.logDebug("Package info not found, defaulting to pyfile name [%s] and folder [%s]" % (name, folder))
+ return name, folder
diff --git a/module/plugins/internal/SimpleHoster.py b/module/plugins/internal/SimpleHoster.py
index a2e246d44..666374a22 100644
--- a/module/plugins/internal/SimpleHoster.py
+++ b/module/plugins/internal/SimpleHoster.py
@@ -31,48 +31,65 @@ def replace_patterns(string, ruleslist):
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, re.I)
+ m = re.search(r"%s\s*=\s*([\"']?)((?<=\")[^\"]+|(?<=')[^']+|[^>\s\"'][^>\s]*)\1" % attr_name, tag, re.I)
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:
+
+def parseHtmlForm(attr_str, html, input_names=None):
+ for form in re.finditer(r"(?P<tag><form[^>]*%s[^>]*>)(?P<content>.*?)</?(form|body|html)[^>]*>" % attr_str, html, re.S | re.I):
+ inputs = {}
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))
+ for inputtag in re.finditer(r'(<(input|textarea)[^>]*>)([^<]*(?=</\2)|)', form.group('content'), re.S | re.I):
+ name = parseHtmlTagAttrValue("name", inputtag.group(1))
if name:
- value = parseHtmlTagAttrValue("value", input.group(1))
+ value = parseHtmlTagAttrValue("value", inputtag.group(1))
if value is None:
- inputs[name] = input.group(3) or ''
+ inputs[name] = inputtag.group(3) or ''
else:
inputs[name] = value
-
- return action, inputs
-def parseFileInfo(self, url = '', html = ''):
+ if isinstance(input_names, dict):
+ # check input attributes
+ for key, val in input_names.items():
+ if key in inputs:
+ if isinstance(val, basestring) and inputs[key] == val:
+ continue
+ elif isinstance(val, tuple) and inputs[key] in val:
+ continue
+ elif hasattr(val, "search") and re.match(val, inputs[key]):
+ continue
+ break # attibute value does not match
+ else:
+ break # attibute name does not match
+ else:
+ return action, inputs # passed attribute check
+ else:
+ # no attribute check
+ return action, inputs
+
+ return {}, None # no matching form found
+
+def parseFileInfo(self, url = '', html = ''):
info = {"name" : url, "size" : 0, "status" : 3}
-
- if hasattr(self, "pyfile"):
- url = self.pyfile.url
+
+ if hasattr(self, "pyfile"):
+ url = self.pyfile.url
if hasattr(self, "req") and self.req.http.code == '404':
info['status'] = 1
else:
if not html and hasattr(self, "html"): html = self.html
- if isinstance(self.SH_BROKEN_ENCODING, (str, unicode)):
+ 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
@@ -82,7 +99,7 @@ def parseFileInfo(self, url = '', html = ''):
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())
@@ -129,7 +146,7 @@ class PluginParseError(Exception):
class SimpleHoster(Hoster):
__name__ = "SimpleHoster"
- __version__ = "0.26"
+ __version__ = "0.28"
__pattern__ = None
__type__ = "hoster"
__description__ = """Base hoster plugin"""
@@ -147,13 +164,13 @@ class SimpleHoster(Hoster):
FILE_SIZE_REPLACEMENTS = []
FILE_NAME_REPLACEMENTS = [("&#?\w+;", fixup)]
FILE_URL_REPLACEMENTS = []
-
+
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 = {}
+ self.file_info = {}
def setup(self):
self.resumeDownload = self.multiDL = True if self.premium else False
@@ -161,6 +178,7 @@ class SimpleHoster(Hoster):
def process(self, pyfile):
pyfile.url = replace_patterns(pyfile.url, self.FILE_URL_REPLACEMENTS)
+ self.req.setOption("timeout", 120)
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()):
@@ -168,13 +186,17 @@ class SimpleHoster(Hoster):
else:
self.handleFree()
+ def load(self, url, get={}, post={}, ref=True, cookies=True, just_header=False, decode=False):
+ if type(url) == unicode: url = url.encode('utf8')
+ return Hoster.load(self, url=url, get=get, post=post, ref=ref, cookies=cookies, just_header=just_header, decode=decode)
+
def getFileInfo(self):
self.logDebug("URL: %s" % self.pyfile.url)
if hasattr(self, "TEMP_OFFLINE_PATTERN") and re.search(self.TEMP_OFFLINE_PATTERN, self.html):
self.tempOffline()
name, size, status = parseFileInfo(self)[:3]
-
+
if status == 1:
self.offline()
elif status != 2:
@@ -202,26 +224,28 @@ class SimpleHoster(Hoster):
def parseError(self, 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
-
+ 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")
+ self.retry(max_tries = max_tries, reason="Download limit reached")
+
+ def parseHtmlForm(self, attr_str='', input_names=None):
+ return parseHtmlForm(attr_str, self.html, input_names)
- def parseHtmlForm(self, attr_str):
- return parseHtmlForm(attr_str, self.html)
-
- def checkTrafficLeft(self):
+ def checkTrafficLeft(self):
traffic = self.account.getAccountInfo(self.user, True)["trafficleft"]
+ if traffic == -1:
+ return True
size = self.pyfile.size / 1024
- self.logInfo("Filesize: %i KiB, Traffic left for user %s: %i KiB" % (size, self.user, traffic))
+ self.logInfo("Filesize: %i KiB, Traffic left for user %s: %i KiB" % (size, self.user, traffic))
return size <= traffic \ No newline at end of file
diff --git a/module/plugins/internal/XFSPAccount.py b/module/plugins/internal/XFSPAccount.py
index ad25ad2c8..8333c7265 100644
--- a/module/plugins/internal/XFSPAccount.py
+++ b/module/plugins/internal/XFSPAccount.py
@@ -33,7 +33,7 @@ class XFSPAccount(Account):
MAIN_PAGE = None
- VALID_UNTIL_PATTERN = r'>Premium account expire:</TD><TD><b>([^<]+)</b>'
+ VALID_UNTIL_PATTERN = r'>Premium.[Aa]ccount expire:</TD><TD><b>([^<]+)</b>'
TRAFFIC_LEFT_PATTERN = r'>Traffic available today:</TD><TD><b>([^<]+)</b>'
def loadAccountInfo(self, user, req):