diff options
Diffstat (limited to 'module/plugins')
125 files changed, 6716 insertions, 1744 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 | 
