diff options
Diffstat (limited to 'module')
126 files changed, 6722 insertions, 1757 deletions
diff --git a/module/plugins/accounts/AlldebridCom.py b/module/plugins/accounts/AlldebridCom.py new file mode 100644 index 000000000..f87a1c881 --- /dev/null +++ b/module/plugins/accounts/AlldebridCom.py @@ -0,0 +1,40 @@ +from module.plugins.Account import Account
+import xml.dom.minidom as dom
+from BeautifulSoup import BeautifulSoup
+from time import time
+import re
+
+class AlldebridCom(Account):
+ __name__ = "AlldebridCom"
+ __version__ = "0.2"
+ __type__ = "account"
+ __description__ = """AllDebrid.com account plugin"""
+ __author_name__ = ("Andy, Voigt")
+ __author_mail__ = ("spamsales@online.de")
+
+ def loadAccountInfo(self, user, req):
+ data = self.getAccountData(user)
+ page = req.load("http://www.alldebrid.com/account/")
+ soup=BeautifulSoup(page)
+ #Try to parse expiration date directly from the control panel page (better accuracy)
+ try:
+ time_text=soup.find('div',attrs={'class':'remaining_time_text'}).strong.string
+ self.log.debug("Account expires in: %s" % time_text)
+ p = re.compile('\d+')
+ exp_data=p.findall(time_text)
+ exp_time=time()+int(exp_data[0])*24*60*60+int(exp_data[1])*60*60+(int(exp_data[2])-1)*60
+ #Get expiration date from API
+ except:
+ data = self.getAccountData(user)
+ page = req.load("http://www.alldebrid.com/api.php?action=info_user&login=%s&pw=%s" % (user, data["password"]))
+ self.log.debug(page)
+ xml = dom.parseString(page)
+ exp_time=time()+int(xml.getElementsByTagName("date")[0].childNodes[0].nodeValue)*86400
+ account_info = {"validuntil": exp_time, "trafficleft": -1}
+ return account_info
+
+ def login(self, user, data, req):
+ page = req.load("http://www.alldebrid.com/register/?action=login&login_login=%s&login_password=%s" % (user, data["password"]))
+
+ if "This login doesn't exist" in page:
+ self.wrongPassword()
diff --git a/module/plugins/accounts/BayfilesCom.py b/module/plugins/accounts/BayfilesCom.py new file mode 100644 index 000000000..0d036488b --- /dev/null +++ b/module/plugins/accounts/BayfilesCom.py @@ -0,0 +1,51 @@ +# -*- 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 +""" + +from module.plugins.Account import Account +from module.common.json_layer import json_loads +import re +from time import time, mktime, strptime + +class BayfilesCom(Account): + __name__ = "BayfilesCom" + __version__ = "0.02" + __type__ = "account" + __description__ = """bayfiles.com account plugin""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + def loadAccountInfo(self, user, req): + for i in range(2): + response = json_loads(req.load("http://api.bayfiles.com/v1/account/info")) + self.logDebug(response) + if not response["error"]: + break + self.logWarning(response["error"]) + self.relogin() + + return {"premium": bool(response['premium']), \ + "trafficleft": -1, \ + "validuntil": response['expires'] if response['expires'] >= int(time()) else -1} + + def login(self, user, data, req): + response = json_loads(req.load("http://api.bayfiles.com/v1/account/login/%s/%s" % (user, data["password"]))) + self.logDebug(response) + if response["error"]: + self.logError(response["error"]) + self.wrongPassword()
\ No newline at end of file diff --git a/module/plugins/accounts/BitshareCom.py b/module/plugins/accounts/BitshareCom.py index b0cd1efcd..a4f56e31c 100644 --- a/module/plugins/accounts/BitshareCom.py +++ b/module/plugins/accounts/BitshareCom.py @@ -21,7 +21,7 @@ from module.plugins.Account import Account class BitshareCom(Account): __name__ = "BitshareCom" - __version__ = "0.1" + __version__ = "0.11" __type__ = "account" __description__ = """Bitshare account plugin""" __author_name__ = ("Paul King") @@ -39,6 +39,6 @@ class BitshareCom(Account): def login(self, user, data, req): - page = req.load("http://bitshare.com/login.html", post={ "user" : user, "pass" : data["password"], "submit" :"1"}, cookies=True) - if "Wrong Username or Password" in page: + page = req.load("http://bitshare.com/login.html", post={ "user" : user, "password" : data["password"], "submit" :"Login"}, cookies=True) + if "login" in req.lastEffectiveURL: self.wrongPassword() diff --git a/module/plugins/accounts/CoolshareCz.py b/module/plugins/accounts/CoolshareCz.py new file mode 100644 index 000000000..03686c729 --- /dev/null +++ b/module/plugins/accounts/CoolshareCz.py @@ -0,0 +1,71 @@ +# -*- 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 +""" + +#shares code with WarserverCz + +from module.plugins.Account import Account +import re +from time import mktime, strptime + +class CoolshareCz(Account): + __name__ = "CoolshareCz" + __version__ = "0.01" + __type__ = "account" + __description__ = """CoolShare.cz account plugin""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + VALID_UNTIL_PATTERN = ur'<li>Neomezené stahování do: <strong>(.+?)<' + TRAFFIC_LEFT_PATTERN = ur'<li>Kredit: <strong>.*?\(\s*(.+?)\s*B\)' + + DOMAIN = "http://www.coolshare.cz" + + def loadAccountInfo(self, user, req): + html = req.load("%s/uzivatele/prehled" % self.DOMAIN, decode = True) + + validuntil = trafficleft = None + premium = False + + found = re.search(self.VALID_UNTIL_PATTERN, html) + if found: + self.logDebug("VALID_UNTIL", found.group(1)) + try: + #validuntil = mktime(strptime(found.group(1), "%d %B %Y")) + premium = True + trafficleft = -1 + except Exception, e: + self.logError(e) + + found = re.search(self.TRAFFIC_LEFT_PATTERN, html) + if found: + self.logDebug("TRAFFIC_LEFT", found.group(1)) + trafficleft = int(found.group(1).replace(" ","")) // 1024 + premium = True if trafficleft > 1 << 18 else False + + return ({"validuntil": validuntil, "trafficleft": trafficleft, "premium": premium}) + + def login(self, user, data, req): + html = req.load('%s/uzivatele/prihlaseni?do=prihlaseni-submit' % self.DOMAIN, + post = {"username": user, + "password": data['password'], + "send": u"Přihlásit"}, + decode = True) + + if '<p class="chyba">' in html: + self.wrongPassword()
\ No newline at end of file diff --git a/module/plugins/accounts/DdlstorageCom.py b/module/plugins/accounts/DdlstorageCom.py new file mode 100644 index 000000000..01d165f23 --- /dev/null +++ b/module/plugins/accounts/DdlstorageCom.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- +from module.plugins.internal.XFSPAccount import XFSPAccount + +class DdlstorageCom(XFSPAccount): + __name__ = "DdlstorageCom" + __version__ = "0.01" + __type__ = "account" + __description__ = """DDLStorage.com account plugin""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + MAIN_PAGE = "http://ddlstorage.com/"
\ No newline at end of file diff --git a/module/plugins/accounts/EasybytezCom.py b/module/plugins/accounts/EasybytezCom.py index cf2b16394..ba7829b83 100644 --- a/module/plugins/accounts/EasybytezCom.py +++ b/module/plugins/accounts/EasybytezCom.py @@ -18,13 +18,14 @@ """ from module.plugins.Account import Account +from module.plugins.internal.SimpleHoster import parseHtmlForm import re from module.utils import parseFileSize from time import mktime, strptime class EasybytezCom(Account): __name__ = "EasybytezCom" - __version__ = "0.01" + __version__ = "0.02" __type__ = "account" __description__ = """EasyBytez.com account plugin""" __author_name__ = ("zoidberg") @@ -33,36 +34,40 @@ class EasybytezCom(Account): VALID_UNTIL_PATTERN = r'<TR><TD>Premium account expire:</TD><TD><b>([^<]+)</b>' TRAFFIC_LEFT_PATTERN = r'<TR><TD>Traffic available today:</TD><TD><b>(?P<S>[^<]+)</b>' - def loadAccountInfo(self, user, req): - #self.relogin(user) + def loadAccountInfo(self, user, req): html = req.load("http://www.easybytez.com/?op=my_account", decode = True) - validuntil = -1 + validuntil = trafficleft = None + premium = 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: - premium = False - - #found = re.search(self.TRAFFIC_LEFT_PATTERN, html) - #trafficleft = parseFileSize(found.group('S')) / 1024 if found else 0 - #self.premium = True if trafficleft else False - trafficleft = -1 + 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('http://www.easybytez.com/', post = { - "login": user, - "op": "login", - "password": data['password'], - "redirect": "http://easybytez.com/" - }, decode = True) + html = req.load('http://www.easybytez.com/login.html', decode = True) + action, inputs = parseHtmlForm('name="FL"', html) + inputs.update({"login": user, + "password": data['password'], + "redirect": "http://www.easybytez.com/"}) + + html = req.load(action, post = inputs, decode = True) - if 'Incorrect Login or Password' in html: + if 'Incorrect Login or Password' in html or '>Error<' in html: self.wrongPassword()
\ No newline at end of file diff --git a/module/plugins/accounts/FilecloudIo.py b/module/plugins/accounts/FilecloudIo.py new file mode 100644 index 000000000..cf9f92209 --- /dev/null +++ b/module/plugins/accounts/FilecloudIo.py @@ -0,0 +1,49 @@ +# -*- 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 +""" + +from module.plugins.Account import Account + +class FilecloudIo(Account): + __name__ = "FilecloudIo" + __version__ = "0.01" + __type__ = "account" + __description__ = """FilecloudIo account plugin""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + def loadAccountInfo(self, user, req): + return ({"validuntil": -1, "trafficleft": -1, "premium": False}) + + def login(self, user, data, req): + req.cj.setCookie("secure.filecloud.io", "lang", "en") + html = req.load('https://secure.filecloud.io/user-login.html') + + if not hasattr(self, "form_data"): + self.form_data = {} + + self.form_data["username"] = user + self.form_data["password"] = data['password'] + + html = req.load('https://secure.filecloud.io/user-login_p.html', + post = self.form_data, + multipart = True) + + self.logged_in = True if "you have successfully logged in - filecloud.io" in html else False + self.form_data = {} +
\ No newline at end of file diff --git a/module/plugins/accounts/FilefactoryCom.py b/module/plugins/accounts/FilefactoryCom.py new file mode 100644 index 000000000..356c5d22a --- /dev/null +++ b/module/plugins/accounts/FilefactoryCom.py @@ -0,0 +1,54 @@ +# -*- 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 +""" + +from module.plugins.Account import Account +import re +from time import mktime, strptime + +class FilefactoryCom(Account): + __name__ = "FilefactoryCom" + __version__ = "0.12" + __type__ = "account" + __description__ = """filefactory.com account plugin""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + ACCOUNT_INFO_PATTERN = r'<a href="/premium/">.*?datetime="(.*?)"' + + def loadAccountInfo(self, user, req): + html = req.load("http://www.filefactory.com/member/") + + found = re.search(self.ACCOUNT_INFO_PATTERN, html) + if found: + premium = True + validuntil = mktime(strptime(re.sub(r"(\d)[a-z]{2} ", r"\1 ", found.group(1)),"%d %B, %Y")) + else: + premium = False + validuntil = -1 + + return {"premium": premium, "trafficleft": -1, "validuntil": validuntil} + + def login(self, user, data, req): + html = req.load("http://www.filefactory.com/member/login.php", post={ + "email": user, + "password": data["password"], + "redirect": "/"}) + + if '/member/login.php?err=1' in req.http.header: + self.wrongPassword() diff --git a/module/plugins/accounts/FilejungleCom.py b/module/plugins/accounts/FilejungleCom.py new file mode 100644 index 000000000..8ac25c201 --- /dev/null +++ b/module/plugins/accounts/FilejungleCom.py @@ -0,0 +1,60 @@ +# -*- 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 +""" + +from module.plugins.Account import Account +import re +from time import mktime, strptime + +class FilejungleCom(Account): + __name__ = "FilejungleCom" + __version__ = "0.11" + __type__ = "account" + __description__ = """filejungle.com account plugin""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + login_timeout = 60 + + URL = "http://filejungle.com/" + TRAFFIC_LEFT_PATTERN = r'"/extend_premium\.php">Until (\d+ [A-Za-z]+ \d+)<br' + LOGIN_FAILED_PATTERN = r'<span htmlfor="loginUser(Name|Password)" generated="true" class="fail_info">' + + def loadAccountInfo(self, user, req): + html = req.load(self.URL + "dashboard.php") + found = re.search(self.TRAFFIC_LEFT_PATTERN, html) + if found: + premium = True + validuntil = mktime(strptime(found.group(1), "%d %b %Y")) + else: + premium = False + validuntil = -1 + + return {"premium": premium, "trafficleft": -1, "validuntil": validuntil} + + def login(self, user, data, req): + html = req.load(self.URL + "login.php", post={ + "loginUserName": user, + "loginUserPassword": data["password"], + "loginFormSubmit": "Login", + "recaptcha_challenge_field": "", + "recaptcha_response_field": "", + "recaptcha_shortencode_field": ""}) + + if re.search(self.LOGIN_FAILED_PATTERN, html): + self.wrongPassword()
\ No newline at end of file diff --git a/module/plugins/accounts/FourSharedCom.py b/module/plugins/accounts/FourSharedCom.py new file mode 100644 index 000000000..bd3820277 --- /dev/null +++ b/module/plugins/accounts/FourSharedCom.py @@ -0,0 +1,48 @@ +# -*- 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 +""" + +from module.plugins.Account import Account +from module.common.json_layer import json_loads + +class FourSharedCom(Account): + __name__ = "FourSharedCom" + __version__ = "0.01" + __type__ = "account" + __description__ = """FourSharedCom account plugin""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + def loadAccountInfo(self, user, req): + #fixme + return ({"validuntil": -1, "trafficleft": -1, "premium": False}) + + def login(self, user, data, req): + req.cj.setCookie("www.4shared.com", "4langcookie", "en") + response = req.load('http://www.4shared.com/login', + post = {"login": user, + "password": data['password'], + "remember": "false", + "doNotRedirect": "true"}) + self.logDebug(response) + response = json_loads(response) + + if not "ok" in response or response['ok'] != True: + if "rejectReason" in response and response['rejectReason'] != True: + self.logError(response['rejectReason']) + self.wrongPassword()
\ No newline at end of file diff --git a/module/plugins/accounts/FshareVn.py b/module/plugins/accounts/FshareVn.py index 46d2d5166..e51009f50 100644 --- a/module/plugins/accounts/FshareVn.py +++ b/module/plugins/accounts/FshareVn.py @@ -24,7 +24,7 @@ import re class FshareVn(Account): __name__ = "FshareVn" - __version__ = "0.01" + __version__ = "0.02" __type__ = "account" __description__ = """fshare.vn account plugin""" __author_name__ = ("zoidberg") @@ -47,13 +47,13 @@ class FshareVn(Account): return {"validuntil": validuntil, "trafficleft": trafficleft} def login(self, user, data, req): - req.http.c.setopt(REFERER, "http://www.fshare.vn/login.php") + req.http.c.setopt(REFERER, "https://www.fshare.vn/login.php") - html = req.load('http://www.fshare.vn/login.php', post = { + html = req.load('https://www.fshare.vn/login.php', post = { "login_password" : data['password'], "login_useremail" : user, - "url_refe" : "http://www.fshare.vn/login.php" + "url_refe" : "https://www.fshare.vn/login.php" }, referer = True, decode = True) if not '<img alt="VIP"' in html: - self.wrongPassword()
\ No newline at end of file + self.wrongPassword() diff --git a/module/plugins/accounts/HellshareCz.py b/module/plugins/accounts/HellshareCz.py index fc44e9307..8ed134f59 100644 --- a/module/plugins/accounts/HellshareCz.py +++ b/module/plugins/accounts/HellshareCz.py @@ -22,7 +22,7 @@ import re class HellshareCz(Account): __name__ = "HellshareCz" - __version__ = "0.11" + __version__ = "0.12" __type__ = "account" __description__ = """hellshare.cz account plugin""" __author_name__ = ("zoidberg") @@ -37,17 +37,19 @@ class HellshareCz(Account): found = re.search(self.CREDIT_LEFT_PATTERN, html) if found is None: credits = 0 + premium = False else: credits = int(found.group(1)) * 1024 + premium = True - return {"validuntil": -1, "trafficleft": credits} + return {"validuntil": -1, "trafficleft": credits, "premium": premium} def login(self, user, data, req): - html = req.load('http://www.hellshare.com/login?do=loginForm-submit', post={ "login": "Log in", "password": data["password"], - "username": user + "username": user, + "perm_login": "on" }) if "<p>You input a wrong user name or wrong password</p>" in html: diff --git a/module/plugins/accounts/HotfileCom.py b/module/plugins/accounts/HotfileCom.py index 9b54e6a3c..23e42dacf 100644 --- a/module/plugins/accounts/HotfileCom.py +++ b/module/plugins/accounts/HotfileCom.py @@ -14,7 +14,7 @@ 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: mkaay + @author: mkaay, JoKoT3 """ from module.plugins.Account import Account @@ -23,11 +23,11 @@ import hashlib class HotfileCom(Account): __name__ = "HotfileCom" - __version__ = "0.1" + __version__ = "0.2" __type__ = "account" __description__ = """hotfile.com account plugin""" - __author_name__ = ("mkaay") - __author_mail__ = ("mkaay@mkaay.de") + __author_name__ = ("mkaay","JoKoT3") + __author_mail__ = ("mkaay@mkaay.de","jokot3@gmail.com") def loadAccountInfo(self, user, req): resp = self.apiCall("getuserinfo", user=user) @@ -39,14 +39,18 @@ class HotfileCom(Account): key, value = p.split("=") info[key] = value - info["premium_until"] = info["premium_until"].replace("T"," ") - zone = info["premium_until"][19:] - info["premium_until"] = info["premium_until"][:19] - zone = int(zone[:3]) + if info['is_premium'] == '1': + info["premium_until"] = info["premium_until"].replace("T"," ") + zone = info["premium_until"][19:] + info["premium_until"] = info["premium_until"][:19] + zone = int(zone[:3]) + + validuntil = int(mktime(strptime(info["premium_until"], "%Y-%m-%d %H:%M:%S"))) + (zone*3600) + tmp = {"validuntil":validuntil, "trafficleft":-1, "premium":True} - validuntil = int(mktime(strptime(info["premium_until"], "%Y-%m-%d %H:%M:%S"))) + (zone*3600) - - tmp = {"validuntil":validuntil, "trafficleft":-1} + elif info['is_premium'] == '0': + tmp = {"premium":False} + return tmp def apiCall(self, method, post={}, user=None): @@ -79,4 +83,4 @@ class HotfileCom(Account): page = req.load("http://hotfile.com/login.php", post={"returnto": "/", "user": user, "pass": data["password"]}, cookies=True) if "Bad username/password" in page: - self.wrongPassword() + self.wrongPassword()
\ No newline at end of file diff --git a/module/plugins/accounts/MultishareCz.py b/module/plugins/accounts/MultishareCz.py index cc3e430af..39439cbbe 100644 --- a/module/plugins/accounts/MultishareCz.py +++ b/module/plugins/accounts/MultishareCz.py @@ -25,7 +25,7 @@ from module.utils import parseFileSize class MultishareCz(Account): __name__ = "MultishareCz" - __version__ = "0.01" + __version__ = "0.02" __type__ = "account" __description__ = """multishare.cz account plugin""" __author_name__ = ("zoidberg") @@ -54,5 +54,5 @@ class MultishareCz(Account): "jmeno": user }, decode = True) - if not u'<title>MultiShare.cz :: Profil uživatele</title>' in html: + if '<div class="akce-chyba akce">' in html: self.wrongPassword()
\ No newline at end of file diff --git a/module/plugins/accounts/NetloadIn.py b/module/plugins/accounts/NetloadIn.py index 6febf2ff1..cef3e298b 100755 --- a/module/plugins/accounts/NetloadIn.py +++ b/module/plugins/accounts/NetloadIn.py @@ -23,18 +23,18 @@ from time import time class NetloadIn(Account): __name__ = "NetloadIn" - __version__ = "0.2" + __version__ = "0.22" __type__ = "account" __description__ = """netload.in account plugin""" - __author_name__ = ("RaNaN", "DHMH") - __author_mail__ = ("RaNaN@pyload.org", "DHMH@pyload.org") + __author_name__ = ("RaNaN", "CryNickSystems") + __author_mail__ = ("RaNaN@pyload.org", "webmaster@pcProfil.de") def loadAccountInfo(self, user, req): - page = req.load("http://netload.in/index.php?id=2") - left = r">(\d+) Tage, (\d+) Stunden<" + page = req.load("http://netload.in/index.php?id=2&lang=de") + left = r">(\d+) (Tag|Tage), (\d+) Stunden<" left = re.search(left, page) if left: - validuntil = time() + int(left.group(1)) * 24 * 60 * 60 + int(left.group(2)) * 60 * 60 + validuntil = time() + int(left.group(1)) * 24 * 60 * 60 + int(left.group(3)) * 60 * 60 trafficleft = -1 premium = True else: @@ -44,6 +44,6 @@ class NetloadIn(Account): return {"validuntil": validuntil, "trafficleft": trafficleft, "premium" : premium} def login(self, user, data,req): - page = req.load("http://netload.in/index.php", None, { "txtuser" : user, "txtpass" : data['password'], "txtcheck" : "login", "txtlogin" : ""}, cookies=True) + page = req.load("http://netload.in/index.php", None, { "txtuser" : user, "txtpass" : data['password'], "txtcheck" : "login", "txtlogin" : "Login"}, cookies=True) if "password or it might be invalid!" in page: self.wrongPassword() diff --git a/module/plugins/accounts/PremiumizeMe.py b/module/plugins/accounts/PremiumizeMe.py new file mode 100644 index 000000000..768fcd783 --- /dev/null +++ b/module/plugins/accounts/PremiumizeMe.py @@ -0,0 +1,40 @@ +from module.plugins.Account import Account
+
+from module.common.json_layer import json_loads
+
+class PremiumizeMe(Account):
+ __name__ = "PremiumizeMe"
+ __version__ = "0.1"
+ __type__ = "account"
+ __description__ = """Premiumize.Me account plugin"""
+
+ __author_name__ = ("Florian Franzen")
+ __author_mail__ = ("FlorianFranzen@gmail.com")
+
+ def loadAccountInfo(self, user, req):
+
+ # Get user data from premiumize.me
+ status = self.getAccountStatus(user, req)
+
+ # Parse account info
+ account_info = {"validuntil": float(status['result']['expires']),
+ "trafficleft": status['result']['trafficleft_bytes'] / 1024}
+
+ return account_info
+
+ def login(self, user, data, req):
+
+ # Get user data from premiumize.me
+ status = self.getAccountStatus(user, req)
+
+ # Check if user and password are valid
+ if status['status'] != 200:
+ self.wrongPassword()
+
+
+ def getAccountStatus(self, user, req):
+
+ # Use premiumize.me API v1 (see https://secure.premiumize.me/?show=api) to retrieve account info and return the parsed json answer
+ answer = req.load("https://api.premiumize.me/pm-api/v1.php?method=accountstatus¶ms[login]=%s¶ms[pass]=%s" % (user, self.accounts[user]['password']))
+ return json_loads(answer)
+
\ No newline at end of file diff --git a/module/plugins/accounts/RapidshareCom.py b/module/plugins/accounts/RapidshareCom.py index e69f17e62..15722e099 100644 --- a/module/plugins/accounts/RapidshareCom.py +++ b/module/plugins/accounts/RapidshareCom.py @@ -21,7 +21,7 @@ from module.plugins.Account import Account class RapidshareCom(Account): __name__ = "RapidshareCom" - __version__ = "0.21" + __version__ = "0.22" __type__ = "account" __description__ = """Rapidshare.com account plugin""" __author_name__ = ("mkaay") @@ -41,8 +41,11 @@ class RapidshareCom(Account): continue k, v = t.split("=") info[k] = v + + validuntil = int(info["billeduntil"]) + premium = True if validuntil else False - tmp = {"validuntil":int(info["billeduntil"]), "trafficleft":-1, "maxtraffic":-1} + tmp = {"premium": premium, "validuntil": validuntil, "trafficleft":-1, "maxtraffic":-1} return tmp diff --git a/module/plugins/accounts/RealdebridCom.py b/module/plugins/accounts/RealdebridCom.py index 4a2cf9368..9460fc815 100644 --- a/module/plugins/accounts/RealdebridCom.py +++ b/module/plugins/accounts/RealdebridCom.py @@ -1,35 +1,35 @@ -#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-from module.plugins.MultiHoster import MultiHoster
-import xml.dom.minidom as dom
-
-class RealdebridCom(MultiHoster):
- __name__ = "RealdebridCom"
- __version__ = "0.5"
- __type__ = "account"
- __description__ = """Real-Debrid.com account plugin"""
- __author_name__ = ("Devirex, Hazzard")
- __author_mail__ = ("naibaf_11@yahoo.de")
-
- def loadAccountInfo(self, req):
- page = req.load("http://real-debrid.com/api/account.php")
- xml = dom.parseString(page)
- account_info = {"validuntil": int(xml.getElementsByTagName("expiration")[0].childNodes[0].nodeValue),
- "trafficleft": -1}
-
- return account_info
-
- def login(self, req):
- page = req.load("https://real-debrid.com/ajax/login.php?user=%s&pass=%s" % (self.loginname, self.password))
- #page = req.load("https://real-debrid.com/login.html", post={"user": user, "pass": data["password"]}, cookies=True)
-
- if "Your login informations are incorrect" in page:
- self.wrongPassword()
-
-
- def loadHosterList(self, req):
- https = "https" if self.getConfig("https") else "http"
- page = req.load(https + "://real-debrid.com/api/hosters.php").replace("\"","").strip()
-
+#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from module.plugins.MultiHoster import MultiHoster +import xml.dom.minidom as dom + +class RealdebridCom(MultiHoster): + __name__ = "RealdebridCom" + __version__ = "0.5" + __type__ = "account" + __description__ = """Real-Debrid.com account plugin""" + __author_name__ = ("Devirex, Hazzard") + __author_mail__ = ("naibaf_11@yahoo.de") + + def loadAccountInfo(self, req): + page = req.load("http://real-debrid.com/api/account.php") + xml = dom.parseString(page) + account_info = {"validuntil": int(xml.getElementsByTagName("expiration")[0].childNodes[0].nodeValue), + "trafficleft": -1} + + return account_info + + def login(self, req): + page = req.load("https://real-debrid.com/ajax/login.php?user=%s&pass=%s" % (self.loginname, self.password)) + #page = req.load("https://real-debrid.com/login.html", post={"user": user, "pass": data["password"]}, cookies=True) + + if "Your login informations are incorrect" in page: + self.wrongPassword() + + + def loadHosterList(self, req): + https = "https" if self.getConfig("https") else "http" + page = req.load(https + "://real-debrid.com/api/hosters.php").replace("\"","").strip() + return[x.strip() for x in page.split(",") if x.strip()]
\ No newline at end of file diff --git a/module/plugins/accounts/RyushareCom.py b/module/plugins/accounts/RyushareCom.py new file mode 100644 index 000000000..f734eb11b --- /dev/null +++ b/module/plugins/accounts/RyushareCom.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from module.plugins.internal.XFSPAccount import XFSPAccount + +class RyushareCom(XFSPAccount): + __name__ = "RyushareCom" + __version__ = "0.03" + __type__ = "account" + __description__ = """ryushare.com account plugin""" + __author_name__ = ("zoidberg", "trance4us") + __author_mail__ = ("zoidberg@mujmail.cz", "") + + MAIN_PAGE = "http://ryushare.com/" + + def login(self, user, data, req): + req.lastURL = "http://ryushare.com/login.python" + html = req.load("http://ryushare.com/login.python", post={"login": user, "password": data["password"], "op": "login"}) + if 'Incorrect Login or Password' in html or '>Error<' in html: + self.wrongPassword()
\ No newline at end of file diff --git a/module/plugins/accounts/ShareRapidCom.py b/module/plugins/accounts/ShareRapidCom.py index 9828b1f7e..aad229475 100644 --- a/module/plugins/accounts/ShareRapidCom.py +++ b/module/plugins/accounts/ShareRapidCom.py @@ -5,32 +5,30 @@ from module.plugins.Account import Account class ShareRapidCom(Account): __name__ = "ShareRapidCom" - __version__ = "0.1" + __version__ = "0.31" __type__ = "account" __description__ = """ShareRapid account plugin""" __author_name__ = ("MikyWoW") def loadAccountInfo(self, user, req): src = req.load("http://share-rapid.com/mujucet/", cookies=True) - if "Kredit:" in src: - start = src.index('Kredit:</td><td>') - src = src[start+16:] - start = src.index('GB') - kredit = src[0:start-1] - ret = float(kredit)*1024*1024 - tmp = {"premium": True, "trafficleft": ret, "validuntil": -1} + found = re.search(r'<tr><td>GB:</td><td>(.*?) GB', src) + if found: + ret = float(found.group(1)) * (1 << 20) + tmp = {"premium": True, "trafficleft": ret, "validuntil": -1} else: - tmp = {"premium": False, "trafficleft": None, "validuntil": None} + tmp = {"premium": False, "trafficleft": None, "validuntil": None} return tmp def login(self, user, data, req): htm = req.load("http://share-rapid.com/prihlaseni/", cookies=True) if "Heslo:" in htm: - start = htm.index('id="inp_hash" name="hash" value="') - htm = htm[start+33:] - hashes = htm[0:32] - html = req.load("http://share-rapid.com/prihlaseni/", + start = htm.index('id="inp_hash" name="hash" value="') + htm = htm[start+33:] + hashes = htm[0:32] + htm = req.load("http://share-rapid.com/prihlaseni/", post={"hash": hashes,"login": user, "pass1": data["password"],"remember": 0, "sbmt": "P%C5%99ihl%C3%A1sit"}, cookies=True) - if "Heslo:" in html: - self.wrongPassword()
\ No newline at end of file + + #if "Heslo:" in htm: + # self.wrongPassword()
\ No newline at end of file diff --git a/module/plugins/accounts/StahnuTo.py b/module/plugins/accounts/StahnuTo.py new file mode 100644 index 000000000..8a4523bc5 --- /dev/null +++ b/module/plugins/accounts/StahnuTo.py @@ -0,0 +1,49 @@ +# -*- 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 +""" + +from module.plugins.Account import Account +from module.utils import parseFileSize +import re + +class StahnuTo(Account): + __name__ = "StahnuTo" + __version__ = "0.02" + __type__ = "account" + __description__ = """StahnuTo account plugin""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + #login_timeout = 60 + + def loadAccountInfo(self, user, req): + html = req.load("http://www.stahnu.to/") + + found = re.search(r'>VIP: (\d+.*)<', html) + trafficleft = parseFileSize(found.group(1)) * 1024 if found else 0 + + return {"premium": trafficleft > (512 * 1024), "trafficleft": trafficleft, "validuntil": -1} + + def login(self, user, data, req): + html = req.load("http://www.stahnu.to/login.php", post={ + "username": user, + "password": data["password"], + "submit": "Login"}) + + if not '<a href="logout.php">' in html: + self.wrongPassword()
\ No newline at end of file diff --git a/module/plugins/accounts/TurbobitNet.py b/module/plugins/accounts/TurbobitNet.py new file mode 100644 index 000000000..c4b819131 --- /dev/null +++ b/module/plugins/accounts/TurbobitNet.py @@ -0,0 +1,56 @@ +# -*- 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 +""" + +from module.plugins.Account import Account +import re +from time import mktime, strptime + +class TurbobitNet(Account): + __name__ = "TurbobitNet" + __version__ = "0.01" + __type__ = "account" + __description__ = """TurbobitNet account plugin""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + #login_timeout = 60 + + def loadAccountInfo(self, user, req): + html = req.load("http://turbobit.net") + + found = re.search(r'<u>Turbo Access</u> to ([0-9.]+)', html) + if found: + premium = True + validuntil = mktime(strptime(found.group(1), "%d.%m.%Y")) + else: + premium = False + validuntil = -1 + + return {"premium": premium, "trafficleft": -1, "validuntil": validuntil} + + def login(self, user, data, req): + req.cj.setCookie("turbobit.net", "user_lang", "en") + + html = req.load("http://turbobit.net/user/login", post={ + "user[login]": user, + "user[pass]": data["password"], + "user[submit]": "Login"}) + + if not '<div class="menu-item user-name">' in html: + self.wrongPassword()
\ No newline at end of file diff --git a/module/plugins/accounts/UlozTo.py b/module/plugins/accounts/UlozTo.py index 36e1ae342..0c4ecda6a 100644 --- a/module/plugins/accounts/UlozTo.py +++ b/module/plugins/accounts/UlozTo.py @@ -5,28 +5,30 @@ import re class UlozTo(Account): __name__ = "UlozTo" - __version__ = "0.01" + __version__ = "0.03" __type__ = "account" __description__ = """uloz.to account plugin""" __author_name__ = ("zoidberg") __author_mail__ = ("zoidberg@mujmail.cz") - TRAFFIC_LEFT_PATTERN = r'<li class="credit"><a href="/kredit/" class="coins" title="[^"]* GB = ([^"]+) MB">' + TRAFFIC_LEFT_PATTERN = r'<li class="menu-kredit"><a href="/kredit/" title="[^"]*?GB = ([0-9.]+) MB">' def loadAccountInfo(self, user, req): - html = req.load("http://www.uloz.to/statistiky/", decode = True) + #this cookie gets lost somehow after each request + self.phpsessid = req.cj.getCookie("PHPSESSID") + html = req.load("http://www.ulozto.net/", decode = True) + req.cj.setCookie("www.ulozto.net", "PHPSESSID", self.phpsessid) found = re.search(self.TRAFFIC_LEFT_PATTERN, html) trafficleft = int(float(found.group(1).replace(' ','').replace(',','.')) * 1000 / 1.024) if found else 0 - self.premium = True if trafficleft else False + self.premium = True if trafficleft else False return {"validuntil": -1, "trafficleft": trafficleft} def login(self, user, data, req): - html = req.load('http://www.uloz.to/?do=authForm-submit', post = { - "login": "Přihlásit", + html = req.load('http://www.ulozto.net/login?do=loginForm-submit', post = { + "login": "Submit", "password": data['password'], - "trvale": "on", "username": user }, decode = True) diff --git a/module/plugins/accounts/UploadedTo.py b/module/plugins/accounts/UploadedTo.py index b4d194396..e10b93e8d 100644 --- a/module/plugins/accounts/UploadedTo.py +++ b/module/plugins/accounts/UploadedTo.py @@ -23,18 +23,18 @@ from time import time class UploadedTo(Account): __name__ = "UploadedTo" - __version__ = "0.21" + __version__ = "0.23" __type__ = "account" - __description__ = """ul.to account plugin""" + __description__ = """ul.net account plugin""" __author_name__ = ("mkaay") __author_mail__ = ("mkaay@mkaay.de") def loadAccountInfo(self, user, req): - req.load("http://uploaded.to/language/en") - html = req.load("http://uploaded.to/me") + req.load("http://uploaded.net/language/en") + html = req.load("http://uploaded.net/me") - premium = '<a href="me#premium"><em>Premium</em>' in html or '<em>Premium</em></th>' in html + premium = '<a href="register"><em>Premium</em>' in html or '<em>Premium</em></th>' in html if premium: raw_traffic = re.search(r'<th colspan="2"><b class="cB">([^<]+)', html).group(1) @@ -56,10 +56,10 @@ class UploadedTo(Account): def login(self, user, data, req): - req.load("http://uploaded.to/language/en") - req.cj.setCookie("uploaded.to", "lang", "en") + req.load("http://uploaded.net/language/en") + req.cj.setCookie("uploaded.net", "lang", "en") - page = req.load("http://uploaded.to/io/login", post={ "id" : user, "pw" : data["password"], "_" : ""}) + page = req.load("http://uploaded.net/io/login", post={ "id" : user, "pw" : data["password"], "_" : ""}) if "User and password do not match!" in page: self.wrongPassword() diff --git a/module/plugins/accounts/UploadheroCom.py b/module/plugins/accounts/UploadheroCom.py new file mode 100644 index 000000000..f1e0649e6 --- /dev/null +++ b/module/plugins/accounts/UploadheroCom.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from module.plugins.Account import Account
+import re,datetime,time
+
+class UploadheroCom(Account):
+ __name__ = "UploadheroCom"
+ __version__ = "0.1"
+ __type__ = "account"
+ __description__ = """Uploadhero.com account plugin"""
+ __author_name__ = ("mcmyst")
+ __author_mail__ = ("mcmyst@hotmail.fr")
+
+
+ def loadAccountInfo(self, user, req):
+ premium_pattern = re.compile('Il vous reste <span class="bleu">([0-9]+)</span> jours premium.')
+
+ data = self.getAccountData(user)
+ page = req.load("http://uploadhero.com/my-account")
+
+ if premium_pattern.search(page):
+ end_date = datetime.date.today() + datetime.timedelta(days=int(premium_pattern.search(page).group(1)))
+ end_date = time.mktime(future.timetuple())
+ account_info = {"validuntil": end_date, "trafficleft": -1, "premium": True}
+ else:
+ account_info = {"validuntil": -1, "trafficleft": -1, "premium": False}
+
+ return account_info
+
+ def login(self, user, data, req):
+ page = req.load("http://uploadhero.com/lib/connexion.php", post={"pseudo_login": user, "password_login": data["password"]})
+
+ if "mot de passe invalide" in page:
+ self.wrongPassword()
\ No newline at end of file diff --git a/module/plugins/accounts/UploadstationCom.py b/module/plugins/accounts/UploadstationCom.py new file mode 100644 index 000000000..e86cec7ce --- /dev/null +++ b/module/plugins/accounts/UploadstationCom.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- + +from module.plugins.accounts.FilejungleCom import FilejungleCom + +class UploadstationCom(FilejungleCom): + __name__ = "UploadstationCom" + __version__ = "0.1" + __type__ = "account" + __description__ = """uploadstation.com account plugin""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + URL = "http://uploadstation.com/" diff --git a/module/plugins/accounts/WarserverCz.py b/module/plugins/accounts/WarserverCz.py new file mode 100644 index 000000000..b3cafdb5f --- /dev/null +++ b/module/plugins/accounts/WarserverCz.py @@ -0,0 +1,33 @@ +# -*- 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 +""" + +from module.plugins.accounts.CoolshareCz import CoolshareCz +import re +from module.utils import parseFileSize +from time import mktime, strptime + +class WarserverCz(CoolshareCz): + __name__ = "WarserverCz" + __version__ = "0.01" + __type__ = "account" + __description__ = """Warserver.cz account plugin""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + DOMAIN = "http://www.warserver.cz"
\ No newline at end of file diff --git a/module/plugins/accounts/YibaishiwuCom.py b/module/plugins/accounts/YibaishiwuCom.py new file mode 100644 index 000000000..e2aa6f11d --- /dev/null +++ b/module/plugins/accounts/YibaishiwuCom.py @@ -0,0 +1,51 @@ +# -*- 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 +""" + +from module.plugins.Account import Account +import re + +class YibaishiwuCom(Account): + __name__ = "YibaishiwuCom" + __version__ = "0.01" + __type__ = "account" + __description__ = """115.com account plugin""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + ACCOUNT_INFO_PATTERN = r'var USER_PERMISSION = {(.*?)}' + + def loadAccountInfo(self, user, req): + #self.relogin(user) + html = req.load("http://115.com/", decode = True) + + found = re.search(self.ACCOUNT_INFO_PATTERN, html, re.S) + premium = True if (found and 'is_vip: 1' in found.group(1)) else False + validuntil = trafficleft = (-1 if found else 0) + return dict({"validuntil": validuntil, "trafficleft": trafficleft, "premium": premium}) + + def login(self, user, data, req): + html = req.load('http://passport.115.com/?ac=login', post = { + "back": "http://www.115.com/", + "goto": "http://115.com/", + "login[account]": user, + "login[passwd]": data['password'] + }, decode = True) + + if not 'var USER_PERMISSION = {' in html: + self.wrongPassword()
\ No newline at end of file diff --git a/module/plugins/accounts/ZeveraCom.py b/module/plugins/accounts/ZeveraCom.py index 26eac64b6..61a66cd89 100644 --- a/module/plugins/accounts/ZeveraCom.py +++ b/module/plugins/accounts/ZeveraCom.py @@ -1,105 +1,49 @@ -# -*- coding: utf-8 -*-
-from module.plugins.MultiHoster import MultiHoster
-
-import re
-from time import mktime, strptime
-
-class ZeveraCom(MultiHoster):
- __name__ = "ZeveraCom"
- __version__ = "0.11"
- __type__ = "account"
- __description__ = """Zevera.com account plugin"""
- __author_name__ = ("zoidberg")
- __author_mail__ = ("zoidberg@mujmail.cz")
-
- api_url = "http://zevera.com/API.ashx"
-
- def loadAccountInfo(self, req):
- dataRet = self.loadAPIRequest(req)
- account_info = {
- "trafficleft": dataRet['AccountInfo']['AvailableTODAYTrafficForUseInMBytes'] * 1024,
- "validuntil": -1 #dataRet['AccountInfo']['EndSubscriptionDate']
- }
-
- return account_info
-
- def login(self, req):
- if self.loadAPIRequest(req, parse = False) == 'Login Error':
- self.wrongPassword()
-
- def loadHosterList(self, req):
- page = req.load("http://www.zevera.com/jDownloader.ashx?cmd=gethosters")
- return [x.strip() for x in page.replace("\"", "").split(",")]
-
- def loadAPIRequest(self, req, parse = True, **kwargs):
- get_dict = {
- 'cmd': 'download_request',
- 'login': self.loginname,
- 'pass': self.password
- }
- get_dict.update(kwargs)
-
- response = req.load(self.api_url, get = get_dict, decode = True)
- self.logDebug(response)
- return self.parseAPIRequest(response) if parse else response
-
- def parseAPIRequest(self, api_response):
-
- try:
- arFields = iter(api_response.split('TAG BEGIN DATA#')[1].split('#END DATA')[0].split('#'))
-
- retData = {
- 'VersionMajor': arFields.next(),
- 'VersionMinor': arFields.next(),
- 'ErrorCode': int(arFields.next()),
- 'ErrorMessage': arFields.next(),
- 'Update_Wait': arFields.next()
- }
- serverInfo = {
- 'DateTimeOnServer': mktime(strptime(arFields.next(),"%Y/%m/%d %H:%M:%S")),
- 'DAY_Traffic_LimitInMBytes': int(arFields.next())
- }
- accountInfo = {
- 'EndSubscriptionDate': mktime(strptime(arFields.next(),"%Y/%m/%d %H:%M:%S")),
- 'TrafficUsedInMBytesDayToday': int(arFields.next()),
- 'AvailableEXTRATrafficForUseInMBytes': int(arFields.next()),
- 'AvailableTODAYTrafficForUseInMBytes': int(arFields.next())
- }
- fileInfo = {
- 'FileID': arFields.next(),
- 'Title': arFields.next(),
- 'RealFileName': arFields.next(),
- 'FileNameOnServer': arFields.next(),
- 'StorageServerURL': arFields.next(),
- 'Token': arFields.next(),
- 'FileSizeInBytes': int(arFields.next()),
- 'StatusID': int(arFields.next())
- }
- progress = {
- 'BytesReceived': int(arFields.next()),
- 'TotalBytesToReceive': int(arFields.next()),
- 'Percentage': arFields.next(),
- 'StatusText': arFields.next(),
- 'ProgressText': arFields.next()
- }
- fileInfo.update({
- 'Progress': progress,
- 'FilePassword': arFields.next(),
- 'Keywords': arFields.next(),
- 'ImageURL4Download': arFields.next(),
- 'CategoryID': arFields.next(),
- 'CategoryText': arFields.next(),
- 'Notes': arFields.next()
- })
- retData.update({
- 'ServerInfo': serverInfo,
- 'AccountInfo': accountInfo,
- 'FileInfo': fileInfo
- })
-
- except Exception, e:
- self.logError(e)
- return None
-
- self.logDebug(retData)
- return retData
\ No newline at end of file +# -*- coding: utf-8 -*- +from module.plugins.Account import Account + +import re +from time import mktime, strptime + +class ZeveraCom(Account): + __name__ = "ZeveraCom" + __version__ = "0.21" + __type__ = "account" + __description__ = """Zevera.com account plugin""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + def loadAccountInfo(self, user, req): + data = self.getAPIData(req) + if data == "No traffic": + account_info = {"trafficleft": 0, "validuntil": 0, "premium": False} + else: + account_info = { + "trafficleft": int(data['availabletodaytraffic']) * 1024, + "validuntil": mktime(strptime(data['endsubscriptiondate'],"%Y/%m/%d %H:%M:%S")), + "premium": True + } + return account_info + + def login(self, user, data, req): + self.loginname = user + self.password = data["password"] + if self.getAPIData(req) == "No traffic": + self.wrongPassword() + + def getAPIData(self, req, just_header = False, **kwargs): + get_data = { + 'cmd': 'accountinfo', + 'login': self.loginname, + 'pass': self.password + } + get_data.update(kwargs) + + response = req.load("http://www.zevera.com/jDownloader.ashx", get = get_data, decode = True, just_header = just_header) + self.logDebug(response) + + if ':' in response: + if not just_header: + response = response.replace(',','\n') + return dict((y.strip().lower(), z.strip()) for (y,z) in [x.split(':',1) for x in response.splitlines() if ':' in x]) + else: + return response
\ No newline at end of file diff --git a/module/plugins/addons/AlldebridCom.py b/module/plugins/addons/AlldebridCom.py new file mode 100644 index 000000000..f9657ed8c --- /dev/null +++ b/module/plugins/addons/AlldebridCom.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- + +# should be working + +from module.network.RequestFactory import getURL +from module.plugins.internal.MultiHoster import MultiHoster + +class AlldebridCom(MultiHoster): + __name__ = "AlldebridCom" + __version__ = "0.11" + __type__ = "hook" + + __config__ = [("activated", "bool", "Activated", "False"), + ("https", "bool", "Enable HTTPS", "False"), + ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"), + ("hosterList", "str", "Hoster list (comma separated)", "")] + + __description__ = """Real-Debrid.com hook plugin""" + __author_name__ = ("Andy, Voigt") + __author_mail__ = ("spamsales@online.de") + + replacements = [("freakshare.net", "freakshare.com")] + + def getHoster(self): + https = "https" if self.getConfig("https") else "http" + page = getURL(https + "://www.alldebrid.com/api.php?action=get_host").replace("\"","").strip() + + hosters = set([x.strip() for x in page.split(",") if x.strip()]) + + configMode = self.getConfig('hosterListMode') + if configMode in ("listed", "unlisted"): + configList = set(self.getConfig('hosterList').strip().lower().replace('|',',').replace(';',',').split(',')) + configList.discard(u'') + if configMode == "listed": + hosters &= configList + else: + hosters -= configList + + return list(hosters) diff --git a/module/plugins/addons/BypassCaptcha.py b/module/plugins/addons/BypassCaptcha.py new file mode 100644 index 000000000..24ad17dd8 --- /dev/null +++ b/module/plugins/addons/BypassCaptcha.py @@ -0,0 +1,143 @@ +# -*- 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: RaNaN, Godofdream, zoidberg +""" + +from thread import start_new_thread +from pycurl import FORM_FILE, LOW_SPEED_TIME + +from module.network.RequestFactory import getURL, getRequest +from module.network.HTTPRequest import BadHeader + +from module.plugins.Hook import Hook + +PYLOAD_KEY = "4f771155b640970d5607f919a615bdefc67e7d32" + +class BypassCaptchaException(Exception): + def __init__(self, err): + self.err = err + + def getCode(self): + return self.err + + def __str__(self): + return "<BypassCaptchaException %s>" % self.err + + def __repr__(self): + return "<BypassCaptchaException %s>" % self.err + +class BypassCaptcha(Hook): + __name__ = "BypassCaptcha" + __version__ = "0.03" + __description__ = """send captchas to BypassCaptcha.com""" + __config__ = [("activated", "bool", "Activated", True), + ("force", "bool", "Force BC even if client is connected", False), + ("passkey", "password", "Passkey", "")] + __author_name__ = ("RaNaN", "Godofdream", "zoidberg") + __author_mail__ = ("RaNaN@pyload.org", "soilfcition@gmail.com", "zoidberg@mujmail.cz") + + SUBMIT_URL = "http://bypasscaptcha.com/upload.php" + RESPOND_URL = "http://bypasscaptcha.com/check_value.php" + GETCREDITS_URL = "http://bypasscaptcha.com/ex_left.php" + + def setup(self): + self.info = {} + + def getCredits(self): + response = getURL(self.GETCREDITS_URL, + post = {"key": self.getConfig("passkey")} + ) + + data = dict([x.split(' ',1) for x in response.splitlines()]) + return int(data['Left']) + + + def submit(self, captcha, captchaType="file", match=None): + req = getRequest() + + #raise timeout threshold + req.c.setopt(LOW_SPEED_TIME, 80) + + try: + response = req.load(self.SUBMIT_URL, + post={"vendor_key": PYLOAD_KEY, + "key": self.getConfig("passkey"), + "gen_task_id": "1", + "file": (FORM_FILE, captcha)}, + multipart=True) + finally: + req.close() + + data = dict([x.split(' ',1) for x in response.splitlines()]) + if not data or "Value" not in data: + raise BypassCaptchaException(response) + + result = data['Value'] + ticket = data['TaskId'] + self.logDebug("result %s : %s" % (ticket,result)) + + return ticket, result + + def respond(self, ticket, success): + try: + response = getURL(self.RESPOND_URL, + post={"task_id": ticket, + "key": self.getConfig("passkey"), + "cv": 1 if success else 0} + ) + except BadHeader, e: + self.logError("Could not send response.", str(e)) + + def newCaptchaTask(self, task): + if "service" in task.data: + return False + + if not task.isTextual(): + return False + + if not self.getConfig("passkey"): + return False + + if self.core.isClientConnected() and not self.getConfig("force"): + return False + + if self.getCredits() > 0: + task.handler.append(self) + task.data['service'] = self.__name__ + task.setWaiting(100) + start_new_thread(self.processCaptcha, (task,)) + + else: + self.logInfo("Your %s account has not enough credits" % self.__name__) + + def captchaCorrect(self, task): + if task.data['service'] == self.__name__ and "ticket" in task.data: + self.respond(task.data["ticket"], True) + + def captchaInvalid(self, task): + if task.data['service'] == self.__name__ and "ticket" in task.data: + self.respond(task.data["ticket"], False) + + def processCaptcha(self, task): + c = task.captchaFile + try: + ticket, result = self.submit(c) + except BypassCaptchaException, e: + task.error = e.getCode() + return + + task.data["ticket"] = ticket + task.setResult(result)
\ No newline at end of file diff --git a/module/plugins/addons/CaptchaBrotherhood.py b/module/plugins/addons/CaptchaBrotherhood.py new file mode 100644 index 000000000..a22a5ee1d --- /dev/null +++ b/module/plugins/addons/CaptchaBrotherhood.py @@ -0,0 +1,169 @@ +# -*- 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: mkaay, RaNaN, zoidberg +""" +from __future__ import with_statement + +from thread import start_new_thread + +import pycurl +import StringIO +from urllib import urlencode +from time import sleep +import Image + +from module.network.RequestFactory import getURL, getRequest +from module.network.HTTPRequest import BadHeader +from module.plugins.Hook import Hook + +class CaptchaBrotherhoodException(Exception): + def __init__(self, err): + self.err = err + + def getCode(self): + return self.err + + def __str__(self): + return "<CaptchaBrotherhoodException %s>" % self.err + + def __repr__(self): + return "<CaptchaBrotherhoodException %s>" % self.err + +class CaptchaBrotherhood(Hook): + __name__ = "CaptchaBrotherhood" + __version__ = "0.03" + __description__ = """send captchas to CaptchaBrotherhood.com""" + __config__ = [("activated", "bool", "Activated", False), + ("username", "str", "Username", ""), + ("force", "bool", "Force CT even if client is connected", False), + ("passkey", "password", "Password", ""),] + __author_name__ = ("RaNaN", "zoidberg") + __author_mail__ = ("RaNaN@pyload.org", "zoidberg@mujmail.cz") + + API_URL = "http://ocrhood.gazcad.com/" + + def setup(self): + self.info = {} + + def getCredits(self): + response = getURL(self.API_URL + "askCredits.aspx", + get = {"username": self.getConfig("username"), + "password": self.getConfig("passkey")}) + if not response.startswith("OK"): + raise CaptchaBrotherhoodException(response) + else: + credits = int(response[3:]) + self.logInfo(_("%d credits left") % credits) + self.info["credits"] = credits + return credits + + def submit(self, captcha, captchaType="file", match=None): + try: + img = Image.open(captcha) + output = StringIO.StringIO() + self.logDebug("CAPTCHA IMAGE", img, img.format, img.mode) + if img.format in ("GIF", "JPEG"): + img.save(output, img.format) + else: + if img.mode != "RGB": + img = img.convert("RGB") + img.save(output, "JPEG") + data = output.getvalue() + output.close() + except Exception, e: + raise CaptchaBrotherhoodException("Reading or converting captcha image failed: %s" % e) + + req = getRequest() + + url = "%ssendNewCaptcha.aspx?%s" % (self.API_URL, + urlencode({"username": self.getConfig("username"), + "password": self.getConfig("passkey"), + "captchaSource": "pyLoad", + "timeout": "80"}) + ) + + req.c.setopt(pycurl.URL, url) + req.c.setopt(pycurl.POST, 1) + req.c.setopt(pycurl.POSTFIELDS, data) + req.c.setopt(pycurl.HTTPHEADER, [ "Content-Type: text/html" ]) + + try: + req.c.perform() + response = req.getResponse() + except Exception, e: + raise CaptchaBrotherhoodException("Submit captcha image failed") + + req.close() + + if not response.startswith("OK"): + raise CaptchaBrotherhoodException(response[1]) + + ticket = response[3:] + + for i in range(15): + sleep(5) + response = self.get_api("askCaptchaResult", ticket) + if response.startswith("OK-answered"): + return ticket, response[12:] + + raise CaptchaBrotherhoodException("No solution received in time") + + def get_api(self, api, ticket): + response = getURL("%s%s.aspx" % (self.API_URL, api), + get={"username": self.getConfig("username"), + "password": self.getConfig("passkey"), + "captchaID": ticket} + ) + if not response.startswith("OK"): + raise CaptchaBrotherhoodException("Unknown response: %s" % response) + + return response + + def newCaptchaTask(self, task): + if "service" in task.data: + return False + + if not task.isTextual(): + return False + + if not self.getConfig("username") or not self.getConfig("passkey"): + return False + + if self.core.isClientConnected() and not self.getConfig("force"): + return False + + if self.getCredits() > 10: + task.handler.append(self) + task.data['service'] = self.__name__ + task.setWaiting(100) + start_new_thread(self.processCaptcha, (task,)) + else: + self.logInfo("Your CaptchaBrotherhood Account has not enough credits") + + def captchaInvalid(self, task): + if task.data['service'] == self.__name__ and "ticket" in task.data: + response = self.get_api("complainCaptcha", task.data['ticket']) + + def processCaptcha(self, task): + c = task.captchaFile + try: + ticket, result = self.submit(c) + except CaptchaBrotherhoodException, e: + task.error = e.getCode() + return + + task.data["ticket"] = ticket + task.setResult(result)
\ No newline at end of file diff --git a/module/plugins/addons/CaptchaTrader.py b/module/plugins/addons/CaptchaTrader.py index b3374ec1d..889fa38ef 100644 --- a/module/plugins/addons/CaptchaTrader.py +++ b/module/plugins/addons/CaptchaTrader.py @@ -46,7 +46,7 @@ class CaptchaTraderException(Exception): class CaptchaTrader(Addon): __name__ = "CaptchaTrader" - __version__ = "0.13" + __version__ = "0.14" __description__ = """send captchas to captchatrader.com""" __config__ = [("activated", "bool", "Activated", True), ("username", "str", "Username", ""), @@ -55,9 +55,9 @@ class CaptchaTrader(Addon): __author_name__ = ("RaNaN") __author_mail__ = ("RaNaN@pyload.org") - SUBMIT_URL = "http://captchatrader.com/api/submit" - RESPOND_URL = "http://captchatrader.com/api/respond" - GETCREDITS_URL = "http://captchatrader.com/api/get_credits/username:%(user)s/password:%(password)s/" + SUBMIT_URL = "http://api.captchatrader.com/submit" + RESPOND_URL = "http://api.captchatrader.com/respond" + GETCREDITS_URL = "http://api.captchatrader.com/get_credits/username:%(user)s/password:%(password)s/" def setup(self): self.info = {} diff --git a/module/plugins/addons/Checksum.py b/module/plugins/addons/Checksum.py new file mode 100644 index 000000000..cb6f4bfe8 --- /dev/null +++ b/module/plugins/addons/Checksum.py @@ -0,0 +1,123 @@ +# -*- 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 +""" +from __future__ import with_statement +import hashlib, zlib +from os.path import getsize, isfile + +from module.utils import save_join, fs_encode +from module.plugins.Hook import Hook + +def computeChecksum(local_file, algorithm): + if algorithm in getattr(hashlib, "algorithms", ("md5", "sha1", "sha224", "sha256", "sha384", "sha512")): + h = getattr(hashlib, algorithm)() + chunk_size = 128 * h.block_size + + with open(local_file, 'rb') as f: + for chunk in iter(lambda: f.read(chunk_size), ''): + h.update(chunk) + + return h.hexdigest() + + elif algorithm in ("adler32", "crc32"): + hf = getattr(zlib, algorithm) + last = 0 + + with open(local_file, 'rb') as f: + for chunk in iter(lambda: f.read(8192), ''): + last = hf(chunk, last) + + return "%x" % last + + else: + return None + +class Checksum(Hook): + __name__ = "Checksum" + __version__ = "0.05" + __description__ = "Verify downloaded file size and checksum (enable in general preferences)" + __config__ = [("activated", "bool", "Activated", True), + ("action", "fail;retry;nothing", "What to do if check fails?", "retry"), + ("max_tries", "int", "Number of retries", 2)] + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + def setup(self): + self.algorithms = sorted(getattr(hashlib, "algorithms", ("md5", "sha1", "sha224", "sha256", "sha384", "sha512")), reverse = True) + self.algorithms.extend(["crc32", "adler32"]) + + if not self.config['general']['checksum']: + self.logInfo("Checksum validation is disabled in general configuration") + + def downloadFinished(self, pyfile): + """ + Compute checksum for the downloaded file and compare it with the hash provided by the hoster. + pyfile.plugin.check_data should be a dictionary which can contain: + a) if known, the exact filesize in bytes (e.g. "size": 123456789) + b) hexadecimal hash string with algorithm name as key (e.g. "md5": "d76505d0869f9f928a17d42d66326307") + """ + if hasattr(pyfile.plugin, "check_data") and (isinstance(pyfile.plugin.check_data, dict)): + data = pyfile.plugin.check_data.copy() + elif hasattr(pyfile.plugin, "api_data") and (isinstance(pyfile.plugin.api_data, dict)): + data = pyfile.plugin.api_data.copy() + else: + return + + self.logDebug(data) + + download_folder = self.config['general']['download_folder'] + local_file = fs_encode(save_join(download_folder, pyfile.package().folder, pyfile.name)) + + if not isfile(local_file): + self.checkFailed(pyfile, "File does not exist") + + # validate file size + if "size" in data: + api_size = int(data['size']) + file_size = getsize(local_file) + if api_size != file_size: + self.logWarning("File %s has incorrect size: %d B (%d expected)" % (pyfile.name, file_size, api_size)) + self.checkFailed(pyfile, "Incorrect file size") + del data['size'] + + # validate checksum + if data and self.config['general']['checksum']: + if "checksum" in data: + data['md5'] = data['checksum'] + + for key in self.algorithms: + if key in data: + checksum = computeChecksum(local_file, key.replace("-","").lower()) + if checksum: + if checksum == data[key]: + self.logInfo('File integrity of "%s" verified by %s checksum (%s).' % (pyfile.name, key.upper(), checksum)) + return + else: + self.logWarning("%s checksum for file %s does not match (%s != %s)" % (key.upper(), pyfile.name, checksum, data[key])) + self.checkFailed(pyfile, "Checksums do not match") + else: + self.logWarning("Unsupported hashing algorithm: %s" % key.upper()) + else: + self.logWarning("Unable to validate checksum for file %s" % (pyfile.name)) + + def checkFailed(self, pyfile, msg): + action = self.getConfig("action") + if action == "fail": + pyfile.plugin.fail(reason = msg) + elif action == "retry": + pyfile.plugin.retry(reason = msg, max_tries = self.getConfig("max_tries"))
\ No newline at end of file diff --git a/module/plugins/addons/DeathByCaptcha.py b/module/plugins/addons/DeathByCaptcha.py new file mode 100644 index 000000000..59ff40ded --- /dev/null +++ b/module/plugins/addons/DeathByCaptcha.py @@ -0,0 +1,210 @@ +# -*- 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: mkaay, RaNaN, zoidberg +""" +from __future__ import with_statement + +from thread import start_new_thread +from pycurl import FORM_FILE, HTTPHEADER, RESPONSE_CODE +from time import sleep +from base64 import b64encode +import re + +from module.network.RequestFactory import getURL, getRequest +from module.network.HTTPRequest import BadHeader +from module.plugins.Hook import Hook +from module.common.json_layer import json_loads + +class DeathByCaptchaException(Exception): + DBC_ERRORS = {'not-logged-in': 'Access denied, check your credentials', + 'invalid-credentials': 'Access denied, check your credentials', + 'banned': 'Access denied, account is suspended', + 'insufficient-funds': 'Insufficient account balance to decrypt CAPTCHA', + 'invalid-captcha': 'CAPTCHA is not a valid image', + 'service-overload': 'CAPTCHA was rejected due to service overload, try again later', + 'invalid-request': 'Invalid request', + 'timed-out': 'No CAPTCHA solution received in time' } + + def __init__(self, err): + self.err = err + + def getCode(self): + return self.err + + def getDesc(self): + if self.err in self.DBC_ERRORS.keys(): + return self.DBC_ERRORS[self.err] + else: + return self.err + + def __str__(self): + return "<DeathByCaptchaException %s>" % self.err + + def __repr__(self): + return "<DeathByCaptchaException %s>" % self.err + +class DeathByCaptcha(Hook): + __name__ = "DeathByCaptcha" + __version__ = "0.03" + __description__ = """send captchas to DeathByCaptcha.com""" + __config__ = [("activated", "bool", "Activated", False), + ("username", "str", "Username", ""), + ("passkey", "password", "Password", ""), + ("force", "bool", "Force DBC even if client is connected", False)] + __author_name__ = ("RaNaN", "zoidberg") + __author_mail__ = ("RaNaN@pyload.org", "zoidberg@mujmail.cz") + + API_URL = "http://api.dbcapi.me/api/" + + def setup(self): + self.info = {} + + def call_api(self, api="captcha", post=False, multipart=False): + req = getRequest() + req.c.setopt(HTTPHEADER, ["Accept: application/json", + "User-Agent: pyLoad %s" % self.core.version]) + + if post: + if not isinstance(post, dict): + post = {} + post.update({"username": self.getConfig("username"), + "password": self.getConfig("passkey")}) + + response = None + try: + json = req.load("%s%s" % (self.API_URL, api), + post = post, + multipart=multipart) + self.logDebug(json) + response = json_loads(json) + + if "error" in response: + raise DeathByCaptchaException(response['error']) + elif "status" not in response: + raise DeathByCaptchaException(str(response)) + + except BadHeader, e: + if 403 == e.code: + raise DeathByCaptchaException('not-logged-in') + elif 413 == e.code: + raise DeathByCaptchaException('invalid-captcha') + elif 503 == e.code: + raise DeathByCaptchaException('service-overload') + elif e.code in (400, 405): + raise DeathByCaptchaException('invalid-request') + else: + raise + + finally: + req.close() + + return response + + def getCredits(self): + response = self.call_api("user", True) + + if 'is_banned' in response and response['is_banned']: + raise DeathByCaptchaException('banned') + elif 'balance' in response and 'rate' in response: + self.info.update(response) + else: + raise DeathByCaptchaException(response) + + def getStatus(self): + response = self.call_api("status", False) + + if 'is_service_overloaded' in response and response['is_service_overloaded']: + raise DeathByCaptchaException('service-overload') + + def submit(self, captcha, captchaType="file", match=None): + #workaround multipart-post bug in HTTPRequest.py + if re.match("^[A-Za-z0-9]*$", self.getConfig("passkey")): + multipart = True + data = (FORM_FILE, captcha) + else: + multipart = False + with open(captcha, 'rb') as f: + data = f.read() + data = "base64:" + b64encode(data) + + response = self.call_api("captcha", {"captchafile": data}, multipart) + + if "captcha" not in response: + raise DeathByCaptchaException(response) + ticket = response['captcha'] + + for i in range(24): + sleep(5) + response = self.call_api("captcha/%d" % ticket, False) + if response['text'] and response['is_correct']: + break + else: + raise DeathByCaptchaException('timed-out') + + result = response['text'] + self.logDebug("result %s : %s" % (ticket,result)) + + return ticket, result + + def newCaptchaTask(self, task): + if "service" in task.data: + return False + + if not task.isTextual(): + return False + + if not self.getConfig("username") or not self.getConfig("passkey"): + return False + + if self.core.isClientConnected() and not self.getConfig("force"): + return False + + try: + self.getStatus() + self.getCredits() + except DeathByCaptchaException, e: + self.logError(e.getDesc()) + return False + + balance, rate = self.info["balance"], self.info["rate"] + self.logInfo("Account balance: US$%.3f (%d captchas left at %.2f cents each)" % (balance / 100, balance // rate, rate)) + + if balance > rate: + task.handler.append(self) + task.data['service'] = self.__name__ + task.setWaiting(180) + start_new_thread(self.processCaptcha, (task,)) + + def captchaInvalid(self, task): + if task.data['service'] == self.__name__ and "ticket" in task.data: + try: + response = self.call_api("captcha/%d/report" % task.data["ticket"], True) + except DeathByCaptchaException, e: + self.logError(e.getDesc()) + except Exception, e: + self.logError(e) + + def processCaptcha(self, task): + c = task.captchaFile + try: + ticket, result = self.submit(c) + except DeathByCaptchaException, e: + task.error = e.getCode() + self.logError(e.getDesc()) + return + + task.data["ticket"] = ticket + task.setResult(result)
\ No newline at end of file diff --git a/module/plugins/addons/DownloadScheduler.py b/module/plugins/addons/DownloadScheduler.py new file mode 100644 index 000000000..7cadede38 --- /dev/null +++ b/module/plugins/addons/DownloadScheduler.py @@ -0,0 +1,78 @@ +# -*- 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. + 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 + Original idea by new.cze +""" + +import re +from time import localtime +from module.plugins.Hook import Hook + +class DownloadScheduler(Hook): + __name__ = "DownloadScheduler" + __version__ = "0.20" + __description__ = """Download Scheduler""" + __config__ = [("activated", "bool", "Activated", "False"), + ("timetable", "str", "List time periods as hh:mm full or number(kB/s)", "0:00 full, 7:00 250, 10:00 0, 17:00 150")] + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + def setup(self): + self.cb = None # callback to scheduler job; will be by removed hookmanager when hook unloaded + + def coreReady(self): + self.updateSchedule() + + def updateSchedule(self, schedule = None): + if schedule is None: + schedule = self.getConfig("timetable") + + schedule = re.findall("(\d{1,2}):(\d{2})[\s]*(-?\d+)", schedule.lower().replace("full", "-1").replace("none", "0")) + if not schedule: + self.logError("Invalid schedule") + return + + t0 = localtime() + now = (t0.tm_hour, t0.tm_min, t0.tm_sec, "X") + schedule = sorted([(int(x[0]), int(x[1]), 0, int(x[2])) for x in schedule] + [now]) + + self.logDebug("Schedule", schedule) + + for i, v in enumerate(schedule): + if v[3] == "X": + last, next = schedule[i-1], schedule[(i+1) % len(schedule)] + self.logDebug("Now/Last/Next", now, last, next) + + self.setDownloadSpeed(last[3]) + + next_time = (((24 + next[0] - now[0])* 60 + next[1] - now[1]) * 60 + next[2] - now[2]) % 86400 + self.core.scheduler.removeJob(self.cb) + self.cb = self.core.scheduler.addJob(next_time, self.updateSchedule, threaded=False) + + def setDownloadSpeed(self, speed): + if speed == 0: + self.logInfo("Stopping download server. (Running downloads will not be aborted.)") + self.core.api.pauseServer() + else: + self.core.api.unpauseServer() + + if speed > 0: + self.logInfo("Setting download speed to %d kB/s" % speed) + self.core.api.setConfigValue("download","limit_speed",1) + self.core.api.setConfigValue("download","max_speed",speed) + else: + self.logInfo("Setting download speed to FULL") + self.core.api.setConfigValue("download","limit_speed",0) + self.core.api.setConfigValue("download","max_speed",-1)
\ No newline at end of file diff --git a/module/plugins/addons/EasybytezCom.py b/module/plugins/addons/EasybytezCom.py index 4dd39cca6..21a988555 100644 --- a/module/plugins/addons/EasybytezCom.py +++ b/module/plugins/addons/EasybytezCom.py @@ -11,11 +11,11 @@ def getConfigSet(option): class EasybytezCom(MultiHoster): __name__ = "EasybytezCom" - __version__ = "0.01" + __version__ = "0.02" __type__ = "hook" __config__ = [("activated", "bool", "Activated", "False"), - ("includeHoster", "str", "Use only for downloads from (comma-separated hosters)", ""), - ("excludeHoster", "str", "Do not use for downloads from (comma-separated hosters)", "")] + ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"), + ("hosterList", "str", "Hoster list (comma separated)", "")] __description__ = """EasyBytez.com hook plugin""" __author_name__ = ("zoidberg") __author_mail__ = ("zoidberg@mujmail.cz") @@ -24,9 +24,13 @@ class EasybytezCom(MultiHoster): hoster = set(['2shared.com', 'easy-share.com', 'filefactory.com', 'fileserve.com', 'filesonic.com', 'hotfile.com', 'mediafire.com', 'megaupload.com', 'netload.in', 'rapidshare.com', 'uploading.com', 'wupload.com', 'oron.com', 'uploadstation.com', 'ul.to', 'uploaded.to']) - option = self.getConfig('includeHoster').strip() - if option: hoster &= getConfigSet(option) - option = self.getConfig('excludeHoster').strip() - if option: hoster -= getConfigSet(option) + configMode = self.getConfig('hosterListMode') + if configMode in ("listed", "unlisted"): + configList = set(self.getConfig('hosterList').strip().lower().replace('|',',').replace(';',',').split(',')) + configList.discard(u'') + if configMode == "listed": + hoster &= configList + else: + hoster -= configList return list(hoster)
\ No newline at end of file diff --git a/module/plugins/addons/ExpertDecoders.py b/module/plugins/addons/ExpertDecoders.py new file mode 100644 index 000000000..2e66e49ca --- /dev/null +++ b/module/plugins/addons/ExpertDecoders.py @@ -0,0 +1,112 @@ +# -*- 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: mkaay, RaNaN, zoidberg +""" +from __future__ import with_statement + +from thread import start_new_thread +from pycurl import FORM_FILE, LOW_SPEED_TIME +from uuid import uuid4 +from base64 import b64encode + +from module.network.RequestFactory import getURL, getRequest +from module.network.HTTPRequest import BadHeader + +from module.plugins.Hook import Hook + +class ExpertDecoders(Hook): + __name__ = "ExpertDecoders" + __version__ = "0.01" + __description__ = """send captchas to expertdecoders.com""" + __config__ = [("activated", "bool", "Activated", False), + ("force", "bool", "Force CT even if client is connected", False), + ("passkey", "password", "Access key", ""),] + __author_name__ = ("RaNaN", "zoidberg") + __author_mail__ = ("RaNaN@pyload.org", "zoidberg@mujmail.cz") + + API_URL = "http://www.fasttypers.org/imagepost.ashx" + + def setup(self): + self.info = {} + + def getCredits(self): + response = getURL(self.API_URL, post = { "key": self.getConfig("passkey"), "action": "balance" }) + + if response.isdigit(): + self.logInfo(_("%s credits left") % response) + self.info["credits"] = credits = int(response) + return credits + else: + self.logError(response) + return 0 + + def processCaptcha(self, task): + task.data["ticket"] = ticket = uuid4() + result = None + + with open(task.captchaFile, 'rb') as f: + data = f.read() + data = b64encode(data) + #self.logDebug("%s: %s : %s" % (ticket, task.captchaFile, data)) + + req = getRequest() + #raise timeout threshold + req.c.setopt(LOW_SPEED_TIME, 80) + + try: + result = req.load(self.API_URL, + post={ "action": "upload", + "key": self.getConfig("passkey"), + "file": data, + "gen_task_id": ticket } + ) + finally: + req.close() + + self.logDebug("result %s : %s" % (ticket, result)) + task.setResult(result) + + def newCaptchaTask(self, task): + if not task.isTextual(): + return False + + if not self.getConfig("passkey"): + return False + + if self.core.isClientConnected() and not self.getConfig("force"): + return False + + if self.getCredits() > 0: + task.handler.append(self) + task.setWaiting(100) + start_new_thread(self.processCaptcha, (task,)) + + else: + self.logInfo(_("Your ExpertDecoders Account has not enough credits")) + + def captchaInvalid(self, task): + if "ticket" in task.data: + + try: + response = getURL(self.API_URL, + post={ "action": "refund", + "key": self.getConfig("passkey"), + "gen_task_id": task.data["ticket"] } + ) + self.logInfo("Request refund: %s" % response) + + except BadHeader, e: + self.logError("Could not send refund request.", str(e))
\ No newline at end of file diff --git a/module/plugins/addons/ImageTyperz.py b/module/plugins/addons/ImageTyperz.py new file mode 100644 index 000000000..59b6334a7 --- /dev/null +++ b/module/plugins/addons/ImageTyperz.py @@ -0,0 +1,160 @@ +# -*- 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: mkaay, RaNaN, zoidberg +""" +from __future__ import with_statement + +from thread import start_new_thread +from pycurl import FORM_FILE, LOW_SPEED_TIME + +from module.network.RequestFactory import getURL, getRequest +from module.network.HTTPRequest import BadHeader + +from module.plugins.Hook import Hook +import re +from base64 import b64encode + +class ImageTyperzException(Exception): + def __init__(self, err): + self.err = err + + def getCode(self): + return self.err + + def __str__(self): + return "<ImageTyperzException %s>" % self.err + + def __repr__(self): + return "<ImageTyperzException %s>" % self.err + +class ImageTyperz(Hook): + __name__ = "ImageTyperz" + __version__ = "0.03" + __description__ = """send captchas to ImageTyperz.com""" + __config__ = [("activated", "bool", "Activated", True), + ("username", "str", "Username", ""), + ("passkey", "password", "Password", ""), + ("force", "bool", "Force IT even if client is connected", False)] + __author_name__ = ("RaNaN", "zoidberg") + __author_mail__ = ("RaNaN@pyload.org", "zoidberg@mujmail.cz") + + SUBMIT_URL = "http://captchatypers.com/Forms/UploadFileAndGetTextNEW.ashx" + RESPOND_URL = "http://captchatypers.com/Forms/SetBadImage.ashx" + GETCREDITS_URL = "http://captchatypers.com/Forms/RequestBalance.ashx" + + def setup(self): + self.info = {} + + def getCredits(self): + response = getURL(self.GETCREDITS_URL, + post = {"action": "REQUESTBALANCE", + "username": self.getConfig("username"), + "password": self.getConfig("passkey")} + ) + + if response.startswith('ERROR'): + raise ImageTyperzException(response) + + try: + balance = float(response) + except: + raise ImageTyperzException("invalid response") + + self.logInfo("Account balance: $%s left" % response) + return balance + + def submit(self, captcha, captchaType="file", match=None): + req = getRequest() + #raise timeout threshold + req.c.setopt(LOW_SPEED_TIME, 80) + + try: + #workaround multipart-post bug in HTTPRequest.py + if re.match("^[A-Za-z0-9]*$", self.getConfig("passkey")): + multipart = True + data = (FORM_FILE, captcha) + else: + multipart = False + with open(captcha, 'rb') as f: + data = f.read() + data = b64encode(data) + + response = req.load(self.SUBMIT_URL, + post={ "action": "UPLOADCAPTCHA", + "username": self.getConfig("username"), + "password": self.getConfig("passkey"), + "file": data}, + multipart = multipart) + finally: + req.close() + + if response.startswith("ERROR"): + raise ImageTyperzException(response) + else: + data = response.split('|') + if len(data) == 2: + ticket, result = data + else: + raise ImageTyperzException("Unknown response %s" % response) + + return ticket, result + + def newCaptchaTask(self, task): + if "service" in task.data: + return False + + if not task.isTextual(): + return False + + if not self.getConfig("username") or not self.getConfig("passkey"): + return False + + if self.core.isClientConnected() and not self.getConfig("force"): + return False + + if self.getCredits() > 0: + task.handler.append(self) + task.data['service'] = self.__name__ + task.setWaiting(100) + start_new_thread(self.processCaptcha, (task,)) + + else: + self.logInfo("Your %s account has not enough credits" % self.__name__) + + def captchaInvalid(self, task): + if task.data['service'] == self.__name__ and "ticket" in task.data: + response = getURL(self.RESPOND_URL, + post={"action": "SETBADIMAGE", + "username": self.getConfig("username"), + "password": self.getConfig("passkey"), + "imageid": task.data["ticket"]} + ) + + if response == "SUCCESS": + self.logInfo("Bad captcha solution received, requested refund") + else: + self.logError("Bad captcha solution received, refund request failed", response) + + def processCaptcha(self, task): + c = task.captchaFile + try: + ticket, result = self.submit(c) + except ImageTyperzException, e: + task.error = e.getCode() + return + + task.data["ticket"] = ticket + task.setResult(result)
\ No newline at end of file diff --git a/module/plugins/addons/LinkdecrypterCom.py b/module/plugins/addons/LinkdecrypterCom.py new file mode 100644 index 000000000..ac939afd9 --- /dev/null +++ b/module/plugins/addons/LinkdecrypterCom.py @@ -0,0 +1,54 @@ +# -*- 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 module.plugins.Hook import Hook +from module.network.RequestFactory import getURL +from module.utils import remove_chars + +class LinkdecrypterCom(Hook): + __name__ = "LinkdecrypterCom" + __version__ = "0.14" + __description__ = """linkdecrypter.com - regexp loader""" + __config__ = [ ("activated", "bool", "Activated" , "True") ] + __author_name__ = ("zoidberg") + + def coreReady(self): + page = getURL("http://linkdecrypter.com/") + m = re.search(r'<b>Supported</b>: <i>([^+<]*)', page) + if not m: + self.logError(_("Crypter list not found")) + return + + online = m.group(1).split(', ') + builtin = [ name.lower() for name in self.core.pluginManager.crypterPlugins.keys() ] + builtin.extend([ "downloadserienjunkiesorg" ]) + + online = [ crypter.replace(".", "\\.") for crypter in online if remove_chars(crypter, "-.") not in builtin ] + if not online: + self.logError(_("Crypter list is empty")) + return + + regexp = r"https?://([^.]+\.)*?(%s)/.*" % "|".join(online) + + dict = self.core.pluginManager.crypterPlugins[self.__name__] + dict["pattern"] = regexp + dict["re"] = re.compile(regexp) + + self.logDebug("REGEXP: " + regexp)
\ No newline at end of file diff --git a/module/plugins/addons/MultishareCz.py b/module/plugins/addons/MultishareCz.py index a934f43ef..a00c6cb2b 100644 --- a/module/plugins/addons/MultishareCz.py +++ b/module/plugins/addons/MultishareCz.py @@ -11,26 +11,30 @@ def getConfigSet(option): class MultishareCz(MultiHoster): __name__ = "MultishareCz" - __version__ = "0.01" + __version__ = "0.03" __type__ = "hook" __config__ = [("activated", "bool", "Activated", "False"), - ("includeHoster", "str", "Use only for downloads from (bar-separated hosters)", ""), - ("excludeHoster", "str", "Do not use for downloads from (bar-separated hosters)", "rapidshare.com|uloz.to")] + ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"), + ("hosterList", "str", "Hoster list (comma separated)", "uloz.to")] __description__ = """MultiShare.cz hook plugin""" __author_name__ = ("zoidberg") __author_mail__ = ("zoidberg@mujmail.cz") - #replacements = [("freakshare.net", "freakshare.com")] - HOSTER_PATTERN = r'<img class="logo-shareserveru"[^>]*alt="([^"]+)"></td>\s*<td class="stav"><img src="/img/loga/ok.png" alt="OK">' + replacements = [("share-rapid.cz", "sharerapid.com")] + HOSTER_PATTERN = r'<img class="logo-shareserveru"[^>]*?alt="([^"]+)"></td>\s*<td class="stav">[^>]*?alt="OK"' def getHoster(self): page = getURL("http://www.multishare.cz/monitoring/") - hoster = set(m.group(1).lower() for m in re.finditer(self.HOSTER_PATTERN, page)) + hosters = set(h.lower().strip() for h in re.findall(self.HOSTER_PATTERN, page)) - option = self.getConfig('includeHoster').strip() - if option: hoster &= getConfigSet(option) - option = self.getConfig('excludeHoster').strip() - if option: hoster -= getConfigSet(option) + configMode = self.getConfig('hosterListMode') + if configMode in ("listed", "unlisted"): + configList = set(self.getConfig('hosterList').strip().lower().replace('|',',').replace(';',',').split(',')) + configList.discard(u'') + if configMode == "listed": + hosters &= configList + elif configMode == "unlisted": + hosters -= configList - return list(hoster)
\ No newline at end of file + return list(hosters)
\ No newline at end of file diff --git a/module/plugins/addons/PremiumizeMe.py b/module/plugins/addons/PremiumizeMe.py new file mode 100644 index 000000000..3825e9219 --- /dev/null +++ b/module/plugins/addons/PremiumizeMe.py @@ -0,0 +1,65 @@ +from module.plugins.internal.MultiHoster import MultiHoster + +from module.common.json_layer import json_loads +from module.network.RequestFactory import getURL + +class PremiumizeMe(MultiHoster): + __name__ = "PremiumizeMe" + __version__ = "0.1" + __type__ = "hook" + __description__ = """Premiumize.Me hook plugin""" + + __config__ = [("activated", "bool", "Activated", "False"), + ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported):", "all"), + ("hosterList", "str", "Hoster list (comma separated)", "")] + + __author_name__ = ("Florian Franzen") + __author_mail__ = ("FlorianFranzen@gmail.com") + + replacements = [("freakshare.net", "freakshare.com")] + + interval = 0 # Disable periodic calls, we dont use them anyway + + def getHoster(self): + # If no accounts are available there will be no hosters available + if not self.account or not self.account.canUse(): + return [] + + # Get account data + (user, data) = self.account.selectAccount() + + # Get supported hosters list from premiumize.me using the json API v1 (see https://secure.premiumize.me/?show=api) + answer = getURL("https://api.premiumize.me/pm-api/v1.php?method=hosterlist¶ms[login]=%s¶ms[pass]=%s" % (user, data['password'])) + data = json_loads(answer) + + + # If account is not valid thera are no hosters available + if data['status'] != 200: + return [] + + # Extract hosters from json file + hosters = set(data['result']['hosterlist']) + + + # Read config to check if certain hosters should not be handled + configMode = self.getConfig('hosterListMode') + if configMode in ("listed", "unlisted"): + configList = set(self.getConfig('hosterList').strip().lower().replace('|',',').replace(';',',').split(',')) + configList.discard(u'') + if configMode == "listed": + hosters &= configList + else: + hosters -= configList + + return list(hosters) + + def coreReady(self): + # Get account plugin and check if there is a valid account available + self.account = self.core.accountManager.getAccountPlugin("PremiumizeMe") + if not self.account.canUse(): + self.account = None + self.logError(_("Please add a valid premiumize.me account first and restart pyLoad.")) + return + + # Run the overwriten core ready which actually enables the multihoster hook + return MultiHoster.coreReady(self)
\ No newline at end of file diff --git a/module/plugins/addons/RealdebridCom.py b/module/plugins/addons/RealdebridCom.py new file mode 100644 index 000000000..bd3179673 --- /dev/null +++ b/module/plugins/addons/RealdebridCom.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- + +from module.network.RequestFactory import getURL +from module.plugins.internal.MultiHoster import MultiHoster + +class RealdebridCom(MultiHoster): + __name__ = "RealdebridCom" + __version__ = "0.41" + __type__ = "hook" + + __config__ = [("activated", "bool", "Activated", "False"), + ("https", "bool", "Enable HTTPS", "False"), + ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported):", "all"), + ("hosterList", "str", "Hoster list (comma separated)", "")] + __description__ = """Real-Debrid.com hook plugin""" + __author_name__ = ("Devirex, Hazzard") + __author_mail__ = ("naibaf_11@yahoo.de") + + replacements = [("freakshare.net", "freakshare.com")] + + def getHoster(self): + https = "https" if self.getConfig("https") else "http" + page = getURL(https + "://real-debrid.com/api/hosters.php").replace("\"","").strip() + + hosters = set([x.strip() for x in page.split(",") if x.strip()]) + + configMode = self.getConfig('hosterListMode') + if configMode in ("listed", "unlisted"): + configList = set(self.getConfig('hosterList').strip().lower().replace('|',',').replace(';',',').split(',')) + configList.discard(u'') + if configMode == "listed": + hosters &= configList + else: + hosters -= configList + + return list(hosters) diff --git a/module/plugins/addons/XFileSharingPro.py b/module/plugins/addons/XFileSharingPro.py new file mode 100644 index 000000000..3981db2d0 --- /dev/null +++ b/module/plugins/addons/XFileSharingPro.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- + +from module.plugins.Hook import Hook +import re + +class XFileSharingPro(Hook): + __name__ = "XFileSharingPro" + __version__ = "0.03" + __type__ = "hook" + __config__ = [ ("activated" , "bool" , "Activated" , "True"), + ("loadDefault", "bool", "Include default (built-in) hoster list" , "True"), + ("includeList", "str", "Include hosters (comma separated)", ""), + ("excludeList", "str", "Exclude hosters (comma separated)", "") ] + __description__ = """Hoster URL pattern loader for the generic XFileSharingPro plugin""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + def coreReady(self): + self.loadPattern() + + def loadPattern(self): + hosterList = self.getConfigSet('includeList') + excludeList = self.getConfigSet('excludeList') + + if self.getConfig('loadDefault'): + hosterList |= set(( + #WORKING HOSTERS: + "azsharing.com", "banashare.com", "fileband.com", "kingsupload.com", "migahost.com", "ryushare.com", "xfileshare.eu", + #NOT TESTED: + "aieshare.com", "amonshare.com", "asixfiles.com", + "bebasupload.com", "boosterking.com", "buckshare.com", "bulletupload.com", "crocshare.com", "ddlanime.com", "divxme.com", + "dopeshare.com", "downupload.com", "eyesfile.com", "eyvx.com", "fik1.com", "file4safe.com", "file4sharing.com", + "fileforth.com", "filemade.com", "filemak.com", "fileplaygroud.com", "filerace.com", "filestrack.com", + "fileupper.com", "filevelocity.com", "fooget.com", "4bytez.com", "freefilessharing.com", "glumbouploads.com", "grupload.com", + "heftyfile.com", "hipfile.com", "host4desi.com", "hulkshare.com", "idupin.com", "imageporter.com", "isharefast.com", + "jalurcepat.com", "laoupload.com", "linkzhost.com", "loombo.com", "maknyos.com", + "mlfat4arab.com", "movreel.com", "netuploaded.com", "ok2upload.com", "180upload.com", "1hostclick.com", "ovfile.com", + "putshare.com", "pyramidfiles.com", "q4share.com", "queenshare.com", "ravishare.com", "rockdizfile.com", "sendmyway.com", + "share76.com", "sharebeast.com", "sharehut.com", "sharerun.com", "shareswift.com", "sharingonline.com", "6ybh-upload.com", + "skipfile.com", "spaadyshare.com", "space4file.com", "speedoshare.com", "uploadbaz.com", "uploadboost.com", "uploadc.com", + "uploaddot.com", "uploadfloor.com", "uploadic.com", "uploadville.com", "uptobox.com", "vidbull.com", "zalaa.com", + "zomgupload.com", "kupload.org", "movbay.org", "multishare.org", "omegave.org", "toucansharing.org", "uflinq.org", + "banicrazy.info", "flowhot.info", "upbrasil.info", "shareyourfilez.biz", "bzlink.us", "cloudcache.cc", "fileserver.cc" + "farshare.to", "kingshare.to", "filemaze.ws", "filehost.ws", "goldfile.eu", "filestock.ru", "moidisk.ru" + "4up.me", "kfiles.kz", "odsiebie.pl", "upchi.co.il", "upit.in", "verzend.be" + )) + + #NOT WORKING: + """ + """ + + hosterList -= (excludeList) + hosterList -= set(('', u'')) + + if not hosterList: + self.unload() + return + + regexp = r"http://(?:[^/]*\.)?(%s)/\w{12}" % ("|".join(sorted(hosterList)).replace('.','\.')) + #self.logDebug(regexp) + + dict = self.core.pluginManager.hosterPlugins['XFileSharingPro'] + dict["pattern"] = regexp + dict["re"] = re.compile(regexp) + self.logDebug("Pattern loaded - handling %d hosters" % len(hosterList)) + + def getConfigSet(self, option): + s = self.getConfig(option).lower().replace('|',',').replace(';',',') + return set([x.strip() for x in s.split(',')]) + + def unload(self): + dict = self.core.pluginManager.hosterPlugins['XFileSharingPro'] + dict["pattern"] = r"^unmatchable$" + dict["re"] = re.compile(r"^unmatchable$")
\ No newline at end of file diff --git a/module/plugins/addons/ZeveraCom.py b/module/plugins/addons/ZeveraCom.py new file mode 100644 index 000000000..46c752c21 --- /dev/null +++ b/module/plugins/addons/ZeveraCom.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- + +from module.network.RequestFactory import getURL +from module.plugins.internal.MultiHoster import MultiHoster + +class ZeveraCom(MultiHoster): + __name__ = "ZeveraCom" + __version__ = "0.01" + __type__ = "hook" + __config__ = [("activated", "bool", "Activated", "False"), + ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"), + ("hosterList", "str", "Hoster list (comma separated)", "")] + __description__ = """Real-Debrid.com hook plugin""" + __author_name__ = ("Devirex, Hazzard") + __author_mail__ = ("naibaf_11@yahoo.de") + + replacements = [("freakshare.net", "freakshare.com"), ("2shared.com", "twoshared.com"), ("4shared.com", "fourshared.com"), + ("easy-share.com", "crocko.com"), ("hellshare.com", "hellshare.cz")] + + def getHoster(self): + page = getURL("http://www.zevera.com/jDownloader.ashx?cmd=gethosters") + hosters = set([x.strip() for x in page.replace("\"", "").split(",")]) + + configMode = self.getConfig('hosterListMode') + if configMode in ("listed", "unlisted"): + configList = set(self.getConfig('hosterList').strip().lower().replace('|',',').replace(';',',').split(',')) + configList.discard(u'') + if configMode == "listed": + hosters &= configList + else: + hosters -= configList + + return list(hosters)
\ No newline at end of file diff --git a/module/plugins/crypter/C1neonCom.py b/module/plugins/crypter/C1neonCom.py new file mode 100644 index 000000000..36b84764e --- /dev/null +++ b/module/plugins/crypter/C1neonCom.py @@ -0,0 +1,133 @@ +# -*- 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: godofdream +""" + +import re +import random +from module.plugins.Crypter import Crypter +from module.common.json_layer import json_loads +class C1neonCom(Crypter): + __name__ = "C1neonCom" + __type__ = "container" + __pattern__ = r"http://(www\.)?c1neon.com/.*?" + __version__ = "0.05" + __config__ = [ + ("changeNameS", "Packagename;Show;Season;Episode", "Rename Show by", "Show"), + ("changeName", "Packagename;Movie", "Rename Movie by", "Movie"), + ("useStreams", "bool", "Use Streams too", False), + ("hosterListMode", "all;onlypreferred", "Use for hosters (if supported)", "all"), + ("randomPreferred", "bool", "Randomize Preferred-List", False), + ("hosterList", "str", "Preferred Hoster list (comma separated, no ending)", "2shared,Bayfiles,Netload,Rapidshare,Share-online"), + ("ignoreList", "str", "Ignored Hoster list (comma separated, no ending)", "Megaupload") + ] + __description__ = """C1neon.Com Container Plugin""" + __author_name__ = ("godofdream") + __author_mail__ = ("soilfiction@gmail.com") + + VALUES_PATTERN = r"var subcats = (.*?)(;</script>|;var)" + SHOW_PATTERN = r"title='(.*?)'" + SERIE_PATTERN = r"<title>.*Serie.*</title>" + + def decrypt(self, pyfile): + src = self.req.load(str(pyfile.url)) + + pattern = re.compile(self.VALUES_PATTERN, re.DOTALL) + data = json_loads(re.search(pattern, src).group(1)) + + # Get package info + links = [] + Showname = re.search(self.SHOW_PATTERN, src) + if Showname: + Showname = Showname.group(1).decode("utf-8") + else: + Showname = self.pyfile.package().name + + if re.search(self.SERIE_PATTERN, src): + for Season in data: + self.logDebug("Season " + Season) + for Episode in data[Season]: + self.logDebug("Episode " + Episode) + links.extend(self.getpreferred(data[Season][Episode])) + if self.getConfig("changeNameS") == "Episode": + self.packages.append((data[Season][Episode]['info']['name'].split("»")[0], links, data[Season][Episode]['info']['name'].split("»")[0])) + links = [] + + if self.getConfig("changeNameS") == "Season": + self.packages.append((Showname + " Season " + Season, links, Showname + " Season " + Season)) + links = [] + + if self.getConfig("changeNameS") == "Show": + if links == []: + self.fail('Could not extract any links (Out of Date?)') + else: + self.packages.append((Showname, links, Showname)) + + elif self.getConfig("changeNameS") == "Packagename": + if links == []: + self.fail('Could not extract any links (Out of Date?)') + else: + self.core.files.addLinks(links, self.pyfile.package().id) + else: + for Movie in data: + links.extend(self.getpreferred(data[Movie])) + if self.getConfig("changeName") == "Movie": + if links == []: + self.fail('Could not extract any links (Out of Date?)') + else: + self.packages.append((Showname, links, Showname)) + + elif self.getConfig("changeName") == "Packagename": + if links == []: + self.fail('Could not extract any links (Out of Date?)') + else: + self.core.files.addLinks(links, self.pyfile.package().id) + + #selects the preferred hoster, after that selects any hoster (ignoring the one to ignore) + #selects only one Hoster + def getpreferred(self, hosterslist): + hosterlist = {} + if 'u' in hosterslist: + hosterlist.update(hosterslist['u']) + if ('d' in hosterslist): + hosterlist.update(hosterslist['d']) + if self.getConfig("useStreams") and 's' in hosterslist: + hosterlist.update(hosterslist['s']) + + result = [] + preferredList = self.getConfig("hosterList").strip().lower().replace('|',',').replace('.','').replace(';',',').split(',') + if self.getConfig("randomPreferred") == True: + random.shuffle(preferredList) + for preferred in preferredList: + for Hoster in hosterlist: + if preferred == Hoster.split('<')[0].strip().lower().replace('.',''): + for Part in hosterlist[Hoster]: + self.logDebug("selected " + Part[3]) + result.append(str(Part[3])) + return result + + ignorelist = self.getConfig("ignoreList").strip().lower().replace('|',',').replace('.','').replace(';',',').split(',') + if self.getConfig('hosterListMode') == "all": + for Hoster in hosterlist: + if Hoster.split('<')[0].strip().lower().replace('.','') not in ignorelist: + for Part in hosterlist[Hoster]: + self.logDebug("selected " + Part[3]) + result.append(str(Part[3])) + return result + return result + + + diff --git a/module/plugins/crypter/DdlstorageComFolder.py b/module/plugins/crypter/DdlstorageComFolder.py new file mode 100644 index 000000000..d536032c6 --- /dev/null +++ b/module/plugins/crypter/DdlstorageComFolder.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- + +import re +from module.plugins.Crypter import Crypter +from module.plugins.hoster.MediafireCom import checkHTMLHeader +from module.common.json_layer import json_loads + +class DdlstorageComFolder(Crypter): + __name__ = "DdlstorageComFolder" + __type__ = "crypter" + __pattern__ = r"http://(?:\w*\.)*?ddlstorage.com/folder/\w{10}" + __version__ = "0.01" + __description__ = """DDLStorage.com Folder Plugin""" + __author_name__ = ("godofdream") + __author_mail__ = ("soilfiction@gmail.com") + + FILE_URL_PATTERN = '<a style="text-decoration:none;" href="http://www.ddlstorage.com/(.*)">' + + def decrypt(self, pyfile): + new_links = [] + # load and parse html + html = self.load(pyfile.url) + found = re.findall(self.FILE_URL_PATTERN, html) + self.logDebug(found) + for link in found: + # file page + new_links.append("http://www.ddlstorage.com/%s" % link) + + if new_links: + self.core.files.addLinks(new_links, self.pyfile.package().id) + else: + self.fail('Could not extract any links') diff --git a/module/plugins/crypter/DontKnowMe.py b/module/plugins/crypter/DontKnowMe.py new file mode 100644 index 000000000..dfa72df47 --- /dev/null +++ b/module/plugins/crypter/DontKnowMe.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- + +import re +import urllib + +from module.plugins.Crypter import Crypter + +class DontKnowMe(Crypter): + __name__ = "DontKnowMe" + __type__ = "crypter" + __pattern__ = r"http://dontknow.me/at/\?.+$" + __version__ = "0.1" + __description__ = """DontKnowMe""" + __author_name__ = ("selaux") + __author_mail__ = ("") + + LINK_PATTERN = r"http://dontknow.me/at/\?(.+)$" + + def decrypt(self, pyfile): + link = re.findall(self.LINK_PATTERN, self.pyfile.url)[0] + self.core.files.addLinks([ urllib.unquote(link) ], self.pyfile.package().id) diff --git a/module/plugins/crypter/DuckCryptInfo.py b/module/plugins/crypter/DuckCryptInfo.py new file mode 100644 index 000000000..6e7166ff8 --- /dev/null +++ b/module/plugins/crypter/DuckCryptInfo.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- + +import re +from module.lib.BeautifulSoup import BeautifulSoup +from module.plugins.Crypter import Crypter + +class DuckCryptInfo(Crypter): + __name__ = "DuckCryptInfo" + __type__ = "container" + __pattern__ = r"http://(?:www\.)?duckcrypt.info/(folder|wait|link)/(\w+)/?(\w*)" + __version__ = "0.01" + __description__ = """DuckCrypt.Info Container Plugin""" + __author_name__ = ("godofdream") + __author_mail__ = ("soilfiction@gmail.com") + + TIMER_PATTERN = r'<span id="timer">(.*)</span>' + + def decrypt(self, pyfile): + url = pyfile.url + # seems we don't need to wait + #src = self.req.load(str(url)) + #found = re.search(self.TIMER_PATTERN, src) + #if found: + # self.logDebug("Sleeping for" % found.group(1)) + # self.setWait(int(found.group(1)) ,False) + found = re.search(self.__pattern__, url) + if not found: + self.fail('Weird error in link') + if str(found.group(1)) == "link": + self.handleLink(url) + else: + self.handleFolder(found) + + + + def handleFolder(self, found): + src = self.load("http://duckcrypt.info/ajax/auth.php?hash=" + str(found.group(2))) + found = re.search(self.__pattern__, src) + self.logDebug("Redirectet to " + str(found.group(0))) + src = self.load(str(found.group(0))) + soup = BeautifulSoup(src) + cryptlinks = soup.find("div", attrs={"class": "folderbox"}).findAll("a") + self.logDebug("Redirectet to " + str(cryptlinks)) + if not cryptlinks: + self.fail('no links found - (Plugin out of date?)') + for clink in cryptlinks: + self.handleLink(clink['href']) + + def handleLink(self, url): + src = self.load(url) + soup = BeautifulSoup(src) + link = soup.find("iframe")["src"] + if not link: + self.logDebug('no links found - (Plugin out of date?)') + else: + self.core.files.addLinks([link], self.pyfile.package().id) + diff --git a/module/plugins/crypter/EmbeduploadCom.py b/module/plugins/crypter/EmbeduploadCom.py index e84a06cc1..8fd70882f 100644 --- a/module/plugins/crypter/EmbeduploadCom.py +++ b/module/plugins/crypter/EmbeduploadCom.py @@ -2,12 +2,13 @@ import re from module.plugins.Crypter import Crypter +from module.network.HTTPRequest import BadHeader class EmbeduploadCom(Crypter): __name__ = "EmbeduploadCom" __type__ = "crypter" __pattern__ = r"http://(www\.)?embedupload.com/\?d=.*" - __version__ = "0.01" + __version__ = "0.02" __description__ = """EmbedUpload.com crypter""" __config__ = [("preferedHoster", "str", "Prefered hoster list (bar-separated) ", "embedupload"), ("ignoredHoster", "str", "Ignored hoster list (bar-separated) ", "")] @@ -18,7 +19,8 @@ class EmbeduploadCom(Crypter): def decrypt(self, pyfile): self.html = self.load(self.pyfile.url, decode=True) - tmp_links = new_links = [] + tmp_links = [] + new_links = [] found = re.findall(self.LINK_PATTERN, self.html) if found: @@ -32,7 +34,7 @@ class EmbeduploadCom(Crypter): ignored_set = set(self.getConfig("ignoredHoster").split('|')) ignored_set = map(lambda s: s.lower().split('.')[0], ignored_set) print "IG", ignored_set - tmp_links.extend([x[1] for x in found if x[0] in ignored_set]) + tmp_links.extend([x[1] for x in found if x[0] not in ignored_set]) self.getLocation(tmp_links, new_links) if new_links: @@ -42,8 +44,11 @@ class EmbeduploadCom(Crypter): def getLocation(self, tmp_links, new_links): for link in tmp_links: - header = self.load(link, just_header = True) - if "location" in header: - new_links.append(header['location']) + try: + header = self.load(link, just_header = True) + if "location" in header: + new_links.append(header['location']) + except BadHeader: + pass
\ No newline at end of file diff --git a/module/plugins/crypter/LinkdecrypterCom.py b/module/plugins/crypter/LinkdecrypterCom.py index 83c74188d..ff21916ef 100644 --- a/module/plugins/crypter/LinkdecrypterCom.py +++ b/module/plugins/crypter/LinkdecrypterCom.py @@ -22,22 +22,21 @@ from module.plugins.Crypter import Crypter class LinkdecrypterCom(Crypter): __name__ = "LinkdecrypterCom" __type__ = "crypter" - #excluded: "1kh\.de|crypt-it\.com|linksave\.in|lix\.in|lof\.cc|multiload\.cz|multiupload\.com|ncrypt\.in|relink\.us|rs-layer\.com|secured\.in|stealth\.to" - __pattern__ = r"http://(\w*\.)?(00\.uz|10001mb\.com|123link\.it|123url\.org|1cl\.in|1tool\.biz|1zh\.us|2joy\.de|2so\.be|3\.ly|5\.gp|6nc\.net|7li\.in|9\.bb|adf\.ly|adflav\.com|adfoc\.us|allanalpass\.com|alturl\.com|amy\.gs|any\.gs|apurl\.ru|aurl\.es|b23\.ru|baberepublic\.com|bai\.lu|bat5\.com|bax\.li|bc\.vc|beam\.to|birurl\.com|bit\.ly|blu\.cc|bofh\.us|boo\.io|c\.ly|capourl\.com|cash4links\.co|cc\.st|cd\.vg|cl\.lk|cli\.gs|cloneurl\.com|convertircodigo\.com|crypt\.to|crypt2\.be|cryptlink\.ws|ddl-warez\.in|deb\.gs|deurl\.me|digzip\.com|djurl\.com|dl-protect\.com|dl\.dropbox\.com|doiop\.com|ehe\.me|embedupload\.com|encript\.in|encurtador\.com|enlacs\.com|evg\.in|extreme-protect\.com|fa\.by|faja\.me|fapoff\.com|fdnlinks\.com|fea\.me|fff\.to|filedeck\.net|filemirrorupload\.com|filesonthe\.net|fileupster\.com|flameupload\.com|freetexthost\.com|fwd4\.me|fyad\.org|galleries\.bz|goandgrab\.info|goblig\.com|goo\.gl|guardlink\.org|h-url\.in|hasurl\.co\.cc|hide-url\.net|hidemyass\.com|hides\.at|hideurl\.biz|ho\.io|hornywood\.tv|href\.hu|id2\.tryjav\.com|ilii\.in|ilix\.in|ily\.me|ino\.me|interupload\.com|is\.gd|ivpaste\.com|j\.mp|j7\.se|je\.pl|jheberg\.com|just\.as|kickupload\.com|klnk\.de|knoffl\.com|kodo\.ameoto\.com|ks\.gs|latwy\.pl|li\.co\.ve|link-go\.info|link-protector\.com|link-safe\.net|link\.file-up\.ru|link4jo\.com|linkanonimo\.com|linkbabes\.com|linkbank\.eu|linkbee\.com|linkblur\.com|linkbucks\.com|linkbun\.ch|linkcrypt\.com|linkcrypt\.ws|linkencrypter\.com|linkhide\.com\.ar|linkhide\.in|linkoculto\.net|linkok\.org|linkprivado\.com|linkprivate\.net|linkprotect\.in|links-protect\.com|links-protect\.info|links-protection\.com|links\.tc|linksafe\.me|linksaver\.info|linkse\.info|linkseguro\.com\.ar|linkseguro\.org|linksole\.com|linksprotec\.com|linksprotegidos\.info|linkssafe\.com|linkto\.net|linkweb\.dk|linkx\.in|linkzip\.net|listedfiles\.com|littleurl\.net|lixk\.me|lixxin\.com|ljv2\.com|lkt\.es|ll11\.org|lnk\.cm|lnk\.co|longr\.us|lovelink\.in|madlink\.sk|maxi-upload\.com|mcaf\.ee|mediahide\.com|megaline\.co|megalinks\.es|megaupper\.com|mf1\.jp|mhz\.me|migre\.me|miniurl\.com|miniurl\.es|miniurl\.org|miniurls\.co|minu\.me|mir\.cr|mirrorcreator\.com|mo\.by|multi-uploadeur\.com|murl\.kz|musicalmente\.info|myooo\.info|mypaqe\.com|mypl\.us|myrapidlinks\.com|myref\.de|myurl\.in|nbanews\.us|nov\.io|okconsolas\.com|oneddl\.canhaz\.it|ow\.ly|p4p\.com\.es|p6l\.org|paste\.frubar\.net|paste\.hotfile-bb\.com|paste\.to|paste\.ubuntu\.com|paste2\.org|paste21\.info|pastebin\.com|paylesssofts\.net|poontown\.net|pqueno\.com|priva\.us|protec-link\.com|protect-ddl\.com|protect-my-links\.com|protected\.socadvnet\.com|protectlinks\.com|protectlinks\.net|protectlk\.com|protege-mes-liens\.com|ptl\.li|qooy\.com|qqc\.co|qvvo\.com|rapidfolder\.com|rapidsafe\.de|rapidsafe\.org|rapidshare\.mu|realfiles\.net|redir\.ec|ref\.so|relinka\.net|rexwo\.com|rqq\.co|rsmonkey\.com|rurls\.ru|s2l\.biz|saf\.li|safe\.mn|safelinking\.net|saferlinks\.com|scut\.ly|sealed\.in|seclnk\.in|seriousfiles\.com|share-links\.biz|sharebee\.com|short-link\.fr|shortlink\.ca|shorturlscript\.net|shrt\.st|simurl\.com|sinl\.es|skroc\.pl|slexy\.org|slnky\.net|smlk\.es|smsdl\.com|sn\.im|snipr\.com|snipurl\.com|snurl\.com|sonofertas\.es|spedr\.com|spreadlink\.us|star-cyber\.com|stu\.tc|subedlc\.com|subirfacil\.com|syl\.me|szort\.pl|t\.co|t7\.hu|takemyfile\.com|takemylinks\.com|textsave\.de|textsnip\.com|thecow\.me|thesefiles\.com|thinfi\.com|tilien\.net|tiny\.cc|tiny\.lt|tinylinks\.co|tinypaste\.com|tinyurl\.com|tinyurlscript\.info|tmf\.myegy\.com|togoto\.us|tot\.to|tra\.kz|trick\.ly|u\.to|uberpicz\.com|ubervidz\.com|ulinks\.net|ultrafiles\.net|undeadlink\.com|uploadjockey\.com|uploadmirrors\.com|uploadonall\.com|upmirror\.com|upsafe\.org|ur\.ly|url-go\.com|url-site\.com|url\.zeta24\.com|url4t\.com|urla\.in|urlbeat\.net|urlcash\.net|urlcorta\.es|urlcrypt\.com|urlcut\.com|urlcut\.in|urldefender\.com|urlink\.at|urln\.tk|urlpulse\.net|urlspy\.co\.cc|urwij|uselink\.info|uucc\.cc|uze\.in|wa9\.la|wcrypt\.in|webtooljungle\.com|weepax\.com|whackyvidz\.com|wtc\.la|x-ls\.ru|x\.co|xa\.ly|xc\.io|xr\.com|xtreemhost\.com|xurl\.cn|xurl\.es|xxs\.ru|youfap\.me|ysu\.me|yvy\.me|yyv\.co|zff\.co|zio\.in|zpag\.es)/.*" - __version__ = "0.23" + __version__ = "0.26" __description__ = """linkdecrypter.com""" __author_name__ = ("zoidberg", "flowlee") TEXTAREA_PATTERN = r'<textarea name="links" wrap="off" readonly="1" class="caja_des">(.+)</textarea>' - PASSWORD_PATTERN = r'<p class="textog" style="color:red"><b>PASSWORD:</b></p>' - CAPTCHA_PATTERN = r'<img style="cursor:crosshair;" src="([^"]+)" alt="Loading CAPTCHA...">' + PASSWORD_PATTERN = r'<input type="text" name="password"' + CAPTCHA_PATTERN = r'<img class="captcha" src="(.+?)"(.*?)>' REDIR_PATTERN = r'<i>(Click <a href="./">here</a> if your browser does not redirect you).</i>' def decrypt(self, pyfile): self.passwords = self.getPassword().splitlines() - new_links = self.decryptAPI() or self.decryptHTML() + # API not working anymore + new_links = self.decryptHTML() if new_links: self.core.files.addLinks(new_links, self.pyfile.package().id) else: @@ -61,35 +60,41 @@ class LinkdecrypterCom(Crypter): return None def decryptHTML(self): - - self.html = self.load('http://linkdecrypter.com', cookies = True) - links_sessid = "links" + self.req.cj.getCookie("PHPSESSID") + retries = 5 - post_dict = { "link_cache": "on", links_sessid: self.pyfile.url, "modo_links": "text" } - self.html = self.load('http://linkdecrypter.com', post = post_dict, cookies = True) + post_dict = { "link_cache": "on", "pro_links": self.pyfile.url, "modo_links": "text" } + self.html = self.load('http://linkdecrypter.com/', post = post_dict, cookies = True) while self.passwords or retries: found = re.search(self.TEXTAREA_PATTERN, self.html, flags=re.DOTALL) - if found: return found.group(1).splitlines() + if found: return [ x for x in found.group(1).splitlines() if '[LINK-ERROR]' not in x ] found = re.search(self.CAPTCHA_PATTERN, self.html) if found: - self.logInfo("Captcha protected link") - captcha = self.decryptCaptcha(url='http://linkdecrypter.com/' + found.group(1)) - self.html = self.load('http://linkdecrypter.com', post={ "captcha": captcha }) + captcha_url = 'http://linkdecrypter.com/' + found.group(1) + result_type = "positional" if "getPos" in found.group(2) else "textual" + + found = re.search(r"<p><i><b>([^<]+)</b></i></p>", self.html) + msg = found.group(1) if found else "" + self.logInfo("Captcha protected link", result_type, msg) + + captcha = self.decryptCaptcha(captcha_url, result_type = result_type) + if result_type == "positional": + captcha = "%d|%d" % captcha + self.html = self.load('http://linkdecrypter.com/', post={ "captcha": captcha }) retries -= 1 elif self.PASSWORD_PATTERN in self.html: if self.passwords: password = self.passwords.pop(0) self.logInfo("Password protected link, trying " + password) - self.html = self.load('http://linkdecrypter.com', post= {'password': password}) + self.html = self.load('http://linkdecrypter.com/', post= {'password': password}) else: self.fail("No or incorrect password") else: retries -= 1 - self.html = self.load('http://linkdecrypter.com', cookies = True) + self.html = self.load('http://linkdecrypter.com/', cookies = True) return None
\ No newline at end of file diff --git a/module/plugins/crypter/LixIn.py b/module/plugins/crypter/LixIn.py index b9fd28a34..379b10764 100644 --- a/module/plugins/crypter/LixIn.py +++ b/module/plugins/crypter/LixIn.py @@ -9,13 +9,13 @@ class LixIn(Crypter): __name__ = "LixIn" __type__ = "container" __pattern__ = r"http://(www.)?lix.in/(?P<id>.*)" - __version__ = "0.2" + __version__ = "0.21" __description__ = """Lix.in Container Plugin""" __author_name__ = ("spoob") __author_mail__ = ("spoob@pyload.org") CAPTCHA_PATTERN='<img src="(?P<image>captcha_img.php\?PHPSESSID=.*?)"' - SUBMIT_PATTERN=r"value='continue .*?'" + SUBMIT_PATTERN=r"value='continue.*?'" LINK_PATTERN=r'name="ifram" src="(?P<link>.*?)"' @@ -46,7 +46,7 @@ class LixIn(Crypter): else: self.logDebug("no captcha/captcha solved") break - else: + else: self.html = self.req.load(url, decode=True, post={"submit" : "submit", "tiny" : id}) diff --git a/module/plugins/crypter/MediafireComFolder.py b/module/plugins/crypter/MediafireComFolder.py index 1d800b1b0..ddd61379c 100644 --- a/module/plugins/crypter/MediafireComFolder.py +++ b/module/plugins/crypter/MediafireComFolder.py @@ -8,8 +8,8 @@ from module.common.json_layer import json_loads class MediafireComFolder(Crypter): __name__ = "MediafireComFolder" __type__ = "crypter" - __pattern__ = r"http://(\w*\.)*mediafire\.com/(folder/|\?sharekey=|(\?\w{13}|\w+)($|[/#]))" - __version__ = "0.13" + __pattern__ = r"http://(\w*\.)*mediafire\.com/(folder/|\?sharekey=|\?\w{13}($|[/#]))" + __version__ = "0.14" __description__ = """Mediafire.com Folder Plugin""" __author_name__ = ("zoidberg") __author_mail__ = ("zoidberg@mujmail.cz") diff --git a/module/plugins/crypter/SerienjunkiesOrg.py b/module/plugins/crypter/SerienjunkiesOrg.py index 2178f5300..dfe34ff6e 100644 --- a/module/plugins/crypter/SerienjunkiesOrg.py +++ b/module/plugins/crypter/SerienjunkiesOrg.py @@ -2,7 +2,7 @@ import re from time import sleep - +import random from module.plugins.Crypter import Crypter from module.lib.BeautifulSoup import BeautifulSoup from module.unescape import unescape @@ -10,36 +10,23 @@ from module.unescape import unescape class SerienjunkiesOrg(Crypter): __name__ = "SerienjunkiesOrg" __type__ = "container" - __pattern__ = r"http://.*?serienjunkies.org/.*?" - __version__ = "0.31" - __config__ = [("preferredHoster", "str", "preferred hoster", - "RapidshareCom,UploadedTo,NetloadIn,FilefactoryCom,FreakshareNet,FilebaseTo,MegauploadCom,HotfileCom,DepositfilesCom,EasyshareCom,KickloadCom") - , - ("changeName", "bool", "Take SJ.org episode name", "True")] + __pattern__ = r"http://.*?(serienjunkies.org|dokujunkies.org)/.*?" + __version__ = "0.36" + __config__ = [ + ("changeNameSJ", "Packagename;Show;Season;Format;Episode", "Take SJ.org name", "Show"), + ("changeNameDJ", "Packagename;Show;Format;Episode", "Take DJ.org name", "Show"), + ("randomPreferred", "bool", "Randomize Preferred-List", False), + ("hosterListMode", "OnlyOne;OnlyPreferred(One);OnlyPreferred(All);All", "Use for hosters (if supported)", "All"), + ("hosterList", "str", "Preferred Hoster list (comma separated)", "RapidshareCom,UploadedTo,NetloadIn,FilefactoryCom,FreakshareNet,FilebaseTo,MegauploadCom,HotfileCom,DepositfilesCom,EasyshareCom,KickloadCom"), + ("ignoreList", "str", "Ignored Hoster list (comma separated)", "MegauploadCom") + ] __description__ = """serienjunkies.org Container Plugin""" - __author_name__ = ("mkaay") - __author_mail__ = ("mkaay@mkaay.de") + __author_name__ = ("mkaay", "godofdream") + __author_mail__ = ("mkaay@mkaay.de", "soilfiction@gmail.com") - def setup(self): - self.hosterMap = { - "rc": "RapidshareCom", - "ff": "FilefactoryCom", - "ut": "UploadedTo", - "ul": "UploadedTo", - "nl": "NetloadIn", - "fs": "FreakshareNet", - "fb": "FilebaseTo", - "mu": "MegauploadCom", - "hf": "HotfileCom", - "df": "DepositfilesCom", - "es": "EasyshareCom", - "kl": "KickloadCom", - "fc": "FilesonicCom", - } - self.hosterMapReverse = dict((v, k) for k, v in self.hosterMap.iteritems()) + def setup(self): self.multiDL = False - self.limitDL = 4 def getSJSrc(self, url): src = self.req.load(str(url)) @@ -51,72 +38,84 @@ class SerienjunkiesOrg(Crypter): def handleShow(self, url): src = self.getSJSrc(url) soup = BeautifulSoup(src) + packageName = self.pyfile.package().name + if self.getConfig("changeNameSJ") == "Show": + found = unescape(soup.find("h2").find("a").string.split(' –')[0]) + if found: + packageName = found + nav = soup.find("div", attrs={"id": "scb"}) + + package_links = [] for a in nav.findAll("a"): - self.packages.append((unescape(a.text), [a["href"]], unescape(a.text))) + if self.getConfig("changeNameSJ") == "Show": + package_links.append(a["href"]) + else: + package_links.append(a["href"] + "#hasName") + if self.getConfig("changeNameSJ") == "Show": + self.packages.append((packageName, package_links, packageName)) + else: + self.core.files.addLinks(package_links, self.pyfile.package().id) + def handleSeason(self, url): src = self.getSJSrc(url) soup = BeautifulSoup(src) post = soup.find("div", attrs={"class": "post-content"}) ps = post.findAll("p") - hosterPattern = re.compile("^http://download\.serienjunkies\.org/f-.*?/([rcfultns]{2})_.*?\.html$") - preferredHoster = self.getConfig("preferredHoster").split(",") - self.log.debug("Preferred hoster: %s" % ", ".join(preferredHoster)) + + seasonName = unescape(soup.find("a", attrs={"rel": "bookmark"}).string).replace("–", "-") groups = {} gid = -1 - seasonName = unescape(soup.find("a", attrs={"rel": "bookmark"}).string) for p in ps: - if re.search("<strong>Dauer|<strong>Sprache|<strong>Format", str(p)): + if re.search("<strong>Sprache|<strong>Format", str(p)): var = p.findAll("strong") - opts = {"Dauer": "", "Uploader": "", "Sprache": "", "Format": "", u"Größe": ""} + opts = {"Sprache": "", "Format": ""} for v in var: - n = unescape(v.string) - n = n.strip() + n = unescape(v.string).strip() n = re.sub(r"^([:]?)(.*?)([:]?)$", r'\2', n) if n.strip() not in opts: continue val = v.nextSibling if not val: continue - val = val.encode("utf-8") - val = unescape(val) val = val.replace("|", "").strip() - val = val.strip() val = re.sub(r"^([:]?)(.*?)([:]?)$", r'\2', val) opts[n.strip()] = val.strip() gid += 1 groups[gid] = {} - groups[gid]["ep"] = [] + groups[gid]["ep"] = {} groups[gid]["opts"] = opts elif re.search("<strong>Download:", str(p)): - links1 = p.findAll("a", attrs={"href": hosterPattern}) - links2 = p.findAll("a", attrs={"href": re.compile("^http://serienjunkies.org/safe/.*$")}) - for link in links1 + links2: - groups[gid]["ep"].append(link["href"]) + parts = str(p).split("<br />") + if re.search("<strong>", parts[0]): + ename = re.search('<strong>(.*?)</strong>',parts[0]).group(1).strip().decode("utf-8").replace("–", "-") + groups[gid]["ep"][ename] = {} + parts.remove(parts[0]) + for part in parts: + hostername = re.search(" \| ([-a-zA-Z0-9]+\.\w+)",part) + if hostername: + hostername = hostername.group(1) + groups[gid]["ep"][ename][hostername] = [] + links = re.findall('href="(.*?)"',part) + for link in links: + groups[gid]["ep"][ename][hostername].append(link + "#hasName") + + links = [] for g in groups.values(): - links = [] - linklist = g["ep"] + for ename in g["ep"]: + links.extend(self.getpreferred(g["ep"][ename])) + if self.getConfig("changeNameSJ") == "Episode": + self.packages.append((ename, links, ename)) + links = [] package = "%s (%s, %s)" % (seasonName, g["opts"]["Format"], g["opts"]["Sprache"]) - linkgroups = {} - for link in linklist: - key = re.sub("^http://download\.serienjunkies\.org/f-.*?/(.{2})_", "", link) - if key not in linkgroups: - linkgroups[key] = [] - linkgroups[key].append(link) - for group in linkgroups.values(): - for pHoster in preferredHoster: - hmatch = False - for link in group: - m = hosterPattern.match(link) - if m: - if pHoster == self.hosterMap[m.group(1)]: - links.append(link) - hmatch = True - break - if hmatch: - break - self.packages.append((package, links, package)) + if self.getConfig("changeNameSJ") == "Format": + self.packages.append((package, links, package)) + links = [] + if (self.getConfig("changeNameSJ") == "Packagename") or re.search("#hasName", url): + self.core.files.addLinks(links, self.pyfile.package().id) + elif (self.getConfig("changeNameSJ") == "Season") or not re.search("#hasName", url): + self.packages.append((seasonName, links, seasonName)) def handleEpisode(self, url): src = self.getSJSrc(url) @@ -127,11 +126,11 @@ class SerienjunkiesOrg(Crypter): soup = BeautifulSoup(src) form = soup.find("form") h1 = soup.find("h1") - packageName = h1.text + if h1.get("class") == "wrap": captchaTag = soup.find(attrs={"src": re.compile("^/secure/")}) if not captchaTag: - sleep(1) + sleep(5) self.retry() captchaUrl = "http://download.serienjunkies.org" + captchaTag["src"] @@ -155,12 +154,15 @@ class SerienjunkiesOrg(Crypter): for link in rawLinks: frameUrl = link["action"].replace("/go-", "/frame/go-") links.append(self.handleFrame(frameUrl)) - - # thx gartd6oDLobo - if not self.getConfig("changeName"): - packageName = self.pyfile.package().name - - self.packages.append((packageName, links, packageName)) + if re.search("#hasName", url) or ((self.getConfig("changeNameSJ") == "Packagename") and (self.getConfig("changeNameDJ") == "Packagename")): + self.core.files.addLinks(links, self.pyfile.package().id) + else: + if h1.text[2] == "_": + eName = h1.text[3:] + else: + eName = h1.text + self.packages.append((eName, links, eName)) + def handleOldStyleLink(self, url): sj = self.req.load(str(url)) @@ -177,18 +179,96 @@ class SerienjunkiesOrg(Crypter): decrypted = self.req.lastEffectiveURL if decrypted == str(url): self.retry() - self.packages.append((self.pyfile.package().name, [decrypted], self.pyfile.package().folder)) + self.core.files.addLinks([decrypted], self.pyfile.package().id) def handleFrame(self, url): self.req.load(str(url)) return self.req.lastEffectiveURL + def handleShowDJ(self, url): + src = self.getSJSrc(url) + soup = BeautifulSoup(src) + post = soup.find("div", attrs={"id": "page_post"}) + ps = post.findAll("p") + found = unescape(soup.find("h2").find("a").string.split(' –')[0]) + if found: + seasonName = found + + groups = {} + gid = -1 + for p in ps: + if re.search("<strong>Sprache|<strong>Format", str(p)): + var = p.findAll("strong") + opts = {"Sprache": "", "Format": ""} + for v in var: + n = unescape(v.string).strip() + n = re.sub(r"^([:]?)(.*?)([:]?)$", r'\2', n) + if n.strip() not in opts: + continue + val = v.nextSibling + if not val: + continue + val = val.replace("|", "").strip() + val = re.sub(r"^([:]?)(.*?)([:]?)$", r'\2', val) + opts[n.strip()] = val.strip() + gid += 1 + groups[gid] = {} + groups[gid]["ep"] = {} + groups[gid]["opts"] = opts + elif re.search("<strong>Download:", str(p)): + parts = str(p).split("<br />") + if re.search("<strong>", parts[0]): + ename = re.search('<strong>(.*?)</strong>',parts[0]).group(1).strip().decode("utf-8").replace("–", "-") + groups[gid]["ep"][ename] = {} + parts.remove(parts[0]) + for part in parts: + hostername = re.search(" \| ([-a-zA-Z0-9]+\.\w+)",part) + if hostername: + hostername = hostername.group(1) + groups[gid]["ep"][ename][hostername] = [] + links = re.findall('href="(.*?)"',part) + for link in links: + groups[gid]["ep"][ename][hostername].append(link + "#hasName") + + links = [] + for g in groups.values(): + for ename in g["ep"]: + links.extend(self.getpreferred(g["ep"][ename])) + if self.getConfig("changeNameDJ") == "Episode": + self.packages.append((ename, links, ename)) + links = [] + package = "%s (%s, %s)" % (seasonName, g["opts"]["Format"], g["opts"]["Sprache"]) + if self.getConfig("changeNameDJ") == "Format": + self.packages.append((package, links, package)) + links = [] + if (self.getConfig("changeNameDJ") == "Packagename") or re.search("#hasName", url): + self.core.files.addLinks(links, self.pyfile.package().id) + elif (self.getConfig("changeNameDJ") == "Show") or not re.search("#hasName", url): + self.packages.append((seasonName, links, seasonName)) + + + + + + + + def handleCategoryDJ(self, url): + package_links = [] + src = self.getSJSrc(url) + soup = BeautifulSoup(src) + content = soup.find("div", attrs={"id": "content"}) + for a in content.findAll("a", attrs={"rel": "bookmark"}): + package_links.append(a["href"]) + self.core.files.addLinks(package_links, self.pyfile.package().id) + def decrypt(self, pyfile): showPattern = re.compile("^http://serienjunkies.org/serie/(.*)/$") seasonPattern = re.compile("^http://serienjunkies.org/.*?/(.*)/$") - episodePattern = re.compile("^http://download.serienjunkies.org/f-.*?.html$") + episodePattern = re.compile("^http://download.serienjunkies.org/f-.*?.html(#hasName)?$") oldStyleLink = re.compile("^http://serienjunkies.org/safe/(.*)$") - framePattern = re.compile("^http://download.serienjunkies.org/frame/go-.*?/$") + categoryPatternDJ = re.compile("^http://dokujunkies.org/.*?(.*)$") + showPatternDJ = re.compile("^http://dokujunkies.org/.*?/(.*)\.html(#hasName)?$") + framePattern = re.compile("^http://download.(serienjunkies.org|dokujunkies.org)/frame/go-.*?/$") url = pyfile.url if framePattern.match(url): self.packages.append((self.pyfile.package().name, [self.handleFrame(url)], self.pyfile.package().name)) @@ -198,5 +278,42 @@ class SerienjunkiesOrg(Crypter): self.handleOldStyleLink(url) elif showPattern.match(url): self.handleShow(url) + elif showPatternDJ.match(url): + self.handleShowDJ(url) elif seasonPattern.match(url): self.handleSeason(url) + elif categoryPatternDJ.match(url): + self.handleCategoryDJ(url) + + #selects the preferred hoster, after that selects any hoster (ignoring the one to ignore) + def getpreferred(self, hosterlist): + + result = [] + preferredList = self.getConfig("hosterList").strip().lower().replace('|',',').replace('.','').replace(';',',').split(',') + if (self.getConfig("randomPreferred") == True) and (self.getConfig("hosterListMode") in ["OnlyOne","OnlyPreferred(One)"]) : + random.shuffle(preferredList) + # we don't want hosters be read two times + hosterlist2 = hosterlist.copy() + + for preferred in preferredList: + for Hoster in hosterlist: + if preferred == Hoster.lower().replace('.',''): + for Part in hosterlist[Hoster]: + self.logDebug("selected " + Part) + result.append(str(Part)) + del(hosterlist2[Hoster]) + if (self.getConfig("hosterListMode") in ["OnlyOne","OnlyPreferred(One)"]): + return result + + + ignorelist = self.getConfig("ignoreList").strip().lower().replace('|',',').replace('.','').replace(';',',').split(',') + if self.getConfig('hosterListMode') in ["OnlyOne","All"]: + for Hoster in hosterlist2: + if Hoster.strip().lower().replace('.','') not in ignorelist: + for Part in hosterlist2[Hoster]: + self.logDebug("selected2 " + Part) + result.append(str(Part)) + + if self.getConfig('hosterListMode') == "OnlyOne": + return result + return result diff --git a/module/plugins/crypter/TrailerzoneInfo.py b/module/plugins/crypter/TrailerzoneInfo.py new file mode 100644 index 000000000..2683c2429 --- /dev/null +++ b/module/plugins/crypter/TrailerzoneInfo.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- + +import re +from module.plugins.Crypter import Crypter + +class TrailerzoneInfo(Crypter): + __name__ = "TrailerzoneInfo" + __type__ = "crypter" + __pattern__ = r"http://(www\.)?trailerzone.info/.*?" + __version__ = "0.02" + __description__ = """TrailerZone.info Crypter Plugin""" + __author_name__ = ("godofdream") + __author_mail__ = ("soilfiction@gmail.com") + + JS_KEY_PATTERN = r"<script>(.*)var t = window" + + def decrypt(self, pyfile): + protectPattern = re.compile("http://(www\.)?trailerzone.info/protect.html.*?") + goPattern = re.compile("http://(www\.)?trailerzone.info/go.html.*?") + url = pyfile.url + if protectPattern.match(url): + self.handleProtect(url) + elif goPattern.match(url): + self.handleGo(url) + + def handleProtect(self, url): + self.handleGo("http://trailerzone.info/go.html#:::" + url.split("#:::",1)[1]) + + def handleGo(self, url): + + src = self.req.load(str(url)) + pattern = re.compile(self.JS_KEY_PATTERN, re.DOTALL) + found = re.search(pattern, src) + + # Get package info + package_links = [] + try: + result = self.js.eval(found.group(1) + " decodeLink('" + url.split("#:::",1)[1] + "');") + result = str(result) + self.logDebug("RESULT: %s" % result) + package_links.append(result) + self.core.files.addLinks(package_links, self.pyfile.package().id) + except Exception, e: + self.logDebug(e) + self.fail('Could not extract any links by javascript') diff --git a/module/plugins/hoster/AlldebridCom.py b/module/plugins/hoster/AlldebridCom.py new file mode 100644 index 000000000..e93e7beb9 --- /dev/null +++ b/module/plugins/hoster/AlldebridCom.py @@ -0,0 +1,91 @@ +#!/usr/nv python
+# -*- coding: utf-8 -*-
+
+import re
+from urllib import quote, unquote
+from random import randrange
+from os import stat
+
+from module.plugins.Hoster import Hoster
+from module.common.json_layer import json_loads
+from module.utils import parseFileSize, fs_encode
+
+
+class AlldebridCom(Hoster):
+ __name__ = "AlldebridCom"
+ __version__ = "0.2"
+ __type__ = "hoster"
+
+ __pattern__ = r"https?://.*alldebrid\..*"
+ __description__ = """Alldebrid.com hoster plugin"""
+ __author_name__ = ("Andy, Voigt")
+ __author_mail__ = ("spamsales@online.de")
+
+ def getFilename(self, url):
+ try:
+ name = unquote(url.rsplit("/", 1)[1])
+ except IndexError:
+ name = "Unknown_Filename..."
+ if name.endswith("..."): #incomplete filename, append random stuff
+ name += "%s.tmp" % randrange(100,999)
+ return name
+
+ def init(self):
+ self.tries = 0
+ self.chunkLimit = 3
+ self.resumeDownload = True
+
+
+ def process(self, pyfile):
+ if not self.account:
+ self.logError(_("Please enter your AllDebrid account or deactivate this plugin"))
+ self.fail("No AllDebrid account provided")
+
+ self.log.debug("AllDebrid: Old URL: %s" % pyfile.url)
+ if re.match(self.__pattern__, pyfile.url):
+ new_url = pyfile.url
+ else:
+ password = self.getPassword().splitlines()
+ if not password: password = ""
+ else: password = password[0]
+
+ url = "http://www.alldebrid.com/service.php?link=%s&json=true&pw=%s" %(pyfile.url, password)
+ page = self.load(url)
+ data = json_loads(page)
+
+ self.log.debug("Json data: %s" % str(data))
+
+ if data["error"]:
+ if data["error"] == "This link isn't available on the hoster website.":
+ self.offline()
+ else:
+ self.logWarning(data["error"])
+ self.tempOffline()
+ else:
+ if self.pyfile.name and not self.pyfile.name.endswith('.tmp'):
+ self.pyfile.name = data["filename"]
+ self.pyfile.size = parseFileSize(data["filesize"])
+ new_url = data["link"]
+
+ if self.getConfig("https"):
+ new_url = new_url.replace("http://", "https://")
+ else:
+ new_url = new_url.replace("https://", "http://")
+
+ self.log.debug("AllDebrid: New URL: %s" % new_url)
+
+ if pyfile.name.startswith("http") or pyfile.name.startswith("Unknown"):
+ #only use when name wasnt already set
+ pyfile.name = self.getFilename(new_url)
+
+ self.download(new_url, disposition=True)
+
+ check = self.checkDownload(
+ {"error": "<title>An error occured while processing your request</title>","empty": re.compile(r"^$")})
+
+ if check == "error":
+ self.retry(reason="An error occured while generating link.", wait_time=60)
+ else:
+ if check == "empty":
+ self.retry(reason="Downloaded File was empty.", wait_time=60)
+
diff --git a/module/plugins/hoster/BasePlugin.py b/module/plugins/hoster/BasePlugin.py index 0e9595265..f1e3006d0 100644 --- a/module/plugins/hoster/BasePlugin.py +++ b/module/plugins/hoster/BasePlugin.py @@ -1,16 +1,18 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- from urlparse import urlparse +from re import search +from urllib import unquote from module.network.HTTPRequest import BadHeader from module.plugins.Hoster import Hoster -from module.utils import html_unescape +from module.utils import html_unescape, remove_chars class BasePlugin(Hoster): __name__ = "BasePlugin" __type__ = "hoster" __pattern__ = r"^unmatchable$" - __version__ = "0.14" + __version__ = "0.15" __description__ = """Base Plugin when any other didnt fit""" __author_name__ = ("RaNaN") __author_mail__ = ("RaNaN@pyload.org") @@ -60,5 +62,28 @@ class BasePlugin(Hoster): def downloadFile(self, pyfile): - pyfile.name = html_unescape(urlparse(pyfile.url).path.split("/")[-1]) - self.download(pyfile.url, disposition=True) + header = self.load(pyfile.url, just_header = True) + #self.logDebug(header) + + if 'location' in header: + self.logDebug("Location: " + header['location']) + url = unquote(header['location']) + else: + url = pyfile.url + + name = html_unescape(unquote(urlparse(url).path.split("/")[-1])) + + if 'content-disposition' in header: + self.logDebug("Content-Disposition: " + header['content-disposition']) + m = search("filename(?P<type>=|\*=(?P<enc>.+)'')(?P<name>.*)", header['content-disposition']) + if m: + disp = m.groupdict() + self.logDebug(disp) + if not disp['enc']: disp['enc'] = 'utf-8' + name = remove_chars(disp['name'], "\"';").strip() + name = unicode(unquote(name), disp['enc']) + + if not name: name = url + pyfile.name = name + self.logDebug("Filename: %s" % pyfile.name) + self.download(url, disposition=True)
\ No newline at end of file diff --git a/module/plugins/hoster/BayfilesCom.py b/module/plugins/hoster/BayfilesCom.py index c771f28c6..190d9a952 100644 --- a/module/plugins/hoster/BayfilesCom.py +++ b/module/plugins/hoster/BayfilesCom.py @@ -26,18 +26,19 @@ class BayfilesCom(SimpleHoster): __name__ = "BayfilesCom" __type__ = "hoster" __pattern__ = r"http://(?:www\.)?bayfiles\.com/file/\w+/\w+/.*" - __version__ = "0.01" + __version__ = "0.04" __description__ = """Bayfiles.com plugin - free only""" __author_name__ = ("zoidberg") __author_mail__ = ("zoidberg@mujmail.cz") FILE_INFO_PATTERN = r'<p title="(?P<N>[^"]+)">[^<]*<strong>(?P<S>[0-9., ]+)(?P<U>[kKMG])i?B</strong></p>' - FILE_OFFLINE_PATTERN = r'<p>The requested file could not be found.</p>' + FILE_OFFLINE_PATTERN = r'(<p>The requested file could not be found.</p>|<title>404 Not Found</title>)' WAIT_PATTERN = r'>Your IP [0-9.]* has recently downloaded a file\. Upgrade to premium or wait (\d+) minutes\.<' VARS_PATTERN = r'var vfid = (\d+);\s*var delay = (\d+);' LINK_PATTERN = r"javascript:window.location.href = '([^']+)';" - + PREMIUM_LINK_PATTERN = r'(?:<a class="highlighted-btn" href="|(?=http://s\d+\.baycdn\.com/dl/))(.*?)"' + def handleFree(self): found = re.search(self.WAIT_PATTERN, self.html) if found: @@ -69,9 +70,24 @@ class BayfilesCom(SimpleHoster): # Get final link and download found = re.search(self.LINK_PATTERN, self.html) if not found: self.parseError("Free link") - url = found.group(1) - self.logDebug("URL: " + url) - + self.startDownload(found.group(1)) + + def handlePremium(self): + found = re.search(self.PREMIUM_LINK_PATTERN, self.html) + if not found: self.parseError("Premium link") + self.startDownload(found.group(1)) + + def startDownload(self, url): + self.logDebug("%s URL: %s" % ("Premium" if self.premium else "Free", url)) self.download(url) + # check download + check = self.checkDownload({ + "waitforfreeslots": re.compile(r"<title>BayFiles</title>"), + "notfound": re.compile(r"<title>404 Not Found</title>") + }) + if check == "waitforfreeslots": + self.retry(60, 300, "Wait for free slot") + elif check == "notfound": + self.retry(60, 300, "404 Not found") -getInfo = create_getInfo(BayfilesCom)
\ No newline at end of file +getInfo = create_getInfo(BayfilesCom) diff --git a/module/plugins/hoster/BitshareCom.py b/module/plugins/hoster/BitshareCom.py index 794e978b2..f5d59d428 100644 --- a/module/plugins/hoster/BitshareCom.py +++ b/module/plugins/hoster/BitshareCom.py @@ -2,6 +2,7 @@ from __future__ import with_statement import re +from pycurl import FOLLOWLOCATION from module.plugins.Hoster import Hoster from module.plugins.ReCaptcha import ReCaptcha @@ -45,22 +46,24 @@ class BitshareCom(Hoster): __name__ = "BitshareCom" __type__ = "hoster" __pattern__ = r"http://(www\.)?bitshare\.com/(files/(?P<id1>[a-zA-Z0-9]+)(/(?P<name>.*?)\.html)?|\?f=(?P<id2>[a-zA-Z0-9]+))" - __version__ = "0.41" + __version__ = "0.45" __description__ = """Bitshare.Com File Download Hoster""" __author_name__ = ("paulking", "fragonib") __author_mail__ = (None, "fragonib[AT]yahoo[DOT]es") HOSTER_DOMAIN = "bitshare.com" FILE_OFFLINE_PATTERN = r'''(>We are sorry, but the requested file was not found in our database|>Error - File not available<|The file was deleted either by the uploader, inactivity or due to copyright claim)''' - FILE_INFO_PATTERN = r'<h1>Downloading\s(?P<name>.+?)\s-\s(?P<size>[\d.]+)\s(?P<units>..)yte</h1>' + FILE_INFO_PATTERN = r'<h1>(Downloading|Streaming)\s(?P<name>.+?)\s-\s(?P<size>[\d.]+)\s(?P<units>..)yte</h1>' FILE_AJAXID_PATTERN = r'var ajaxdl = "(.*?)";' CAPTCHA_KEY_PATTERN = r"http://api\.recaptcha\.net/challenge\?k=(.*?) " def setup(self): - self.multiDL = False + self.multiDL = self.premium self.chunkLimit = 1 def process(self, pyfile): + if self.premium: + self.account.relogin(self.user) self.pyfile = pyfile @@ -71,7 +74,7 @@ class BitshareCom(Hoster): # Load main page self.req.cj.setCookie(self.HOSTER_DOMAIN, "language_selection", "EN") - self.html = self.load(self.pyfile.url, ref=False, decode=True) + self.html = self.load(self.pyfile.url, ref=False, decode=True, cookies = False) # Check offline if re.search(self.FILE_OFFLINE_PATTERN, self.html) is not None: @@ -87,12 +90,20 @@ class BitshareCom(Hoster): # Ajax file id self.ajaxid = re.search(BitshareCom.FILE_AJAXID_PATTERN, self.html).group(1) self.logDebug("File ajax id is [%s]" % self.ajaxid) + + # This may either download our file or forward us to an error page + url = self.getDownloadUrl() + self.logDebug("Downloading file with url [%s]" % url) + self.download(url) - # Handle free downloading - self.handleFree() - - def handleFree(self): - + + def getDownloadUrl(self): + # Return location if direct download is active + if self.premium: + header = self.load(self.pyfile.url, cookies = True, just_header = True) + if 'location' in header: + return header['location'] + # Get download info self.logDebug("Getting download info") response = self.load("http://bitshare.com/files-ajax/" + self.file_id + "/request.html", @@ -107,8 +118,13 @@ class BitshareCom(Hoster): # Waiting if wait > 0: self.logDebug("Waiting %d seconds." % wait) - self.setWait(wait, True) - self.wait() + if wait < 120: + self.setWait(wait, False) + self.wait() + else: + self.setWait(wait - 55, True) + self.wait() + self.retry() # Resolve captcha if captcha == 1: @@ -131,15 +147,14 @@ class BitshareCom(Hoster): post={"request" : "getDownloadURL", "ajaxid" : self.ajaxid}) self.handleErrors(response, '#') url = response.split("#")[-1] - - # Request download URL - # This may either download our file or forward us to an error page - self.logDebug("Downloading file with url [%s]" % url) - self.download(url) + return url + def handleErrors(self, response, separator): self.logDebug("Checking response [%s]" % response) - if "ERROR" in response: + if "ERROR:Session timed out" in response: + self.retry() + elif "ERROR" in response: msg = response.split(separator)[-1] self.fail(msg) @@ -148,5 +163,7 @@ class BitshareCom(Hoster): if "SUCCESS" in response: self.correctCaptcha() return True + elif "ERROR:SESSION ERROR" in response: + self.retry() self.logDebug("Wrong captcha") - self.invalidCaptcha()
\ No newline at end of file + self.invalidCaptcha() diff --git a/module/plugins/hoster/CoolshareCz.py b/module/plugins/hoster/CoolshareCz.py new file mode 100644 index 000000000..7007b6fcb --- /dev/null +++ b/module/plugins/hoster/CoolshareCz.py @@ -0,0 +1,61 @@ +# -*- 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 +""" + +#shares code with WarserverCz + +import re +from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo +from module.network.HTTPRequest import BadHeader +from module.utils import html_unescape + +class CoolshareCz(SimpleHoster): + __name__ = "CoolshareCz" + __type__ = "hoster" + __pattern__ = r"http://(?:\w*\.)?coolshare.cz/stahnout/(?P<ID>\d+)/.+" + __version__ = "0.12" + __description__ = """CoolShare.cz""" + __author_name__ = ("zoidberg") + + FILE_NAME_PATTERN = ur'<h1.*?>Stáhnout (?P<N>[^<]+)</h1>' + FILE_SIZE_PATTERN = r'<li>Velikost: <strong>(?P<S>[^<]+)</strong>' + FILE_OFFLINE_PATTERN = r'<h1>Soubor nenalezen</h1>' + + PREMIUM_URL_PATTERN = r'href="(http://[^/]+/dwn-premium.php.*?)"' + DOMAIN = "http://csd01.coolshare.cz" + + SH_CHECK_TRAFFIC = True + + def handleFree(self): + try: + self.download("%s/dwn-free.php?fid=%s" % (self.DOMAIN, self.file_info['ID'])) + except BadHeader, e: + if e.code == 403: + self.setWait(300, True) + self.wait() + self.retry(max_tries = 24, reason = "Download limit reached") + else: raise + + def handlePremium(self): + found = re.search(self.PREMIUM_URL_PATTERN, self.html) + if not found: self.parseError("Premium URL") + url = html_unescape(found.group(1)) + self.logDebug("Premium URL: " + url) + if not url.startswith("http://"): self.resetAccount() + self.download(url) + +getInfo = create_getInfo(CoolshareCz)
\ No newline at end of file diff --git a/module/plugins/hoster/CramitIn.py b/module/plugins/hoster/CramitIn.py new file mode 100644 index 000000000..a7935c744 --- /dev/null +++ b/module/plugins/hoster/CramitIn.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo + +class CramitIn(XFileSharingPro): + __name__ = "CramitIn" + __type__ = "hoster" + __pattern__ = r"http://(?:\w*\.)*cramit.in/\w{12}" + __version__ = "0.03" + __description__ = """Cramit.in hoster plugin""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + FILE_INFO_PATTERN = r'<span class=t2>\s*(?P<N>.*?)</span>.*?<small>\s*\((?P<S>.*?)\)' + DIRECT_LINK_PATTERN = r'href="(http://cramit.in/file_download/.*?)"' + HOSTER_NAME = "cramit.in" + + def setup(self): + self.multiDL = self.premium + +getInfo = create_getInfo(CramitIn)
\ No newline at end of file diff --git a/module/plugins/hoster/CrockoCom.py b/module/plugins/hoster/CrockoCom.py index bf058b613..27ab52436 100644 --- a/module/plugins/hoster/CrockoCom.py +++ b/module/plugins/hoster/CrockoCom.py @@ -9,13 +9,13 @@ class CrockoCom(SimpleHoster): __name__ = "CrockoCom" __type__ = "hoster" __pattern__ = r"http://(www\.)?(crocko|easy-share).com/.*" - __version__ = "0.12" + __version__ = "0.13" __description__ = """Crocko Download Hoster""" __author_name__ = ("zoidberg") __author_mail__ = ("zoidberg@mujmail.cz") FILE_NAME_PATTERN = r'<span class="fz24">Download:\s*<strong>(?P<N>.*)' - FILE_NAME_PATTERN = r'<span class="tip1"><span class="inner">(?P<S>[^<]+)</span></span>' + FILE_SIZE_PATTERN = r'<span class="tip1"><span class="inner">(?P<S>[^<]+)</span></span>' FILE_OFFLINE_PATTERN = r"<h1>Sorry,<br />the page you're looking for <br />isn't here.</h1>" DOWNLOAD_URL_PATTERN = r"window.location ='([^']+)';" CAPTCHA_URL_PATTERN = re.compile(r"u='(/file_contents/captcha/\w+)';\s*w='(\d+)';") diff --git a/module/plugins/hoster/CzshareCom.py b/module/plugins/hoster/CzshareCom.py index 0ef9c267c..538e3ed86 100644 --- a/module/plugins/hoster/CzshareCom.py +++ b/module/plugins/hoster/CzshareCom.py @@ -45,7 +45,7 @@ class CzshareCom(SimpleHoster): __name__ = "CzshareCom" __type__ = "hoster" __pattern__ = r"http://(\w*\.)*czshare\.(com|cz)/(\d+/|download.php\?).*" - __version__ = "0.86" + __version__ = "0.88" __description__ = """CZshare.com""" __author_name__ = ("zoidberg") @@ -62,7 +62,7 @@ class CzshareCom(SimpleHoster): USER_CREDIT_PATTERN = r'<div class="credit">\s*kredit: <strong>([0-9., ]+)([kKMG]i?B)</strong>\s*</div><!-- .credit -->' def setup(self): - self.resumeDownload = self.multiDL = True if self.premium else False + self.multiDL = self.resumeDownload = True if self.premium else False self.chunkLimit = 1 def process(self, pyfile): @@ -140,16 +140,29 @@ class CzshareCom(SimpleHoster): inputs['captchastring2'] = self.decryptCaptcha(captcha_url) self.logDebug('CAPTCHA_URL:' + captcha_url + ' CAPTCHA:' + inputs['captchastring2']) + self.html = self.load(parsed_url, cookies=True, post=inputs) + + found = re.search("countdown_number = (\d+);", self.html) + self.setWait(int(found.group(1)) if found else 50) + # download the file, destination is determined by pyLoad - self.download(parsed_url, cookies=True, post=inputs) + self.logDebug("WAIT URL", self.req.lastEffectiveURL) + found = re.search("free_wait.php\?server=(.*?)&(.*)", self.req.lastEffectiveURL) + if not found: + raise PluginParseError('Download URL') + url = "http://%s/download.php?%s" % (found.group(1), found.group(2)) + + self.wait() + self.multiDL = True + self.download(url) def checkDownloadedFile(self): # check download check = self.checkDownload({ "tempoffline": re.compile(r"^Soubor je do.asn. nedostupn.$"), "multi_dl": re.compile(self.MULTIDL_PATTERN), - "captcha_err": re.compile(self.FREE_FORM_PATTERN) + "captcha_err": "<li>Zadaný ověřovací kód nesouhlasí!</li>" }) if check == "tempoffline": @@ -160,7 +173,8 @@ class CzshareCom(SimpleHoster): self.invalidCaptcha() self.retry() - def waitForFreeSlot(self): - self.setWait(900, True) + def waitForFreeSlot(self, wait_time = 300): + self.multiDL = False + self.setWait(wait_time, True) self.wait() self.retry()
\ No newline at end of file diff --git a/module/plugins/hoster/DataportCz.py b/module/plugins/hoster/DataportCz.py index 487766201..cef115941 100644 --- a/module/plugins/hoster/DataportCz.py +++ b/module/plugins/hoster/DataportCz.py @@ -17,33 +17,51 @@ """ import re -from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo +from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, PluginParseError +from pycurl import FOLLOWLOCATION class DataportCz(SimpleHoster): __name__ = "DataportCz" __type__ = "hoster" __pattern__ = r"http://.*dataport.cz/file/.*" - __version__ = "0.33" + __version__ = "0.35" __description__ = """Dataport.cz plugin - free only""" __author_name__ = ("zoidberg") - FILE_NAME_PATTERN = r'<h2 style="color: red;">(?P<N>[^<]+)</h2>' - FILE_SIZE_PATTERN = r'<td>Velikost souboru:</td>\s*<td>(?P<S>[0-9.]+)(?P<U>[kKMG])i?B</td>' - URL_PATTERN = r'<td><a href="([^"]+)"[^>]*class="ui-state-default button hover ui-corner-all "><strong>' - NO_SLOTS_PATTERN = r'<td><a href="http://dataport.cz/kredit/"[^>]*class="ui-state-default button hover ui-corner-all ui-state-disabled">' + FILE_NAME_PATTERN = r'<span itemprop="name">(?P<N>[^<]+)</span>' + FILE_SIZE_PATTERN = r'<td class="fil">Velikost</td>\s*<td>(?P<S>[^<]+)</td>' FILE_OFFLINE_PATTERN = r'<h2>Soubor nebyl nalezen</h2>' - def handleFree(self): - if re.search(self.NO_SLOTS_PATTERN, self.html): - self.setWait(900, True) - self.wait() - self.retry(12, 0, "No free slots") - - found = re.search(self.URL_PATTERN, self.html) - if found is None: - self.fail("Parse error (URL)") - download_url = found.group(1) - - self.download(download_url) + CAPTCHA_URL_PATTERN = r'<section id="captcha_bg">\s*<img src="(.*?)"' + FREE_SLOTS_PATTERN = ur'Počet volných slotů: <span class="darkblue">(\d+)</span><br />' + def handleFree(self): + captchas = {"1": "jkeG", "2": "hMJQ", "3": "vmEK", "4": "ePQM", "5": "blBd"} + + for i in range(60): + action, inputs = self.parseHtmlForm('free_download_form') + self.logDebug(action, inputs) + if not action or not inputs: + raise PluginParseError('free_download_form') + + if "captchaId" in inputs and inputs["captchaId"] in captchas: + inputs['captchaCode'] = captchas[inputs["captchaId"]] + else: + raise PluginParseError('captcha') + + self.html = self.download("http://dataport.cz%s" % action, post = inputs) + + check = self.checkDownload({"captcha": 'alert("\u0160patn\u011b opsan\u00fd k\u00f3d z obr\u00e1zu");', + "slot": 'alert("Je n\u00e1m l\u00edto, ale moment\u00e1ln\u011b nejsou'}) + if check == "captcha": + raise PluginParseError('invalid captcha') + elif check == "slot": + self.logDebug("No free slots - wait 60s and retry") + self.setWait(60, False) + self.wait() + self.html = self.load(self.pyfile.url, decode = True) + continue + else: + break + create_getInfo(DataportCz)
\ No newline at end of file diff --git a/module/plugins/hoster/DateiTo.py b/module/plugins/hoster/DateiTo.py new file mode 100644 index 000000000..529a5a06f --- /dev/null +++ b/module/plugins/hoster/DateiTo.py @@ -0,0 +1,92 @@ +# -*- 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 module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo +from module.plugins.ReCaptcha import ReCaptcha + +class DateiTo(SimpleHoster): + __name__ = "DateiTo" + __type__ = "hoster" + __pattern__ = r"http://(?:www\.)?datei\.to/datei/(?P<ID>\w+)\.html" + __version__ = "0.01" + __description__ = """Datei.to plugin - free only""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + FILE_NAME_PATTERN = r'Dateiname:</td>\s*<td colspan="2"><strong>(?P<N>.*?)</' + FILE_SIZE_PATTERN = r'Dateigröße:</td>\s*<td colspan="2">(?P<S>.*?)</' + FILE_OFFLINE_PATTERN = r'>Datei wurde nicht gefunden<|>Bitte wähle deine Datei aus... <' + PARALELL_PATTERN = r'>Du lädst bereits eine Datei herunter<' + + WAIT_PATTERN = r'countdown\({seconds: (\d+)' + DATA_PATTERN = r'url: "(.*?)", data: "(.*?)",' + RECAPTCHA_KEY_PATTERN = r'Recaptcha.create\("(.*?)"' + + def handleFree(self): + url = 'http://datei.to/ajax/download.php' + data = {'P': 'I', 'ID': self.file_info['ID']} + + recaptcha = ReCaptcha(self) + + for i in range(10): + self.logDebug("URL", url, "POST", data) + self.html = self.load(url, post = data) + self.checkErrors() + + if url.endswith('download.php') and 'P' in data: + if data['P'] == 'I': + self.doWait() + + elif data['P'] == 'IV': + break + + found = re.search(self.DATA_PATTERN, self.html) + if not found: self.parseError('data') + url = 'http://datei.to/' + found.group(1) + data = dict(x.split('=') for x in found.group(2).split('&')) + + if url.endswith('recaptcha.php'): + found = re.search(self.RECAPTCHA_KEY_PATTERN, self.html) + recaptcha_key = found.group(1) if found else "6LdBbL8SAAAAAI0vKUo58XRwDd5Tu_Ze1DA7qTao" + + data['recaptcha_challenge_field'], data['recaptcha_response_field'] = recaptcha.challenge(recaptcha_key) + + else: + self.fail('Too bad...') + + download_url = self.html + self.logDebug('Download URL', download_url) + self.download(download_url) + + def checkErrors(self): + found = re.search(self.PARALELL_PATTERN, self.html) + if found: + self.setWait(wait_time + 1, False) + self.wait(300) + self.retry() + + def doWait(self): + found = re.search(self.WAIT_PATTERN, self.html) + wait_time = int(found.group(1)) if found else 30 + self.setWait(wait_time + 1, False) + + self.load('http://datei.to/ajax/download.php', post = {'P': 'Ads'}) + self.wait() + +getInfo = create_getInfo(DateiTo) diff --git a/module/plugins/hoster/DdlstorageCom.py b/module/plugins/hoster/DdlstorageCom.py new file mode 100644 index 000000000..1ad5fa6d8 --- /dev/null +++ b/module/plugins/hoster/DdlstorageCom.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo + +class DdlstorageCom(XFileSharingPro): + __name__ = "DdlstorageCom" + __type__ = "hoster" + __pattern__ = r"http://(?:\w*\.)*?ddlstorage.com/\w{12}" + __version__ = "0.06" + __description__ = """DDLStorage.com hoster plugin""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + FILE_INFO_PATTERN = r'<h2>\s*Download File\s*<span[^>]*>(?P<N>[^>]+)</span></h2>\s*[^\(]*\((?P<S>[^\)]+)\)</h2>' + HOSTER_NAME = "ddlstorage.com" + + def setup(self): + self.resumeDownload = self.multiDL = self.premium + self.chunkLimit = 1 + +getInfo = create_getInfo(DdlstorageCom)
\ No newline at end of file diff --git a/module/plugins/hoster/DepositfilesCom.py b/module/plugins/hoster/DepositfilesCom.py index 87e5e7254..9c13a5f3a 100644 --- a/module/plugins/hoster/DepositfilesCom.py +++ b/module/plugins/hoster/DepositfilesCom.py @@ -3,52 +3,35 @@ import re from urllib import unquote -from module.plugins.internal.SimpleHoster import SimpleHoster, parseFileInfo +from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo from module.network.RequestFactory import getURL from module.plugins.ReCaptcha import ReCaptcha -def getInfo(urls): - result = [] - - for url in urls: - file_info = parseFileInfo(DepositfilesCom, url, getURL(re.sub(r"\.com(/.*?)?/files", ".com/en/files", url), decode=True)) - result.append(file_info) - - yield result - class DepositfilesCom(SimpleHoster): __name__ = "DepositfilesCom" __type__ = "hoster" __pattern__ = r"http://[\w\.]*?depositfiles\.com(/\w{1,3})?/files/[\w]+" - __version__ = "0.36" + __version__ = "0.42" __description__ = """Depositfiles.com Download Hoster""" __author_name__ = ("spoob", "zoidberg") __author_mail__ = ("spoob@pyload.org", "zoidberg@mujmail.cz") - FILE_INFO_PATTERN = r'File name: <b title="(?P<N>[^"]+)">.*\s*<span class="nowrap">File size: <b>(?P<S>[0-9.]+) (?P<U>[kKMG])i?B</b>' + FILE_NAME_PATTERN = r'File name: <b title="(?P<N>[^"]+)' + FILE_SIZE_PATTERN = r'File size: <b>(?P<S>[0-9.]+) (?P<U>[kKMG])i?B</b>' + FILE_INFO_PATTERN = r'<script type="text/javascript">eval\( unescape\(\'(?P<N>.*?)\'' FILE_OFFLINE_PATTERN = r'<span class="html_download_api-not_exists"></span>' - RECAPTCHA_PATTERN = r"Recaptcha.create\('([^']+)', this\);" + FILE_URL_REPLACEMENTS = [(r"\.com(/.*?)?/files", ".com/en/files"), (r"\.html$", "")] + FILE_NAME_REPLACEMENTS = [(r'\%u([0-9A-Fa-f]{4})', lambda m: unichr(int(m.group(1), 16))), (r'.*<b title="(?P<N>[^"]+).*', "\g<N>" )] + + RECAPTCHA_PATTERN = r"Recaptcha.create\('([^']+)'" DOWNLOAD_LINK_PATTERN = r'<form action="(http://.+?\.depositfiles.com/.+?)" method="get"' def setup(self): - self.resumeDownload = self.multiDL = True if self.account else False - - self.pyfile.url = re.sub(r"\.com(/.*?)?/files", ".com/en/files", self.pyfile.url) - - def process(self, pyfile): - if re.search(r"(.*)\.html", self.pyfile.url): - self.pyfile.url = re.search(r"(.*)\.html", self.pyfile.url).group(1) - - self.html = self.load(self.pyfile.url, cookies=True if self.account else False, decode = True) - self.getFileInfo() - - if self.account: - self.handlePremium() - else: - self.handleFree() + self.multiDL = False + self.resumeDownload = self.premium def handleFree(self): - self.html = self.load(self.pyfile.url, post={"gateway_result":"1"}) + self.html = self.load(self.pyfile.url, post={"gateway_result":"1"}, cookies = True) if re.search(self.FILE_OFFLINE_PATTERN, self.html): self.offline() if re.search(r'File is checked, please try again in a minute.', self.html) is not None: @@ -81,7 +64,7 @@ class DepositfilesCom(SimpleHoster): params = {'fid' : found.group(1)} self.logDebug ("FID: %s" % params['fid']) - captcha_key = None + captcha_key = '6LdRTL8SAAAAAE9UOdWZ4d0Ky-aeA7XfSqyWDM2m' found = re.search(self.RECAPTCHA_PATTERN, self.html) if found: captcha_key = found.group(1) self.logDebug ("CAPTCHA_KEY: %s" % captcha_key) @@ -91,9 +74,9 @@ class DepositfilesCom(SimpleHoster): for i in range(5): self.html = self.load("http://depositfiles.com/get_file.php", get = params) - + if '<input type=button value="Continue" onclick="check_recaptcha' in self.html: - if not captcha_key: raise PluginParseError('Captcha key') + if not captcha_key: self.parseError('Captcha key') if 'response' in params: self.invalidCaptcha() params['challenge'], params['response'] = recaptcha.challenge(captcha_key) self.logDebug(params) @@ -106,15 +89,24 @@ class DepositfilesCom(SimpleHoster): self.logDebug ("LINK: %s" % link) break else: - raise PluginParseError('Download link') + self.parseError('Download link') else: self.fail('No valid captcha response received') try: - self.download(link) + self.download(link, disposition = True) except: self.retry(wait_time = 60) def handlePremium(self): + if '<span class="html_download_api-gold_traffic_limit">' in self.html: + self.logWarning("Download limit reached") + self.retry(25, 3600, "Download limit reached") + elif 'onClick="show_gold_offer' in self.html: + self.account.relogin(self.user) + self.retry() link = unquote(re.search('<div id="download_url">\s*<a href="(http://.+?\.depositfiles.com/.+?)"', self.html).group(1)) - self.download(link)
\ No newline at end of file + self.multiDL = True + self.download(link, disposition = True) + +getInfo = create_getInfo(DepositfilesCom)
\ No newline at end of file diff --git a/module/plugins/hoster/DlFreeFr.py b/module/plugins/hoster/DlFreeFr.py index 7cb58e6f4..5b318fd54 100644 --- a/module/plugins/hoster/DlFreeFr.py +++ b/module/plugins/hoster/DlFreeFr.py @@ -2,36 +2,182 @@ # -*- coding: utf-8 -*- import re -from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo +from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, replace_patterns +from module.common.json_layer import json_loads + +import pycurl +from module.network.Browser import Browser +from module.network.CookieJar import CookieJar + +class CustomBrowser(Browser): + def __init__(self, bucket=None, options={}): + Browser.__init__(self, bucket, options) + + def load(self, *args, **kwargs): + post = kwargs.get("post") + if post is None: + if len(args) > 2: + post = args[2] + if post: + self.http.c.setopt(pycurl.FOLLOWLOCATION, 0) + self.http.c.setopt(pycurl.POST, 1) + self.http.c.setopt(pycurl.CUSTOMREQUEST, "POST") + else: + self.http.c.setopt(pycurl.FOLLOWLOCATION, 1) + self.http.c.setopt(pycurl.POST, 0) + self.http.c.setopt(pycurl.CUSTOMREQUEST, "GET") + return Browser.load(self, *args, **kwargs) + +""" +Class to support adyoulike captcha service +""" +class AdYouLike(): + ADYOULIKE_INPUT_PATTERN = r'Adyoulike.create\((.*?)\);' + ADYOULIKE_CALLBACK = r'Adyoulike.g._jsonp_5579316662423138' + ADYOULIKE_CHALLENGE_PATTERN = ADYOULIKE_CALLBACK + r'\((.*?)\)' + + def __init__(self, plugin, engine = "adyoulike"): + self.plugin = plugin + self.engine = engine + + def challenge(self, html): + adyoulike_data_string = None + found = re.search(self.ADYOULIKE_INPUT_PATTERN, html) + if found: + adyoulike_data_string = found.group(1) + else: + self.plugin.fail("Can't read AdYouLike input data") + + ayl_data = json_loads(adyoulike_data_string) #{"adyoulike":{"key":"P~zQ~O0zV0WTiAzC-iw0navWQpCLoYEP"},"all":{"element_id":"ayl_private_cap_92300","lang":"fr","env":"prod"}} + + res = self.plugin.load(r'http://api-ayl.appspot.com/challenge?key=%(ayl_key)s&env=%(ayl_env)s&callback=%(callback)s' % {"ayl_key": ayl_data[self.engine]["key"], "ayl_env": ayl_data["all"]["env"], "callback": self.ADYOULIKE_CALLBACK}) + + found = re.search(self.ADYOULIKE_CHALLENGE_PATTERN, res) + challenge_string = None + if found: + challenge_string = found.group(1) + else: + self.plugin.fail("Invalid AdYouLike challenge") + challenge_data = json_loads(challenge_string) + + return ayl_data, challenge_data + + def result(self, ayl, challenge): + """ + Adyoulike.g._jsonp_5579316662423138({"translations":{"fr":{"instructions_visual":"Recopiez « Soonnight » ci-dessous :"}},"site_under":true,"clickable":true,"pixels":{"VIDEO_050":[],"DISPLAY":[],"VIDEO_000":[],"VIDEO_100":[],"VIDEO_025":[],"VIDEO_075":[]},"medium_type":"image/adyoulike","iframes":{"big":"<iframe src=\"http://www.soonnight.com/campagn.html\" scrolling=\"no\" height=\"250\" width=\"300\" frameborder=\"0\"></iframe>"},"shares":{},"id":256,"token":"e6QuI4aRSnbIZJg02IsV6cp4JQ9~MjA1","formats":{"small":{"y":300,"x":0,"w":300,"h":60},"big":{"y":0,"x":0,"w":300,"h":250},"hover":{"y":440,"x":0,"w":300,"h":60}},"tid":"SqwuAdxT1EZoi4B5q0T63LN2AkiCJBg5"}) + """ + response = None + try: + instructions_visual = challenge["translations"][ayl["all"]["lang"]]["instructions_visual"] + found = re.search(u".*«(.*)».*", instructions_visual) + if found: + response = found.group(1).strip() + else: + self.plugin.fail("Can't parse instructions visual") + except KeyError: + self.plugin.fail("No instructions visual") + + #TODO: Supports captcha + + if not response: + self.plugin.fail("AdYouLike result failed") + + return {"_ayl_captcha_engine" : self.engine, + "_ayl_env" : ayl["all"]["env"], + "_ayl_tid" : challenge["tid"], + "_ayl_token_challenge" : challenge["token"], + "_ayl_response": response } class DlFreeFr(SimpleHoster): __name__ = "DlFreeFr" __type__ = "hoster" - __pattern__ = r"http://dl\.free\.fr/([a-zA-Z0-9]+|getfile\.pl\?file=/[a-zA-Z0-9]+)$" - __version__ = "0.2" + __pattern__ = r"http://dl\.free\.fr/([a-zA-Z0-9]+|getfile\.pl\?file=/[a-zA-Z0-9]+)" + __version__ = "0.23" __description__ = """dl.free.fr download hoster""" - __author_name__ = ("the-razer", "zoidberg") - __author_mail__ = ("daniel_ AT gmx DOT net", "zoidberg@mujmail.cz") + __author_name__ = ("the-razer", "zoidberg", "Toilal") + __author_mail__ = ("daniel_ AT gmx DOT net", "zoidberg@mujmail.cz", "toilal.dev@gmail.com") FILE_NAME_PATTERN = r"Fichier:</td>\s*<td[^>]*>(?P<N>[^>]*)</td>" - FILE_SIZE_PATTERN = r"Taille:</td>\s*<td[^>]*>(?P<S>[\d.]+[KMG])</td>" + FILE_SIZE_PATTERN = r"Taille:</td>\s*<td[^>]*>(?P<S>[\d.]+[KMG])o" FILE_OFFLINE_PATTERN = r"Erreur 404 - Document non trouv|Fichier inexistant|Le fichier demandé n'a pas été trouvé" - FILE_URL_PATTERN = r'href="(?P<url>http://.*?)">Télécharger ce fichier' - + #FILE_URL_PATTERN = r'href="(?P<url>http://.*?)">Télécharger ce fichier' + def setup(self): self.limitDL = 5 self.resumeDownload = True - self.chunkLimit = 1 + self.chunkLimit = 1 - def handleFree(self): - if "Trop de slots utilisés" in self.html: - self.retry(300) + def init(self): + factory = self.core.requestFactory + self.req = CustomBrowser(factory.bucket, factory.getOptions()) + + def process(self, pyfile): + self.req.setCookieJar(None) + + pyfile.url = replace_patterns(pyfile.url, self.FILE_URL_REPLACEMENTS) + valid_url = pyfile.url + headers = self.load(valid_url, just_header = True) - m = re.search(self.FILE_URL_PATTERN, self.html) - if not m: self.parseError('URL') + self.html = None + if headers.get('code') == 302: + valid_url = headers.get('location') + headers = self.load(valid_url, just_header = True) - url = m.group('url') - self.logDebug("File URL [%s]" % url) - self.download(url) + if headers.get('code') == 200: + content_type = headers.get('content-type') + if content_type and content_type.startswith("text/html"): + # Undirect acces to requested file, with a web page providing it (captcha) + self.html = self.load(valid_url) + self.handleFree() + else: + # Direct access to requested file for users using free.fr as Internet Service Provider. + self.download(valid_url, disposition=True) + elif headers.get('code') == 404: + self.offline() + else: + self.fail("Invalid return code: " + str(headers.get('code'))) + + def handleFree(self): + action, inputs = self.parseHtmlForm('action="getfile.pl"') + + adyoulike = AdYouLike(self) + ayl, challenge = adyoulike.challenge(self.html) + result = adyoulike.result(ayl, challenge) + inputs.update(result) + + data = self.load("http://dl.free.fr/getfile.pl", post = inputs) + headers = self.getLastHeaders() + if headers.get("code") == 302 and headers.has_key("set-cookie") and headers.has_key("location"): + found = re.search("(.*?)=(.*?); path=(.*?); domain=(.*?)", headers.get("set-cookie")) + cj = CookieJar(__name__) + if found: + cj.setCookie(found.group(4), found.group(1), found.group(2), found.group(3)) + else: + self.fail("Cookie error") + location = headers.get("location") + self.req.setCookieJar(cj) + self.download(location, disposition=True); + else: + self.fail("Invalid response") + + def getLastHeaders(self): + #parse header + header = {"code": self.req.code} + for line in self.req.http.header.splitlines(): + line = line.strip() + if not line or ":" not in line: continue + + key, none, value = line.partition(":") + key = key.lower().strip() + value = value.strip() + + if key in header: + if type(header[key]) == list: + header[key].append(value) + else: + header[key] = [header[key], value] + else: + header[key] = value + return header -getInfo = create_getInfo(DlFreeFr)
\ No newline at end of file +getInfo = create_getInfo(DlFreeFr) diff --git a/module/plugins/hoster/EasybytezCom.py b/module/plugins/hoster/EasybytezCom.py index 0b46acb83..5f3159b20 100644 --- a/module/plugins/hoster/EasybytezCom.py +++ b/module/plugins/hoster/EasybytezCom.py @@ -17,128 +17,67 @@ """ import re -from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo from random import random +from pycurl import LOW_SPEED_TIME +from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo -class EasybytezCom(SimpleHoster): +class EasybytezCom(XFileSharingPro): __name__ = "EasybytezCom" __type__ = "hoster" - __pattern__ = r"http://(?:\w*\.)?easybytez.com/(\w{6,}).*" - __version__ = "0.06" + __pattern__ = r"http://(?:\w*\.)?easybytez.com/(\w+).*" + __version__ = "0.11" __description__ = """easybytez.com""" __author_name__ = ("zoidberg") __author_mail__ = ("zoidberg@mujmail.cz") - - # shares code with TurbouploadCom FILE_NAME_PATTERN = r'<input type="hidden" name="fname" value="(?P<N>[^"]+)"' FILE_SIZE_PATTERN = r'You have requested <font color="red">[^<]+</font> \((?P<S>[^<]+)\)</font>' - FILE_INFO_PATTERN = r'<tr><td align=right><b>Filename:</b></td><td nowrap>(?P<N>[^<]+)</td></tr>\s*.*?<small>\((?P<S>[^<]+)\)</small>' - FILE_OFFLINE_PATTERN = r'<h2>File Not Found</h2>' + FILE_INFO_PATTERN = r'<tr><td align=right><b>Filename:</b></td><td nowrap>(?P<N>[^<]+)</td></tr>\s*.*?<small>\((?P<S>[^<]+)\)</small>' + FILE_OFFLINE_PATTERN = r'<h1>File not available</h1>' - FORM_INPUT_PATTERN = r'<input[^>]* name="([^"]+)"[^>]*value="([^"]*)"' - WAIT_PATTERN = r'<span id="countdown_str">[^>]*>(\d+)</span> seconds</span>' DIRECT_LINK_PATTERN = r'(http://(\w+\.easybytez\.com|\d+\.\d+\.\d+\.\d+)/files/\d+/\w+/[^"<]+)' - - FORM_PATTERN = r'<form name=["\']?%s[^>]*action=["\']?([^"\' ]+)(.*?)</form>' OVR_DOWNLOAD_LINK_PATTERN = r'<h2>Download Link</h2>\s*<textarea[^>]*>([^<]+)' OVR_KILL_LINK_PATTERN = r'<h2>Delete Link</h2>\s*<textarea[^>]*>([^<]+)' - TEXTAREA_PATTERN = r"<textarea name='([^']+)'>([^<]+)</textarea>" - - HOSTER_URL = "www.easybytez.com" - - def process(self, pyfile): - if not re.match(self.__pattern__, self.pyfile.url): - if self.premium: - self.handleOverriden() - else: - self.fail("Only premium users can download from other hosters with %s" % self.HOSTER_URL) - else: - self.html = self.load(pyfile.url, cookies = False, decode = True) - self.file_info = self.getFileInfo() - - header = self.load(self.pyfile.url, just_header = True, cookies = True) - self.logDebug(header) - - if 'location' in header and re.match(self.DIRECT_LINK_PATTERN, header['location']): - self.downloadLink(header['location']) - elif self.premium: - self.handlePremium() - else: - self.handleFree() - def handleFree(self): - self.download(self.pyfile.url, post = self.getPostParameters(), ref = True, cookies = True) + HOSTER_NAME = "easybytez.com" + def setup(self): + self.resumeDownload = self.multiDL = self.premium + def handlePremium(self): - self.html = self.load(self.pyfile.url, post = self.getPostParameters(premium=True)) + self.html = self.load(self.pyfile.url, post = self.getPostParameters()) found = re.search(self.DIRECT_LINK_PATTERN, self.html) if not found: self.parseError('DIRECT LINK') - self.downloadLink(found.group(1)) - + self.startDownload(found.group(1)) + def handleOverriden(self): - self.html = self.load(self.HOSTER_URL) - action, form = re.search(self.FORM_PATTERN % "url", self.html, re.DOTALL).groups() - inputs = dict(re.findall(self.FORM_INPUT_PATTERN, form)) + self.html = self.load("http://www.%s/" % self.HOSTER_NAME) + action, inputs = self.parseHtmlForm('') upload_id = "%012d" % int(random()*10**12) - action += upload_id + "&js_on=1&utype=prem&upload_type=url" + action += upload_id + "&js_on=1&utype=prem&upload_type=url" inputs['tos'] = '1' inputs['url_mass'] = self.pyfile.url - inputs['up1oad_type'] = 'url' - + inputs['up1oad_type'] = 'url' + self.logDebug(action, inputs) + #wait for file to upload to easybytez.com + self.req.http.c.setopt(LOW_SPEED_TIME, 600) self.html = self.load(action, post = inputs) - - found = re.search(self.FORM_PATTERN % "F1", self.html, re.S | re.I) - if not found: - self.logDebug(self.html) - self.fail("upload failed") - action, form = found.groups() - - inputs = dict(re.findall(self.TEXTAREA_PATTERN, form)) - if not inputs: parseError('TEXTAREA') - self.logDebug(inputs) + + action, inputs = self.parseHtmlForm('F1') + if not inputs: self.parseError('TEXTAREA') + self.logDebug(inputs) if inputs['st'] == 'OK': self.html = self.load(action, post = inputs) + elif inputs['st'] == 'Can not leech file': + self.retry(max_tries=20, wait_time=180, reason=inputs['st']) else: - self.fail(inputs['st']) + self.fail(inputs['st']) + #get easybytez.com link for uploaded file found = re.search(self.OVR_DOWNLOAD_LINK_PATTERN, self.html) if not found: self.parseError('DIRECT LINK (OVR)') self.pyfile.url = found.group(1) self.retry() - - def downloadLink(self, link): - self.logDebug('DIRECT LINK: %s' % link) - self.download(link) - - def getPostParameters(self, premium=False): - inputs = dict(re.findall(self.FORM_INPUT_PATTERN, self.html)) - self.logDebug(inputs) - - if 'op' in inputs and inputs['op'] == 'download2': return inputs - - inputs['referer'] = self.pyfile.url - - if premium: - inputs['method_premium'] = "Premium Download" - if 'method_free' in inputs: del inputs['method_free'] - else: - inputs['method_free'] = "Free Download" - if 'method_premium' in inputs: del inputs['method_premium'] - - self.html = self.load(self.pyfile.url, post = inputs, ref = True, cookies = True) - inputs = dict(re.findall(self.FORM_INPUT_PATTERN, self.html)) - self.logDebug(inputs) - - if not premium: - found = re.search(self.WAIT_PATTERN, self.html) - self.setWait(int(found.group(1)) + 1 if found else 60) - self.wait() - - return inputs - - def urlParseFileName(self): - return html_unescape(urlparse(self.pyfile.url).path.split("/")[-1]) getInfo = create_getInfo(EasybytezCom)
\ No newline at end of file diff --git a/module/plugins/hoster/ExtabitCom.py b/module/plugins/hoster/ExtabitCom.py new file mode 100644 index 000000000..718423986 --- /dev/null +++ b/module/plugins/hoster/ExtabitCom.py @@ -0,0 +1,84 @@ +# -*- 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 module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo +from module.plugins.ReCaptcha import ReCaptcha +from module.common.json_layer import json_loads + +class ExtabitCom(SimpleHoster): + __name__ = "ExtabitCom" + __type__ = "hoster" + __pattern__ = r"http://(\w+\.)*extabit\.com/(file|go)/(?P<ID>\w+)" + __version__ = "0.2" + __description__ = """Extabit.com""" + __author_name__ = ("zoidberg") + + FILE_NAME_PATTERN = r'<th>File:</th>\s*<td class="col-fileinfo">\s*<div title="(?P<N>[^"]+)">' + FILE_SIZE_PATTERN = r'<th>Size:</th>\s*<td class="col-fileinfo">(?P<S>[^<]+)</td>' + FILE_OFFLINE_PATTERN = r'<h1>File not found</h1>' + TEMP_OFFLINE_PATTERN = r">(File is temporary unavailable|No download mirror)<" + + DOWNLOAD_LINK_PATTERN = r'"(http://guest\d+\.extabit\.com/[a-z0-9]+/.*?)"' + + def handleFree(self): + if r">Only premium users can download this file" in self.html: + self.fail("Only premium users can download this file") + + m = re.search(r"Next free download from your ip will be available in <b>(\d+)\s*minutes", self.html) + if m: + self.setWait(int(m.group(1)) * 60, True) + self.wait() + elif "The daily downloads limit from your IP is exceeded" in self.html: + self.setWait(3600, True) + self.wait() + + self.logDebug("URL: " + self.req.http.lastEffectiveURL) + m = re.match(self.__pattern__, self.req.http.lastEffectiveURL) + fileID = m.group('ID') if m else self.file_info('ID') + + m = re.search(r'recaptcha/api/challenge\?k=(\w+)', self.html) + if m: + recaptcha = ReCaptcha(self) + captcha_key = m.group(1) + + for i in range(5): + get_data = {"type": "recaptcha"} + get_data["challenge"], get_data["capture"] = recaptcha.challenge(captcha_key) + response = json_loads(self.load("http://extabit.com/file/%s/" % fileID, get = get_data)) + if "ok" in response: + self.correctCaptcha() + break + else: + self.invalidCaptcha() + else: + self.fail("Invalid captcha") + else: + self.parseError('Captcha') + + if not "href" in response: self.parseError('JSON') + + self.html = self.load("http://extabit.com/file/%s%s" % (fileID, response['href'])) + m = re.search(self.DOWNLOAD_LINK_PATTERN, self.html) + if not m: + self.parseError('Download URL') + url = m.group(1) + self.logDebug("Download URL: " + url) + self.download(url) + +getInfo = create_getInfo(ExtabitCom)
\ No newline at end of file diff --git a/module/plugins/hoster/FastshareCz.py b/module/plugins/hoster/FastshareCz.py new file mode 100644 index 000000000..654a1abe8 --- /dev/null +++ b/module/plugins/hoster/FastshareCz.py @@ -0,0 +1,52 @@ +# -*- 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 module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo + +class FastshareCz(SimpleHoster): + __name__ = "FastshareCz" + __type__ = "hoster" + __pattern__ = r"http://(?:\w*\.)?fastshare.cz/\d+/.+" + __version__ = "0.12" + __description__ = """FastShare.cz""" + __author_name__ = ("zoidberg") + + FILE_NAME_PATTERN = r'<h3><b><span style=color:black;>(?P<N>[^<]+)</b></h3>' + FILE_SIZE_PATTERN = r'<tr><td>Velikost: </td><td style=font-weight:bold>(?P<S>[^<]+)</td></tr>' + FILE_OFFLINE_PATTERN = r'<div id="content">\s*<div style=background-color:white' + SH_HTML_ENCODING = 'cp1250' + + FREE_URL_PATTERN = ur'<form method=post action=(/free/.*?)><b>Stáhnout FREE.*?<img src="([^"]*)">' + + def handleFree(self): + found = re.search(self.FREE_URL_PATTERN, self.html) + if not found: self.parseError("Free URL") + action, captcha_src = found.groups() + captcha = self.decryptCaptcha("http://www.fastshare.cz/" + captcha_src) + self.download("http://www.fastshare.cz/" + action, post = {"code": captcha, "submit": u"stáhnout"}) + + check = self.checkDownload({"paralell_dl": "<script>alert('Pres FREE muzete stahovat jen jeden soubor najednou.')"}) + self.logDebug(self.req.lastEffectiveURL, self.req.lastURL, self.req.code) + + if check == "paralell_dl": + self.setWait(600, True) + self.wait() + self.retry() + +getInfo = create_getInfo(FastshareCz)
\ No newline at end of file diff --git a/module/plugins/hoster/FilecloudIo.py b/module/plugins/hoster/FilecloudIo.py new file mode 100644 index 000000000..4a096e400 --- /dev/null +++ b/module/plugins/hoster/FilecloudIo.py @@ -0,0 +1,112 @@ +# -*- 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 module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, PluginParseError +from module.common.json_layer import json_loads +from module.plugins.ReCaptcha import ReCaptcha +from module.network.RequestFactory import getURL + +class FilecloudIo(SimpleHoster): + __name__ = "FilecloudIo" + __type__ = "hoster" + __pattern__ = r"http://(?:\w*\.)*(?:filecloud\.io|ifile\.it|mihd\.net)/(?P<ID>\w+).*" + __version__ = "0.01" + __description__ = """Filecloud.io (formerly Ifile.it) plugin - free account only""" + __author_name__ = ("zoidberg") + + FILE_SIZE_PATTERN = r'{var __ab1 = (?P<S>\d+);}' + FILE_NAME_PATTERN = r'id="aliasSpan">(?P<N>.*?) <' + FILE_OFFLINE_PATTERN = r'l10n.(FILES__DOESNT_EXIST|REMOVED)' + TEMP_OFFLINE_PATTERN = r'l10n.FILES__WARNING' + + UKEY_PATTERN = r"'ukey'\s*:'(\w+)'," + AB1_PATTERN = r"if\( __ab1 == '(\w+)' \)" + ERROR_MSG_PATTERN = r"var __error_msg\s*=\s*l10n\.(.*?);" + DOWNLOAD_LINK_PATTERN = r'"(http://s\d+.filecloud.io/%s/\d+/.*?)"' + RECAPTCHA_KEY_PATTERN = r"var __recaptcha_public\s*=\s*'([^']+)';" + RECAPTCHA_KEY = '6Lf5OdISAAAAAEZObLcx5Wlv4daMaASRov1ysDB1' + + def setup(self): + self.resumeDownload = self.multiDL = True + self.chunkLimit = 1 + + def handleFree(self): + data = {"ukey": self.file_info['ID']} + + found = re.search(self.AB1_PATTERN, self.html) + if not found: + raise PluginParseError("__AB1") + data["__ab1"] = found.group(1) + + if not self.account: + self.fail("User not logged in") + elif not self.account.logged_in: + recaptcha = ReCaptcha(self) + captcha_challenge, captcha_response = recaptcha.challenge(self.RECAPTCHA_KEY) + self.account.form_data = {"recaptcha_challenge_field" : captcha_challenge, + "recaptcha_response_field" : captcha_response} + self.account.relogin(self.user) + self.retry(max_tries = 2) + + json_url = "http://filecloud.io/download-request.json" + response = self.load(json_url, post = data) + self.logDebug(response) + response = json_loads(response) + + if "error" in response and response["error"]: + self.fail(response) + + self.logDebug(response) + if response["captcha"]: + recaptcha = ReCaptcha(self) + found = re.search(self.RECAPTCHA_KEY_PATTERN, self.html) + captcha_key = found.group(1) if found else self.RECAPTCHA_KEY + data["ctype"] = "recaptcha" + + for i in range(5): + data["recaptcha_challenge"], data["recaptcha_response"] = recaptcha.challenge(captcha_key) + + json_url = "http://filecloud.io/download-request.json" + response = self.load(json_url, post = data) + self.logDebug(response) + response = json_loads(response) + + if "retry" in response and response["retry"]: + self.invalidCaptcha() + else: + self.correctCaptcha() + break + else: + self.fail("Incorrect captcha") + + if response["dl"]: + self.html = self.load('http://filecloud.io/download.html') + found = re.search(self.DOWNLOAD_LINK_PATTERN % self.file_info['ID'], self.html) + if not found: + raise PluginParseError("Download URL") + download_url = found.group(1) + self.logDebug("Download URL: %s" % download_url) + + if "size" in self.file_info and self.file_info['size']: + self.check_data = {"size": int(self.file_info['size'])} + self.download(download_url) + else: + self.fail("Unexpected server response") + +getInfo = create_getInfo(FilecloudIo)
\ No newline at end of file diff --git a/module/plugins/hoster/FiledinoCom.py b/module/plugins/hoster/FiledinoCom.py new file mode 100644 index 000000000..6bdd01b51 --- /dev/null +++ b/module/plugins/hoster/FiledinoCom.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +import re + +class FiledinoCom(XFileSharingPro): + __name__ = "FiledinoCom" + __type__ = "hoster" + __pattern__ = r"http://(?:\w*\.)*(file(dino|fat).com)/\w{12}" + __version__ = "0.02" + __description__ = """FileDino / FileFat hoster plugin""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + FILE_SIZE_PATTERN = r'File Size : </(span|font)><(span|font)[^>]*>(?P<S>.+?)</(span|font)>' + DIRECT_LINK_PATTERN = r'http://www\.file(dino|fat)\.com/cgi-bin/dl\.cgi/' + + def setup(self): + self.HOSTER_NAME = re.search(self.__pattern__, self.pyfile.url).group(1) + self.multiDL = False + +getInfo = create_getInfo(FiledinoCom)
\ No newline at end of file diff --git a/module/plugins/hoster/FilefactoryCom.py b/module/plugins/hoster/FilefactoryCom.py index 37b2bb7ce..135dd90a1 100644 --- a/module/plugins/hoster/FilefactoryCom.py +++ b/module/plugins/hoster/FilefactoryCom.py @@ -1,122 +1,133 @@ # -*- coding: utf-8 -*- -from __future__ import with_statement - from module.network.RequestFactory import getURL from module.plugins.Hoster import Hoster from module.plugins.ReCaptcha import ReCaptcha +from module.utils import parseFileSize +from module.plugins.Plugin import chunks +from module.common.json_layer import json_loads import re -def getInfo(urls): - result = [] +def checkFile(plugin, urls): + file_info = [] + url_dict = {} for url in urls: - - # Get file info html - # @TODO: Force responses in english language so current patterns will be right - html = getURL(url) - if re.search(FilefactoryCom.FILE_OFFLINE_PATTERN, html): - result.append((url, 0, 1, url)) + url_dict[re.search(plugin.__pattern__, url).group('id')] = (url, 0, 0, url) + url_ids = url_dict.keys() + urls = map(lambda url_id: 'http://www.filefactory.com/file/' + url_id, url_ids) - # Name - name = re.search(FilefactoryCom.FILE_NAME_PATTERN, html).group('name') - m = re.search(FilefactoryCom.FILE_INFO_PATTERN, html) + html = getURL("http://www.filefactory.com/tool/links.php", post = {"func": "links", "links": "\n".join(urls)}, decode=True) - # Size - value = float(m.group('size')) - units = m.group('units') - pow = {'KB' : 1, 'MB' : 2, 'GB' : 3}[units] - size = int(value*1024**pow) + for m in re.finditer(plugin.LC_INFO_PATTERN, html): + if m.group('id') in url_ids: + url_dict[m.group('id')] = (m.group('name'), parseFileSize(m.group('size')), 2, url_dict[m.group('id')][3]) + + for m in re.finditer(plugin.LC_OFFLINE_PATTERN, html): + if m.group('id') in url_ids: + url_dict[m.group('id')] = (url_dict[m.group('id')][0], 0, 1, url_dict[m.group('id')][3]) - # Return info - result.append((name, size, 2, url)) - - yield result + file_info = url_dict.values() + return file_info + class FilefactoryCom(Hoster): __name__ = "FilefactoryCom" __type__ = "hoster" - __pattern__ = r"http://(www\.)?filefactory\.com/file/(?P<id>[a-zA-Z0-9]+)" # URLs given out are often longer but this is the requirement - __version__ = "0.3" + __pattern__ = r"http://(?:www\.)?filefactory\.com/file/(?P<id>[a-zA-Z0-9]+).*" # URLs given out are often longer but this is the requirement + __version__ = "0.34" __description__ = """Filefactory.Com File Download Hoster""" - __author_name__ = ("paulking") + __author_name__ = ("paulking", "zoidberg") + LC_INFO_PATTERN = r'<h1 class="name">(?P<name>[^<]+) \((?P<size>[0-9.]+ \w+)\)</h1>\s*<p>http://www.filefactory.com/file/(?P<id>\w+)/' + LC_OFFLINE_PATTERN = r'<p>http://www.filefactory.com/file/(?P<id>\w+)/</p>\s*<p class="errorResponse">' + FILE_OFFLINE_PATTERN = r'<title>File Not Found' FILE_NAME_PATTERN = r'<span class="last">(?P<name>.*?)</span>' FILE_INFO_PATTERN = r'<span>(?P<size>\d(\d|\.)*) (?P<units>..) file uploaded' - FILE_CHECK_PATTERN = r'check:\'(?P<check>.*?)\'' - CAPTCHA_KEY_PATTERN = r'Recaptcha.create\("(?P<recaptchakey>.*?)",' - WAIT_PATH_PATTERN = r'path:"(?P<path>.*?)"' + + FILE_CHECK_PATTERN = r'check:\s*\'(?P<check>.*?)\'' + CAPTCHA_KEY_PATTERN = r'Recaptcha.create\(\s*"(.*?)",' WAIT_PATTERN = r'id="startWait" value="(?P<wait>\d+)"' - FILE_URL_PATTERN = r'<a href="(?P<url>.*?)" id="downloadLinkTarget">' - + FILE_URL_PATTERN = r'<p[^>]*?id="downloadLinkTarget"[^>]*>\s*<a href="(?P<url>.*?)"' + def setup(self): - self.multiDL = False + self.multiDL = self.resumeDownloads = self.premium def process(self, pyfile): - - self.pyfile = pyfile + # Check file + pyfile.name, pyfile.size, status, self.url = checkFile(self, [pyfile.url])[0] + if status != 2: self.offline() + self.logDebug("File Name: %s Size: %d" % (pyfile.name, pyfile.size)) - # Force responses language to US English - self.req.cj.setCookie("filefactory.com", "ff_locale","") - - # Load main page - self.html = self.load(self.pyfile.url, ref=False, decode=True) - - # Check offline - if re.search(self.FILE_OFFLINE_PATTERN, self.html) is not None: - self.offline() + # Handle downloading + url = self.checkDirectDownload(pyfile.url) + if url: + self.download(url) + else: + self.html = self.load(pyfile.url, decode = True) + + if self.premium: + self.handlePremium() + else: + self.handleFree() + + def checkDirectDownload(self, url): + for i in range(5): + header = self.load(url, just_header = True) + if 'location' in header: + url = header['location'].strip() + if not url.startswith("http://"): + url = "http://www.filefactory.com" + url + self.logDebug('URL: ' + url) + elif 'content-disposition' in header: + return url - # File id - self.file_id = re.match(self.__pattern__, self.pyfile.url).group('id') - self.log.debug("%s: File id is [%s]" % (self.__name__, self.file_id)) - - # File name - self.pyfile.name = re.search(self.FILE_NAME_PATTERN, self.html).group('name') - - # Check Id - self.check = re.search(self.FILE_CHECK_PATTERN, self.html).group('check') - self.log.debug("%s: File check code is [%s]" % (self.__name__, self.check)) - - # Handle free downloading - self.handleFree() + return False def handleFree(self): - + if "Currently only Premium Members can download files larger than" in self.html: + self.fail("File too large for free download") + elif "All free download slots on this server are currently in use" in self.html: + self.retry(50, 900, "All free slots are busy") + + # Check Id + self.check = re.search(self.FILE_CHECK_PATTERN, self.html).group('check') + self.logDebug("File check code is [%s]" % self.check) + # Resolve captcha - self.log.debug("%s: File is captcha protected" % self.__name__) - id = re.search(self.CAPTCHA_KEY_PATTERN, self.html).group('recaptchakey') + found = re.search(self.CAPTCHA_KEY_PATTERN, self.html) + recaptcha_key = found.group(1) if found else "6LeN8roSAAAAAPdC1zy399Qei4b1BwmSBSsBN8zm" + recaptcha = ReCaptcha(self) + # Try up to 5 times - for i in range(5): - self.log.debug("%s: Resolving ReCaptcha with key [%s], round %d" % (self.__name__, id, i+1)) - recaptcha = ReCaptcha(self) - challenge, code = recaptcha.challenge(id) - response = self.load("http://www.filefactory.com/file/checkCaptcha.php", - post={"check" : self.check, "recaptcha_challenge_field" : challenge, "recaptcha_response_field" : code}) - captchavalid = self.handleCaptchaErrors(response) - if captchavalid: + for i in range(5): + challenge, code = recaptcha.challenge(recaptcha_key) + response = json_loads(self.load("http://www.filefactory.com/file/checkCaptcha.php", + post={"check" : self.check, "recaptcha_challenge_field" : challenge, "recaptcha_response_field" : code})) + if response['status'] == 'ok': + self.correctCaptcha() break - if not captchavalid: + else: + self.invalidCaptcha() + else: self.fail("No valid captcha after 5 attempts") - - # Get wait URL - waitpath = re.search(self.WAIT_PATH_PATTERN, response).group('path') - waiturl = "http://www.filefactory.com" + waitpath # This will take us to a wait screen - self.log.debug("%s: fetching wait with url [%s]" % (self.__name__, waiturl)) + waiturl = "http://www.filefactory.com" + response['path'] + self.logDebug("Fetching wait with url [%s]" % waiturl) waithtml = self.load(waiturl, decode=True) # Find the wait value and wait wait = int(re.search(self.WAIT_PATTERN, waithtml).group('wait')) - self.log.debug("%s: Waiting %d seconds." % (self.__name__, wait)) + self.logDebug("Waiting %d seconds." % wait) self.setWait(wait, True) self.wait() # Now get the real download url and retrieve the file url = re.search(self.FILE_URL_PATTERN,waithtml).group('url') # this may either download our file or forward us to an error page - self.log.debug("%s: download url %s" % (self.__name__, url)) + self.logDebug("Download URL: %s" % url) dl = self.download(url) check = self.checkDownload({"multiple": "You are currently downloading too many files at once.", @@ -124,17 +135,14 @@ class FilefactoryCom(Hoster): if check == "multiple": self.setWait(15*60) - self.log.debug("%s: Parallel downloads detected waiting 15 minutes" % self.__name__) + self.logDebug("Parallel downloads detected; waiting 15 minutes") self.wait() self.retry() elif check == "error": self.fail("Unknown error") - - def handleCaptchaErrors(self, response): - self.log.debug("%s: Result of captcha resolving [%s]" % (self.__name__, response)) - if 'status:"ok"' in response: - self.correctCaptcha() - return True + + def handlePremium(self): + self.fail('Please enable direct downloads') - self.log.debug("%s: Wrong captcha" % self.__name__) - self.invalidCaptcha() +def getInfo(urls): + for chunk in chunks(urls, 100): yield checkFile(FilefactoryCom, chunk) diff --git a/module/plugins/hoster/FilejungleCom.py b/module/plugins/hoster/FilejungleCom.py index c49cc8506..fd833eef2 100644 --- a/module/plugins/hoster/FilejungleCom.py +++ b/module/plugins/hoster/FilejungleCom.py @@ -16,70 +16,23 @@ @author: zoidberg """ -import re -from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo -from module.network.RequestFactory import getURL -from module.plugins.ReCaptcha import ReCaptcha +from module.plugins.hoster.FileserveCom import FileserveCom, checkFile +from module.plugins.Plugin import chunks -class FilejungleCom(SimpleHoster): +class FilejungleCom(FileserveCom): __name__ = "FilejungleCom" __type__ = "hoster" - __pattern__ = r"http://(?:www\.)?filejungle\.com/f/([^/]+).*" - __version__ = "0.25" + __pattern__ = r"http://(?:www\.)?filejungle\.com/f/(?P<id>[^/]+).*" + __version__ = "0.51" __description__ = """Filejungle.com plugin - free only""" __author_name__ = ("zoidberg") __author_mail__ = ("zoidberg@mujmail.cz") - - FILE_INFO_PATTERN = r'<div id="file_name">(?P<N>[^<]+) <span class="filename_normal">\((?P<S>[0-9.]+) (?P<U>[kKMG])i?B\)</span></div>' - FILE_OFFLINE_PATTERN = r'(This file is no longer available.</h1>|class="error_msg_title"> Invalid or Deleted File. </div>)' - RECAPTCHA_KEY_PATTERN = r"var reCAPTCHA_publickey='([^']+)'" - WAIT_TIME_PATTERN = r'<h1>Please wait for (\d+) seconds to download the next file\.</h1>' - - def handleFree(self): - file_id = re.search(self.__pattern__, self.pyfile.url).group(1) - url = "http://www.filejungle.com/f/%s" % file_id - self.logDebug("File ID: %s" % file_id) - - # Get captcha - found = re.search(self.RECAPTCHA_KEY_PATTERN, self.html) - if not found: self.fail("Captcha key not found") - captcha_key = found.group(1) - - json_response = self.load(self.pyfile.url, post = {"checkDownload" : "check"}, decode = True) - self.logDebug(json_response) - if r'"success":"showCaptcha"' in json_response: - recaptcha = ReCaptcha(self) - for i in range(5): - captcha_challenge, captcha_response = recaptcha.challenge(captcha_key) - self.logDebug("RECAPTCHA: %s : %s : %s" % (captcha_key, captcha_challenge, captcha_response)) - - json_response = self.load("http://www.filejungle.com/checkReCaptcha.php", post = { - "recaptcha_challenge_field" : captcha_challenge, - "recaptcha_response_field" : captcha_response, - "recaptcha_shortencode_field" : file_id - }, decode = True) - self.logDebug(json_response) - if r'{"success":1}' in json_response: - self.correctCaptcha() - break - else: - self.invalidCaptcha() - else: self.fail("Invalid captcha") - elif r'"fail":"timeLimit"' in json_response: - self.html = self.load(url, post = {"checkDownload" : "showError", "errorType" : "timeLimit"}) - found = re.search(self.WAIT_TIME_PATTERN, self.html) - self.retry(5, int(found.group(1)) if found else 1200, "Time limit reached") - else: - self.fail("Unknown server response") - - json_response = self.load(url, post = {"downloadLink" : "wait"}, decode = True) - self.logDebug(json_response[:30]) - found = re.search(r'"waitTime":(\d+)', json_response) - if not found: self.fail("Cannot get wait time") - self.setWait(int(found.group(1))) - self.wait() - - response = self.load(url, post = {"downloadLink" : "show"}) - self.download(url, post = {"download" : "normal"}) - -getInfo = create_getInfo(FilejungleCom) + + URLS = ['http://www.filejungle.com/f/', 'http://www.filejungle.com/check_links.php', 'http://www.filejungle.com/checkReCaptcha.php'] + LINKCHECK_TR = r'<li>\s*(<div class="col1">.*?)</li>' + LINKCHECK_TD = r'<div class="(?:col )?col\d">(?:<[^>]*>| )*([^<]*)' + + LONG_WAIT_PATTERN = r'<h1>Please wait for (\d+) (\w+)\s*to download the next file\.</h1>' + +def getInfo(urls): + for chunk in chunks(urls, 100): yield checkFile(FilejungleCom, chunk)
\ No newline at end of file diff --git a/module/plugins/hoster/FilepostCom.py b/module/plugins/hoster/FilepostCom.py index 834ad7199..bc47856e5 100644 --- a/module/plugins/hoster/FilepostCom.py +++ b/module/plugins/hoster/FilepostCom.py @@ -14,6 +14,11 @@ along with this program; if not, see <http://www.gnu.org/licenses/>. @author: zoidberg + + changelog: + 0.27 - 2012-08-12 - hgg + fix "global name 'js_answer' is not defined" bug + fix captcha bug #1 (failed on non-english "captcha wrong" errors) """ import re @@ -26,7 +31,7 @@ class FilepostCom(SimpleHoster): __name__ = "FilepostCom" __type__ = "hoster" __pattern__ = r"https?://(?:www\.)?(?:filepost\.com/files|fp.io)/([^/]+).*" - __version__ = "0.26" + __version__ = "0.27" __description__ = """Filepost.com plugin - free only""" __author_name__ = ("zoidberg") __author_mail__ = ("zoidberg@mujmail.cz") @@ -81,7 +86,7 @@ class FilepostCom(SimpleHoster): get_dict['JsHttpRequest'] = str(int(time()*10000)) + '-xml' if pokus: post_dict["recaptcha_challenge_field"], post_dict["recaptcha_response_field"] = recaptcha.challenge(captcha_key) - self.logDebug(u"RECAPTCHA: %s : %s : %s" % (captcha_key, post_dict["recaptcha_challenge_field"], post_dict["recaptcha_response_field"])) + self.logDebug(u"RECAPTCHA: %s : %s : %s" % (captcha_key, post_dict["recaptcha_challenge_field"], post_dict["recaptcha_response_field"])) download_url = self.getJsonResponse(get_dict, post_dict, 'link') if download_url: @@ -101,19 +106,30 @@ class FilepostCom(SimpleHoster): if not 'js' in json_response: self.parseError('JSON %s 1' % field) + # i changed js_answer to json_response['js'] since js_answer is nowhere set. + # i don't know the JSON-HTTP specs in detail, but the previous author + # accessed json_response['js']['error'] as well as js_answer['error']. + # see the two lines commented out with "# ~?". if 'error' in json_response['js']: if json_response['js']['error'] == 'download_delay': - self.retry(js_answer['params']['next_download']) + self.retry(json_response['js']['params']['next_download']) + # ~? self.retry(js_answer['params']['next_download']) elif 'Wrong file password' in json_response['js']['error']: return None elif 'You entered a wrong CAPTCHA code' in json_response['js']['error']: return None + elif 'CAPTCHA Code nicht korrekt' in json_response['js']['error']: + return None + elif 'CAPTCHA' in json_response['js']['error']: + self.logDebug('error response is unknown, but mentions CAPTCHA -> return None') + return None else: - self.fail(js_answer['error']) + self.fail(json_response['js']['error']) + # ~? self.fail(js_answer['error']) if not 'answer' in json_response['js'] or not field in json_response['js']['answer']: self.parseError('JSON %s 2' % field) return json_response['js']['answer'][field] -getInfo = create_getInfo(FilepostCom)
\ No newline at end of file +getInfo = create_getInfo(FilepostCom) diff --git a/module/plugins/hoster/FilerioCom.py b/module/plugins/hoster/FilerioCom.py new file mode 100644 index 000000000..3d983bedf --- /dev/null +++ b/module/plugins/hoster/FilerioCom.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo + +class FilerioCom(XFileSharingPro): + __name__ = "FilerioCom" + __type__ = "hoster" + __pattern__ = r"http://(?:\w*\.)*file(rio|keen).com/\w{12}" + __version__ = "0.01" + __description__ = """FileRio.com hoster plugin""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + FILE_OFFLINE_PATTERN = '<b>"File Not Found"</b>|File has been removed due to Copyright Claim' + HOSTER_NAME = "filerio.com" + DIRECT_LINK_PATTERN = r'Download Link:.*?<a href="(.*?)"' + + def setup(self): + self.multiDL = False + +getInfo = create_getInfo(FilerioCom)
\ No newline at end of file diff --git a/module/plugins/hoster/FileserveCom.py b/module/plugins/hoster/FileserveCom.py index ce3836a48..04c297661 100644 --- a/module/plugins/hoster/FileserveCom.py +++ b/module/plugins/hoster/FileserveCom.py @@ -1,168 +1,211 @@ -# -*- coding: utf-8 -*-
-from __future__ import with_statement
-
-import re
-
-from module.plugins.Hoster import Hoster
-from module.plugins.ReCaptcha import ReCaptcha
-
-from module.common.json_layer import json_loads
-from module.network.RequestFactory import getURL
-from module.utils import parseFileSize
-
-
-def getInfo(urls):
- yield [(url, 0, 1, url) for url in urls]
-
-class FileserveCom(Hoster):
- __name__ = "FileserveCom"
- __type__ = "hoster"
- __pattern__ = r"http://(www\.)?fileserve\.com/file/[a-zA-Z0-9]+"
- __version__ = "0.44"
- __description__ = """Fileserve.Com File Download Hoster"""
- __author_name__ = ("jeix", "mkaay", "paul king")
- __author_mail__ = ("jeix@hasnomail.de", "mkaay@mkaay.de", "")
-
- FILE_ID_KEY = r"fileserve\.com/file/(?P<id>\w+)"
- FILE_CHECK_KEY = r"<td>http://www.fileserve\.com/file/(?P<id>\w+)</td>.*?<td>(?P<name>.*?)</td>.*?<td>(?P<units>.*?) (?P<scale>.B)</td>.*?<td>(?P<online>.*?)</td>"
- CAPTCHA_KEY_PATTERN = r"var reCAPTCHA_publickey='(?P<key>.*?)';"
- LONG_WAIT_PATTERN = r"You need to wait (\d+) seconds to start another download"
-
- def init(self):
- if not self.premium:
- self.multiDL = False
- self.resumeDownload = False
- self.chunkLimit = 1
-
- def process(self, pyfile):
- self.fail("Hoster not longer available")
-
- def checkFile(self):
- self.file_id = re.search(self.FILE_ID_KEY, self.pyfile.url).group("id")
- self.logDebug("file id is %s" % self.file_id)
-
- self.pyfile.url = "http://www.fileserve.com/file/" + self.file_id
-
- linkCheck = self.load("http://www.fileserve.com/link-checker.php",
- post={"urls": self.pyfile.url},
- ref=False, cookies=False if self.account else True, decode=True)
-
- linkMatch = re.search(self.FILE_CHECK_KEY, linkCheck.replace("\r\n", ""))
- if not linkMatch:
- self.logDebug("couldn't extract file status")
- self.offline()
-
- if linkMatch.group("online").find("Available"):
- self.logDebug("file is not available : %s" % linkMatch.group("online"))
- self.offline()
-
- self.pyfile.name = linkMatch.group("name")
-
-
- def handlePremium(self):
- # TODO: handle login timeouts
- self.download(self.pyfile.url)
-
- check = self.checkDownload({"login": '<form action="/login.php" method="POST">'})
-
- if check == "login":
- self.account.relogin(self.user)
- self.retry(reason=_("Not logged in."))
-
-
- def handleFree(self):
- self.html = self.load(self.pyfile.url)
- action = self.load(self.pyfile.url, post={"checkDownload": "check"}, decode=True)
- action = json_loads(action.replace(u"\ufeff", ""))
- self.logDebug("action is : %s" % action)
-
- if "fail" in action:
- if action["fail"] == "timeLimit":
- html = self.load(self.pyfile.url,
- post={"checkDownload": "showError",
- "errorType": "timeLimit"},
- decode=True)
- wait = re.search(self.LONG_WAIT_PATTERN, html)
- if wait:
- wait = int(wait.group(1))
- else:
- wait = 720
- self.setWait(wait, True)
- self.wait()
- self.retry()
-
- elif action["fail"] == "parallelDownload":
- self.logWarning(_("Parallel download error, now waiting 60s."))
- self.retry(wait_time=60, reason="parallelDownload")
-
- else:
- self.fail("Download check returned %s" % action["fail"])
-
- if action["success"] == "showCaptcha":
- self.doCaptcha()
- self.doTimmer()
- elif action["success"] == "showTimmer":
- self.doTimmer()
-
- # show download link
- response = self.load(self.pyfile.url, post={"downloadLink": "show"}, decode=True)
- self.logDebug("show downloadLink response : %s" % response)
- if not response.find("fail"):
- self.fail("Couldn't retrieve download url")
-
- # this may either download our file or forward us to an error page
- self.download(self.pyfile.url, post={"download": "normal"})
-
- check = self.checkDownload({"expired": "Your download link has expired",
- "wait": re.compile(self.LONG_WAIT_PATTERN),
- "limit": "Your daily download limit has been reached"})
-
- if check == "expired":
- self.logDebug("Download link was expired")
- self.retry()
- elif check == "wait":
- wait_time = 720
- if self.lastCheck is not None:
- wait_time = int(self.lastCheck.group(1))
- self.setWait(wait_time + 3, True)
- self.wait()
- self.retry()
- elif check == "limit":
- #download limited reached for today (not a exact time known)
-
- self.setWait(180 * 60, True) # wait 3 hours
- self.wait()
- self.retry(max_tries=0)
-
- self.thread.m.reconnecting.wait(3) # Ease issue with later downloads appearing to be in parallel
-
- def doTimmer(self):
- wait = self.load(self.pyfile.url,
- post={"downloadLink": "wait"},
- decode=True).replace(u"\ufeff", "") # remove UTF8 BOM
- self.logDebug("wait response : %s" % wait)
-
- if not wait.find("fail"):
- self.fail("Failed getting wait time")
-
- self.setWait(int(wait)) # remove UTF8 BOM
- self.wait()
-
- def doCaptcha(self):
- captcha_key = re.search(self.CAPTCHA_KEY_PATTERN, self.html).group("key")
- recaptcha = ReCaptcha(self)
-
- for i in range(5):
- challenge, code = recaptcha.challenge(captcha_key)
-
- response = json_loads(self.load("http://www.fileserve.com/checkReCaptcha.php",
- post={'recaptcha_challenge_field': challenge,
- 'recaptcha_response_field': code,
- 'recaptcha_shortencode_field': self.file_id}).replace(u"\ufeff", ""))
- self.logDebug("reCaptcha response : %s" % response)
- if not response["success"]:
- self.invalidCaptcha()
- else:
- self.correctCaptcha()
- break
-
+# -*- 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/>. +""" + +import re +from module.plugins.Hoster import Hoster +from module.network.RequestFactory import getURL +from module.plugins.ReCaptcha import ReCaptcha +from module.common.json_layer import json_loads +from module.utils import parseFileSize +from module.plugins.Plugin import chunks + +def checkFile(plugin, urls): + html = getURL(plugin.URLS[1], post = {"urls": "\n".join(urls)}, decode=True) + + file_info = [] + for li in re.finditer(plugin.LINKCHECK_TR, html, re.DOTALL): + try: + cols = re.findall(plugin.LINKCHECK_TD, li.group(1)) + if cols: + file_info.append(( + cols[1] if cols[1] != '--' else cols[0], + parseFileSize(cols[2]) if cols[2] != '--' else 0, + 2 if cols[3].startswith('Available') else 1, + cols[0])) + except Exception, e: + continue + + return file_info + +class FileserveCom(Hoster): + __name__ = "FileserveCom" + __type__ = "hoster" + __pattern__ = r"http://(?:www\.)?fileserve\.com/file/(?P<id>[^/]+).*" + __version__ = "0.51" + __description__ = """Fileserve.Com File Download Hoster""" + __author_name__ = ("jeix", "mkaay", "paul king", "zoidberg") + __author_mail__ = ("jeix@hasnomail.de", "mkaay@mkaay.de", "", "zoidberg@mujmail.cz") + + URLS = ['http://www.fileserve.com/file/', 'http://www.fileserve.com/link-checker.php', 'http://www.fileserve.com/checkReCaptcha.php'] + LINKCHECK_TR = r'<tr>\s*(<td>http://www.fileserve\.com/file/.*?)</tr>' + LINKCHECK_TD = r'<td>(?:<[^>]*>| )*([^<]*)' + + CAPTCHA_KEY_PATTERN = r"var reCAPTCHA_publickey='(?P<key>[^']+)'" + LONG_WAIT_PATTERN = r'<li class="title">You need to wait (\d+) (\w+) to start another download\.</li>' + LINK_EXPIRED_PATTERN = "Your download link has expired" + DAILY_LIMIT_PATTERN = "Your daily download limit has been reached" + NOT_LOGGED_IN_PATTERN = '<form (name="loginDialogBoxForm"|id="login_form")|<li><a href="/login.php">Login</a></li>' + + # shares code with FilejungleCom and UploadstationCom + + def setup(self): + self.resumeDownload = self.multiDL = True if self.premium else False + + self.file_id = re.search(self.__pattern__, self.pyfile.url).group('id') + self.url = "%s%s" % (self.URLS[0], self.file_id) + self.logDebug("File ID: %s URL: %s" % (self.file_id, self.url)) + + def process(self, pyfile): + pyfile.name, pyfile.size, status, self.url = checkFile(self, [self.url])[0] + if status != 2: self.offline() + self.logDebug("File Name: %s Size: %d" % (pyfile.name, pyfile.size)) + + if self.premium: + self.handlePremium() + else: + self.handleFree() + + def handleFree(self): + self.html = self.load(self.url) + action = self.load(self.url, post={"checkDownload": "check"}, decode=True) + action = json_loads(action) + self.logDebug(action) + + if "fail" in action: + if action["fail"] == "timeLimit": + self.html = self.load(self.url, + post={"checkDownload": "showError", + "errorType": "timeLimit"}, + decode=True) + + self.doLongWait(re.search(self.LONG_WAIT_PATTERN, self.html)) + + elif action["fail"] == "parallelDownload": + self.logWarning(_("Parallel download error, now waiting 60s.")) + self.retry(wait_time=60, reason="parallelDownload") + + else: + self.fail("Download check returned %s" % action["fail"]) + + elif "success" in action: + if action["success"] == "showCaptcha": + self.doCaptcha() + self.doTimmer() + elif action["success"] == "showTimmer": + self.doTimmer() + + else: + self.fail("Unknown server response") + + # show download link + response = self.load(self.url, post={"downloadLink": "show"}, decode=True) + self.logDebug("show downloadLink response : %s" % response) + if "fail" in response: + self.fail("Couldn't retrieve download url") + + # this may either download our file or forward us to an error page + self.download(self.url, post = {"download": "normal"}) + self.logDebug(self.req.http.lastEffectiveURL) + + check = self.checkDownload({"expired": self.LINK_EXPIRED_PATTERN, + "wait": re.compile(self.LONG_WAIT_PATTERN), + "limit": self.DAILY_LIMIT_PATTERN}) + + if check == "expired": + self.logDebug("Download link was expired") + self.retry() + elif check == "wait": + self.doLongWait(self.lastCheck) + elif check == "limit": + #download limited reached for today (not a exact time known) + self.setWait(180 * 60, True) # wait 3 hours + self.wait() + self.retry(max_tries=0) + + self.thread.m.reconnecting.wait(3) # Ease issue with later downloads appearing to be in parallel + + def doTimmer(self): + response = self.load(self.url, + post={"downloadLink": "wait"}, + decode=True) + self.logDebug("wait response : %s" % response[:80]) + + if "fail" in response: + self.fail("Failed getting wait time") + + if self.__name__ == "FilejungleCom": + found = re.search(r'"waitTime":(\d+)', response) + if not found: self.fail("Cannot get wait time") + wait_time = int(found.group(1)) + else: + wait_time = int(response) + 3 + + self.setWait(wait_time) + self.wait() + + def doCaptcha(self): + captcha_key = re.search(self.CAPTCHA_KEY_PATTERN, self.html).group("key") + recaptcha = ReCaptcha(self) + + for i in range(5): + challenge, code = recaptcha.challenge(captcha_key) + + response = json_loads(self.load(self.URLS[2], + post={'recaptcha_challenge_field': challenge, + 'recaptcha_response_field': code, + 'recaptcha_shortencode_field': self.file_id})) + self.logDebug("reCaptcha response : %s" % response) + if not response["success"]: + self.invalidCaptcha() + else: + self.correctCaptcha() + break + else: self.fail("Invalid captcha") + + def doLongWait(self, m): + wait_time = (int(m.group(1)) * {'seconds':1, 'minutes':60, 'hours':3600}[m.group(2)]) if m else 720 + self.setWait(wait_time, True) + self.wait() + self.retry() + + def handlePremium(self): + premium_url = None + if self.__name__ == "FileserveCom": + #try api download + response = self.load("http://app.fileserve.com/api/download/premium/", + post = {"username": self.user, + "password": self.account.getAccountData(self.user)["password"], + "shorten": self.file_id}, + decode = True) + if response: + response = json_loads(response) + if response['error_code'] == "302": premium_url = response['next'] + elif response['error_code'] in ["305", "500"]: self.tempOffline() + elif response['error_code'] in ["403", "605"]: self.resetAccount() + elif response['error_code'] in ["606", "607", "608"]: self.offline() + else: self.logError(response['error_code'], response['error_message']) + + self.download(premium_url or self.pyfile.url) + + if not premium_url: + check = self.checkDownload({"login": re.compile(self.NOT_LOGGED_IN_PATTERN)}) + + if check == "login": + self.account.relogin(self.user) + self.retry(reason=_("Not logged in.")) + +def getInfo(urls): + for chunk in chunks(urls, 100): yield checkFile(FileserveCom, chunk)
\ No newline at end of file diff --git a/module/plugins/hoster/FourSharedCom.py b/module/plugins/hoster/FourSharedCom.py index 2b27eed28..551706283 100644 --- a/module/plugins/hoster/FourSharedCom.py +++ b/module/plugins/hoster/FourSharedCom.py @@ -7,33 +7,45 @@ import re class FourSharedCom(SimpleHoster): __name__ = "FourSharedCom" __type__ = "hoster" - __pattern__ = r"http://[\w\.]*?4shared(-china)?\.com/(account/)?(download|get|file|document|photo|video|audio)/.+?/.*" - __version__ = "0.25" + __pattern__ = r"http://[\w\.]*?4shared(-china)?\.com/(account/)?(download|get|file|document|photo|video|audio|office)/.+?/.*" + __version__ = "0.28" __description__ = """4Shared Download Hoster""" __author_name__ = ("jeix", "zoidberg") __author_mail__ = ("jeix@hasnomail.de", "zoidberg@mujmail.cz") - FILE_NAME_PATTERN = '<meta name="title" content="(?P<N>[^"]+)" />' + FILE_NAME_PATTERN = r'<meta name="title" content="(?P<N>.+?)"' FILE_SIZE_PATTERN = '<span title="Size: (?P<S>[0-9,.]+) (?P<U>[kKMG])i?B">' FILE_OFFLINE_PATTERN = 'The file link that you requested is not valid\.|This file was deleted.' FILE_NAME_REPLACEMENTS = [(r"&#(\d+).", lambda m: unichr(int(m.group(1))))] + FILE_SIZE_REPLACEMENTS = [(",", "")] - DOWNLOAD_BUTTON_PATTERN = '<a href="([^"]+)"\s*class="dbtn' - DOWNLOAD_URL_PATTERN = r"<a class=\"linkShowD3\" href='([^']+)'>Download file now</a>" + DOWNLOAD_BUTTON_PATTERN = 'id="btnLink" href="(.*?)"' + FID_PATTERN = 'name="d3fid" value="(.*?)"' + DOWNLOAD_URL_PATTERN = r'name="d3link" value="(.*?)"' def handleFree(self): + if not self.account: + self.fail("User not logged in") + found = re.search(self.DOWNLOAD_BUTTON_PATTERN, self.html) if found: link = found.group(1) else: link = re.sub(r'/(download|get|file|document|photo|video|audio)/', r'/get/', self.pyfile.url) - + self.html = self.load(link) found = re.search(self.DOWNLOAD_URL_PATTERN, self.html) if not found: self.parseError('Download link') link = found.group(1) + try: + found = re.search(self.FID_PATTERN, self.html) + response = self.load('http://www.4shared.com/web/d2/getFreeDownloadLimitInfo?fileId=%s' % found.group(1)) + self.logDebug(response) + except: + pass + self.setWait(20) self.wait() self.download(link) diff --git a/module/plugins/hoster/FreakshareCom.py b/module/plugins/hoster/FreakshareCom.py index 869b8a99e..56e02cbdc 100644 --- a/module/plugins/hoster/FreakshareCom.py +++ b/module/plugins/hoster/FreakshareCom.py @@ -9,10 +9,10 @@ class FreakshareCom(Hoster): __name__ = "FreakshareCom"
__type__ = "hoster"
__pattern__ = r"http://(?:www\.)?freakshare\.(net|com)/files/\S*?/"
- __version__ = "0.33"
+ __version__ = "0.37"
__description__ = """Freakshare.com Download Hoster"""
- __author_name__ = ("sitacuisses","spoob","mkaay")
- __author_mail__ = ("sitacuisses@yahoo.de","spoob@pyload.org","mkaay@mkaay.de")
+ __author_name__ = ("sitacuisses","spoob","mkaay", "Toilal")
+ __author_mail__ = ("sitacuisses@yahoo.de","spoob@pyload.org","mkaay@mkaay.de", "toilal.dev@gmail.com")
def setup(self):
self.html = None
@@ -22,6 +22,7 @@ class FreakshareCom(Hoster): def process(self, pyfile):
self.pyfile = pyfile
+
pyfile.url = pyfile.url.replace("freakshare.net/","freakshare.com/")
if self.account:
@@ -36,10 +37,22 @@ class FreakshareCom(Hoster): self.download(self.pyfile.url, post=self.req_opts)
- check = self.checkDownload({"bad": "bad try"})
+ check = self.checkDownload({"bad": "bad try",
+ "paralell": "> Sorry, you cant download more then 1 files at time. <",
+ "empty": "Warning: Unknown: Filename cannot be empty",
+ "wrong_captcha": "Wrong Captcha!"})
+
if check == "bad":
self.fail("Bad Try.")
-
+ if check == "paralell":
+ self.setWait(300, True)
+ self.wait()
+ self.retry()
+ if check == "empty":
+ self.fail("File not downloadable")
+ if check == "wrong_captcha":
+ self.invalidCaptcha()
+ self.retry()
def prepare(self):
pyfile = self.pyfile
@@ -61,6 +74,7 @@ class FreakshareCom(Hoster): return True
def download_html(self):
+ self.load("http://freakshare.com/index.php", {"language": "EN"}); # Set english language in server session
self.html = self.load(self.pyfile.url)
def get_file_url(self):
@@ -105,16 +119,11 @@ class FreakshareCom(Hoster): if self.html is None:
self.download_html()
- if "Der Traffic f\xc3\xbcr heute ist verbraucht!" in self.html or "Your Traffic is used up for today" in self.html:
+ if "Your Traffic is used up for today" in self.html:
self.wantReconnect = True
return 24*3600
- if re.search(r"This file does not exist!", self.html) is not None:
- self.offline()
- timestring = re.search('\s*var\sdownloadWait\s=\s(\d*);', self.html)
- if timestring:
- return int(timestring.group(1)) + 1 #add 1 sec as tenths of seconds are cut off
- timestring = re.search('\s*var\stime\s=\s(\d*)[.0];', self.html)
+ timestring = re.search('\s*var\s(?:downloadWait|time)\s=\s(\d*)[.\d]*;', self.html)
if timestring:
return int(timestring.group(1)) + 1 #add 1 sec as tenths of seconds are cut off
else:
@@ -126,7 +135,7 @@ class FreakshareCom(Hoster): """
if self.html is None:
self.download_html()
- if re.search(r"Sorry, this Download doesnt exist anymore", self.html) is not None:
+ if re.search(r"This file does not exist!", self.html) is not None:
return False
else:
return True
@@ -134,10 +143,7 @@ class FreakshareCom(Hoster): def get_download_options(self):
re_envelope = re.search(r".*?value=\"Free\sDownload\".*?\n*?(.*?<.*?>\n*)*?\n*\s*?</form>", self.html).group(0) #get the whole request
to_sort = re.findall(r"<input\stype=\"hidden\"\svalue=\"(.*?)\"\sname=\"(.*?)\"\s\/>", re_envelope)
- request_options = []
-
- for item in to_sort: #Name value pairs are output reversed from regex, so we reorder them
- request_options.append((item[1], item[0]))
+ request_options = dict((n, v) for (v, n) in to_sort)
herewego = self.load(self.pyfile.url, None, request_options) # the actual download-Page
@@ -146,21 +152,16 @@ class FreakshareCom(Hoster): # fp.write(herewego)
to_sort = re.findall(r"<input\stype=\".*?\"\svalue=\"(\S*?)\".*?name=\"(\S*?)\"\s.*?\/>", herewego)
- request_options = []
+ request_options = dict((n, v) for (v, n) in to_sort)
# comment this in, when it doesnt work as well
#print "\n\n%s\n\n" % ";".join(["%s=%s" % x for x in to_sort])
-
- for item in to_sort: #Same as above
- request_options.append((item[1], item[0]))
challenge = re.search(r"http://api\.recaptcha\.net/challenge\?k=([0-9A-Za-z]+)", herewego)
if challenge:
re_captcha = ReCaptcha(self)
- challenge, result = re_captcha.challenge(challenge.group(1))
-
- request_options.append(("recaptcha_challenge_field", challenge))
- request_options.append(("recaptcha_response_field", result))
+ request_options["recaptcha_challenge_field"], request_options["recaptcha_response_field"] \
+ = re_captcha.challenge(challenge.group(1))
return request_options
diff --git a/module/plugins/hoster/FshareVn.py b/module/plugins/hoster/FshareVn.py index 5a8b00c17..977e97211 100644 --- a/module/plugins/hoster/FshareVn.py +++ b/module/plugins/hoster/FshareVn.py @@ -16,23 +16,27 @@ def getInfo(urls): yield file_info +def doubleDecode(m): + return m.group(1).decode('raw_unicode_escape') + class FshareVn(SimpleHoster): __name__ = "FshareVn" __type__ = "hoster" __pattern__ = r"http://(www\.)?fshare.vn/file/.*" - __version__ = "0.12" + __version__ = "0.13" __description__ = """FshareVn Download Hoster""" __author_name__ = ("zoidberg") __author_mail__ = ("zoidberg@mujmail.cz") - FILE_INFO_PATTERN = r'<p>(?P<N>[^<]+)<\\/p>\\r\\n\s*<p>(?P<S>[0-9,.]+)\s*(?P<U>[kKMG])i?B<\\/p>' + FILE_INFO_PATTERN = r'<p>(?P<N>[^<]+)<\\/p>[\\trn\s]*<p>(?P<S>[0-9,.]+)\s*(?P<U>[kKMG])i?B<\\/p>' FILE_OFFLINE_PATTERN = r'<div class=\\"f_left file_(enable|w)\\">' + FILE_NAME_REPLACEMENTS = [("(.*)", doubleDecode)] DOWNLOAD_URL_PATTERN = r"<a class=\"bt_down\" id=\"down\".*window.location='([^']+)'\">" FORM_PATTERN = r'<form action="" method="post" name="frm_download">(.*?)</form>' FORM_INPUT_PATTERN = r'<input[^>]* name="?([^" ]+)"? value="?([^" ]+)"?[^>]*>' VIP_URL_PATTERN = r'<form action="([^>]+)" method="get" name="frm_download">' - WAIT_PATTERN = u"Vui lòng chờ cho lượt download kế tiếp !" + WAIT_PATTERN = u"Vui lòng chờ lượt download kế tiếp" def process(self, pyfile): self.html = self.load('http://www.fshare.vn/check_link.php', post = { @@ -40,15 +44,17 @@ class FshareVn(SimpleHoster): "arrlinks": pyfile.url }, decode = True) self.getFileInfo() - if self.account and self.premium: - self.handlePremium() - else: - self.handleFree() + + url = self.handlePremium() if self.premium else self.handleFree() + self.download(url) + self.checkDownloadedFile() def handleFree(self): self.html = self.load(self.pyfile.url, decode = True) if self.WAIT_PATTERN in self.html: - self.retry(300, 20, "Try again later...") + self.retry(20, 300, "Try again later...") + + self.checkErrors() found = re.search(self.FORM_PATTERN, self.html, re.DOTALL) if not found: self.parseError('FORM') @@ -68,15 +74,18 @@ class FshareVn(SimpleHoster): self.setWait(int(found.group(1)) if found else 30) self.wait() - self.download(url) + return url def handlePremium(self): header = self.load(self.pyfile.url, just_header = True) if 'location' in header and header['location'].startswith('http://download'): self.logDebug('Direct download') - self.download(self.pyfile.url) + return self.pyfile.url else: self.html = self.load(self.pyfile.url) + + self.checkErrors() + found = re.search(self.VIP_URL_PATTERN, self.html) if not found: if self.retries >= 3: self.resetAccount() @@ -84,4 +93,17 @@ class FshareVn(SimpleHoster): self.retry(5, 1, 'VIP URL not found') url = found.group(1) self.logDebug('VIP URL: ' + url) - self.download(url)
\ No newline at end of file + return url + + def checkErrors(self): + if '/error.php?' in self.req.lastEffectiveURL: + self.offline() + + def checkDownloadedFile(self): + # check download + check = self.checkDownload({ + "not_found": ("<head><title>404 Not Found</title></head>") + }) + + if check == "not_found": + self.fail("File not found on server")
\ No newline at end of file diff --git a/module/plugins/hoster/GigapetaCom.py b/module/plugins/hoster/GigapetaCom.py new file mode 100644 index 000000000..28ba35abe --- /dev/null +++ b/module/plugins/hoster/GigapetaCom.py @@ -0,0 +1,73 @@ +# -*- 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 random import randint +from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo +from pycurl import FOLLOWLOCATION + +class GigapetaCom(SimpleHoster): + __name__ = "GigapetaCom" + __type__ = "hoster" + __pattern__ = r"http://(?:www\.)?gigapeta\.com/dl/\w+" + __version__ = "0.01" + __description__ = """GigaPeta.com plugin - free only""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + SH_COOKIES = [("http://gigapeta.com", "lang", "us")] + FILE_NAME_PATTERN = r'<img src=".*" alt="file" />-->\s*(?P<N>.*?)\s*</td>' + FILE_SIZE_PATTERN = r'<th>\s*Size\s*</th>\s*<td>\s*(?P<S>.*?)\s*</td>' + FILE_OFFLINE_PATTERN = r'<div id="page_error">' + + def handleFree(self): + captcha_key = str(randint(1,100000000)) + captcha_url = "http://gigapeta.com/img/captcha.gif?x=%s" % captcha_key + + self.req.http.c.setopt(FOLLOWLOCATION, 0) + + for i in range(5): + self.checkErrors() + + captcha = self.decryptCaptcha(captcha_url) + self.html = self.load(self.pyfile.url, post = { + "captcha_key": captcha_key, + "captcha": captcha, + "download": "Download"}) + + found = re.search(r"Location\s*:\s*(.*)", self.req.http.header, re.I) + if found: + download_url = found.group(1) + break + elif "Entered figures don`t coincide with the picture" in self.html: + self.invalidCaptcha() + else: + self.fail("No valid captcha code entered") + + self.req.http.c.setopt(FOLLOWLOCATION, 1) + self.logDebug("Download URL: %s" % download_url) + self.download(download_url) + + def checkErrors(self): + if "All threads for IP" in self.html: + self.logDebug("Your IP is already downloading a file - wait and retry") + self.setWait(300, True) + self.wait() + self.retry() + +getInfo = create_getInfo(GigapetaCom)
\ No newline at end of file diff --git a/module/plugins/hoster/HellshareCz.py b/module/plugins/hoster/HellshareCz.py index cc8341f8e..0add79ed9 100644 --- a/module/plugins/hoster/HellshareCz.py +++ b/module/plugins/hoster/HellshareCz.py @@ -26,7 +26,7 @@ class HellshareCz(SimpleHoster): __name__ = "HellshareCz" __type__ = "hoster" __pattern__ = r"(http://(?:.*\.)*hellshare\.(?:cz|com|sk|hu)/[^?]*/\d+).*" - __version__ = "0.76" + __version__ = "0.77" __description__ = """Hellshare.cz""" __author_name__ = ("zoidberg") @@ -46,18 +46,15 @@ class HellshareCz(SimpleHoster): self.chunkLimit = 1 def process(self, pyfile): - if self.account: - self.account.relogin(self.user) - pyfile.url = re.search(self.__pattern__, pyfile.url).group(1) self.html = self.load(pyfile.url, decode = True) self.getFileInfo() found = re.search(self.SHOW_WINDOW_PATTERN, self.html) if not found: self.parseError('SHOW WINDOW') - url = found.group(1) - self.logDebug("SHOW WINDOW: " + url) - self.html = self.load("http://download.hellshare.com" + url, decode=True) + self.url = "http://www.hellshare.com" + found.group(1) + self.logDebug("SHOW WINDOW: " + self.url) + self.html = self.load(self.url, decode=True) if self.account: self.handlePremium() diff --git a/module/plugins/hoster/HotfileCom.py b/module/plugins/hoster/HotfileCom.py index e618d0f4f..df652edcc 100644 --- a/module/plugins/hoster/HotfileCom.py +++ b/module/plugins/hoster/HotfileCom.py @@ -32,24 +32,26 @@ class HotfileCom(Hoster): __name__ = "HotfileCom" __type__ = "hoster" __pattern__ = r"http://(www.)?hotfile\.com/dl/\d+/[0-9a-zA-Z]+/" - __version__ = "0.32" + __version__ = "0.34" __description__ = """Hotfile.com Download Hoster""" - __author_name__ = ("sitacuisses","spoob","mkaay") - __author_mail__ = ("sitacuisses@yhoo.de","spoob@pyload.org","mkaay@mkaay.de") + __author_name__ = ("sitacuisses","spoob","mkaay","JoKoT3") + __author_mail__ = ("sitacuisses@yhoo.de","spoob@pyload.org","mkaay@mkaay.de","jokot3@gmail.com") FILE_OFFLINE_PATTERN = r'File is removed' def setup(self): self.html = [None, None] self.wantReconnect = False - self.multiDL = False self.htmlwithlink = None self.url = None - if self.account: + if self.premium: self.multiDL = True self.resumeDownload = True self.chunkLimit = -1 + else: + self.multiDL = False + self.chunkLimit = 1 def apiCall(self, method, post, login=False): if not self.account and login: @@ -73,7 +75,7 @@ class HotfileCom(Hoster): pyfile.name = self.apiData["name"] - if not self.account: + if not self.premium: self.downloadHTML() if self.FILE_OFFLINE_PATTERN in self.html[0]: @@ -127,14 +129,9 @@ class HotfileCom(Hoster): free_limit_pattern = re.compile(r"timerend=d\.getTime\(\)\+(\d+);") matches = free_limit_pattern.findall(self.html[0]) if matches: - for match in matches: - if int(match) in (60000,15000,0): - continue - else: - waittime = int(match)/1000 + 65 - if waittime > 300: - self.wantReconnect = True - return waittime - return 65 + wait_time = (sum([int(match) for match in matches])/1000) or 60 + if wait_time > 300: + self.wantReconnect = True + return wait_time + 1 else: - self.fail("Don't know how long to wait. Cannot proceed.") + self.fail("Don't know how long to wait. Cannot proceed.")
\ No newline at end of file diff --git a/module/plugins/hoster/IcyFilesCom.py b/module/plugins/hoster/IcyFilesCom.py new file mode 100644 index 000000000..3f966d936 --- /dev/null +++ b/module/plugins/hoster/IcyFilesCom.py @@ -0,0 +1,112 @@ +# -*- 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: godofdream +""" + +import re +from module.plugins.Hoster import Hoster +from module.network.RequestFactory import getURL + +def getInfo(urls): + result = [] + for url in urls: + html = getURL(url, decode=True) + if re.search(IcyFilesCom.FILE_OFFLINE_PATTERN, html): + # File offline + result.append((url, 0, 1, url)) + else: + # Get file info + name = re.search(IcyFilesCom.FILE_NAME_PATTERN, html) + size = re.search(IcyFilesCom.SIZE_PATTERN, html) + if name is not None: + name = name.group(1) + size = (int(size.group(1)) * 1000000) + result.append((name, size, 2, url)) + yield result + + +class IcyFilesCom(Hoster): + __name__ = "IcyFilesCom" + __type__ = "hoster" + __pattern__ = r"http://(?:www\.)?icyfiles\.com/(.*)" + __version__ = "0.04" + __description__ = """IcyFiles.com plugin - free only""" + __author_name__ = ("godofdream") + __author_mail__ = ("soilfiction@gmail.com") + + FILE_NAME_PATTERN = r'<div id="file">(.*?)</div>' + SIZE_PATTERN = r'<li>(\d+) <span>Size/mb' + FILE_OFFLINE_PATTERN = r'The requested File cant be found' + WAIT_LONGER_PATTERN = r'All download tickets are in use\. please try it again in a few seconds' + WAIT_PATTERN = r'<div class="counter">(\d+)</div>' + TOOMUCH_PATTERN = r'Sorry dude, you have downloaded too much\. Please wait (\d+) seconds' + + + def setup(self): + self.multiDL = False + + def process(self, pyfile): + self.html = self.load(pyfile.url, decode=True) + # check if offline + if re.search(self.FILE_OFFLINE_PATTERN, self.html): + self.offline() + # All Downloadtickets in use + timmy = re.search(self.WAIT_LONGER_PATTERN, self.html) + if timmy: + self.logDebug("waitforfreeslot") + self.waitForFreeSlot() + # Wait the waittime + timmy = re.search(self.WAIT_PATTERN, self.html) + if timmy: + self.logDebug("waiting", timmy.group(1)) + self.setWait(int(timmy.group(1)) + 2, False) + self.wait() + # Downloaded to much + timmy = re.search(self.TOOMUCH_PATTERN, self.html) + if timmy: + self.logDebug("too much", timmy.group(1)) + self.setWait(int(timmy.group(1)), True) + self.wait() + # Find Name + found = re.search(self.FILE_NAME_PATTERN, self.html) + if found is None: + self.fail("Parse error (NAME)") + pyfile.name = found.group(1) + # Get the URL + url = pyfile.url + found = re.search(self.__pattern__, url) + if found is None: + self.fail("Parse error (URL)") + download_url = "http://icyfiles.com/download.php?key=" + found.group(1) + self.download(download_url) + # check download + check = self.checkDownload({ + "notfound": re.compile(r"^<head><title>404 Not Found</title>$"), + "skippedcountdown": re.compile(r"^Dont skip the countdown$"), + "waitforfreeslots": re.compile(self.WAIT_LONGER_PATTERN), + "downloadedtoomuch": re.compile(self.TOOMUCH_PATTERN) + }) + if check == "skippedcountdown": + self.fail("Countdown error") + elif check == "notfound": + self.fail("404 Not found") + elif check == "waitforfreeslots": + self.waitForFreeSlot() + elif check == "downloadedtoomuch": + self.retry() + + def waitForFreeSlot(self): + self.retry(60, 60, "Wait for free slot") diff --git a/module/plugins/hoster/IfileIt.py b/module/plugins/hoster/IfileIt.py index ec830f3b2..bf394f340 100644 --- a/module/plugins/hoster/IfileIt.py +++ b/module/plugins/hoster/IfileIt.py @@ -25,8 +25,8 @@ from module.network.RequestFactory import getURL class IfileIt(SimpleHoster): __name__ = "IfileIt" __type__ = "hoster" - __pattern__ = r"http://(?:\w*\.)*(?:ifile\.it|mihd\.net)/(\w+).*" - __version__ = "0.24" + __pattern__ = r"^unmatchable$" + __version__ = "0.27" __description__ = """Ifile.it""" __author_name__ = ("zoidberg") @@ -35,28 +35,29 @@ class IfileIt(SimpleHoster): DOWNLOAD_LINK_PATTERN = r'</span> If it doesn\'t, <a target="_blank" href="([^"]+)">' RECAPTCHA_KEY_PATTERN = r"var __recaptcha_public\s*=\s*'([^']+)';" FILE_INFO_PATTERN = r'<span style="cursor: default;[^>]*>\s*(?P<N>.*?)\s* \s*<strong>\s*(?P<S>[0-9.]+)\s*(?P<U>[kKMG])i?B\s*</strong>\s*</span>' - FILE_OFFLINE_PATTERN = r'$\("#errorPnl"\)\.empty\(\)\.append\( "no such file" \);' + FILE_OFFLINE_PATTERN = r'<span style="cursor: default;[^>]*>\s* \s*<strong>\s*</strong>\s*</span>' + TEMP_OFFLINE_PATTERN = r'<span class="msg_red">Downloading of this file is temporarily disabled</span>' def handleFree(self): ukey = re.search(self.__pattern__, self.pyfile.url).group(1) - json_url = 'http://ifile.it/download-request2.json?ukey=' + ukey - - json_response = json_loads(self.load(json_url)) + json_url = 'http://ifile.it/new_download-request.json' + post_data = {"ukey" : ukey, "ab": "0"} + + json_response = json_loads(self.load(json_url, post = post_data)) self.logDebug(json_response) + if json_response['status'] == 3: + self.offline() + if json_response["captcha"]: captcha_key = re.search(self.RECAPTCHA_KEY_PATTERN, self.html).group(1) recaptcha = ReCaptcha(self) + post_data["ctype"] = "recaptcha" for i in range(5): - captcha_challenge, captcha_response = recaptcha.challenge(captcha_key) - - json_response = json_loads(self.load(json_url, post={ - "ctype": "recaptcha", - "recaptcha_challenge": captcha_challenge, - "recaptcha_response": captcha_response - })) - + post_data["recaptcha_challenge"], post_data["recaptcha_response"] = recaptcha.challenge(captcha_key) + json_response = json_loads(self.load(json_url, post = post_data)) self.logDebug(json_response) + if json_response["retry"]: self.invalidCaptcha() else: @@ -65,11 +66,9 @@ class IfileIt(SimpleHoster): else: self.fail("Incorrect captcha") - # load twice - self.html = self.load(self.pyfile.url) - self.html = self.load(self.pyfile.url) - download_url = re.search(self.DOWNLOAD_LINK_PATTERN, self.html).group(1) + if not "ticket_url" in json_response: + self.parseError("Download URL") - self.download(download_url) + self.download(json_response["ticket_url"]) getInfo = create_getInfo(IfileIt)
\ No newline at end of file diff --git a/module/plugins/hoster/IfolderRu.py b/module/plugins/hoster/IfolderRu.py index 83b98ecc9..b84f77c5c 100644 --- a/module/plugins/hoster/IfolderRu.py +++ b/module/plugins/hoster/IfolderRu.py @@ -24,8 +24,8 @@ from module.network.RequestFactory import getURL class IfolderRu(SimpleHoster): __name__ = "IfolderRu" __type__ = "hoster" - __pattern__ = r"http://(?:\w*\.)?ifolder.ru/(\d+).*" - __version__ = "0.33" + __pattern__ = r"http://(?:[^.]*\.)?ifolder.ru/(\d+).*" + __version__ = "0.35" __description__ = """ifolder.ru""" __author_name__ = ("zoidberg") __author_mail__ = ("zoidberg@mujmail.cz") @@ -33,7 +33,7 @@ class IfolderRu(SimpleHoster): FILE_SIZE_REPLACEMENTS = [(u'Кб', 'KB'), (u'Мб', 'MB'), (u'Гб', 'GB')] FILE_NAME_PATTERN = ur'(?:<div><span>)?Название:(?:</span>)? <b>(?P<N>[^<]+)</b><(?:/div|br)>' FILE_SIZE_PATTERN = ur'(?:<div><span>)?Размер:(?:</span>)? <b>(?P<S>[^<]+)</b><(?:/div|br)>' - FILE_OFFLINE_PATTERN = ur'<p>Файл номер <b>[^<]*</b> не найден !!!</p>' + FILE_OFFLINE_PATTERN = ur'<p>Файл номер <b>[^<]*</b> (не найден|удален) !!!</p>' SESSION_ID_PATTERN = r'<a href=(http://ints.ifolder.ru/ints/sponsor/\?bi=\d*&session=([^&]+)&u=[^>]+)>' FORM1_PATTERN = r'<form method=post name="form1" ID="Form1" style="margin-bottom:200px">(.*?)</form>' diff --git a/module/plugins/hoster/JumbofilesCom.py b/module/plugins/hoster/JumbofilesCom.py new file mode 100644 index 000000000..9e8adb512 --- /dev/null +++ b/module/plugins/hoster/JumbofilesCom.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +import re +from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo +from module.utils import html_unescape + +class JumbofilesCom(SimpleHoster): + __name__ = "JumbofilesCom" + __type__ = "hoster" + __pattern__ = r"http://(?:\w*\.)*jumbofiles.com/(\w{12}).*" + __version__ = "0.02" + __description__ = """JumboFiles.com hoster plugin""" + __author_name__ = ("godofdream") + __author_mail__ = ("soilfiction@gmail.com") + + FILE_INFO_PATTERN = '<TR><TD>(?P<N>[^<]+?)\s*<small>\((?P<S>[\d.]+)\s*(?P<U>[KMG][bB])\)</small></TD></TR>' + FILE_OFFLINE_PATTERN = 'Not Found or Deleted / Disabled due to inactivity or DMCA' + DIRECT_LINK_PATTERN = '<meta http-equiv="refresh" content="10;url=(.+)">' + + def setup(self): + self.resumeDownload = True + self.multiDL = True + + def handleFree(self): + ukey = re.search(self.__pattern__, self.pyfile.url).group(1) + post_data = {"id" : ukey, "op": "download3", "rand": ""} + html = self.load(self.pyfile.url, post = post_data, decode=True) + url = re.search(self.DIRECT_LINK_PATTERN, html).group(1) + self.logDebug("Download " + url) + self.download(url) + +getInfo = create_getInfo(JumbofilesCom) diff --git a/module/plugins/hoster/LetitbitNet.py b/module/plugins/hoster/LetitbitNet.py index 4ff2b9750..88e708bf5 100644 --- a/module/plugins/hoster/LetitbitNet.py +++ b/module/plugins/hoster/LetitbitNet.py @@ -19,12 +19,13 @@ import re from random import random from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo +from module.common.json_layer import json_loads class LetitbitNet(SimpleHoster): __name__ = "LetitbitNet" __type__ = "hoster" - __pattern__ = r"http://(?:\w*\.)*letitbit.net/download/.*" - __version__ = "0.13" + __pattern__ = r"http://(?:\w*\.)*(letitbit|shareflare).net/download/.*" + __version__ = "0.19" __description__ = """letitbit.net""" __author_name__ = ("zoidberg") __author_mail__ = ("zoidberg@mujmail.cz") @@ -32,8 +33,14 @@ class LetitbitNet(SimpleHoster): CHECK_URL_PATTERN = r"ajax_check_url\s*=\s*'((http://[^/]+)[^']+)';" SECONDS_PATTERN = r"seconds\s*=\s*(\d+);" - FILE_INFO_PATTERN = r'<h1[^>]*>File: <a[^>]*><span>(?P<N>[^<]+)</span></a>\s*\[<span>(?P<S>[^<]+)</span>]</h1>' - FILE_OFFLINE_PATTERN = r'<div id="download_content" class="hide-block">[^<]*<br>File not found<br /></div>' + FILE_INFO_PATTERN = r'<h1[^>]*>File:.*?<span>(?P<N>[^<]+)</span>.*?\[<span>(?P<S>[^<]+)</span>]</h1>' + FILE_OFFLINE_PATTERN = r'>File not found<' + + DOMAIN = "http://letitbit.net" + FILE_URL_REPLACEMENTS = [(r"(?<=http://)([^/]+)", "letitbit.net")] + + def setup(self): + self.resumeDownload = self.multiDL = True def handleFree(self): action, inputs = self.parseHtmlForm('id="ifree_form"') @@ -42,8 +49,9 @@ class LetitbitNet(SimpleHoster): #self.logDebug(action, inputs) inputs['desc'] = "" - self.html = self.load("http://letitbit.net" + action, post = inputs, cookies = True) - + self.html = self.load(self.DOMAIN + action, post = inputs, cookies = True) + + """ action, inputs = self.parseHtmlForm('id="d3_form"') if not action: self.parseError("page 2 / d3_form") #self.logDebug(action, inputs) @@ -59,23 +67,44 @@ class LetitbitNet(SimpleHoster): except Exception, e: self.logError(e) self.parseError("page 3 / js") - - response = self.load(ajax_check_url, post = inputs, cookies = True) - if response != '1': self.fail('Unknown response (ajax_check_url)') + """ + + found = re.search(self.SECONDS_PATTERN, self.html) + seconds = int(found.group(1)) if found else 60 + self.setWait(seconds+1) + self.wait() + + response = self.load("%s/ajax/download3.php" % self.DOMAIN, post = " ", cookies = True) + if response != '1': self.parseError('Unknown response - ajax_check_url') for i in range(5): - captcha = self.decryptCaptcha('%s/captcha_new.php?rand=%d' % (captcha_url, random() * 100000), cookies = True) - response = self.load(captcha_url + '/ajax/check_captcha.php', post = {"code": captcha}, cookies = True) + captcha = self.decryptCaptcha('%s/captcha_new.php?rand=%d' % (self.DOMAIN, random() * 100000), cookies = True) + response = self.load('%s/ajax/check_captcha.php' % self.DOMAIN, post = {"code": captcha}, cookies = True) self.logDebug(response) - if response.startswith('http://'): - download_url = response - self.correctCaptcha() + if not response: + self.invalidCaptcha() + elif response.startswith('['): + urls = json_loads(response) + break + elif response.startswith('http://'): + urls = [response] break else: - self.invalidCaptcha() + self.parseError("Unknown response - captcha check") + else: self.fail("No valid captcha solution received") - self.download(download_url) + self.correctCaptcha() + + for download_url in urls: + try: + self.logDebug("Download URL", download_url) + self.download(download_url) + break + except Exception, e: + self.logError(e) + else: + self.fail("Download did not finish correctly") getInfo = create_getInfo(LetitbitNet)
\ No newline at end of file diff --git a/module/plugins/hoster/LoadTo.py b/module/plugins/hoster/LoadTo.py index b1204cb2d..66bc6f407 100644 --- a/module/plugins/hoster/LoadTo.py +++ b/module/plugins/hoster/LoadTo.py @@ -33,7 +33,7 @@ def getInfo(urls): # Get file info name = re.search(LoadTo.FILE_NAME_PATTERN, html) size = re.search(LoadTo.SIZE_PATTERN, html) - if name is not None: + if name is not None and size is not None: name = name.group(1) size = size.group(1) result.append((name, size, 2, url)) @@ -42,14 +42,14 @@ def getInfo(urls): class LoadTo(Hoster): __name__ = "LoadTo" __type__ = "hoster" - __pattern__ = r"http://.*load.to/.*" - __version__ = "0.1" + __pattern__ = r"http://(www.*?\.)?load\.to/.{7,10}?/.*" + __version__ = "0.1002" __description__ = """load.to""" __author_name__ = ("halfman") __author_mail__ = ("Pulpan3@gmail.com") - FILE_NAME_PATTERN = r'<div class="toolarge"><h1>([^<]+)</h1></div>' - URL_PATTERN = r'<form method="post" action="([^"]+)"' + FILE_NAME_PATTERN = r'<div class="toolarge"><h1>(.+?)</h1></div>' + URL_PATTERN = r'<form method="post" action="(.+?)"' SIZE_PATTERN = r'<div class="download_table_right">(\d+) Bytes</div>' FILE_OFFLINE_PATTERN = r'Can\'t find file. Please check URL.<br />' WAIT_PATTERN = r'type="submit" value="Download \((\d+)\)"' @@ -64,11 +64,6 @@ class LoadTo(Hoster): if re.search(self.FILE_OFFLINE_PATTERN, self.html): self.offline() - timmy = re.search(self.WAIT_PATTERN, self.html) - if timmy: - self.setWait(timmy.group(1)) - self.wait() - found = re.search(self.FILE_NAME_PATTERN, self.html) if found is None: self.fail("Parse error (NAME)") @@ -78,5 +73,10 @@ class LoadTo(Hoster): if found is None: self.fail("Parse error (URL)") download_url = found.group(1) + + timmy = re.search(self.WAIT_PATTERN, self.html) + if timmy: + self.setWait(timmy.group(1)) + self.wait() - self.download(download_url)
\ No newline at end of file + self.download(download_url) diff --git a/module/plugins/hoster/MediafireCom.py b/module/plugins/hoster/MediafireCom.py index c1d6e3595..dce16118f 100644 --- a/module/plugins/hoster/MediafireCom.py +++ b/module/plugins/hoster/MediafireCom.py @@ -58,7 +58,7 @@ class MediafireCom(SimpleHoster): __name__ = "MediafireCom" __type__ = "hoster" __pattern__ = r"http://(\w*\.)*mediafire\.com/(file/|(download.php)?\?)(\w{11}|\w{15})($|/)" - __version__ = "0.74" + __version__ = "0.76" __description__ = """Mediafire.com plugin - free only""" __author_name__ = ("zoidberg") __author_mail__ = ("zoidberg@mujmail.cz") @@ -75,7 +75,7 @@ class MediafireCom(SimpleHoster): FILE_OFFLINE_PATTERN = r'class="error_msg_title"> Invalid or Deleted File. </div>' def setup(self): - self.multiDL = True + self.multiDL = False def process(self, pyfile): self.url, result = checkHTMLHeader(pyfile.url) @@ -83,15 +83,18 @@ class MediafireCom(SimpleHoster): if result == 0: self.html = self.load(self.url, decode = True) - self.checkCaptcha() + self.checkCaptcha() + self.multiDL = True self.getFileInfo() + if self.account: self.handlePremium() else: self.handleFree() elif result == 1: self.offline() - else: + else: + self.multiDL = True self.download(self.url, disposition = True) def handleFree(self): @@ -104,6 +107,7 @@ class MediafireCom(SimpleHoster): else: self.fail("No or incorrect password") + """ links = re.findall(self.DOWNLOAD_LINK_PATTERN, self.html) link_count = len(links) self.logDebug('LINKS ', links) @@ -131,6 +135,11 @@ class MediafireCom(SimpleHoster): else: zindex, download_url = links[0] + """ + found = re.search(r'kNO = "(http://.*?)";', self.html) + if not found: self.parseError("Download URL") + download_url = found.group(1) + self.logDebug("DOWNLOAD LINK:", download_url) self.download(download_url) diff --git a/module/plugins/hoster/NarodRu.py b/module/plugins/hoster/NarodRu.py new file mode 100644 index 000000000..335860de9 --- /dev/null +++ b/module/plugins/hoster/NarodRu.py @@ -0,0 +1,66 @@ +# -*- 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 random import random +from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo + +class NarodRu(SimpleHoster): + __name__ = "NarodRu" + __type__ = "hoster" + __pattern__ = r"http://(www\.)?narod(\.yandex)?\.ru/(disk|start/[0-9]+\.\w+-narod\.yandex\.ru)/(?P<ID>\d+)/.+" + __version__ = "0.1" + __description__ = """Narod.ru""" + __author_name__ = ("zoidberg") + + FILE_NAME_PATTERN = r'<dt class="name">(?:<[^<]*>)*(?P<N>[^<]+)</dt>' + FILE_SIZE_PATTERN = r'<dd class="size">(?P<S>\d[^<]*)</dd>' + FILE_OFFLINE_PATTERN = r'<title>404</title>|Файл удален с сервиса|Закончился срок хранения файла\.' + + FILE_SIZE_REPLACEMENTS = [(u'КБ', 'KB'), (u'МБ', 'MB'), (u'ГБ', 'GB')] + FILE_URL_REPLACEMENTS = [("narod.yandex.ru/", "narod.ru/"), (r"/start/[0-9]+\.\w+-narod\.yandex\.ru/([0-9]{6,15})/\w+/(\w+)", r"/disk/\1/\2")] + + CAPTCHA_PATTERN = r'<number url="(.*?)">(\w+)</number>' + DOWNLOAD_LINK_PATTERN = r'<a class="h-link" rel="yandex_bar" href="(.+?)">' + + def handleFree(self): + for i in range(5): + self.html = self.load('http://narod.ru/disk/getcapchaxml/?rnd=%d' % int(random() * 777)) + found = re.search(self.CAPTCHA_PATTERN, self.html) + if not found: self.parseError('Captcha') + post_data = {"action": "sendcapcha"} + captcha_url, post_data['key'] = found.groups() + post_data['rep'] = self.decryptCaptcha(captcha_url) + + self.html = self.load(self.pyfile.url, post = post_data, decode = True) + found = re.search(self.DOWNLOAD_LINK_PATTERN, self.html) + if found: + url = 'http://narod.ru' + found.group(1) + self.correctCaptcha() + break + elif u'<b class="error-msg"><strong>Ошиблись?</strong>' in self.html: + self.invalidCaptcha() + else: + self.parseError('Download link') + else: + self.fail("No valid captcha code entered") + + self.logDebug('Download link: ' + url) + self.download(url) + +getInfo = create_getInfo(NarodRu)
\ No newline at end of file diff --git a/module/plugins/hoster/NetloadIn.py b/module/plugins/hoster/NetloadIn.py index d768090e8..9310b5c34 100644 --- a/module/plugins/hoster/NetloadIn.py +++ b/module/plugins/hoster/NetloadIn.py @@ -24,7 +24,7 @@ def getInfo(urls): if match: ids = ids + match.group(1) +";" - api = getURL(apiurl+ids) + api = getURL(apiurl+ids, decode = True) if api is None or len(api) < 10: print "Netload prefetch: failed " @@ -53,14 +53,14 @@ class NetloadIn(Hoster): __name__ = "NetloadIn" __type__ = "hoster" __pattern__ = r"http://.*netload\.in/(?:datei(.*?)(?:\.htm|/)|index.php?id=10&file_id=)" - __version__ = "0.33" + __version__ = "0.40" __description__ = """Netload.in Download Hoster""" __author_name__ = ("spoob", "RaNaN", "Gregy") __author_mail__ = ("spoob@pyload.org", "ranan@pyload.org", "gregy@gregy.cz") def setup(self): self.multiDL = False - if self.account: + if self.premium: self.multiDL = True self.chunkLimit = -1 self.resumeDownload = True @@ -77,7 +77,7 @@ class NetloadIn(Hoster): if self.api_data and self.api_data["filename"]: self.pyfile.name = self.api_data["filename"] - if self.account: + if self.premium: self.log.debug("Netload: Use Premium Account") return True @@ -96,8 +96,8 @@ class NetloadIn(Hoster): self.api_data = False return - apiurl = "http://netload.in/share/fileinfos2.php" - src = self.load(apiurl, cookies=False, get={"file_id": match.group(1)}).strip() + apiurl = "http://api.netload.in/info.php" + src = self.load(apiurl, cookies=False, get={"file_id": match.group(1), "auth": "Zf9SnQh9WiReEsb18akjvQGqT0I830e8", "bz": "1", "md5": "1"}, decode = True).strip() if not src and n <= 3: sleep(0.2) self.download_api_data(n+1) @@ -105,7 +105,7 @@ class NetloadIn(Hoster): self.log.debug("Netload: APIDATA: "+src) self.api_data = {} - if src and src not in ("unknown file_data", "unknown_server_data"): + if src and src not in ("unknown file_data", "unknown_server_data", "No input file specified."): lines = src.split(";") self.api_data["exists"] = True self.api_data["fileid"] = lines[0] @@ -145,7 +145,11 @@ class NetloadIn(Hoster): self.offline() name = re.search(r'class="dl_first_filename">([^<]+)', page, re.MULTILINE) - self.pyfile.name = name.group(1).strip() + # the found filename is not truncated + if name: + name = name.group(1).strip() + if not name.endswith(".."): + self.pyfile.name = name captchawaited = False for i in range(10): @@ -160,11 +164,11 @@ class NetloadIn(Hoster): self.log.debug("Netload: try number %d " % i) - if re.search(r"(We will prepare your download..)", page) is not None: + if ">Your download is being prepared.<" in page: self.log.debug("Netload: We will prepare your download") self.final_wait(page) return True - if re.search(r"(We had a reqeust with the IP)", page) is not None: + if ">An access request has been made from IP address <" in page: wait = self.get_wait_time(page) if wait == 0: self.log.debug("Netload: Wait was 0 setting 30") @@ -211,7 +215,7 @@ class NetloadIn(Hoster): def get_file_url(self, page): try: - file_url_pattern = r"<a class=\"Orange_Link\" href=\"(http://.+)\".?>Click here" + file_url_pattern = r"<a class=\"Orange_Link\" href=\"(http://.+)\".?>Or click here" attempt = re.search(file_url_pattern, page) if attempt is not None: return attempt.group(1) @@ -232,12 +236,12 @@ class NetloadIn(Hoster): def proceed(self, url): self.log.debug("Netload: Downloading..") - self.download(url) + self.download(url, disposition=True) check = self.checkDownload({"empty": re.compile(r"^$"), "offline": re.compile("The file was deleted")}) if check == "empty": - self.log.info(_("Downloaded File was empty")) + self.logInfo(_("Downloaded File was empty")) self.retry() elif check == "offline": self.offline() diff --git a/module/plugins/hoster/OneFichierCom.py b/module/plugins/hoster/OneFichierCom.py index 16401891b..128942b75 100644 --- a/module/plugins/hoster/OneFichierCom.py +++ b/module/plugins/hoster/OneFichierCom.py @@ -6,49 +6,44 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo class OneFichierCom(SimpleHoster): __name__ = "OneFichierCom" __type__ = "hoster" - __pattern__ = r"(http://\w+\.((1fichier|d(es)?fichiers|pjointe)\.(com|fr|net|org)|(cjoint|mesfichiers|piecejointe|oi)\.(org|net)|tenvoi\.(com|org|net)|dl4free\.com|alterupload\.com|megadl.fr))" - __version__ = "0.4" + __pattern__ = r"(http://(\w+)\.((1fichier|d(es)?fichiers|pjointe)\.(com|fr|net|org)|(cjoint|mesfichiers|piecejointe|oi)\.(org|net)|tenvoi\.(com|org|net)|dl4free\.com|alterupload\.com|megadl.fr))" + __version__ = "0.43" __description__ = """1fichier.com download hoster""" __author_name__ = ("fragonib", "the-razer", "zoidberg") __author_mail__ = ("fragonib[AT]yahoo[DOT]es", "daniel_ AT gmx DOT net", "zoidberg@mujmail.cz") - FILE_NAME_PATTERN = r'">File name :</th>[\t\r\n ]+<td>(?P<N>.*?)</td>' - FILE_SIZE_PATTERN = r'<th>File size :</th>\s+<td>(?P<S>[\d\.]*) (?P<U>\w+)</td>' + FILE_NAME_PATTERN = r'">File name :</th>\s*<td>(?P<N>[^<]+)</td>' + FILE_SIZE_PATTERN = r'<th>File size :</th>\s*<td>(?P<S>[^<]+)</td>' FILE_OFFLINE_PATTERN = r'The (requested)? file (could not be found|has been deleted)' FILE_URL_REPLACEMENTS = [(r'(http://[^/]*).*', r'\1/en/')] DOWNLOAD_LINK_PATTERN = r'<br/> <br/> <br/> \s+<a href="(?P<url>http://.*?)"' PASSWORD_PROTECTED_TOKEN = "protected by password" - WAITING_TOKEN = "Please wait a few seconds" + WAITING_TOKEN = "Please wait a few seconds" - def handleFree(self): + def process(self, pyfile): + found = re.search(self.__pattern__, pyfile.url) + file_id = found.group(2) + url = "http://%s.%s/en/" % (found.group(2), found.group(3)) + self.html = self.load(url, decode = True) + if self.WAITING_TOKEN in self.html: - self.waitAndRetry(60) + self.waitAndRetry(120) + + self.getFileInfo() + + url, inputs = self.parseHtmlForm('action="http://%s' % file_id) + if not url or not inputs: + self.parseError("Download link not found") # Check for protection - if self.isProtected(): - password = self.getPassword() - self.logDebug("Submitting password [%s]" % password) - self.download(url, post={"password" : password}) - else: - downloadLink = self.getDownloadLink() - self.download(downloadLink) + if "pass" in inputs: + inputs['pass'] = self.getPassword() + + self.download(url, post = inputs) # Check download self.checkDownloadedFile() - - def isProtected(self): - if self.PASSWORD_PROTECTED_TOKEN in self.html: - self.logDebug("Links are password protected") - return True - return False - - def getDownloadLink(self): - m = re.search(self.DOWNLOAD_LINK_PATTERN, self.html) - if m is not None: - url = m.group('url') - self.logDebug("Got file URL [%s]" % url) - return url def checkDownloadedFile(self): check = self.checkDownload({"wait": self.WAITING_TOKEN}) @@ -60,4 +55,4 @@ class OneFichierCom(SimpleHoster): self.wait() self.retry() -getInfo = create_getInfo(OneFichierCom)
\ No newline at end of file +getInfo = create_getInfo(OneFichierCom) diff --git a/module/plugins/hoster/OronCom.py b/module/plugins/hoster/OronCom.py index e659beee5..864b7e96a 100755 --- a/module/plugins/hoster/OronCom.py +++ b/module/plugins/hoster/OronCom.py @@ -16,7 +16,7 @@ def getInfo(urls): result.append((url, 0, 1, url)) continue - m = re.search(OronCom.FILE_INFO_PATTERN, html) + m = re.search(OronCom.FILE_INFO_PATTERN, html, re.MULTILINE) if m: name = m.group(1) size = parseFileSize(m.group(2), m.group(3)) @@ -31,11 +31,11 @@ def getInfo(urls): class OronCom(Hoster): __name__ = "OronCom" __type__ = "hoster" - __pattern__ = r"http://(?:www\.)?oron.com/(?!folder/)" - __version__ = "0.14" - __description__ = "File Hoster: Oron.com" + __pattern__ = r"http://(?:www.)?oron.com/(?!folder)\w+" + __version__ = "0.16" + __description__ = "Oron.com Hoster Plugin" __author_name__ = ("chrox", "DHMH") - __author_mail__ = ("chrox@pyload.org", "DHMH@pyload.org") + __author_mail__ = ("chrox@pyload.org", "webmaster@pcProfil.de") FILE_INFO_PATTERN = r'(?:Filename|Dateiname): <b class="f_arial f_14px">(.*?)</b>\s*<br>\s*(?:Größe|File size): ([0-9,\.]+) (Kb|Mb|Gb)' @@ -50,7 +50,8 @@ class OronCom(Hoster): #self.load("http://oron.com/?op=change_lang&lang=german") # already logged in, so the above line shouldn't be necessary self.html = self.load(self.pyfile.url, ref=False, decode=True).encode("utf-8").replace("\n", "") - if "File could not be found" in self.html or "Datei nicht gefunden" in self.html: + if "File could not be found" in self.html or "Datei nicht gefunden" in self.html or \ + "This file has been blocked for TOS violation." in self.html: self.offline() self.html = self.html.replace("\t", "") m = re.search(self.FILE_INFO_PATTERN, self.html) @@ -126,13 +127,13 @@ class OronCom(Hoster): self.logError("error in parsing site") def handlePremium(self): - self.account.getAccountInfo(True) - self.logDebug("Traffic left: %s" % self.account.formatTrafficleft()) - self.logDebug("File Size: %s" % self.pyfile.formatSize()) + info = self.account.getAccountInfo(self.user, True) + self.logDebug("Traffic left: %s" % info['trafficleft']) + self.logDebug("File Size: %d" % int(self.pyfile.size / 1024)) - if int(self.pyfile.size / 1024) > self.account.trafficleft: + if int(self.pyfile.size / 1024) > info["trafficleft"]: self.logInfo(_("Not enough traffic left")) - self.account.empty() + self.account.empty(self.user) self.fail(_("Traffic exceeded")) post_url = "http://oron.com/" + self.file_id @@ -144,4 +145,3 @@ class OronCom(Hoster): self.html = self.load(post_url, post=post_dict, ref=False, decode=True).encode("utf-8") link = re.search('href="(.*?)" class="atitle"', self.html).group(1) self.download(link) - diff --git a/module/plugins/hoster/PremiumizeMe.py b/module/plugins/hoster/PremiumizeMe.py new file mode 100644 index 000000000..4ae59d198 --- /dev/null +++ b/module/plugins/hoster/PremiumizeMe.py @@ -0,0 +1,50 @@ +from module.plugins.Hoster import Hoster
+
+from module.common.json_layer import json_loads
+
+class PremiumizeMe(Hoster):
+ __name__ = "PremiumizeMe"
+ __version__ = "0.11"
+ __type__ = "hoster"
+ __description__ = """Premiumize.Me hoster plugin"""
+
+ # Since we want to allow the user to specify the list of hoster to use we let MultiHoster.coreReady create the regex patterns for us using getHosters in our PremiumizeMe hook.
+ __pattern__ = None
+
+ __author_name__ = ("Florian Franzen")
+ __author_mail__ = ("FlorianFranzen@gmail.com")
+
+ def process(self, pyfile):
+ # Check account
+ if not self.account or not self.account.canUse():
+ self.logError(_("Please enter a valid premiumize.me account or deactivate this plugin"))
+ self.fail("No valid premiumize.me account provided")
+
+ # In some cases hostsers do not supply us with a filename at download, so we are going to set a fall back filename (e.g. for freakshare or xfileshare)
+ self.pyfile.name = self.pyfile.name.split('/').pop() # Remove everthing before last slash
+
+ # Correction for automatic assigned filename: Removing html at end if needed
+ suffix_to_remove = ["html", "htm", "php", "php3", "asp", "shtm", "shtml", "cfml", "cfm"]
+ temp = self.pyfile.name.split('.')
+ if temp.pop() in suffix_to_remove:
+ self.pyfile.name = ".".join(temp)
+
+ # Get account data
+ (user, data) = self.account.selectAccount()
+
+ # Get rewritten link using the premiumize.me api v1 (see https://secure.premiumize.me/?show=api)
+ answer = self.load("https://api.premiumize.me/pm-api/v1.php?method=directdownloadlink¶ms[login]=%s¶ms[pass]=%s¶ms[link]=%s" % (user, data['password'], self.pyfile.url))
+ data = json_loads(answer)
+
+ # Check status and decide what to do
+ status = data['status']
+ if status == 200:
+ self.download(data['result']['location'], disposition=True)
+ elif status == 400:
+ self.fail("Invalid link")
+ elif status == 404:
+ self.offline()
+ elif status >= 500:
+ self.tempOffline()
+ else:
+ self.fail(data['statusmessage'])
diff --git a/module/plugins/hoster/PutlockerCom.py b/module/plugins/hoster/PutlockerCom.py new file mode 100644 index 000000000..8cfcd4d9e --- /dev/null +++ b/module/plugins/hoster/PutlockerCom.py @@ -0,0 +1,126 @@ +# -*- 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: jeix +""" + +import re +from module.plugins.Hoster import Hoster +from module.network.RequestFactory import getURL + +def getInfo(urls): + result = [] + + for url in urls: + + html = getURL(url) + if re.search(PutlockerCom.PATTERN_OFFLINE, html): + result.append((url, 0, 1, url)) + else: + name = re.search(PutlockerCom.PATTERN_FILENAME_1, html) + if name is None: + name = re.search(PutlockerCom.PATTERN_FILENAME_2, html) + if name is None: + result.append((url, 0, 1, url)) + continue + + name = name.group(1) + + # size = re.search(PutlockerCom.PATTERN_FILESIZE, html) + # if size is None: + # result.append((url, 0, 1, url)) + # continue + + # size = size.group(1) + + result.append((name, 0, 2, url)) + yield result + +class PutlockerCom(Hoster): + __name__ = "PutlockerCom" + __type__ = "hoster" + __pattern__ = r'http://(www\.)?putlocker\.com/(file|embed)/[A-Z0-9]+' + __version__ = "0.2" + __description__ = """Putlocker.Com""" + __author_name__ = ("jeix") + + PATTERN_OFFLINE = r"This file doesn't exist, or has been removed." + PATTERN_FILENAME_1 = "site-content.*?<h1>(.*?)<strong" + PATTERN_FILENAME_2 = "<title>(.*?) \|" + PATTERN_FILESIZE = "site-content.*?<h1>.*?<strong>\\((.*?)\\)" + + + def process(self, pyfile): + + self.pyfile = pyfile + self.html = self.load(pyfile.url, decode=True) + + if not self._checkOnline(): + self.offline() + + self.pyfile.name = self._getName() + + self.link = self._getLink() + if not self.link.startswith('http://'): + self.link = "http://www.putlocker.com" + self.link + self.download( self.link ) + + def _checkOnline(self): + if re.search(self.PATTERN_OFFLINE, self.html): + return False + else: + return True + + def _getName(self): + name = re.search(self.PATTERN_FILENAME_1, self.html) + if name is None: + name = re.search(self.PATTERN_FILENAME_2, self.html) + # if name is None: + # self.fail("%s: Plugin broken." % self.__name__) + + return name.group(1) + + def _getLink(self): + self.hash = re.search("<input type=\"hidden\" value=\"([a-z0-9]+)\" name=\"hash\">", self.html) + # if self.hash is None: + # self.fail("%s: Plugin broken." % self.__name__) + + self.param = "hash=" + self.hash.group(1) + "&confirm=Continue+as+Free+User" + self.html2 = self.load(self.pyfile.url, post=self.param) + if ">You have exceeded the daily stream limit for your country\\. You can wait until tomorrow" in self.html2 or "(>This content server has been temporarily disabled for upgrades|Try again soon\\. You can still download it below\\.<)" in self.html2: + self.waittime = 2 * 60 * 60 + self.retry(wait_time=self.waittime, reason="Waiting %s seconds" % self.waittime) + + self.link = re.search("<a href=\"/gopro\\.php\">Tired of ads and waiting\\? Go Pro\\!</a>[\t\n\rn ]+</div>[\t\n\rn ]+<a href=\"(/.*?)\"", self.html2) + if self.link is None: + self.link = re.search("\"(/get_file\\.php\\?download=[A-Z0-9]+\\&key=[a-z0-9]+)\"", self.html2) + + if self.link is None: + self.link = re.search("\"(/get_file\\.php\\?download=[A-Z0-9]+\\&key=[a-z0-9]+&original=1)\"", self.html2) + + if self.link is None: + self.link = re.search("playlist: \\'(/get_file\\.php\\?stream=[A-Za-z0-9=]+)\\'", self.html2) + if not self.link is None: + self.html3 = self.load("http://www.putlocker.com" + self.link.group(1)) + self.link = re.search("media:content url=\"(http://.*?)\"", self.html3) + if self.link is None: + self.link = re.search("\"(http://media\\-b\\d+\\.putlocker\\.com/download/\\d+/.*?)\"", self.html3) + + # if link is None: + # self.fail("%s: Plugin broken." % self.__name__) + + return self.link.group(1).replace("&", "&") + + diff --git a/module/plugins/hoster/RapidgatorNet.py b/module/plugins/hoster/RapidgatorNet.py new file mode 100644 index 000000000..678a3d707 --- /dev/null +++ b/module/plugins/hoster/RapidgatorNet.py @@ -0,0 +1,181 @@ +# -*- 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 pycurl import HTTPHEADER +from random import random + +from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo +from module.common.json_layer import json_loads +from module.plugins.ReCaptcha import ReCaptcha + +class AdsCaptcha(): + def __init__(self, plugin): + self.plugin = plugin + + 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(): + def __init__(self,plugin): + self.plugin = plugin + + def challenge(self, src): + html = self.plugin.req.load("http://api.solvemedia.com/papi/challenge.script?k=%s" % src, cookies=True) + try: + ckey = re.search("ckey:.*?'(.*?)',",html).group(1) + html = self.plugin.req.load("http://api.solvemedia.com/papi/_challenge.js?k=%s" % ckey, cookies=True) + challenge = re.search('"chid".*?: "(.*?)"',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") + + +class RapidgatorNet(SimpleHoster): + __name__ = "RapidgatorNet" + __type__ = "hoster" + __pattern__ = r"http://(?:www\.)?(rapidgator.net)/file/(\d+)" + __version__ = "0.06" + __description__ = """rapidgator.net""" + __author_name__ = ("zoidberg","chrox") + + FILE_INFO_PATTERN = r'Downloading:(\s*<[^>]*>)*\s*(?P<N>.*?)(\s*<[^>]*>)*\s*File size:\s*<strong>(?P<S>.*?)</strong>' + FILE_OFFLINE_PATTERN = r'<title>File not found</title>' + + JSVARS_PATTERN = r"\s+var\s*(startTimerUrl|getDownloadUrl|captchaUrl|fid|secs)\s*=\s*'?(.*?)'?;" + DOWNLOAD_LINK_PATTERN = r"location.href = '(.*?)'" + RECAPTCHA_KEY_PATTERN = r'"http://api.recaptcha.net/challenge?k=(.*?)"' + ADSCAPTCHA_SRC_PATTERN = r'(http://api.adscaptcha.com/Get.aspx[^"\']*)' + SOLVEMEDIA_PATTERN = r'http:\/\/api\.solvemedia\.com\/papi\/challenge\.script\?k=(.*?)"' + + def handleFree(self): + if "You can download files up to 500 MB in free mode" in self.html \ + or "This file can be downloaded by premium only" in self.html: + self.fail("Premium account needed for download") + + self.checkWait() + + jsvars = dict(re.findall(self.JSVARS_PATTERN, self.html)) + self.logDebug(jsvars) + + self.req.http.lastURL = self.pyfile.url + self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With: XMLHttpRequest"]) + + url = "http://rapidgator.net%s?fid=%s" % (jsvars.get('startTimerUrl', '/download/AjaxStartTimer'), jsvars["fid"]) + jsvars.update(self.getJsonResponse(url)) + + self.setWait(int(jsvars.get('secs', 30)) + 1, False) + self.wait() + + url = "http://rapidgator.net%s?sid=%s" % (jsvars.get('getDownloadUrl', '/download/AjaxGetDownload'), jsvars["sid"]) + jsvars.update(self.getJsonResponse(url)) + + self.req.http.lastURL = self.pyfile.url + self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With:"]) + + url = "http://rapidgator.net%s" % jsvars.get('captchaUrl', '/download/captcha') + self.html = self.load(url) + found = re.search(self.ADSCAPTCHA_SRC_PATTERN, self.html) + if found: + captcha_key = found.group(1) + captcha = AdsCaptcha(self) + else: + found = re.search(self.RECAPTCHA_KEY_PATTERN, self.html) + if found: + captcha_key = found.group(1) + captcha = ReCaptcha(self) + + else: + found = re.search(self.SOLVEMEDIA_PATTERN, self.html) + if found: + captcha_key = found.group(1) + captcha = SolveMedia(self) + else: + self.parseError("Captcha:"+st) + if captcha.__class__.__name__ == "SolveMedia": + captcha_prov = "adcopy" + else: + captcha_prov = captcha.__class__.__name__.lower() + + for i in range(5): + self.checkWait() + captcha_challenge, captcha_response = captcha.challenge(captcha_key) + + self.html = self.load(url, post={ + "DownloadCaptchaForm[captcha]": "", + "adcopy_challenge": captcha_challenge, + "adcopy_response": captcha_response + }) + + if 'The verification code is incorrect' in self.html: + self.invalidCaptcha() + else: + self.correctCaptcha() + break + else: + self.fail("No valid captcha solution received") + + found = re.search(self.DOWNLOAD_LINK_PATTERN, self.html) + if not found: + self.parseError("download link") + download_url = found.group(1) + self.logDebug(download_url) + self.download(download_url) + + def checkWait(self): + found = re.search(r"(?:Delay between downloads must be not less than|Try again in)\s*(\d+)\s*(hour|min)", self.html) + if found: + wait_time = int(found.group(1)) * {"hour": 60, "min": 1}[found.group(2)] + else: + found = re.search(r"You have reached your (daily|hourly) downloads limit", self.html) + if found: + wait_time = 60 + else: + return + + self.logDebug("Waiting %d minutes" % wait_time) + self.setWait(wait_time * 60, True) + self.wait() + self.retry(max_tries = 24) + + def getJsonResponse(self, url): + response = self.load(url, decode = True) + if not response.startswith('{'): + self.retry() + self.logDebug(url, response) + return json_loads(response) + +getInfo = create_getInfo(RapidgatorNet) + diff --git a/module/plugins/hoster/RapidshareCom.py b/module/plugins/hoster/RapidshareCom.py index a4a72eb53..6aacd684e 100644 --- a/module/plugins/hoster/RapidshareCom.py +++ b/module/plugins/hoster/RapidshareCom.py @@ -50,7 +50,7 @@ class RapidshareCom(Hoster): __name__ = "RapidshareCom" __type__ = "hoster" __pattern__ = r"https?://[\w\.]*?rapidshare.com/(?:files/(?P<id>\d*?)/(?P<name>[^?]+)|#!download\|(?:\w+)\|(?P<id_new>\d+)\|(?P<name_new>[^|]+))" - __version__ = "1.37" + __version__ = "1.38" __description__ = """Rapidshare.com Download Hoster""" __config__ = [("server", "Cogent;Deutsche Telekom;Level(3);Level(3) #2;GlobalCrossing;Level(3) #3;Teleglobe;GlobalCrossing #2;TeliaSonera #2;Teleglobe #2;TeliaSonera #3;TeliaSonera", "Preferred Server", "None")] __author_name__ = ("spoob", "RaNaN", "mkaay") @@ -60,17 +60,14 @@ class RapidshareCom(Hoster): self.html = None self.no_download = True self.api_data = None - self.multiDL = False self.offset = 0 self.dl_dict = {} self.id = None self.name = None - - if self.account: - self.multiDL = True - self.chunkLimit = -1 - self.resumeDownload = True + + self.chunkLimit = -1 if self.premium else 1 + self.multiDL = self.resumeDownload = self.premium def process(self, pyfile): self.url = self.pyfile.url @@ -90,7 +87,7 @@ class RapidshareCom(Hoster): if self.api_data["status"] == "1": self.pyfile.name = self.get_file_name() - if self.account: + if self.premium: self.handlePremium() else: self.handleFree() @@ -225,5 +222,4 @@ class RapidshareCom(Hoster): def get_file_name(self): if self.api_data["filename"]: return self.api_data["filename"] - return self.url.split("/")[-1] - + return self.url.split("/")[-1]
\ No newline at end of file diff --git a/module/plugins/hoster/RarefileNet.py b/module/plugins/hoster/RarefileNet.py new file mode 100644 index 000000000..8339d40eb --- /dev/null +++ b/module/plugins/hoster/RarefileNet.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +import re +from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from module.utils import html_unescape + +class RarefileNet(XFileSharingPro): + __name__ = "RarefileNet" + __type__ = "hoster" + __pattern__ = r"http://(?:\w*\.)*rarefile.net/\w{12}" + __version__ = "0.01" + __description__ = """Rarefile.net hoster plugin""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + FILE_NAME_PATTERN = r'<td><font color="red">(?P<N>.*?)</font></td>' + FILE_SIZE_PATTERN = r'<td>Size : (?P<S>.+?) ' + + def handleCaptcha(self, inputs): + captcha_div = re.search(r'<b>Enter code.*?<div.*?>(.*?)</div>', self.html, re.S).group(1) + self.logDebug(captcha_div) + numerals = re.findall('<span.*?padding-left\s*:\s*(\d+).*?>(\d)</span>', html_unescape(captcha_div)) + inputs['code'] = "".join([a[1] for a in sorted(numerals, key = lambda num: int(num[0]))]) + self.logDebug("CAPTCHA", inputs['code'], numerals) + return 3 + +getInfo = create_getInfo(RarefileNet)
\ No newline at end of file diff --git a/module/plugins/hoster/RealdebridCom.py b/module/plugins/hoster/RealdebridCom.py index 46ac51c82..3c796232e 100644 --- a/module/plugins/hoster/RealdebridCom.py +++ b/module/plugins/hoster/RealdebridCom.py @@ -1,86 +1,88 @@ -#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-import re
-from time import time
-from urllib import quote, unquote
-from random import randrange
-
-from module.utils import encode, parseFileSize
-from module.common.json_layer import json_loads
-from module.plugins.Hoster import Hoster
-
-class RealdebridCom(Hoster):
- __version__ = "0.43"
- __pattern__ = r"https?://.*real-debrid\..*"
- __description__ = """Real-Debrid.com hoster plugin"""
- __config__ = [("https", "bool", _("Enable HTTPS"), False)]
-
- __author_name__ = ("Devirex, Hazzard")
- __author_mail__ = ("naibaf_11@yahoo.de")
-
- def getFilename(self, url):
- try:
- name = unquote(url.rsplit("/", 1)[1])
- except IndexError:
- name = "Unknown_Filename..."
- if name.endswith("..."): #incomplete filename, append random stuff
- name += "%s.tmp" % randrange(100,999)
- return name
-
- def init(self):
- self.tries = 0
- self.chunkLimit = 3
- self.resumeDownload = True
-
-
- def process(self, pyfile):
- if not self.account:
- self.logError(_("Please enter your Real-debrid account or deactivate this plugin"))
- self.fail("No Real-debrid account provided")
-
- self.log.debug("Real-Debrid: Old URL: %s" % pyfile.url)
- if re.match(self.__pattern__, pyfile.url):
- new_url = pyfile.url
- else:
- password = self.getPassword().splitlines()
- if not password: password = ""
- else: password = password[0]
-
- url = "http://real-debrid.com/ajax/unrestrict.php?lang=en&link=%s&password=%s&time=%s" % (quote(encode(pyfile.url), ""), password, int(time()*1000))
- page = self.load(url)
- data = json_loads(page)
-
- self.logDebug("Returned Data: %s" % data)
-
- if data["error"] != 0:
- if data["message"] == "Your file is unavailable on the hoster.":
- self.offline()
- else:
- self.logWarning(data["message"])
- self.tempOffline()
- else:
- self.pyfile.name = data["file_name"]
- self.pyfile.size = parseFileSize(data["file_size"])
- new_url = data['generated_links'].split('|')[-1]
-
- if self.getConfig("https"):
- new_url = new_url.replace("http://", "https://")
- else:
- new_url = new_url.replace("https://", "http://")
-
- self.log.debug("Real-Debrid: New URL: %s" % new_url)
-
- if pyfile.name.startswith("http") or pyfile.name.startswith("Unknown"):
- #only use when name wasnt already set
- pyfile.name = self.getFilename(new_url)
-
- self.download(new_url, disposition=True)
-
- check = self.checkDownload(
- {"error": "<title>An error occured while processing your request</title>"})
-
- if check == "error":
- #usual this download can safely be retried
- self.retry(reason="An error occured while generating link.", wait_time=60)
-
+#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import re +from time import time +from urllib import quote, unquote +from random import randrange + +from module.utils import parseFileSize, remove_chars +from module.common.json_layer import json_loads +from module.plugins.Hoster import Hoster + +class RealdebridCom(Hoster): + __name__ = "RealdebridCom" + __version__ = "0.49" + __type__ = "hoster" + + __pattern__ = r"https?://.*real-debrid\..*" + __description__ = """Real-Debrid.com hoster plugin""" + __author_name__ = ("Devirex, Hazzard") + __author_mail__ = ("naibaf_11@yahoo.de") + + def getFilename(self, url): + try: + name = unquote(url.rsplit("/", 1)[1]) + except IndexError: + name = "Unknown_Filename..." + if not name or name.endswith(".."): #incomplete filename, append random stuff + name += "%s.tmp" % randrange(100,999) + return name + + def init(self): + self.tries = 0 + self.chunkLimit = 3 + self.resumeDownload = True + + + def process(self, pyfile): + if not self.account: + self.logError(_("Please enter your Real-debrid account or deactivate this plugin")) + self.fail("No Real-debrid account provided") + + self.log.debug("Real-Debrid: Old URL: %s" % pyfile.url) + if re.match(self.__pattern__, pyfile.url): + new_url = pyfile.url + else: + password = self.getPassword().splitlines() + if not password: password = "" + else: password = password[0] + + url = "http://real-debrid.com/ajax/unrestrict.php?lang=en&link=%s&password=%s&time=%s" % (quote(pyfile.url, ""), password, int(time()*1000)) + page = self.load(url) + data = json_loads(page) + + self.logDebug("Returned Data: %s" % data) + + if data["error"] != 0: + if data["message"] == "Your file is unavailable on the hoster.": + self.offline() + else: + self.logWarning(data["message"]) + self.tempOffline() + else: + if self.pyfile.name is not None and self.pyfile.name.endswith('.tmp') and data["file_name"]: + self.pyfile.name = data["file_name"] + self.pyfile.size = parseFileSize(data["file_size"]) + new_url = data['generated_links'][0][-1] + + if self.getConfig("https"): + new_url = new_url.replace("http://", "https://") + else: + new_url = new_url.replace("https://", "http://") + + self.log.debug("Real-Debrid: New URL: %s" % new_url) + + if pyfile.name.startswith("http") or pyfile.name.startswith("Unknown") or pyfile.name.endswith('..'): + #only use when name wasnt already set + pyfile.name = self.getFilename(new_url) + + self.download(new_url, disposition=True) + + check = self.checkDownload( + {"error": "<title>An error occured while processing your request</title>"}) + + if check == "error": + #usual this download can safely be retried + self.retry(reason="An error occured while generating link.", wait_time=60) + diff --git a/module/plugins/hoster/RyushareCom.py b/module/plugins/hoster/RyushareCom.py new file mode 100644 index 000000000..b3d7bafc6 --- /dev/null +++ b/module/plugins/hoster/RyushareCom.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo + +class RyushareCom(XFileSharingPro): + __name__ = "RyushareCom" + __type__ = "hoster" + __pattern__ = r"http://(?:\w*\.)*?ryushare.com/\w{12}" + __version__ = "0.02" + __description__ = """ryushare.com hoster plugin""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + HOSTER_NAME = "ryushare.com" + + def setup(self): + self.resumeDownload = self.multiDL = self.premium + +getInfo = create_getInfo(RyushareCom)
\ No newline at end of file diff --git a/module/plugins/hoster/Share4webCom.py b/module/plugins/hoster/Share4webCom.py new file mode 100644 index 000000000..ef9c2acf8 --- /dev/null +++ b/module/plugins/hoster/Share4webCom.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from module.plugins.hoster.UnibytesCom import UnibytesCom +from module.plugins.internal.SimpleHoster import create_getInfo + +class Share4webCom(UnibytesCom): + __name__ = "Share4webCom" + __type__ = "hoster" + __pattern__ = r"http://(www\.)?share4web\.com/get/\w+" + __version__ = "0.1" + __description__ = """Share4web.com""" + __author_name__ = ("zoidberg") + + DOMAIN = 'http://www.share4web.com' + +getInfo = create_getInfo(UnibytesCom)
\ No newline at end of file diff --git a/module/plugins/hoster/ShareRapidCom.py b/module/plugins/hoster/ShareRapidCom.py index b9ce61e18..4a25d4027 100644 --- a/module/plugins/hoster/ShareRapidCom.py +++ b/module/plugins/hoster/ShareRapidCom.py @@ -3,66 +3,102 @@ import re from pycurl import HTTPHEADER -from module.network.RequestFactory import getRequest +from module.network.RequestFactory import getRequest, getURL from module.network.HTTPRequest import BadHeader from module.plugins.internal.SimpleHoster import SimpleHoster, parseFileInfo +from module.common.json_layer import json_loads +def checkFile(url): + info = {"name" : url, "size" : 0, "status" : 3} + + response = getURL("http://share-rapid.com/checkfiles.php", post = {"files": url}, decode = True) + info = json_loads(response) + + if "error" in info: + if info['error'] == False: + info['name'] = info['filename'] + info['status'] = 2 + elif info['msg'] == "Not found": + info['status'] = 1 #offline + elif info['msg'] == "Service Unavailable": + info['status'] = 6 #temp.offline + + return info + def getInfo(urls): - file_info = [] for url in urls: - h = getRequest() - try: - h.c.setopt(HTTPHEADER, ["Accept: text/html"]) - html = h.load(url, cookies = True, decode = True) - file_info = parseFileInfo(ShareRapidCom, url, html) - finally: - h.close() - yield file_info + info = checkFile(url) + if "filename" in info: + yield info['name'], info['size'], info['status'], url + else: + file_info = (url, 0, 3, url) + h = getRequest() + try: + h.c.setopt(HTTPHEADER, ["Accept: text/html"]) + html = h.load(url, cookies = True, decode = True) + file_info = parseFileInfo(ShareRapidCom, url, html) + finally: + h.close() + yield file_info class ShareRapidCom(SimpleHoster): __name__ = "ShareRapidCom" __type__ = "hoster" - __pattern__ = r"http://(?:www\.)?((share(-?rapid\.(biz|com|cz|info|eu|net|org|pl|sk)|-(central|credit|free|net)\.cz|-ms\.net)|(s-?rapid|rapids)\.(cz|sk))|(e-stahuj|mediatack|premium-rapidshare|rapidshare-premium|qiuck)\.cz|kadzet\.com|stahuj-zdarma\.eu|strelci\.net|universal-share\.com)/(stahuj/.+)" - __version__ = "0.47" + __pattern__ = r"http://(?:www\.)?((share(-?rapid\.(biz|com|cz|info|eu|net|org|pl|sk)|-(central|credit|free|net)\.cz|-ms\.net)|(s-?rapid|rapids)\.(cz|sk))|(e-stahuj|mediatack|premium-rapidshare|rapidshare-premium|qiuck)\.cz|kadzet\.com|stahuj-zdarma\.eu|strelci\.net|universal-share\.com)/stahuj/(.+)" + __version__ = "0.50" __description__ = """Share-rapid.com plugin - premium only""" __author_name__ = ("MikyWoW", "zoidberg") __author_mail__ = ("MikyWoW@seznam.cz", "zoidberg@mujmail.cz") FILE_NAME_PATTERN = r'<h1[^>]*><span[^>]*>(?:<a[^>]*>)?(?P<N>[^<]+)' FILE_SIZE_PATTERN = r'<td class="i">Velikost:</td>\s*<td class="h"><strong>\s*(?P<S>[0-9.]+) (?P<U>[kKMG])i?B</strong></td>' + FILE_OFFLINE_PATTERN = ur'Nastala chyba 404|Soubor byl smazán' + DOWNLOAD_URL_PATTERN = r'<a href="([^"]+)" title="Stahnout">([^<]+)</a>' ERR_LOGIN_PATTERN = ur'<div class="error_div"><strong>Stahování je přístupné pouze přihlášeným uživatelům' ERR_CREDIT_PATTERN = ur'<div class="error_div"><strong>Stahování zdarma je možné jen přes náš' - FILE_OFFLINE_PATTERN = ur'Nastala chyba 404|Soubor byl smazán' def setup(self): self.chunkLimit = 1 self.resumeDownload = True def process(self, pyfile): - if not self.account: self.fail("User not logged in") - url = "http://share-rapid.com/" + re.search(self.__pattern__, pyfile.url).groups()[-1] - self.logDebug("URL: " + url) - + if not self.account: self.fail("User not logged in") + + self.info = checkFile(pyfile.url) + self.logDebug(self.info) + + pyfile.status = self.info['status'] + + if pyfile.status == 2: + pyfile.name = self.info['name'] + pyfile.size = self.info['size'] + elif pyfile.status == 1: + self.offline() + elif pyfile.status == 6: + self.tempOffline() + else: + self.fail("Unexpected file status") + + url = "http://share-rapid.com/stahuj/%s" % self.info['filepath'] try: self.html = self.load(url, decode=True) except BadHeader, e: self.account.relogin(self.user) self.retry(3, 0, str(e)) - - self.getFileInfo() found = re.search(self.DOWNLOAD_URL_PATTERN, self.html) if found is not None: - link, pyfile.name = found.groups() + link = found.group(1) self.logDebug("Premium link: %s" % link) + + self.check_data = {"size": pyfile.size} self.download(link) else: - self.logError("Download URL not found") if re.search(self.ERR_LOGIN_PATTERN, self.html): - self.relogin() + self.relogin(self.user) self.retry(3,0,"User login failed") elif re.search(self.ERR_CREDIT_PATTERN, self.html): self.fail("Not enough credit left") else: - self.fail("Download link not found")
\ No newline at end of file + self.fail("Download link not found")
\ No newline at end of file diff --git a/module/plugins/hoster/ShareonlineBiz.py b/module/plugins/hoster/ShareonlineBiz.py index 2d1fc8d85..b40cd51dd 100644 --- a/module/plugins/hoster/ShareonlineBiz.py +++ b/module/plugins/hoster/ShareonlineBiz.py @@ -5,10 +5,12 @@ import re from base64 import b64decode import hashlib import random -from time import sleep +from time import time, sleep -from module.plugins.Hoster import Hoster, chunks +from module.plugins.Hoster import Hoster from module.network.RequestFactory import getURL +from module.plugins.Plugin import chunks +from module.plugins.ReCaptcha import ReCaptcha as _ReCaptcha def getInfo(urls): api_url_base = "http://api.share-online.biz/linkcheck.php" @@ -32,14 +34,21 @@ def getInfo(urls): result.append((fields[2], int(fields[3]), status, chunk[i])) yield result +#suppress ocr plugin +class ReCaptcha(_ReCaptcha): + def result(self, server, challenge): + return self.plugin.decryptCaptcha("%simage"%server, get={"c":challenge}, cookies=True, forceUser=True, imgtype="jpg") + class ShareonlineBiz(Hoster): __name__ = "ShareonlineBiz" __type__ = "hoster" __pattern__ = r"http://[\w\.]*?(share\-online\.biz|egoshare\.com)/(download.php\?id\=|dl/)[\w]+" - __version__ = "0.22" + __version__ = "0.33" __description__ = """Shareonline.biz Download Hoster""" - __author_name__ = ("spoob", "mkaay") - __author_mail__ = ("spoob@pyload.org", "mkaay@mkaay.de") + __author_name__ = ("spoob", "mkaay", "zoidberg") + __author_mail__ = ("spoob@pyload.org", "mkaay@mkaay.de", "zoidberg@mujmail.cz") + + ERROR_INFO_PATTERN = r'<p class="b">Information:</p>\s*<div>\s*<strong>(.*?)</strong>' def setup(self): # range request not working? @@ -48,21 +57,29 @@ class ShareonlineBiz(Hoster): self.file_id = re.search(r"(id\=|/dl/)([a-zA-Z0-9]+)", self.pyfile.url).group(2) self.pyfile.url = "http://www.share-online.biz/dl/" + self.file_id - self.multiDL = False - self.chunkLimit = 1 - if self.premium: - self.multiDL = True - - def process(self, pyfile): - self.downloadAPIData() - pyfile.name = self.api_data["filename"] - pyfile.sync() + self.resumeDownload = self.multiDL = self.premium + #self.chunkLimit = 1 + self.check_data = None + + def process(self, pyfile): if self.premium: self.handleAPIPremium() - #self.handleWebsitePremium() + #web-download fallback removed - didn't work anyway else: self.handleFree() + + """ + check = self.checkDownload({"failure": re.compile(self.ERROR_INFO_PATTERN)}) + if check == "failure": + try: + self.retry(reason = self.lastCheck.group(1).decode("utf8")) + except: + self.retry(reason = "Unknown error") + """ + + if self.api_data: + self.check_data = {"size": int(self.api_data['size']), "md5": self.api_data['md5']} def downloadAPIData(self): api_url_base = "http://api.share-online.biz/linkcheck.php?md5=1" @@ -76,101 +93,98 @@ class ShareonlineBiz(Hoster): self.offline() self.api_data["filename"] = fields[2] self.api_data["size"] = fields[3] # in bytes - self.api_data["checksum"] = fields[4].strip().lower().replace("\n\n", "") # md5 + self.api_data["md5"] = fields[4].strip().lower().replace("\n\n", "") # md5 - def handleFree(self): - self.resumeDownload = False + def handleFree(self): + self.downloadAPIData() + self.pyfile.name = self.api_data["filename"] + self.pyfile.size = int(self.api_data["size"]) - self.html = self.load(self.pyfile.url) #refer, stuff - self.html = self.load("%s/free/" % self.pyfile.url, post={"dl_free":"1", "choice": "free"}) - if re.search(r"/failure/full/1", self.req.lastEffectiveURL): - self.setWait(120) - self.log.info("%s: no free slots, waiting 120 seconds" % self.__name__) - self.wait() - self.retry(max_tries=60) + self.html = self.load(self.pyfile.url, cookies = True) #refer, stuff + self.setWait(3) + self.wait() + + self.html = self.load("%s/free/" % self.pyfile.url, post={"dl_free":"1", "choice": "free"}, decode = True) + self.checkErrors() - if "Captcha number error or expired" in self.html: - captcha = self.decryptCaptcha("http://www.share-online.biz/captcha.php", get={"rand":"0.%s" % random.randint(10**15,10**16)}) + found = re.search(r'var wait=(\d+);', self.html) - self.log.debug("%s Captcha: %s" % (self.__name__, captcha)) - sleep(3) - - self.html = self.load(self.pyfile.url, post={"captchacode": captcha}) + recaptcha = ReCaptcha(self) + for i in range(5): + challenge, response = recaptcha.challenge("6LdatrsSAAAAAHZrB70txiV5p-8Iv8BtVxlTtjKX") + self.setWait(int(found.group(1)) if found else 30) + response = self.load("%s/free/captcha/%d" % (self.pyfile.url, int(time() * 1000)), post = { + 'dl_free': '1', + 'recaptcha_challenge_field': challenge, + 'recaptcha_response_field': response}) - if r"Der Download ist Ihnen zu langsam" not in self.html and r"The download is too slow for you" not in self.html: - self.fail("Plugin defect. Save dumps and report.") - - if "Kein weiterer Download-Thread möglich!" in self.html: #TODO corresponding translation - self.retry(wait_time=30, reason=_("Parallel download issue")) + if not response == '0': + break - m = re.search("var wait=(\d+);", self.html[1]) - wait_time = int(m.group(1)) if m else 30 - self.setWait(wait_time) - self.log.debug("%s: Waiting %d seconds." % (self.__name__, wait_time)) - self.wait() + else: self.fail("No valid captcha solution received") - file_url_pattern = r'var\sdl="(.*?)"' - download_url = b64decode(re.search(file_url_pattern, self.html).group(1)) + download_url = response.decode("base64") + self.logDebug(download_url) + if not download_url.startswith("http://"): + self.parseError("download url") + self.wait() self.download(download_url) - - check = self.checkDownload({"invalid" : "Dieses Download-Ticket ist ungültig!", - "error" : "Es ist ein unbekannter Fehler aufgetreten"}) - if check == "invalid": - self.retry(reason=_("Invalid download ticket")) - elif check == "error": - self.fail(reason=_("ShareOnline internal problems")) - - def handleAPIPremium(self): #should be working better - self.resumeDownload = True - - info = self.account.getUserAPI(self.req) - if info["dl"].lower() == "not_available": - self.fail("DL API error") - self.req.cj.setCookie("share-online.biz", "dl", info["dl"]) - - + def checkErrors(self): + found = re.search(r"/failure/(.*?)/1", self.req.lastEffectiveURL) + if found: + err = found.group(1) + found = re.search(self.ERROR_INFO_PATTERN, self.html) + msg = found.group(1) if found else "" + self.logError(err, msg or "Unknown error occurred") + + if err in ('freelimit', 'size', 'proxy'): + self.fail(msg or "Premium account needed") + if err in ('invalid'): + self.fail(msg or "File not available") + elif err in ('server'): + self.setWait(600, False) + elif err in ('expired'): + self.setWait(30, False) + else: + self.setWait(300, True) + + self.wait() + self.retry(max_tries=25, reason = msg) + + def handleAPIPremium(self): #should be working better + self.account.getAccountInfo(self.user, True) src = self.load("http://api.share-online.biz/account.php?username=%s&password=%s&act=download&lid=%s" % (self.user, self.account.accounts[self.user]["password"], self.file_id), post={}) - dlinfo = {} + self.api_data = dlinfo = {} for line in src.splitlines(): key, value = line.split(": ") dlinfo[key.lower()] = value - if not dlinfo["status"].lower() == "online": + self.logDebug(dlinfo) + if not dlinfo["status"] == "online": self.offline() + self.pyfile.name = dlinfo["name"] + self.pyfile.size = int(dlinfo["size"]) + dlLink = dlinfo["url"] - if dlLink.startswith("/_dl.php"): - self.log.debug("got invalid downloadlink, falling back") - self.handleWebsitePremium() + if dlLink == "server_under_maintenance": + self.tempoffline() else: self.download(dlLink) - def handleWebsitePremium(self): #seems to be buggy - self.resumeDownload = False - - self.html = self.load(self.pyfile.url) - if r"Die Nummer ist leider nicht richtig oder ausgelaufen!" in self.html: - self.retry() - - try: - download_url = re.search('loadfilelink\.decode\("(.*?)"\);', self.html, re.S).group(1) - except: - self.fail("Session issue") - - self.download(download_url) - def checksum(self, local_file): - if self.api_data and self.api_data["checksum"]: + if self.api_data and "md5" in self.api_data and self.api_data["md5"]: h = hashlib.md5() f = open(local_file, "rb") h.update(f.read()) f.close() hexd = h.hexdigest() - if hexd == self.api_data["checksum"]: + if hexd == self.api_data["md5"]: return True, 0 else: return False, 1 else: + self.logWarning("MD5 checksum missing") return True, 5 diff --git a/module/plugins/hoster/ShragleCom.py b/module/plugins/hoster/ShragleCom.py index 9ebf4917b..8fe05a2b9 100644 --- a/module/plugins/hoster/ShragleCom.py +++ b/module/plugins/hoster/ShragleCom.py @@ -2,84 +2,105 @@ # -*- coding: utf-8 -*- import re -import time +from pycurl import FOLLOWLOCATION from module.plugins.Hoster import Hoster +from module.plugins.internal.SimpleHoster import parseHtmlForm +from module.plugins.ReCaptcha import ReCaptcha +from module.network.RequestFactory import getURL + +API_KEY = "078e5ca290d728fd874121030efb4a0d" + +def parseFileInfo(self, url): + file_id = re.match(self.__pattern__, url).group('ID') + + data = getURL( + "http://www.cloudnator.com/api.php?key=%s&action=getStatus&fileID=%s" % (API_KEY, file_id), + decode = True + ).split() + + if len(data) == 4: + name, size, md5, status = data + size = int(size) + + if hasattr(self, "check_data"): + self.checkdata = {"size": size, "md5": md5} + + return name, size, 2 if status == "0" else 1, url + else: + return url, 0, 1, url + +def getInfo(urls): + for url in urls: + file_info = parseFileInfo(plugin, url) + yield file_info class ShragleCom(Hoster): __name__ = "ShragleCom" __type__ = "hoster" - __pattern__ = r"http://(?:www.)?shragle.com/files/" - __version__ = "0.1" - __description__ = """Shragle Download PLugin""" - __author_name__ = ("RaNaN") - __author_mail__ = ("RaNaN@pyload.org") + __pattern__ = r"http://(?:www.)?(cloudnator|shragle).com/files/(?P<ID>.*?)/" + __version__ = "0.20" + __description__ = """Cloudnator.com (Shragle.com) Download PLugin""" + __author_name__ = ("RaNaN", "zoidberg") + __author_mail__ = ("RaNaN@pyload.org", "zoidberg@mujmail.cz") def setup(self): self.html = None self.multiDL = False + self.check_data = None def process(self, pyfile): - self.pyfile = pyfile - - if not self.file_exists(): + #get file status and info + self.pyfile.name, self.pyfile.size, status = parseFileInfo(self, pyfile.url)[:3] + if status != 2: self.offline() - - self.pyfile.name = self.get_file_name() - self.setWait(self.get_waiting_time()) - self.wait() + self.handleFree() - self.proceed(self.get_file_url()) - - def get_waiting_time(self): - if self.html is None: - self.download_html() - - timestring = re.search('\s*var\sdownloadWait\s=\s(\d*);', self.html) - if timestring: - return int(timestring.group(1)) - else: - return 10 - - def download_html(self): + def handleFree(self): self.html = self.load(self.pyfile.url) - - def get_file_url(self): - """ returns the absolute downloadable filepath - """ - if self.html is None: - self.download_html() - - self.fileID = re.search(r'name="fileID"\svalue="(.*?)"', self.html).group(1) - self.dlSession = re.search(r'name="dlSession"\svalue="(.*?)"', self.html).group(1) - self.userID = re.search(r'name="userID"\svalue="(.*?)"', self.html).group(1) - self.password = re.search(r'name="password"\svalue="(.*?)"', self.html).group(1) - self.lang = re.search(r'name="lang"\svalue="(.*?)"', self.html).group(1) - return re.search(r'id="download"\saction="(.*?)"', self.html).group(1) - - def get_file_name(self): - if self.html is None: - self.download_html() - - #file_name_pattern = r'You want to download \xc2\xbb<strong>(.*?)</strong>\xc2\xab' - file_name_pattern = r'<h2 class="colorgrey center" style="overflow:hidden;width:1000px;"> (.*)<br /><span style="font-size:12px;font-weight:normal; width:100px;"> ([\d\.]*) MB</span></h2>' - res = re.search(file_name_pattern, self.html) - if res: - return res.group(1) - else: - self.fail("filename cant be extracted") - - def file_exists(self): - """ returns True or False - """ - if self.html is None: - self.download_html() - - if re.search(r"html", self.html) is None: - return False + + #get wait time + found = re.search('\s*var\sdownloadWait\s=\s(\d+);', self.html) + self.setWait(int(found.group(1)) if found else 30) + + #parse download form + action, inputs = parseHtmlForm('id="download', self.html) + + #solve captcha + found = re.search('recaptcha/api/(?:challenge|noscript)?k=(.+?)', self.html) + captcha_key = found.group(1) if found else "6LdEFb0SAAAAAAwM70vnYo2AkiVkCx-xmfniatHz" + + recaptcha = ReCaptcha(self) + + inputs['recaptcha_challenge_field'], inputs['recaptcha_response_field'] = recaptcha.challenge(captcha_key) + self.wait() + + #validate + self.req.http.c.setopt(FOLLOWLOCATION, 0) + self.html = self.load(action, post = inputs) + + found = re.search(r"Location\s*:\s*(\S*)", self.req.http.header, re.I) + if found: + self.correctCaptcha() + download_url = found.group(1) else: - return True - - def proceed(self, url): - self.download(url, post={'fileID': self.fileID, 'dlSession': self.dlSession, 'userID': self.userID, 'password': self.password, 'lang': self.lang}) + if "Sicherheitscode falsch" in self.html: + self.invalidCaptcha() + self.retry(max_tries = 5, reason = "Invalid captcha") + else: + self.fail("Invalid session") + + #download + self.req.http.c.setopt(FOLLOWLOCATION, 1) + self.download(download_url) + + check = self.checkDownload({ + "ip_blocked": re.compile(r'<div class="error".*IP.*loading') + }) + if check == "ip_blocked": + self.setWait(1800, True) + self.wait() + self.retry() + +
\ No newline at end of file diff --git a/module/plugins/hoster/StahnuTo.py b/module/plugins/hoster/StahnuTo.py index a78615dba..354a99b1a 100644 --- a/module/plugins/hoster/StahnuTo.py +++ b/module/plugins/hoster/StahnuTo.py @@ -32,29 +32,32 @@ def getInfo(urls): class StahnuTo(SimpleHoster): __name__ = "StahnuTo" __type__ = "hoster" - __pattern__ = r"http://(\w*\.)?stahnu.to/(files/get/|.*\?file=)([^/]+).*" - __version__ = "0.12" + __pattern__ = r"http://(?:\w*\.)?stahnu.to/(?:files/get/|.*\?file=)(?P<ID>[^/]+).*" + __version__ = "0.14" __description__ = """stahnu.to""" __author_name__ = ("zoidberg") - FILE_NAME_PATTERN = r"<div class='nadpis-01'><h2>(?<N>[^<]+)</h2></div>" - FILE_SIZE_PATTERN = r'<td>Velikost souboru<br /><span>(?<S>[^<]+)\s*(?<U>[kKMG])i?[Bb]</span></td>' + FILE_NAME_PATTERN = r"<td colspan='2'>Název souboru<br /><span>(?P<N>[^<]+)</span>" + FILE_SIZE_PATTERN = r'<td>Velikost souboru<br /><span>(?P<S>[^<]+)\s*(?P<U>[kKMG])i?[Bb]</span></td>' FILE_OFFLINE_PATTERN = r'<!-- Obsah - start -->\s*<!-- Obsah - end -->' - #FILE_OFFLINE_PATTERN = r'<h2 align="center">Tento soubor neexistuje nebo byl odstraněn! </h2>' - CAPTCHA_PATTERN = r'<img src="captcha/captcha.php" id="captcha" /></td>' def setup(self): self.multiDL = True def process(self, pyfile): + if not self.account: + self.fail("Please enter your stahnu.to account") + found = re.search(self.__pattern__, pyfile.url) - file_id = found.group(3) + file_id = found.group(1) - self.html = self.load("http://stahnu.to/?file=" + file_id, decode=True) + self.html = self.load("http://www.stahnu.to/getfile.php?file=%s" % file_id, decode=True) self.getFileInfo() + + if "K stažení souboru se musíte <strong>zdarma</strong> přihlásit!" in self.html: + self.account.relogin(self.user) + self.retry() - self.download("http://stahnu.to/files/gen/" + file_id, post={ - "file": file_id, - "user": "Anonym", - "commenttext": "" + self.download("http://www.stahnu.to/files/gen/" + file_id, post={ + "downloadbutton": u"STÁHNOUT" }) diff --git a/module/plugins/hoster/TurbobitNet.py b/module/plugins/hoster/TurbobitNet.py new file mode 100644 index 000000000..b3b01c92b --- /dev/null +++ b/module/plugins/hoster/TurbobitNet.py @@ -0,0 +1,169 @@ +# -*- coding: utf-8 -*- +""" + Copyright (C) 2012 pyLoad team + Copyright (C) 2012 JD-Team support@jdownloader.org + + 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 +import random +from urllib import quote +from binascii import hexlify, unhexlify +from Crypto.Cipher import ARC4 + +from module.network.RequestFactory import getURL +from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, timestamp +from module.plugins.ReCaptcha import ReCaptcha + +from pycurl import HTTPHEADER + +class TurbobitNet(SimpleHoster): + __name__ = "TurbobitNet" + __type__ = "hoster" + __pattern__ = r"http://(?:\w*\.)?(turbobit.net|unextfiles.com)/(?:download/free/)?(?P<ID>\w+).*" + __version__ = "0.07" + __description__ = """Turbobit.net plugin""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + FILE_INFO_PATTERN = r"<span class='file-icon1[^>]*>(?P<N>[^<]+)</span>\s*\((?P<S>[^\)]+)\)\s*</h1>" #long filenames are shortened + FILE_NAME_PATTERN = r'<meta name="keywords" content="\s+(?P<N>[^,]+)' #full name but missing on page2 + FILE_OFFLINE_PATTERN = r'<h2>File Not Found</h2>|html\(\'File was not found' + FILE_URL_REPLACEMENTS = [(r"http://(?:\w*\.)?(turbobit.net|unextfiles.com)/(?:download/free/)?(?P<ID>\w+).*", "http://turbobit.net/\g<ID>.html")] + SH_COOKIES = [("turbobit.net", "user_lang", "en")] + + CAPTCHA_KEY_PATTERN = r'src="http://api\.recaptcha\.net/challenge\?k=([^"]+)"' + DOWNLOAD_URL_PATTERN = r'(?P<url>/download/redirect/[^"\']+)' + LIMIT_WAIT_PATTERN = r'<div id="time-limit-text">\s*.*?<span id=\'timeout\'>(\d+)</span>' + CAPTCHA_SRC_PATTERN = r'<img alt="Captcha" src="(.*?)"' + + def handleFree(self): + self.url = "http://turbobit.net/download/free/%s" % self.file_info['ID'] + self.html = self.load(self.url) + + rtUpdate = self.getRtUpdate() + + self.solveCaptcha() + self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With: XMLHttpRequest"]) + self.url = self.getDownloadUrl(rtUpdate) + + self.wait() + self.html = self.load(self.url) + self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With:"]) + self.downloadFile() + + def solveCaptcha(self): + for i in range(5): + found = re.search(self.LIMIT_WAIT_PATTERN, self.html) + if found: + wait_time = int(found.group(1)) + self.setWait(wait_time, wait_time > 60) + self.wait() + self.retry() + + action, inputs = self.parseHtmlForm("action='#'") + if not inputs: self.parseError("captcha form") + self.logDebug(inputs) + + if inputs['captcha_type'] == 'recaptcha': + recaptcha = ReCaptcha(self) + found = re.search(self.CAPTCHA_KEY_PATTERN, self.html) + captcha_key = found.group(1) if found else '6LcTGLoSAAAAAHCWY9TTIrQfjUlxu6kZlTYP50_c' + inputs['recaptcha_challenge_field'], inputs['recaptcha_response_field'] = recaptcha.challenge(captcha_key) + else: + found = re.search(self.CAPTCHA_SRC_PATTERN, self.html) + if not found: self.parseError('captcha') + captcha_url = found.group(1) + inputs['captcha_response'] = self.decryptCaptcha(captcha_url) + + self.logDebug(inputs) + self.html = self.load(self.url, post = inputs) + + if not "<div class='download-timer-header'>" in self.html: + self.invalidCaptcha() + else: + self.correctCaptcha() + break + else: self.fail("Invalid captcha") + + def getRtUpdate(self): + rtUpdate = self.getStorage("rtUpdate") + if not rtUpdate: + if self.getStorage("version") != self.__version__ or int(self.getStorage("timestamp", 0)) + 86400000 < timestamp(): + # that's right, we are even using jdownloader updates + rtUpdate = getURL("http://update0.jdownloader.org/pluginstuff/tbupdate.js") + rtUpdate = self.decrypt(rtUpdate.splitlines()[1]) + # but we still need to fix the syntax to work with other engines than rhino + rtUpdate = re.sub(r'for each\(var (\w+) in(\[[^\]]+\])\)\{',r'zza=\2;for(var zzi=0;zzi<zza.length;zzi++){\1=zza[zzi];',rtUpdate) + rtUpdate = re.sub(r"for\((\w+)=",r"for(var \1=", rtUpdate) + + self.logDebug("rtUpdate") + self.setStorage("rtUpdate", rtUpdate) + self.setStorage("timestamp", timestamp()) + self.setStorage("version", self.__version__) + else: + self.logError("Unable to download, wait for update...") + self.tempOffline() + + return rtUpdate + + def getDownloadUrl(self, rtUpdate): + self.req.http.lastURL = self.url + + found = re.search("(/\w+/timeout\.js\?\w+=)([^\"\'<>]+)", self.html) + url = "http://turbobit.net%s%s" % (found.groups() if found else ('/files/timeout.js?ver=', ''.join(random.choice('0123456789ABCDEF') for x in range(32)))) + fun = self.load(url) + + self.setWait(65, False) + + for b in [1,3]: + self.jscode = "var id = \'%s\';var b = %d;var inn = \'%s\';%sout" % (self.file_info['ID'], b, quote(fun), rtUpdate) + + try: + out = self.js.eval(self.jscode) + self.logDebug("URL", self.js.engine, out) + if out.startswith('/download/'): + return "http://turbobit.net%s" % out.strip() + except Exception, e: + self.logError(e) + else: + if self.retries >= 2: + # retry with updated js + self.delStorage("rtUpdate") + self.retry() + + def decrypt(self, data): + cipher = ARC4.new(hexlify('E\x15\xa1\x9e\xa3M\xa0\xc6\xa0\x84\xb6H\x83\xa8o\xa0')) + return unhexlify(cipher.encrypt(unhexlify(data))) + + def getLocalTimeString(): + lt = time.localtime() + tz = time.altzone if lt.tm_isdst else time.timezone + return "%s GMT%+03d%02d" % (time.strftime("%a %b %d %Y %H:%M:%S", lt), -tz // 3600, tz % 3600) + + def handlePremium(self): + self.logDebug("Premium download as user %s" % self.user) + self.downloadFile() + + def downloadFile(self): + found = re.search(self.DOWNLOAD_URL_PATTERN, self.html) + if not found: self.parseError("download link") + self.url = "http://turbobit.net" + found.group('url') + self.logDebug(self.url) + self.download(self.url) + +getInfo = create_getInfo(TurbobitNet)
\ No newline at end of file diff --git a/module/plugins/hoster/TwoSharedCom.py b/module/plugins/hoster/TwoSharedCom.py index 89c4b7781..8401e0cb0 100644 --- a/module/plugins/hoster/TwoSharedCom.py +++ b/module/plugins/hoster/TwoSharedCom.py @@ -8,15 +8,18 @@ class TwoSharedCom(SimpleHoster): __name__ = "TwoSharedCom" __type__ = "hoster" __pattern__ = r"http://[\w\.]*?2shared.com/(account/)?(download|get|file|document|photo|video|audio)/.*" - __version__ = "0.10" + __version__ = "0.11" __description__ = """2Shared Download Hoster""" __author_name__ = ("zoidberg") __author_mail__ = ("zoidberg@mujmail.cz") - FILE_NAME_PATTERN = r'<meta name="Description" content="(?P<N>.*) download free at 2shared' + FILE_NAME_PATTERN = r'<h1>(?P<N>.*)</h1>' FILE_SIZE_PATTERN = r'<span class="dtitle">File size:</span>\s*(?P<S>[0-9,.]+) (?P<U>[kKMG])i?B' FILE_OFFLINE_PATTERN = r'The file link that you requested is not valid\.|This file was deleted\.' DOWNLOAD_URL_PATTERN = r"window.location ='([^']+)';" + + def setup(self): + self.resumeDownload = self.multiDL = True def handleFree(self): found = re.search(self.DOWNLOAD_URL_PATTERN, self.html) diff --git a/module/plugins/hoster/UlozTo.py b/module/plugins/hoster/UlozTo.py index 6b699e39f..cf2f09311 100644 --- a/module/plugins/hoster/UlozTo.py +++ b/module/plugins/hoster/UlozTo.py @@ -21,116 +21,137 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo def convertDecimalPrefix(m): # decimal prefixes used in filesize and traffic - return ("%%.%df" % {'k':3,'M':6,'G':9}[m.group(2)] % float(m.group(1))).replace('.','') + return ("%%.%df" % {'k':3,'M':6,'G':9}[m.group(2)] % float(m.group(1))).replace('.','') class UlozTo(SimpleHoster): __name__ = "UlozTo" __type__ = "hoster" - __pattern__ = r"http://(\w*\.)?(uloz\.to|ulozto\.(cz|sk|net)|bagruj.cz|zachowajto.pl)/.*" - __version__ = "0.81" + __pattern__ = r"http://(\w*\.)?(uloz\.to|ulozto\.(cz|sk|net)|bagruj.cz|zachowajto.pl)/(?:live/)?(?P<id>\w+/[^/?]*)" + __version__ = "0.89" __description__ = """uloz.to""" __author_name__ = ("zoidberg") - FILE_NAME_PATTERN = r'<a share_url="[^&]*&t=(?P<N>[^"]+)"' - #FILE_NAME_PATTERN = r'<h2 class="nadpis" style="margin-left:196px;"><a href="[^"]+">(?P<N>[^<]+)</a></h2>' - FILE_SIZE_PATTERN = r'<div class="info_velikost" style="top:-55px;">\s*<div>[^<]*\s+(?P<S>[0-9.]+\s[kMG]B)\s*</div>\s*</div>' - FILE_SIZE_REPLACEMENTS = [('([0-9.]+)\s([kMG])B', convertDecimalPrefix)] - FILE_OFFLINE_PATTERN = r'http://www.uloz.to/(neexistujici|smazano|nenalezeno)' - - PASSWD_PATTERN = r'<input type="password" class="text" name="file_password" id="frmfilepasswordForm-file_password" />' - VIPLINK_PATTERN = r'<a href="[^"]*\?disclaimer=1" class="linkVip">' - FREE_URL_PATTERN = r'<form name="dwn" action="([^"]+)"' - PREMIUM_URL_PATTERN = r'<a onclick[^>]*href="([^"]+)[^>]*class="linkVip"' - CAPTCHA_PATTERN = r'<img style=".*src="([^"]+)" alt="Captcha" class="captcha"' - CAPTCHA_NB_PATTERN = r'<input class="captcha_nb" type="hidden" name="captcha_nb" value="([0-9]+)" >' + FILE_NAME_PATTERN = r'<a href="#download" class="jsShowDownload">(?P<N>[^<]+)</a>' + FILE_SIZE_PATTERN = r'<span id="fileSize">.*?(?P<S>[0-9.]+\s[kMG]B)</span>' + FILE_INFO_PATTERN = r'<p>File <strong>(?P<N>[^<]+)</strong> is password protected</p>' + FILE_OFFLINE_PATTERN = r'<title>404 - Page not found</title>|<h1 class="h1">File (has been deleted|was banned)</h1>' + FILE_SIZE_REPLACEMENTS = [('([0-9.]+)\s([kMG])B', convertDecimalPrefix)] + FILE_URL_REPLACEMENTS = [(r"(?<=http://)([^/]+)", "www.ulozto.net")] + + PASSWD_PATTERN = r'<div class="passwordProtectedFile">' + VIPLINK_PATTERN = r'<a href="[^"]*\?disclaimer=1" class="linkVip">' + FREE_URL_PATTERN = r'<div class="freeDownloadForm"><form action="([^"]+)"' + PREMIUM_URL_PATTERN = r'<div class="downloadForm"><form action="([^"]+)"' + + def setup(self): + self.multiDL = self.premium + self.resumeDownload = True def process(self, pyfile): - # check file online - header = self.load(pyfile.url, just_header=True) - if "location" in header: - self.logDebug('LOCATION: ' + header['location']) - if "utm_source=old" in header['location'] or re.search(self.FILE_OFFLINE_PATTERN, header['location']): - self.offline() - - self.html = self.load(pyfile.url, decode=True) - - # password protected links - passwords = self.getPassword().splitlines() + pyfile.url = re.sub(r"(?<=http://)([^/]+)", "www.ulozto.net", pyfile.url) + self.html = self.load(pyfile.url, decode = True, cookies = True) + + passwords = self.getPassword().splitlines() while self.PASSWD_PATTERN in self.html: if passwords: password = passwords.pop(0) self.logInfo("Password protected link, trying " + password) - self.html = self.load(pyfile.url, get = {"do": "filepasswordForm-submit"}, post={"file_password": password, "fpwdsend": 'Odeslat'}, cookies=True) + self.html = self.load(pyfile.url, get = {"do": "passwordProtectedForm-submit"}, + post={"password": password, "password_send": 'Send'}, cookies=True) else: self.fail("No or incorrect password") - - self.file_info = self.getFileInfo() - - # adult content + if re.search(self.VIPLINK_PATTERN, self.html): self.html = self.load(pyfile.url, get={"disclaimer": "1"}) - + + self.file_info = self.getFileInfo() + if self.premium and self.checkTrafficLeft(): self.handlePremium() - else: + else: self.handleFree() - def handleFree(self): - parsed_url = self.findDownloadURL(premium=False) + self.doCheckDownload() + def handleFree(self): + action, inputs = self.parseHtmlForm('id="frm-downloadDialog-freeDownloadForm"') + if not action or not inputs: + self.parseError("free download form") + # get and decrypt captcha - captcha = self.getStorage("captchaUser") - captcha_nb = self.getStorage("captchaNb") - captcha_url = "DUMMY" - - if not captcha or not captcha_nb: - found = re.search(self.CAPTCHA_PATTERN, self.html) - if not found: self.parseError("CAPTCHA") - captcha_url = found.group(1) - - found = re.search(self.CAPTCHA_NB_PATTERN, self.html) - if not found: self.parseError("CAPTCHA_NB") - captcha_nb = found.group(1) - - captcha = self.decryptCaptcha(captcha_url) + captcha_id_field = captcha_text_field = None + captcha_id = captcha_text = None - self.log.debug('CAPTCHA_URL:' + captcha_url + ' CAPTCHA:' + captcha + ' CAPTCHA_NB:' + captcha_nb) + for key in inputs.keys(): + found = re.match("captcha.*(id|text|value)", key) + if found: + if found.group(1) == "id": + captcha_id_field = key + else: + captcha_text_field = key + + if not captcha_id_field or not captcha_text_field: + self.parseError("CAPTCHA form changed") + + """ + captcha_id = self.getStorage("captcha_id") + captcha_text = self.getStorage("captcha_text") + + if not captcha_id or not captcha_text: + """ + captcha_id = inputs[captcha_id_field] + captcha_text = self.decryptCaptcha("http://img.uloz.to/captcha/%s.png" % captcha_id) - # download and check - self.download(parsed_url, post={"captcha_user": captcha, "captcha_nb": captcha_nb}, cookies=True) - self.doCheckDownload() + self.log.debug(' CAPTCHA ID:' + captcha_id + ' CAPTCHA TEXT:' + captcha_text) - self.setStorage("captchaUser", captcha) - self.setStorage("captchaNb", captcha_nb) - - def handlePremium(self): - parsed_url = self.findDownloadURL(premium=True) - self.download(parsed_url) - self.doCheckDownload() + """ + self.setStorage("captcha_id", captcha_id) + self.setStorage("captcha_text", captcha_text) + """ + self.multiDL = True + + inputs.update({captcha_id_field: captcha_id, captcha_text_field: captcha_text}) + self.download("http://www.ulozto.net" + action, post=inputs, cookies=True) + + def handlePremium(self): + self.download(self.pyfile.url + "?do=directDownload") + #parsed_url = self.findDownloadURL(premium=True) + #self.download(parsed_url, post={"download": "Download"}) + def findDownloadURL(self, premium=False): msg = "%s link" % ("Premium" if premium else "Free") found = re.search(self.PREMIUM_URL_PATTERN if premium else self.FREE_URL_PATTERN, self.html) if not found: self.parseError(msg) - parsed_url = found.group(1) + parsed_url = "http://www.ulozto.net" + found.group(1) self.logDebug("%s: %s" % (msg, parsed_url)) return parsed_url - + def doCheckDownload(self): check = self.checkDownload({ - "wrong_captcha": re.compile(self.CAPTCHA_PATTERN), + "wrong_captcha": re.compile(r'<ul class="error">\s*<li>Error rewriting the text.</li>'), "offline": re.compile(self.FILE_OFFLINE_PATTERN), - "passwd": self.PASSWD_PATTERN + "passwd": self.PASSWD_PATTERN, + "server_error": 'src="http://img.ulozto.cz/error403/vykricnik.jpg"', #paralell dl, server overload etc. + "not_found": "<title>Ulož.to</title>" }) if check == "wrong_captcha": - self.delStorage("captchaUser") - self.delStorage("captchaNb") + self.delStorage("captcha_id") + self.delStorage("captcha_text") self.invalidCaptcha() self.retry(reason="Wrong captcha code") elif check == "offline": self.offline() elif check == "passwd": self.fail("Wrong password") + elif check == "server_error": + self.logError("Server error, try downloading later") + self.multiDL = False + self.setWait(3600, True) + self.wait() + self.retry() + elif check == "not_found": + self.fail("Server error - file not downloadable") -getInfo = create_getInfo(UlozTo)
\ No newline at end of file +getInfo = create_getInfo(UlozTo)
\ No newline at end of file diff --git a/module/plugins/hoster/UnibytesCom.py b/module/plugins/hoster/UnibytesCom.py new file mode 100644 index 000000000..3c8552271 --- /dev/null +++ b/module/plugins/hoster/UnibytesCom.py @@ -0,0 +1,80 @@ +# -*- 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 pycurl import FOLLOWLOCATION +from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo + +class UnibytesCom(SimpleHoster): + __name__ = "UnibytesCom" + __type__ = "hoster" + __pattern__ = r"http://(www\.)?unibytes\.com/[a-zA-Z0-9-._ ]{11}B" + __version__ = "0.1" + __description__ = """UniBytes.com""" + __author_name__ = ("zoidberg") + + FILE_INFO_PATTERN = r'<span[^>]*?id="fileName"[^>]*>(?P<N>[^>]+)</span>\s*\((?P<S>\d.*?)\)' + DOMAIN = 'http://www.unibytes.com' + + WAIT_PATTERN = r'Wait for <span id="slowRest">(\d+)</span> sec' + DOWNLOAD_LINK_PATTERN = r'<a href="([^"]+)">Download</a>' + + def handleFree(self): + action, post_data = self.parseHtmlForm('id="startForm"') + self.req.http.c.setopt(FOLLOWLOCATION, 0) + + for i in range(8): + self.logDebug(action, post_data) + self.html = self.load(self.DOMAIN + action, post = post_data) + + found = re.search(r'location:\s*(\S+)', self.req.http.header, re.I) + if found: + url = found.group(1) + break + + if '>Somebody else is already downloading using your IP-address<' in self.html: + self.setWait(600, True) + self.wait() + self.retry() + + if post_data['step'] == 'last': + found = re.search(self.DOWNLOAD_LINK_PATTERN, self.html) + if found: + url = found.group(1) + self.correctCaptcha() + break + else: + self.invalidCaptcha() + + last_step = post_data['step'] + action, post_data = self.parseHtmlForm('id="stepForm"') + + if last_step == 'timer': + found = re.search(self.WAIT_PATTERN, self.html) + self.setWait(int(found.group(1)) if found else 60, False) + self.wait() + elif last_step in ('captcha', 'last'): + post_data['captcha'] = self.decryptCaptcha(self.DOMAIN + '/captcha.jpg') + else: + self.fail("No valid captcha code entered") + + self.logDebug('Download link: ' + url) + self.req.http.c.setopt(FOLLOWLOCATION, 1) + self.download(url) + +getInfo = create_getInfo(UnibytesCom)
\ No newline at end of file diff --git a/module/plugins/hoster/UploadStationCom.py b/module/plugins/hoster/UploadStationCom.py index fea5f4245..d24682e4d 100644 --- a/module/plugins/hoster/UploadStationCom.py +++ b/module/plugins/hoster/UploadStationCom.py @@ -1,141 +1,21 @@ # -*- coding: utf-8 -*-
-from __future__ import with_statement
+from module.plugins.hoster.FileserveCom import FileserveCom, checkFile
+from module.plugins.Plugin import chunks
-from module.network.RequestFactory import getURL
-from module.plugins.Hoster import Hoster
-from module.plugins.ReCaptcha import ReCaptcha
-
-import re
-
-def getInfo(urls):
- yield [(url, 0, 1, url) for url in urls]
-
-class UploadStationCom(Hoster):
+class UploadStationCom(FileserveCom):
__name__ = "UploadStationCom"
__type__ = "hoster"
- __pattern__ = r"http://(www\.)?uploadstation\.com/file/(?P<id>[A-Za-z0-9]+)"
- __version__ = "0.33"
+ __pattern__ = r"http://(?:www\.)?uploadstation\.com/file/(?P<id>[A-Za-z0-9]+)"
+ __version__ = "0.51"
__description__ = """UploadStation.Com File Download Hoster"""
- __author_name__ = ("fragonib")
- __author_mail__ = ("fragonib[AT]yahoo[DOT]es")
-
- FILE_OFFLINE_PATTERN = r'''<h1>File not available</h1>|<h1>File is not available</h1>'''
- FILE_TITLE_PATTERN = r'''<div class=\"download_item\">(.*?)</div>'''
- FILE_SIZE_PATTERN = r'''<div><span>File size: <b>(.*?) (KB|MB|GB)</b>'''
- CAPTCHA_PRESENT_TOKEN = '<div class="speedBox" id="showCaptcha" style="display:none;">'
- CAPTCHA_KEY_PATTERN = r"var reCAPTCHA_publickey='(.*?)';"
- CAPTCHA_WRONG_TOKEN = 'incorrect-captcha-sol'
- WAITING_PATTERN = r".*?(\d+).*?"
- TIME_LIMIT_TOKEN = '"fail":"timeLimit"'
- TIME_LIMIT_WAIT_PATTERN = r"You need to wait (\d+) seconds to download next file."
- DOWNLOAD_RESTRICTION_TOKEN = '"To remove download restriction, please choose your suitable plan as below</h1>"'
-
- def setup(self):
- self.multiDL = False
- self.fileId = ''
- self.html = ''
-
- def process(self, pyfile):
-
- self.fail("Hoster not longer available")
-
- # Get URL
- self.html = self.load(self.pyfile.url, ref=False, decode=True)
-
- # Is offline?
- m = re.search(UploadStationCom.FILE_OFFLINE_PATTERN, self.html)
- if m is not None:
- self.offline()
-
- # Id & Title
- self.fileId = re.search(self.__pattern__, self.pyfile.url).group('id')
- self.pyfile.name = re.search(UploadStationCom.FILE_TITLE_PATTERN, self.html).group(1)
-
- # Free account
- self.handleFree()
-
- def handleFree(self):
-
- # Not needed yet
- # pattern = r'''\"(/landing/.*?/download_captcha\.js)\"'''
- # jsPage = re.search(pattern, self.html).group(1)
- # self.jsPage = self.load("http://uploadstation.com" + jsPage)
-
- # Check download
- response = self.load(self.pyfile.url, post={"checkDownload" : "check"}, decode=True)
- self.logDebug("Checking download, response [%s]" % response.encode('ascii', 'ignore'))
- self.handleErrors(response)
-
- # We got a captcha?
- if UploadStationCom.CAPTCHA_PRESENT_TOKEN in self.html:
- id = re.search(UploadStationCom.CAPTCHA_KEY_PATTERN, self.html).group(1)
- self.logDebug("Resolving ReCaptcha with key [%s]" % id)
- recaptcha = ReCaptcha(self)
- challenge, code = recaptcha.challenge(id)
- response = self.load('http://www.uploadstation.com/checkReCaptcha.php',
- post={'recaptcha_challenge_field' : challenge,
- 'recaptcha_response_field' : code,
- 'recaptcha_shortencode_field' : self.fileId})
- self.logDebug("Result of captcha resolving [%s]" % response.encode('ascii', 'ignore'))
- self.handleCaptchaErrors(response)
-
- # Process waiting
- response = self.load(self.pyfile.url, post={"downloadLink" : "wait"})
- m = re.search(UploadStationCom.WAITING_PATTERN, response)
- if m is not None:
- wait = int(m.group(1))
- if wait == 404:
- self.logDebug("No wait time returned")
- self.fail("No wait time returned")
-
- self.logDebug("Waiting %d seconds." % wait)
- self.setWait(wait + 3)
- self.wait()
-
- # Show download link
- self.load(self.pyfile.url, post={"downloadLink" : "show"})
-
- # This may either download our file or forward us to an error page
- self.logDebug("Downloading file.")
- dl = self.download(self.pyfile.url, post={"download" : "normal"})
- self.handleDownloadedFile()
-
- def handleErrors(self, response):
-
- if UploadStationCom.TIME_LIMIT_TOKEN in response:
- wait = 300
- html = self.load(self.pyfile.url, post={"checkDownload" : "showError", "errorType" : "timeLimit"})
- m = re.search(UploadStationCom.TIME_LIMIT_WAIT_PATTERN, html)
- if m is not None:
- wait = int(m.group(1))
-
- self.logInfo("Time limit reached, waiting %d seconds." % wait)
- self.setWait(wait, True)
- self.wait()
- self.retry()
+ __author_name__ = ("fragonib", "zoidberg")
+ __author_mail__ = ("fragonib[AT]yahoo[DOT]es", "zoidberg@mujmail.cz")
- if UploadStationCom.DOWNLOAD_RESTRICTION_TOKEN in response:
- wait = 720
- self.logInfo("Free account time limit reached, waiting %d seconds." % wait)
- self.setWait(wait, True)
- self.wait()
- self.retry()
-
- def handleCaptchaErrors(self, response):
- if UploadStationCom.CAPTCHA_WRONG_TOKEN in response:
- self.logInfo("Invalid captcha response, retrying.")
- self.invalidCaptcha()
- self.retry()
- else:
- self.correctCaptcha()
-
- def handleDownloadedFile(self):
- check = self.checkDownload({"wait": re.compile(UploadStationCom.TIME_LIMIT_WAIT_PATTERN)})
- if check == "wait":
- wait = 720
- if self.lastCheck is not None:
- wait = int(self.lastCheck.group(1))
- self.logDebug("Failed, you need to wait %d seconds for another download." % wait)
- self.setWait(wait + 3, True)
- self.wait()
- self.retry()
+ URLS = ['http://www.uploadstation.com/file/', 'http://www.uploadstation.com/check-links.php', 'http://www.uploadstation.com/checkReCaptcha.php']
+ LINKCHECK_TR = r'<div class="details (?:white|grey)">(.*?)\t{9}</div>'
+ LINKCHECK_TD = r'<div class="(?:col )?col\d">(?:<[^>]*>| )*([^<]*)'
+
+ LONG_WAIT_PATTERN = r'<h1>You have to wait (\d+) (\w+) to download the next file\.</h1>'
+
+def getInfo(urls):
+ for chunk in chunks(urls, 100): yield checkFile(UploadStationCom, chunk)
\ No newline at end of file diff --git a/module/plugins/hoster/UploadedTo.py b/module/plugins/hoster/UploadedTo.py index 751dcda25..3cb1e71ff 100644 --- a/module/plugins/hoster/UploadedTo.py +++ b/module/plugins/hoster/UploadedTo.py @@ -10,19 +10,10 @@ from module.plugins.ReCaptcha import ReCaptcha key = "bGhGMkllZXByd2VEZnU5Y2NXbHhYVlZ5cEE1bkEzRUw=".decode('base64') -def correctDownloadLink(url): - url = re.sub("http://.*?/", "http://uploaded.to/",url, 1) - url = re.sub("\\.to/.*?id=", ".to/file/", url, 1) - - if "/file/" not in url: - url = url.replace("uploaded.to/", "uploaded.to/file/") - - parts = url.split("/") - return "/".join(parts[:min(5,len(parts))]) + "/" - def getID(url): - """ returns id of corrected url""" - return re.search(r"uploaded.to/file/([^/]+)", url).group(1) + """ returns id from file url""" + m = re.match(r"http://[\w\.-]*?(uploaded\.(to|net)(/file/|/?\?id=|.*?&id=)|ul\.to/)(?P<ID>\w+)", url) + return m.group('ID') def getAPIData(urls): post = {"apikey" : key} @@ -30,18 +21,17 @@ def getAPIData(urls): idMap = {} for i, url in enumerate(urls): - newUrl = correctDownloadLink(url) - id = getID(newUrl) + id = getID(url) post["id_%s" % i] = id idMap[id] = url - api = unicode(getURL("http://uploaded.to/api/filemultiple", post=post, decode=False), 'iso-8859-1') + api = unicode(getURL("http://uploaded.net/api/filemultiple", post=post, decode=False), 'iso-8859-1') result = {} if api: for line in api.splitlines(): - data = line.split(",") + data = line.split(",", 4) if data[1] in idMap: result[data[1]] = (data[0], data[2], data[4], data[3], idMap[data[1]]) @@ -82,11 +72,11 @@ def getInfo(urls): class UploadedTo(Hoster): __name__ = "UploadedTo" __type__ = "hoster" - __pattern__ = r"(http://[\w\.-]*?uploaded\.to/.*?(file/|\?id=|&id=)[\w]+/?)|(http://[\w\.]*?ul\.to/(\?id=|&id=)?[\w\-]+/.+)|(http://[\w\.]*?ul\.to/(\?id=|&id=)?[\w\-]+/?)" - __version__ = "0.53" - __description__ = """Uploaded.to Download Hoster""" - __author_name__ = ("spoob", "mkaay") - __author_mail__ = ("spoob@pyload.org", "mkaay@mkaay.de") + __pattern__ = r"http://[\w\.-]*?(uploaded\.(to|net)(/file/|/?\?id=|.*?&id=)|ul\.to/)\w+" + __version__ = "0.62" + __description__ = """Uploaded.net Download Hoster""" + __author_name__ = ("spoob", "mkaay", "zoidberg", "netpok") + __author_mail__ = ("spoob@pyload.org", "mkaay@mkaay.de", "zoidberg@mujmail.cz", "netpok@gmail.com") FILE_INFO_PATTERN = r'<a href="file/(?P<ID>\w+)" id="filename">(?P<N>[^<]+)</a> \s*<small[^>]*>(?P<S>[^<]+)</small>' FILE_OFFLINE_PATTERN = r'<small class="cL">Error: 404</small>' @@ -103,12 +93,12 @@ class UploadedTo(Hoster): self.multiDL = True self.resumeDownload = True - - self.pyfile.url = correctDownloadLink(self.pyfile.url) self.fileID = getID(self.pyfile.url) + self.pyfile.url = "http://uploaded.net/file/%s" % self.fileID def process(self, pyfile): - self.req.cj.setCookie("uploaded.to", "lang", "en") + self.req.cj.setCookie("uploaded.net", "lang", "en") # doesn't work anymore + self.load("http://uploaded.net/language/en") api = getAPIData([pyfile.url]) @@ -156,24 +146,42 @@ class UploadedTo(Hoster): self.resetAccount() self.fail(_("Traffic exceeded")) - self.download("http://uploaded.to/file/%s/ddl" % self.fileID) - + header = self.load("http://uploaded.net/file/%s" % self.fileID, just_header=True) + if "location" in header: + #Direct download + print "Direct Download: " + header['location'] + self.download(header['location']) + else: + #Indirect download + self.html = self.load("http://uploaded.net/file/%s" % self.fileID) + found = re.search(r'<div class="tfree".*\s*<form method="post" action="(.*?)"', self.html) + if not found: + self.fail("Download URL not found. Try to enable direct downloads.") + url = found.group(1) + print "Premium URL: " + url + self.download(url, post={}) def handleFree(self): self.html = self.load(self.pyfile.url, decode=True) + + if 'var free_enabled = false;' in self.html: + self.logError("Free-download capacities exhausted.") + self.retry(24, 300) - wait = re.search(r"Current waiting period: <span>(\d+)</span> seconds", self.html).group(1) - self.setWait(wait) + found = re.search(r"Current waiting period: <span>(\d+)</span> seconds", self.html) + if not found: + self.fail("File not downloadable for free users") + self.setWait(int(found.group(1))) - js = self.load("http://uploaded.to/js/download.js", decode=True) + js = self.load("http://uploaded.net/js/download.js", decode=True) challengeId = re.search(r'Recaptcha\.create\("([^"]+)', js) - url = "http://uploaded.to/io/ticket/captcha/%s" % self.fileID + url = "http://uploaded.net/io/ticket/captcha/%s" % self.fileID downloadURL = "" for i in range(5): - self.req.lastURL = str(self.url) + #self.req.lastURL = str(self.url) re_captcha = ReCaptcha(self) challenge, result = re_captcha.challenge(challengeId.group(1)) options = {"recaptcha_challenge_field" : challenge, "recaptcha_response_field": result} @@ -190,18 +198,24 @@ class UploadedTo(Hoster): self.retry() elif "limit-parallel" in result: self.fail("Cannot download in parallel") - elif "limit-dl" in result: - self.setWait(30 * 60, True) + elif "You have reached the max. number of possible free downloads for this hour" in result: # limit-dl + self.setWait(60 * 60, True) self.wait() self.retry() elif 'err:"captcha"' in result: + self.logError("ul.net captcha is disabled") self.invalidCaptcha() elif "type:'download'" in result: self.correctCaptcha() downloadURL = re.search("url:'([^']+)", result).group(1) break + else: + self.fail("Unknown error '%s'") + self.setWait(60 * 60, True) + self.wait() + self.retry() if not downloadURL: self.fail("No Download url retrieved/all captcha attempts failed") - self.download(downloadURL)
\ No newline at end of file + self.download(downloadURL) diff --git a/module/plugins/hoster/UploadheroCom.py b/module/plugins/hoster/UploadheroCom.py new file mode 100644 index 000000000..eb7b5fb23 --- /dev/null +++ b/module/plugins/hoster/UploadheroCom.py @@ -0,0 +1,84 @@ +# -*- 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 module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo + +class UploadheroCom(SimpleHoster): + __name__ = "UploadheroCom" + __type__ = "hoster" + __pattern__ = r"http://(?:www\.)?uploadhero\.com/dl/\w+" + __version__ = "0.12" + __description__ = """UploadHero.com plugin""" + __author_name__ = ("mcmyst", "zoidberg") + __author_mail__ = ("mcmyst@hotmail.fr", "zoidberg@mujmail.cz") + + SH_COOKIES = [("http://uploadhero.com", "lang", "en")] + FILE_NAME_PATTERN = r'<div class="nom_de_fichier">(?P<N>.*?)</div>' + FILE_SIZE_PATTERN = r'Taille du fichier : </span><strong>(?P<S>.*?)</strong>' + FILE_OFFLINE_PATTERN = r'<p class="titre_dl_2">|<div class="raison"><strong>Le lien du fichier ci-dessus n\'existe plus.' + + DOWNLOAD_URL_PATTERN = r'<a href="([^"]+)" id="downloadnow"' + + IP_BLOCKED_PATTERN = r'href="(/lightbox_block_download.php\?min=.*?)"' + IP_WAIT_PATTERN = r'<span id="minutes">(\d+)</span>.*\s*<span id="seconds">(\d+)</span>' + + CAPTCHA_PATTERN = r'"(/captchadl\.php\?[a-z0-9]+)"' + FREE_URL_PATTERN = r'var magicomfg = \'<a href="(http://[^<>"]*?)"|"(http://storage\d+\.uploadhero\.com/\?d=[A-Za-z0-9]+/[^<>"/]+)"' + + def handleFree(self): + self.checkErrors() + + found = re.search(self.CAPTCHA_PATTERN, self.html) + if not found: self.parseError("Captcha URL") + captcha_url = "http://uploadhero.com" + found.group(1) + + for i in range(5): + captcha = self.decryptCaptcha(captcha_url) + self.html = self.load(self.pyfile.url, get = {"code": captcha}) + found = re.search(self.FREE_URL_PATTERN, self.html) + if found: + self.correctCaptcha() + download_url = found.group(1) or found.group(2) + break + else: + self.invalidCaptcha() + else: + self.fail("No valid captcha code entered") + + self.download(download_url) + + def handlePremium(self): + self.log.debug("%s: Use Premium Account" % self.__name__) + self.html = self.load(self.pyfile.url) + link = re.search(self.DOWNLOAD_URL_PATTERN, self.html).group(1) + self.log.debug("Downloading link : '%s'" % link) + self.download(link) + + def checkErrors(self): + found = re.search(self.IP_BLOCKED_PATTERN, self.html) + if found: + self.html = self.load("http://uploadhero.com%s" % found.group(1)) + + found = re.search(self.IP_WAIT_PATTERN, self.html) + wait_time = (int(found.group(1)) * 60 + int(found.group(2))) if found else 300 + self.setWait(wait_time, True) + self.wait() + self.retry() + +getInfo = create_getInfo(UploadheroCom)
\ No newline at end of file diff --git a/module/plugins/hoster/UploadingCom.py b/module/plugins/hoster/UploadingCom.py index 1278bfc01..4a157a787 100644 --- a/module/plugins/hoster/UploadingCom.py +++ b/module/plugins/hoster/UploadingCom.py @@ -18,20 +18,22 @@ """
import re
+from pycurl import HTTPHEADER
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, timestamp
+from module.common.json_layer import json_loads
class UploadingCom(SimpleHoster):
__name__ = "UploadingCom"
__type__ = "hoster"
- __pattern__ = r"http://(?:www\.)?uploading\.com/files/(?:get/)?[\w\d]+/?"
- __version__ = "0.30"
+ __pattern__ = r"http://(?:www\.)?uploading\.com/files/(?:get/)?(?P<ID>[\w\d]+)"
+ __version__ = "0.32"
__description__ = """Uploading.Com File Download Hoster"""
__author_name__ = ("jeix", "mkaay", "zoidberg")
__author_mail__ = ("jeix@hasnomail.de", "mkaay@mkaay.de", "zoidberg@mujmail.cz")
FILE_NAME_PATTERN = r'<title>Download (?P<N>.*?) for free on uploading.com</title>'
FILE_SIZE_PATTERN = r'<span>File size: (?P<S>.*?)</span>'
- FILE_OFFLINE_PATTERN = r'<h2 style=".*?">The requested file is not found</h2>'
+ FILE_OFFLINE_PATTERN = r'<h2.*?>The requested file is not found</h2>'
def process(self, pyfile):
# set lang to english
@@ -47,21 +49,20 @@ class UploadingCom(SimpleHoster): self.file_info = self.getFileInfo()
if self.premium:
- url = self.handlePremium()
+ self.handlePremium()
else:
- url = self.handleFree()
-
- self.download(url)
+ self.handleFree()
def handlePremium(self):
postData = {'action': 'get_link',
- 'code': re.search('code: "(.*?)",', self.html).group(1),
+ 'code': self.file_info['ID'],
'pass': 'undefined'}
self.html = self.load('http://uploading.com/files/get/?JsHttpRequest=%d-xml' % timestamp(), post=postData)
url = re.search(r'"link"\s*:\s*"(.*?)"', self.html)
if url:
- return url.group(1).replace("\\/", "/")
+ url = url.group(1).replace("\\/", "/")
+ self.download(url)
raise Exception("Plugin defect.")
@@ -72,39 +73,38 @@ class UploadingCom(SimpleHoster): self.logWarning(self.pyfile.error)
self.retry(max_tries=6, wait_time = 21600 if found.group(2) else 900, reason = self.pyfile.error)
- self.code = re.search(r'name="code" value="(.*?)"', self.html).group(1)
- self.fileid = re.search(r'name="file_id" value="(.*?)"', self.html).group(1)
-
- postData = {'action': 'second_page',
- 'code': self.code,
- 'file_id': self.fileid}
-
- self.html = self.load(self.pyfile.url, post=postData)
+ ajax_url = "http://uploading.com/files/get/?ajax"
+ self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With: XMLHttpRequest"])
+ self.req.http.lastURL = self.pyfile.url
- wait_time = re.search(r'timead_counter">(\d+)<', self.html)
- if not wait_time:
- wait_time = re.search(r'start_timer\((\d+)\)', self.html)
-
- if wait_time:
- wait_time = int(wait_time.group(1))
+ response = json_loads(self.load(ajax_url, post = {'action': 'second_page', 'code': self.file_info['ID']}))
+ if 'answer' in response and 'wait_time' in response['answer']:
+ wait_time = int(response['answer']['wait_time'])
self.log.info("%s: Waiting %d seconds." % (self.__name__, wait_time))
self.setWait(wait_time)
self.wait()
+ else:
+ self.pluginParseError("AJAX/WAIT")
+ response = json_loads(self.load(ajax_url, post = {'action': 'get_link', 'code': self.file_info['ID'], 'pass': 'false'}))
+ if 'answer' in response and 'link' in response['answer']:
+ url = response['answer']['link']
+ else:
+ self.pluginParseError("AJAX/URL")
+
+ self.html = self.load(url)
+ found = re.search(r'<form id="file_form" action="(.*?)"', self.html)
+ if found:
+ url = found.group(1)
+ else:
+ self.pluginParseError("URL")
- postData = {'action': 'get_link',
- 'code': self.code,
- 'pass': 'undefined'}
-
- if r'var captcha_src' in self.html[1]:
- captcha_url = "http://uploading.com/general/captcha/download%s/?ts=%d" % (self.fileid, timestamp())
- postData['captcha_code'] = self.decryptCaptcha(captcha_url)
-
- self.html = self.load('http://uploading.com/files/get/?JsHttpRequest=%d-xml' % timestamp(), post=postData)
- url = re.search(r'"link"\s*:\s*"(.*?)"', self.html)
- if url:
- return url.group(1).replace("\\/", "/")
-
- raise Exception("Plugin defect.")
+ self.download(url)
+
+ check = self.checkDownload({"html" : re.compile("\A<!DOCTYPE html PUBLIC")})
+ if check == "html":
+ self.logWarning("Redirected to a HTML page, wait 10 minutes and retry")
+ self.setWait(600, True)
+ self.wait()
getInfo = create_getInfo(UploadingCom)
\ No newline at end of file diff --git a/module/plugins/hoster/WarserverCz.py b/module/plugins/hoster/WarserverCz.py new file mode 100644 index 000000000..423170319 --- /dev/null +++ b/module/plugins/hoster/WarserverCz.py @@ -0,0 +1,34 @@ +# -*- 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 module.plugins.hoster.CoolshareCz import CoolshareCz +from module.plugins.internal.SimpleHoster import create_getInfo + +class WarserverCz(CoolshareCz): + __name__ = "WarserverCz" + __type__ = "hoster" + __pattern__ = r"http://(?:\w*\.)?warserver.cz/stahnout/(?P<ID>\d+)/.+" + __version__ = "0.11" + __description__ = """Warserver.cz""" + __author_name__ = ("zoidberg") + + FILE_NAME_PATTERN = r'<h1.*?>(?P<N>[^<]+)</h1>' + DOMAIN = "http://s01.warserver.cz" + +getInfo = create_getInfo(WarserverCz)
\ No newline at end of file diff --git a/module/plugins/hoster/WebshareCz.py b/module/plugins/hoster/WebshareCz.py new file mode 100644 index 000000000..b60fda7e4 --- /dev/null +++ b/module/plugins/hoster/WebshareCz.py @@ -0,0 +1,45 @@ +# -*- 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 module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo +from module.network.HTTPRequest import BadHeader + +class WebshareCz(SimpleHoster): + __name__ = "WebshareCz" + __type__ = "hoster" + __pattern__ = r"http://(\w+\.)?webshare.cz/(stahnout/)?(?P<ID>\w{10})-.+" + __version__ = "0.11" + __description__ = """WebShare.cz""" + __author_name__ = ("zoidberg") + + FILE_NAME_PATTERN = r'<h3>Stahujete soubor: </h3>\s*<div class="textbox">(?P<N>[^<]+)</div>' + FILE_SIZE_PATTERN = r'<h3>Velikost souboru je: </h3>\s*<div class="textbox">(?P<S>[^<]+)</div>' + FILE_OFFLINE_PATTERN = r'<h3>Soubor ".*?" nebyl nalezen.</h3>' + + DOWNLOAD_LINK_PATTERN = r'id="download_link" href="(?P<url>.*?)"' + + def handleFree(self): + url_a = re.search(r"(var l.*)", self.html).group(1) + url_b = re.search(r"(var keyStr.*)", self.html).group(1) + url = self.js.eval("%s\n%s\ndec(l)" % (url_a, url_b)) + + self.logDebug('Download link: ' + url) + self.download(url) + +getInfo = create_getInfo(WebshareCz)
\ No newline at end of file diff --git a/module/plugins/hoster/WrzucTo.py b/module/plugins/hoster/WrzucTo.py new file mode 100644 index 000000000..4a5e89f22 --- /dev/null +++ b/module/plugins/hoster/WrzucTo.py @@ -0,0 +1,58 @@ +# -*- 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 module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo +from pycurl import HTTPHEADER + +class WrzucTo(SimpleHoster): + __name__ = "WrzucTo" + __type__ = "hoster" + __pattern__ = r"http://(?:\w+\.)*?wrzuc\.to/([a-zA-Z0-9]+(\.wt|\.html)|(\w+/?linki/[a-zA-Z0-9]+))" + __version__ = "0.01" + __description__ = """Wrzuc.to plugin - free only""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + SH_COOKIES = [("http://www.wrzuc.to", "language", "en")] + FILE_SIZE_PATTERN = r'class="info">\s*<tr>\s*<td>(?P<S>.*?)</td>' + FILE_NAME_PATTERN = r'id="file_info">\s*<strong>(?P<N>.*?)</strong>' + + def setup(self): + self.multiDL = True + + def handleFree(self): + data = dict(re.findall(r'(md5|file): "(.*?)"', self.html)) + if len(data) != 2: self.parseError('File ID') + + self.req.http.c.setopt(HTTPHEADER, ["X-Requested-With: XMLHttpRequest"]) + self.req.http.lastURL = self.pyfile.url + self.load("http://www.wrzuc.to/ajax/server/prepair", post = {"md5": data['md5']}) + + self.req.http.lastURL = self.pyfile.url + self.html = self.load("http://www.wrzuc.to/ajax/server/download_link", post = {"file": data['file']}) + + data.update(re.findall(r'"(download_link|server_id)":"(.*?)"', self.html)) + if len(data) != 4: self.parseError('Download URL') + + download_url = "http://%s.wrzuc.to/pobierz/%s" % (data['server_id'], data['download_link']) + self.logDebug("Download URL: %s" % download_url) + self.download(download_url) + +getInfo = create_getInfo(WrzucTo) + diff --git a/module/plugins/hoster/XFileSharingPro.py b/module/plugins/hoster/XFileSharingPro.py new file mode 100644 index 000000000..8e213e9bf --- /dev/null +++ b/module/plugins/hoster/XFileSharingPro.py @@ -0,0 +1,286 @@ +# -*- 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 random import random +from urllib import unquote +from urlparse import urlparse +from pycurl import FOLLOWLOCATION, LOW_SPEED_TIME +from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, PluginParseError +from module.plugins.ReCaptcha import ReCaptcha +from module.utils import html_unescape + +class XFileSharingPro(SimpleHoster): + """ + Common base for XFileSharingPro hosters like EasybytezCom, CramitIn, FiledinoCom... + Some hosters may work straight away when added to __pattern__ + However, most of them will NOT work because they are either down or running a customized version + """ + __name__ = "XFileSharingPro" + __type__ = "hoster" + __pattern__ = r"^unmatchable$" + __version__ = "0.11" + __description__ = """XFileSharingPro common hoster base""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + FILE_NAME_PATTERN = r'<input type="hidden" name="fname" value="(?P<N>[^"]+)"' + FILE_SIZE_PATTERN = r'You have requested <font color="red">[^<]+</font> \((?P<S>[^<]+)\)</font>' + FILE_INFO_PATTERN = r'<tr><td align=right><b>Filename:</b></td><td nowrap>(?P<N>[^<]+)</td></tr>\s*.*?<small>\((?P<S>[^<]+)\)</small>' + FILE_OFFLINE_PATTERN = r'<(b|h2)>File Not Found</(b|h2)>' + + WAIT_PATTERN = r'<span id="countdown_str">.*?>(\d+)</span>' + LONG_WAIT_PATTERN = r'(?P<H>\d+(?=\s*hour))?.*?(?P<M>\d+(?=\s*minute))?.*?(?P<S>\d+(?=\s*second))?' + OVR_DOWNLOAD_LINK_PATTERN = r'<h2>Download Link</h2>\s*<textarea[^>]*>([^<]+)' + OVR_KILL_LINK_PATTERN = r'<h2>Delete Link</h2>\s*<textarea[^>]*>([^<]+)' + CAPTCHA_URL_PATTERN = r'(http://[^"\']+?/captchas?/[^"\']+)' + RECAPTCHA_URL_PATTERN = r'http://[^"\']+?recaptcha[^"\']+?\?k=([^"\']+)"' + CAPTCHA_DIV_PATTERN = r'<b>Enter code.*?<div.*?>(.*?)</div>' + ERROR_PATTERN = r'class=["\']err["\'][^>]*>(.*?)</' + + def setup(self): + self.__pattern__ = self.core.pluginManager.hosterPlugins[self.__name__]['pattern'] + self.multiDL = True + self.chunkLimit = 1 + + def process(self, pyfile): + if not hasattr(self, "HOSTER_NAME"): + self.HOSTER_NAME = re.search(self.__pattern__, self.pyfile.url).group(1) + if not hasattr(self, "DIRECT_LINK_PATTERN"): + self.DIRECT_LINK_PATTERN = r'(http://(\w+\.%s|\d+\.\d+\.\d+\.\d+)(:\d+/d/|/files/\d+/\w+/)[^"\'<]+)' % self.HOSTER_NAME + + self.captcha = self.errmsg = None + self.passwords = self.getPassword().splitlines() + + if not re.match(self.__pattern__, self.pyfile.url): + if self.premium: + self.handleOverriden() + else: + self.fail("Only premium users can download from other hosters with %s" % self.HOSTER_NAME) + else: + try: + self.html = self.load(pyfile.url, cookies = False, decode = True) + self.file_info = self.getFileInfo() + except PluginParseError: + self.file_info = None + + self.req.http.lastURL = self.pyfile.url + + self.req.http.c.setopt(FOLLOWLOCATION, 0) + self.html = self.load(self.pyfile.url, cookies = True, decode = True) + self.header = self.req.http.header + self.req.http.c.setopt(FOLLOWLOCATION, 1) + + self.location = None + found = re.search("Location\s*:\s*(.*)", self.header, re.I) + if found and re.match(self.DIRECT_LINK_PATTERN, found.group(1)): + self.location = found.group(1).strip() + + if not self.file_info: + pyfile.name = html_unescape(unquote(urlparse(self.location if self.location else pyfile.url).path.split("/")[-1])) + + if self.location: + self.startDownload(self.location) + elif self.premium: + self.handlePremium() + else: + self.handleFree() + + def handleFree(self): + url = self.getDownloadLink() + self.logDebug("Download URL: %s" % url) + self.startDownload(url) + + def getDownloadLink(self): + for i in range(5): + self.logDebug("Getting download link: #%d" % i) + data = self.getPostParameters() + + self.req.http.c.setopt(FOLLOWLOCATION, 0) + self.html = self.load(self.pyfile.url, post = data, ref = True, decode = True) + self.header = self.req.http.header + self.req.http.c.setopt(FOLLOWLOCATION, 1) + + found = re.search("Location\s*:\s*(.*)", self.header, re.I) + if found: + break + + found = re.search(self.DIRECT_LINK_PATTERN, self.html, re.S) + if found: + break + + else: + if captcha in self.err: + self.fail("No valid captcha code entered") + else: + self.fail("Download link not found") + + return found.group(1) + + def handlePremium(self): + self.html = self.load(self.pyfile.url, post = self.getPostParameters()) + found = re.search(self.DIRECT_LINK_PATTERN, self.html) + if not found: self.parseError('DIRECT LINK') + self.startDownload(found.group(1)) + + def handleOverriden(self): + #only tested with easybytez.com + self.html = self.load("http://www.%s/" % self.HOSTER_NAME) + action, inputs = self.parseHtmlForm('') + upload_id = "%012d" % int(random()*10**12) + action += upload_id + "&js_on=1&utype=prem&upload_type=url" + inputs['tos'] = '1' + inputs['url_mass'] = self.pyfile.url + inputs['up1oad_type'] = 'url' + + self.logDebug(self.HOSTER_NAME, action, inputs) + #wait for file to upload to easybytez.com + self.req.http.c.setopt(LOW_SPEED_TIME, 600) + self.html = self.load(action, post = inputs) + + action, inputs = self.parseHtmlForm('F1') + if not inputs: self.parseError('TEXTAREA') + self.logDebug(self.HOSTER_NAME, inputs) + if inputs['st'] == 'OK': + self.html = self.load(action, post = inputs) + elif inputs['st'] == 'Can not leech file': + self.retry(max_tries=20, wait_time=180, reason=inputs['st']) + else: + self.fail(inputs['st']) + + #get easybytez.com link for uploaded file + found = re.search(self.OVR_DOWNLOAD_LINK_PATTERN, self.html) + if not found: self.parseError('DIRECT LINK (OVR)') + self.pyfile.url = found.group(1) + self.retry() + + def startDownload(self, link): + if self.captcha: self.correctCaptcha() + self.logDebug('DIRECT LINK: %s' % link) + self.download(link) + + def checkErrors(self): + found = re.search(self.ERROR_PATTERN, self.html) + if found: + self.errmsg = found.group(1) + self.logWarning(re.sub(r"<.*?>"," ",self.errmsg)) + + if 'wait' in self.errmsg: + wait_time = sum([int(v) * {"hour": 3600, "minute": 60, "second": 1}[u] for v, u in re.findall('(\d+)\s*(hour|minute|second)?', self.errmsg)]) + self.setWait(wait_time, True) + self.wait() + elif 'limit' in self.errmsg: + self.setWait(3600, True) + self.wait() + self.retry(25) + elif 'captcha' in self.errmsg: + self.invalidCaptcha() + elif 'countdown' or 'Expired session' in self.errmsg: + self.retry(3) + elif 'maintenance' in self.errmsg: + self.tempOffline() + elif 'download files up to' in self.errmsg: + self.fail("File too large for free download") + elif 'requires premium' in self.errmsg: + self.fail("File can be downloaded by premium users only") + else: + self.fail(self.errmsg) + + else: + self.errmsg = None + + return self.errmsg + + def getPostParameters(self): + for i in range(3): + if not self.errmsg: self.checkErrors() + + action, inputs = self.parseHtmlForm('F1') + if not inputs: + action, inputs = self.parseHtmlForm("action=(''|\"\")") + if not inputs: + if self.errmsg: + self.retry() + else: + self.parseError("Form not found") + + self.logDebug(self.HOSTER_NAME, inputs) + + if 'op' in inputs and inputs['op'] in ('download2', 'download3'): + if "password" in inputs: + if self.passwords: + inputs['password'] = self.passwords.pop(0) + else: + self.fail("No or invalid passport") + + if not self.premium: + found = re.search(self.WAIT_PATTERN, self.html) + if found: + wait_time = int(found.group(1)) + 1 + self.setWait(wait_time, False) + else: + wait_time = 0 + + self.captcha = self.handleCaptcha(inputs) + + if wait_time: self.wait() + + self.errmsg = None + return inputs + + else: + inputs['referer'] = self.pyfile.url + + if self.premium: + inputs['method_premium'] = "Premium Download" + if 'method_free' in inputs: del inputs['method_free'] + else: + inputs['method_free'] = "Free Download" + if 'method_premium' in inputs: del inputs['method_premium'] + + self.html = self.load(self.pyfile.url, post = inputs, ref = True) + self.errmsg = None + + else: self.parseError('FORM: %s' % (inputs['op'] if 'op' in inputs else 'UNKNOWN')) + + def handleCaptcha(self, inputs): + found = re.search(self.RECAPTCHA_URL_PATTERN, self.html) + if found: + recaptcha_key = unquote(found.group(1)) + self.logDebug("RECAPTCHA KEY: %s" % recaptcha_key) + recaptcha = ReCaptcha(self) + inputs['recaptcha_challenge_field'], inputs['recaptcha_response_field'] = recaptcha.challenge(recaptcha_key) + return 1 + else: + found = re.search(self.CAPTCHA_URL_PATTERN, self.html) + if found: + captcha_url = found.group(1) + inputs['code'] = self.decryptCaptcha(captcha_url) + return 2 + else: + found = re.search(self.CAPTCHA_DIV_PATTERN, self.html, re.S) + if found: + captcha_div = found.group(1) + self.logDebug(captcha_div) + numerals = re.findall('<span.*?padding-left\s*:\s*(\d+).*?>(\d)</span>', html_unescape(captcha_div)) + inputs['code'] = "".join([a[1] for a in sorted(numerals, key = lambda num: int(num[0]))]) + self.logDebug("CAPTCHA", inputs['code'], numerals) + return 3 + return 0 + +getInfo = create_getInfo(XFileSharingPro)
\ No newline at end of file diff --git a/module/plugins/hoster/YibaishiwuCom.py b/module/plugins/hoster/YibaishiwuCom.py new file mode 100644 index 000000000..5926cc227 --- /dev/null +++ b/module/plugins/hoster/YibaishiwuCom.py @@ -0,0 +1,54 @@ +# -*- 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 module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo +from module.common.json_layer import json_loads + +class YibaishiwuCom(SimpleHoster): + __name__ = "YibaishiwuCom" + __type__ = "hoster" + __pattern__ = r"http://(?:www\.)?(?:u\.)?115.com/file/(?P<ID>\w+)" + __version__ = "0.11" + __description__ = """115.com""" + __author_name__ = ("zoidberg") + + FILE_NAME_PATTERN = r"file_name: '(?P<N>[^']+)'" + FILE_SIZE_PATTERN = r"file_size: '(?P<S>[^']+)'" + FILE_OFFLINE_PATTERN = ur'<h3><i style="color:red;">哎呀!提取码不存在!不妨搜搜看吧!</i></h3>' + + AJAX_URL_PATTERN = r'(/\?ct=(pickcode|download)[^"\']+)' + + def handleFree(self): + found = re.search(self.AJAX_URL_PATTERN, self.html) + if not found: self.parseError("AJAX URL") + url = found.group(1) + self.logDebug(('FREEUSER' if found.group(2) == 'download' else 'GUEST') + ' URL', url) + + response = json_loads(self.load("http://115.com" + url, decode = False)) + for mirror in (response['urls'] if 'urls' in response else response['data'] if 'data' in response else []): + try: + url = mirror['url'].replace('\\','') + self.logDebug("Trying URL: " + url) + header = self.download(url) + break + except: + continue + else: self.fail('No working link found') + +getInfo = create_getInfo(YibaishiwuCom)
\ No newline at end of file diff --git a/module/plugins/hoster/ZeveraCom.py b/module/plugins/hoster/ZeveraCom.py index d1fa80802..8be725d2f 100644 --- a/module/plugins/hoster/ZeveraCom.py +++ b/module/plugins/hoster/ZeveraCom.py @@ -1,83 +1,108 @@ -#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-from module.plugins.Hoster import Hoster
-from module.utils import html_unescape
-from urllib import quote, unquote
-from time import sleep
-
-class ZeveraCom(Hoster):
- __name__ = "ZeveraCom"
- __version__ = "0.11"
- __type__ = "hoster"
- __pattern__ = r"http://zevera.com/.*"
- __description__ = """zevera.com hoster plugin"""
- __author_name__ = ("zoidberg")
- __author_mail__ = ("zoidberg@mujmail.cz")
-
- api_url = "http://zevera.com/API.ashx"
-
- def process(self, pyfile):
- if not self.account:
- self.logError(_("Please enter your zevera.com account or deactivate this plugin"))
- self.fail("No zevera.com account provided")
-
- self.logDebug("zevera.com: Old URL: %s" % pyfile.url)
-
- last_size = retries = 0
- olink = self.pyfile.url #quote(self.pyfile.url.encode('utf_8'))
-
- for i in range(100):
- self.retData = self.account.loadAPIRequest(self.req, cmd = 'download_request', olink = olink)
- self.checkAPIErrors(self.retData)
-
- if self.retData['FileInfo']['StatusID'] == 100:
- break
- elif self.retData['FileInfo']['StatusID'] == 99:
- self.fail('Failed to initialize download (99)')
- else:
- if self.retData['FileInfo']['Progress']['BytesReceived'] <= last_size:
- if retries >= 6:
- self.fail('Failed to initialize download (%d)' % self.retData['FileInfo']['StatusID'] )
- retries += 1
- else:
- retries = 0
-
- last_size = self.retData['FileInfo']['Progress']['BytesReceived']
-
- pyfile.progress = self.retData['FileInfo']['Progress']['Percentage']
-
- self.setWait(self.retData['Update_Wait'])
- self.wait()
-
- pyfile.progress = 0
- pyfile.name = self.crazyDecode(self.retData['FileInfo']['RealFileName'])
- pyfile.size = self.retData['FileInfo']['FileSizeInBytes']
-
- self.retData = self.account.loadAPIRequest(self.req, cmd = 'download_start', FileID = self.retData['FileInfo']['FileID'])
- self.checkAPIErrors(self.retData)
-
- self.download(self.api_url, get = {
- 'cmd': "open_stream",
- 'login': self.account.loginname,
- 'pass': self.account.password,
- 'FileID': self.retData['FileInfo']['FileID'],
- 'startBytes': 0
- }
- )
-
- def checkAPIErrors(self, retData):
- if not retData:
- self.fail('Unknown API response')
-
- if retData['ErrorCode']:
- self.logError(retData['ErrorCode'], retData['ErrorMessage'])
- self.fail('ERROR: ' + retData['ErrorMessage'])
-
- if self.pyfile.size / 1024000 > retData['AccountInfo']['AvailableTODAYTrafficForUseInMBytes']:
- self.logWarning("Not enough data left to download the file")
-
- def crazyDecode(self, ustring):
- # accepts decoded ie. unicode string - API response is double-quoted, double-utf8-encoded
- # no idea what the proper order of calling these functions would be :-/
- return html_unescape(unquote(unquote(ustring.replace('@DELIMITER@','#'))).encode('raw_unicode_escape').decode('utf-8'))
\ No newline at end of file +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from module.plugins.Hoster import Hoster +from module.utils import html_unescape +from urllib import quote, unquote +from time import sleep + +class ZeveraCom(Hoster): + __name__ = "ZeveraCom" + __version__ = "0.20" + __type__ = "hoster" + __pattern__ = r"http://zevera.com/.*" + __description__ = """zevera.com hoster plugin""" + __author_name__ = ("zoidberg") + __author_mail__ = ("zoidberg@mujmail.cz") + + def setup(self): + self.resumeDownload = self.multiDL = True + self.chunkLimit = 1 + + def process(self, pyfile): + if not self.account: + self.logError(_("Please enter your zevera.com account or deactivate this plugin")) + self.fail("No zevera.com account provided") + + self.logDebug("zevera.com: Old URL: %s" % pyfile.url) + + if self.account.getAPIData(self.req, cmd = "checklink", olink = pyfile.url) != "Alive": + self.fail("Offline or not downloadable - contact Zevera support") + + header = self.account.getAPIData(self.req, just_header = True, cmd="generatedownloaddirect", olink = pyfile.url) + if not "location" in header: + self.fail("Unable to initialize download - contact Zevera support") + + self.download(header['location'], disposition = True) + + check = self.checkDownload({"error" : 'action="ErrorDownload.aspx'}) + if check == "error": + self.fail("Error response received - contact Zevera support") + + """ + # BitAPI not used - defunct, probably abandoned by Zevera + + api_url = "http://zevera.com/API.ashx" + + def process(self, pyfile): + if not self.account: + self.logError(_("Please enter your zevera.com account or deactivate this plugin")) + self.fail("No zevera.com account provided") + + self.logDebug("zevera.com: Old URL: %s" % pyfile.url) + + last_size = retries = 0 + olink = self.pyfile.url #quote(self.pyfile.url.encode('utf_8')) + + for i in range(100): + self.retData = self.account.loadAPIRequest(self.req, cmd = 'download_request', olink = olink) + self.checkAPIErrors(self.retData) + + if self.retData['FileInfo']['StatusID'] == 100: + break + elif self.retData['FileInfo']['StatusID'] == 99: + self.fail('Failed to initialize download (99)') + else: + if self.retData['FileInfo']['Progress']['BytesReceived'] <= last_size: + if retries >= 6: + self.fail('Failed to initialize download (%d)' % self.retData['FileInfo']['StatusID'] ) + retries += 1 + else: + retries = 0 + + last_size = self.retData['FileInfo']['Progress']['BytesReceived'] + + self.setWait(self.retData['Update_Wait']) + self.wait() + + pyfile.name = self.retData['FileInfo']['RealFileName'] + pyfile.size = self.retData['FileInfo']['FileSizeInBytes'] + + self.retData = self.account.loadAPIRequest(self.req, cmd = 'download_start', FileID = self.retData['FileInfo']['FileID']) + self.checkAPIErrors(self.retData) + + self.download(self.api_url, get = { + 'cmd': "open_stream", + 'login': self.account.loginname, + 'pass': self.account.password, + 'FileID': self.retData['FileInfo']['FileID'], + 'startBytes': 0 + } + ) + + def checkAPIErrors(self, retData): + if not retData: + self.fail('Unknown API response') + + if retData['ErrorCode']: + self.logError(retData['ErrorCode'], retData['ErrorMessage']) + #self.fail('ERROR: ' + retData['ErrorMessage']) + + if self.pyfile.size / 1024000 > retData['AccountInfo']['AvailableTODAYTrafficForUseInMBytes']: + self.logWarning("Not enough data left to download the file") + + def crazyDecode(self, ustring): + # accepts decoded ie. unicode string - API response is double-quoted, double-utf8-encoded + # no idea what the proper order of calling these functions would be :-/ + return html_unescape(unquote(unquote(ustring.replace('@DELIMITER@','#'))).encode('raw_unicode_escape').decode('utf-8')) + """
\ No newline at end of file diff --git a/module/plugins/hoster/ZippyshareCom.py b/module/plugins/hoster/ZippyshareCom.py index 5b32b4068..6b0b01003 100644 --- a/module/plugins/hoster/ZippyshareCom.py +++ b/module/plugins/hoster/ZippyshareCom.py @@ -1,51 +1,186 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -import re -from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo +import re, subprocess, tempfile, os +from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, timestamp +from module.plugins.ReCaptcha import ReCaptcha +from module.common.json_layer import json_loads class ZippyshareCom(SimpleHoster): __name__ = "ZippyshareCom" __type__ = "hoster" - __pattern__ = r"(http://www\d{0,2}\.zippyshare.com)/v(?:/|iew.jsp.*key=)(\d+)" - __version__ = "0.31" + __pattern__ = r"(?P<HOST>http://www\d{0,2}\.zippyshare.com)/v(?:/|iew.jsp.*key=)(?P<KEY>\d+)" + __version__ = "0.36" __description__ = """Zippyshare.com Download Hoster""" __author_name__ = ("spoob", "zoidberg") __author_mail__ = ("spoob@pyload.org", "zoidberg@mujmail.cz") + __config__ = [("swfdump_path", "string", "Path to swfdump", "")] FILE_NAME_PATTERN = r'>Name:</font>\s*<font [^>]*>(?P<N>[^<]+)</font><br />' FILE_SIZE_PATTERN = r'>Size:</font>\s*<font [^>]*>(?P<S>[0-9.,]+) (?P<U>[kKMG]+)i?B</font><br />' FILE_OFFLINE_PATTERN = r'>File does not exist on this server</div>' - DOWNLOAD_URL_PATTERN = r"document\.getElementById\('dlbutton'\).href = ([^;]+);" - SEED_PATTERN = r"seed: (\d*)" + DOWNLOAD_URL_PATTERN = r"<script type=\"text/javascript\">([^<]*?)document\.getElementById\('dlbutton'\).href = ([^;]+);" + SEED_PATTERN = r'swfobject.embedSWF\("([^"]+)".*?seed: (\d+)' + CAPTCHA_KEY_PATTERN = r'Recaptcha.create\("([^"]+)"' + CAPTCHA_SHORTENCODE_PATTERN = r"shortencode: '([^']+)'" + CAPTCHA_DOWNLOAD_PATTERN = r"document.location = '([^']+)'" + + LAST_KNOWN_VALUES = (9, 2374755) #time = (seed * multiply) % modulo def setup(self): self.html = None self.wantReconnect = False self.multiDL = True - def handleFree(self): + def handleFree(self): url = self.get_file_url() + if not url: self.fail("Download URL not found.") self.logDebug("Download URL %s" % url) self.download(url, cookies = True) + check = self.checkDownload({ + "swf_values": re.compile(self.SEED_PATTERN) + }) + + if check == "swf_values": + swf_sts = self.getStorage("swf_sts") + if not swf_sts: + self.setStorage("swf_sts", 2) + self.setStorage("swf_stamp", 0) + elif swf_sts == '1': + self.setStorage("swf_sts", 2) + + self.retry(max_tries = 1) + def get_file_url(self): """ returns the absolute downloadable filepath """ - file_host, file_key = re.search(self.__pattern__, self.pyfile.url).groups() + url = multiply = modulo = None - found = re.search(self.DOWNLOAD_URL_PATTERN, self.html) + found = re.search(self.DOWNLOAD_URL_PATTERN, self.html, re.S) if found: - url = self.js.eval(found.group(1)) + #Method #1: JS eval + url = self.js.eval("\n".join(found.groups())) else: + #Method #2: SWF eval seed_search = re.search(self.SEED_PATTERN, self.html) - if seed_search is None: self.parseError('SEED') + if seed_search: + swf_url, file_seed = seed_search.groups() + + swf_sts = self.getStorage("swf_sts") + swf_stamp = int(self.getStorage("swf_stamp") or 0) + swf_version = self.getStorage("version") + self.logDebug("SWF", swf_sts, swf_stamp, swf_version) + + if not swf_sts: + self.logDebug('Using default values') + multiply, modulo = self.LAST_KNOWN_VALUES + elif swf_sts == "1": + self.logDebug('Using stored values') + multiply = self.getStorage("multiply") + modulo = self.getStorage("modulo") + elif swf_sts == "2": + if swf_version < self.__version__: + self.logDebug('Reverting to default values') + self.setStorage("swf_sts", "") + self.setStorage("version", self.__version__) + multiply, modulo = self.LAST_KNOWN_VALUES + elif (swf_stamp + 3600000) < timestamp(): + swfdump = self.get_swfdump_path() + if swfdump: + multiply, modulo = self.get_swf_values(self.file_info['HOST'] + swf_url, swfdump) + else: + self.logWarning("Swfdump not found. Install swftools to bypass captcha.") + + if multiply and modulo: + self.logDebug("TIME = (%s * %s) %s" % (file_seed, multiply, modulo)) + url = "/download?key=%s&time=%d" % (self.file_info['KEY'], (int(file_seed) * int(multiply)) % int(modulo)) + + if not url: + #Method #3: Captcha + url = self.do_recaptcha() + + return self.file_info['HOST'] + url + + def get_swf_values(self, swf_url, swfdump): + self.logDebug('Parsing values from %s' % swf_url) + multiply = modulo = None + + fd, fpath = tempfile.mkstemp() + try: + swf_data = self.load(swf_url) + os.write(fd, swf_data) + + p = subprocess.Popen([swfdump, '-a', fpath], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = p.communicate() + + if err: + self.logError(err) + else: + m_str = re.search(r'::break.*?{(.*?)}', out, re.S).group(1) + multiply = re.search(r'pushbyte (\d+)', m_str).group(1) + modulo = re.search(r'pushint (\d+)', m_str).group(1) + finally: + os.close(fd) + os.remove(fpath) + + if multiply and modulo: + self.setStorage("multiply", multiply) + self.setStorage("modulo", modulo) + self.setStorage("swf_sts", 1) + self.setStorage("version", self.__version__) + else: + self.logError("Parsing SWF failed: swfdump not installed or plugin out of date") + self.setStorage("swf_sts", 2) - file_seed = int(seed_search.group(1)) - time = str((file_seed * 24) % 6743256) - url = "/download?key=" + str(file_key) + "&time=" + str(time) + self.setStorage("swf_stamp", timestamp()) + + return multiply, modulo + + def get_swfdump_path(self): + # used for detecting if swfdump is installed + def is_exe(ppath): + return os.path.isfile(ppath) and os.access(ppath, os.X_OK) + + program = self.getConfig("swfdump_path") or "swfdump" + swfdump = None + ppath, pname = os.path.split(program) + if ppath: + if is_exe(program): + swfdump = program + else: + for ppath in os.environ["PATH"].split(os.pathsep): + exe_file = os.path.join(ppath, program) + if is_exe(exe_file): + swfdump = exe_file + + # return path to the executable or None if not found + return swfdump + + def do_recaptcha(self): + self.logDebug('Trying to solve captcha') + captcha_key = re.search(self.CAPTCHA_KEY_PATTERN, self.html).group(1) + shortencode = re.search(self.CAPTCHA_SHORTENCODE_PATTERN, self.html).group(1) + url = re.search(self.CAPTCHA_DOWNLOAD_PATTERN, self.html).group(1) + + recaptcha = ReCaptcha(self) + + for i in range(5): + challenge, code = recaptcha.challenge(captcha_key) + + response = json_loads(self.load(self.file_info['HOST'] + '/rest/captcha/test', + post={'challenge': challenge, + 'response': code, + 'shortencode': shortencode})) + self.logDebug("reCaptcha response : %s" % response) + if response == True: + self.correctCaptcha + break + else: + self.invalidCaptcha() + else: self.fail("Invalid captcha") - return file_host + url + return url getInfo = create_getInfo(ZippyshareCom)
\ No newline at end of file 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 diff --git a/module/setup.py b/module/setup.py index de93089b3..88188d1f7 100644 --- a/module/setup.py +++ b/module/setup.py @@ -451,23 +451,16 @@ class Setup(): p1 = True p2 = False while p1 != p2: - if os.name == "nt": - qst = str("Password: ") #no unicode on windows - else: - qst = _("Password: ") - - p1 = getpass(qst.encode("utf-8")) + # getpass(_("Password: ")) will crash on systems with broken locales (Win, NAS) + sys.stdout.write(_("Password: ")) + p1 = getpass("") if len(p1) < 4: - print _("Password to short. Use at least 4 symbols.") + print _("Password too short. Use at least 4 symbols.") continue - if os.name == "nt": - qst = str("Password (again): ") - else: - qst = _("Password (again): ") - - p2 = getpass(qst.encode("utf-8")) + sys.stdout.write(_("Password (again): ")) + p2 = getpass("") if p1 == p2: return p1 |