diff options
| author | 2013-05-20 20:19:00 +0200 | |
|---|---|---|
| committer | 2013-05-20 20:19:00 +0200 | |
| commit | d4451312d80b0443cf7a48142c00dcc7bf3be65a (patch) | |
| tree | b152f6dc0e5a98b4e944648590e34f2f12282a45 | |
| parent | smaller footer (diff) | |
| parent | CloudzerNet: reconnect support (diff) | |
| download | pyload-d4451312d80b0443cf7a48142c00dcc7bf3be65a.tar.xz | |
Merge branch 'stable'
46 files changed, 1329 insertions, 581 deletions
diff --git a/module/plugins/accounts/CzshareCom.py b/module/plugins/accounts/CzshareCom.py index e68248aa8..7b1a8edc5 100644 --- a/module/plugins/accounts/CzshareCom.py +++ b/module/plugins/accounts/CzshareCom.py @@ -17,42 +17,41 @@      @author: zoidberg  """ -from module.plugins.Account import Account  from time import mktime, strptime -from string import replace  import re +from module.plugins.Account import Account + +  class CzshareCom(Account):      __name__ = "CzshareCom" -    __version__ = "0.11" +    __version__ = "0.13"      __type__ = "account"      __description__ = """czshare.com account plugin""" -    __author_name__ = ("zoidberg") -    __author_mail__ = ("zoidberg@mujmail.cz") -     +    __author_name__ = ("zoidberg", "stickell") +    __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it") +      CREDIT_LEFT_PATTERN = r'<tr class="active">\s*<td>([0-9 ,]+) (KiB|MiB|GiB)</td>\s*<td>([^<]*)</td>\s*</tr>'      def loadAccountInfo(self, user, req): -        self.relogin(user)          html = req.load("http://czshare.com/prehled_kreditu/") -         +          found = re.search(self.CREDIT_LEFT_PATTERN, html) -        if found is None: -            credits, validuntil = 0, 0 +        if not found: +            return {"validuntil": 0, "trafficleft": 0}          else: -            credits = float(found.group(1).replace(' ', '').replace(',','.')) -            credits = credits * 1024**{'KiB' : 0, 'MiB' : 1, 'GiB' : 2}[found.group(2)] +            credits = float(found.group(1).replace(' ', '').replace(',', '.')) +            credits = credits * 1024 ** {'KiB': 0, 'MiB': 1, 'GiB': 2}[found.group(2)]              validuntil = mktime(strptime(found.group(3), '%d.%m.%y %H:%M')) -         -        return {"validuntil": validuntil, "trafficleft": credits} -     +            return {"validuntil": validuntil, "trafficleft": credits} +      def login(self, user, data, req): -     +          html = req.load('https://czshare.com/index.php', post={ -                "Prihlasit": "Prihlasit", -                "login-password": data["password"], -                "login-name": user -                }) -                 +            "Prihlasit": "Prihlasit", +            "login-password": data["password"], +            "login-name": user +        }) +          if '<div class="login' in html:              self.wrongPassword() diff --git a/module/plugins/accounts/FastshareCz.py b/module/plugins/accounts/FastshareCz.py index 333ee3761..69bbb0827 100644 --- a/module/plugins/accounts/FastshareCz.py +++ b/module/plugins/accounts/FastshareCz.py @@ -21,32 +21,34 @@ import re  from module.plugins.Account import Account  from module.utils import parseFileSize +  class FastshareCz(Account):      __name__ = "FastshareCz" -    __version__ = "0.01" +    __version__ = "0.02"      __type__ = "account"      __description__ = """fastshare.cz account plugin""" -    __author_name__ = ("zoidberg") -    __author_mail__ = ("zoidberg@mujmail.cz") -     +    __author_name__ = ("zoidberg", "stickell") +    __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it") +      def loadAccountInfo(self, user, req): -        html = req.load("http://www.fastshare.cz/user", decode = True) -                     -        found = re.search(r'Kredit: </td><td>(.+?) ', html)            +        html = req.load("http://www.fastshare.cz/user", decode=True) + +        found = re.search(r'(?:Kredit|Credit)\s*: </td><td>(.+?) ', html)          if found: -            trafficleft = parseFileSize(found.group(1)) / 1024     +            trafficleft = parseFileSize(found.group(1)) / 1024              premium = True if trafficleft else False          else:              trafficleft = None -            premium = False   +            premium = False          return {"validuntil": -1, "trafficleft": trafficleft, "premium": premium} -     +      def login(self, user, data, req): -        html = req.load('http://www.fastshare.cz/sql.php', post = { +        req.load('http://www.fastshare.cz/login')  # Do not remove or it will not login +        html = req.load('http://www.fastshare.cz/sql.php', post={              "heslo": data['password'],              "login": user -            }, decode = True) -         +        }, decode=True) +          if u'>Špatné uživatelské jméno nebo heslo.<' in html:              self.wrongPassword()
\ No newline at end of file diff --git a/module/plugins/accounts/FilefactoryCom.py b/module/plugins/accounts/FilefactoryCom.py index 356c5d22a..8e163e2f6 100644 --- a/module/plugins/accounts/FilefactoryCom.py +++ b/module/plugins/accounts/FilefactoryCom.py @@ -23,13 +23,13 @@ from time import mktime, strptime  class FilefactoryCom(Account):      __name__ = "FilefactoryCom" -    __version__ = "0.12" +    __version__ = "0.13"      __type__ = "account"      __description__ = """filefactory.com account plugin""" -    __author_name__ = ("zoidberg") -    __author_mail__ = ("zoidberg@mujmail.cz") +    __author_name__ = ("zoidberg", "stickell") +    __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it") -    ACCOUNT_INFO_PATTERN = r'<a href="/premium/">.*?datetime="(.*?)"' +    ACCOUNT_INFO_PATTERN = r'<time datetime="([\d-]+)">'      def loadAccountInfo(self, user, req):                html = req.load("http://www.filefactory.com/member/") @@ -37,7 +37,7 @@ class FilefactoryCom(Account):          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")) +            validuntil = mktime(strptime(found.group(1),"%Y-%m-%d"))          else:              premium = False              validuntil = -1    diff --git a/module/plugins/accounts/MultiDebridCom.py b/module/plugins/accounts/MultiDebridCom.py new file mode 100644 index 000000000..904be5ee7 --- /dev/null +++ b/module/plugins/accounts/MultiDebridCom.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- + +############################################################################ +# This program is free software: you can redistribute it and/or modify     # +# it under the terms of the GNU Affero 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 Affero General Public License for more details.                      # +#                                                                          # +# You should have received a copy of the GNU Affero General Public License # +# along with this program.  If not, see <http://www.gnu.org/licenses/>.    # +############################################################################ + +from time import time + +from module.plugins.Account import Account +from module.common.json_layer import json_loads + + +class MultiDebridCom(Account): +    __name__ = "MultiDebridCom" +    __version__ = "0.01" +    __type__ = "account" +    __description__ = """Multi-debrid.com account plugin""" +    __author_name__ = ("stickell") +    __author_mail__ = ("l.stickell@yahoo.it") + +    def loadAccountInfo(self, user, req): +        if 'days_left' in self.json_data: +            validuntil = int(time() + self.json_data['days_left'] * 86400) +            return {"premium": True, "validuntil": validuntil, "trafficleft": -1} +        else: +            self.logError('Unable to get account information') + +    def login(self, user, data, req): +        # Password to use is the API-Password written in http://multi-debrid.com/myaccount +        self.html = req.load("http://multi-debrid.com/api.php", +                             get={"user": user, "pass": data["password"]}) +        self.logDebug('JSON data: ' + self.html) +        self.json_data = json_loads(self.html) +        if self.json_data['status'] != 'ok': +            self.logError('Invalid login. The password to use is the API-Password you find in your "My Account" page') +            self.wrongPassword() diff --git a/module/plugins/accounts/RapidgatorNet.py b/module/plugins/accounts/RapidgatorNet.py index 74825a0f9..85adc71a3 100644 --- a/module/plugins/accounts/RapidgatorNet.py +++ b/module/plugins/accounts/RapidgatorNet.py @@ -24,7 +24,7 @@ from module.common.json_layer import json_loads  class RapidgatorNet(Account):      __name__ = "RapidgatorNet" -    __version__ = "0.03" +    __version__ = "0.04"      __type__ = "account"      __description__ = """rapidgator.net account plugin"""      __author_name__ = ("zoidberg") @@ -46,7 +46,7 @@ class RapidgatorNet(Account):                      self.scheduleRefresh(user, json['response']['reset_in'])                  return {"validuntil": json['response']['expire_date'],  -                        "trafficleft": json['response']['traffic_left'] / 1024,  +                        "trafficleft": int(json['response']['traffic_left']) / 1024,                           "premium": True}              else:                  self.logError(json['response_details']) @@ -71,4 +71,4 @@ class RapidgatorNet(Account):          except Exception, e:              self.logError(e) -        self.wrongPassword()
\ No newline at end of file +        self.wrongPassword() diff --git a/module/plugins/addons/DebridItaliaCom.py b/module/plugins/addons/DebridItaliaCom.py index d570eebe3..80cdc45f6 100644 --- a/module/plugins/addons/DebridItaliaCom.py +++ b/module/plugins/addons/DebridItaliaCom.py @@ -20,7 +20,7 @@ from module.plugins.internal.MultiHoster import MultiHoster  class DebridItaliaCom(MultiHoster):      __name__ = "DebridItaliaCom" -    __version__ = "0.03" +    __version__ = "0.05"      __type__ = "hook"      __config__ = [("activated", "bool", "Activated", "False"),                    ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"), @@ -38,4 +38,4 @@ class DebridItaliaCom(MultiHoster):                  "bitshare.com", "share-links.biz", "putlocker.com", "uploaded.to",                  "speedload.org", "rapidgator.net", "likeupload.net", "cyberlocker.ch",                  "depositfiles.com", "extabit.com", "filefactory.com", "sharefiles.co", -                "ryushare.com", "tusfiles.net", "nowvideo.co"] +                "ryushare.com", "tusfiles.net", "nowvideo.co", "cloudzer.net", "letitbit.net"] diff --git a/module/plugins/addons/DeleteFinished.py b/module/plugins/addons/DeleteFinished.py new file mode 100644 index 000000000..e0df69eef --- /dev/null +++ b/module/plugins/addons/DeleteFinished.py @@ -0,0 +1,86 @@ +  # -*- 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: Walter Purcaro +""" + +from module.plugins.Hook import Hook +from time import time + + +class DeleteFinished(Hook): +    __name__ = "DeleteFinished" +    __version__ = "0.5" +    __description__ = "Automatically delete finished packages from queue" +    __config__ = [ +        ("activated", "bool", "Activated", "False"), +        ("interval", "int", "Delete every (hours)", "72") +    ] +    __author_name__ = ("Walter Purcaro") +    __author_mail__ = ("vuolter@gmail.com") + +    def wakeup(self, pypack): +        # self.logDebug("self.wakeup") +        self.removeEvent("packageFinished", self.wakeup) +        self.info["sleep"] = False + +    def periodical(self): +        # self.logDebug("self.periodical") +        if not self.info["sleep"]: +            self.core.api.deleteFinished() +            self.logDebug("called self.core.api.deleteFinished") +            self.info["sleep"] = True +            self.addEvent("packageFinished", self.wakeup) + +    def addEvent(self, event, handler): +        if event in self.manager.events: +            if handler not in self.manager.events[event]: +                self.manager.events[event].append(handler) +                # self.logDebug("self.addEvent: " + event + ": added handler") +            else: +                # self.logDebug("self.addEvent: " + event + ": NOT added handler") +                return False +        else: +            self.manager.events[event] = [handler] +            # self.logDebug("self.addEvent: " + event + ": added event and handler") +        return True + +    def removeEvent(self, event, handler): +        if event in self.manager.events and handler in self.manager.events[event]: +            self.manager.events[event].remove(handler) +            # self.logDebug("self.removeEvent: " + event + ": removed handler") +            return True +        else: +            # self.logDebug("self.removeEvent: " + event + ": NOT removed handler") +            return False + +    def configEvents(self, plugin=None, name=None, value=None): +        # self.logDebug("self.configEvents") +        interval = self.getConfig("interval") * 3600 +        if interval != self.interval: +            self.interval = interval + +    def unload(self): +        # self.logDebug("self.unload") +        self.removeEvent("pluginConfigChanged", self.configEvents) +        self.removeEvent("packageFinished", self.wakeup) + +    def coreReady(self): +        # self.logDebug("self.coreReady") +        self.info = {"sleep": True} +        self.addEvent("pluginConfigChanged", self.configEvents) +        self.configEvents() +        self.addEvent("packageFinished", self.wakeup) diff --git a/module/plugins/addons/DownloadScheduler.py b/module/plugins/addons/DownloadScheduler.py index 7cadede38..4049d71c5 100644 --- a/module/plugins/addons/DownloadScheduler.py +++ b/module/plugins/addons/DownloadScheduler.py @@ -18,61 +18,69 @@  import re  from time import localtime +  from module.plugins.Hook import Hook +  class DownloadScheduler(Hook):      __name__ = "DownloadScheduler" -    __version__ = "0.20" +    __version__ = "0.21"      __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") -     +    __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"), +                  ("abort", "bool", "Abort active downloads when start period with speed 0", "False")] +    __author_name__ = ("zoidberg", "stickell") +    __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it") +      def setup(self): -        self.cb = None # callback to scheduler job; will be by removed hookmanager when hook unloaded        -     +        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"))          + +    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)       -       + +        self.logDebug("Schedule", schedule) +          for i, v in enumerate(schedule):              if v[3] == "X": -                last, next = schedule[i-1], schedule[(i+1) % len(schedule)] +                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.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):      +                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.)") +            abort = self.getConfig("abort") +            self.logInfo("Stopping download server. (Running downloads will %sbe aborted.)" % ('' if abort else 'not '))              self.core.api.pauseServer() +            if abort: +                self.core.api.stopAllDownloads()          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) +                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 +                self.core.api.setConfigValue("download", "limit_speed", 0) +                self.core.api.setConfigValue("download", "max_speed", -1) diff --git a/module/plugins/addons/MultiDebridCom.py b/module/plugins/addons/MultiDebridCom.py new file mode 100644 index 000000000..c95138648 --- /dev/null +++ b/module/plugins/addons/MultiDebridCom.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- + +############################################################################ +# This program is free software: you can redistribute it and/or modify     # +# it under the terms of the GNU Affero 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 Affero General Public License for more details.                      # +#                                                                          # +# You should have received a copy of the GNU Affero General Public License # +# along with this program.  If not, see <http://www.gnu.org/licenses/>.    # +############################################################################ + +from module.plugins.internal.MultiHoster import MultiHoster +from module.network.RequestFactory import getURL +from module.common.json_layer import json_loads + + +class MultiDebridCom(MultiHoster): +    __name__ = "MultiDebridCom" +    __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)", ""), +                  ("unloadFailing", "bool", "Revert to standard download if download fails", "False"), +                  ("interval", "int", "Reload interval in hours (0 to disable)", "24")] + +    __description__ = """Multi-debrid.com hook plugin""" +    __author_name__ = ("stickell") +    __author_mail__ = ("l.stickell@yahoo.it") + +    def getHoster(self): +        json_data = getURL('http://multi-debrid.com/api.php?hosts', decode=True) +        self.logDebug('JSON data: ' + json_data) +        json_data = json_loads(json_data) + +        return json_data['hosts'] diff --git a/module/plugins/addons/RestartFailed.py b/module/plugins/addons/RestartFailed.py new file mode 100644 index 000000000..7ee53deb9 --- /dev/null +++ b/module/plugins/addons/RestartFailed.py @@ -0,0 +1,124 @@ +  # -*- 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: Walter Purcaro +""" + +from module.plugins.Hook import Hook +from time import time + + +class RestartFailed(Hook): +    __name__ = "RestartFailed" +    __version__ = "1.5" +    __description__ = "Automatically restart failed/aborted downloads" +    __config__ = [ +        ("activated", "bool", "Activated", "True"), +        ("dlFail", "bool", "Restart when download fail", "True"), +        ("dlFail_n", "int", "Only when failed downloads are at least", "5"), +        ("dlFail_i", "int", "Only when elapsed time since last restart is (min)", "10"), +        ("dlPrcs", "bool", "Restart after all downloads are processed", "True"), +        ("recnt", "bool", "Restart after reconnecting", "True"), +        ("rsLoad", "bool", "Restart on plugin activation", "False") +    ] +    __author_name__ = ("Walter Purcaro") +    __author_mail__ = ("vuolter@gmail.com") + +    def restart(self, arg=None): +        # self.logDebug("self.restart") +        self.info["timerflag"] = False +        self.info["dlfailed"] = 0 +        self.core.api.restartFailed() +        self.logDebug("self.restart: self.core.api.restartFailed") +        self.info["lastrstime"] = time() + +    def periodical(self): +        # self.logDebug("self.periodical") +        if self.info["timerflag"]: +            self.restart() + +    def checkInterval(self, arg=None): +        # self.logDebug("self.checkInterval") +        now = time() +        lastrstime = self.info["lastrstime"] +        interval = self.getConfig("dlFail_i") * 60 +        if now < lastrstime + interval: +            self.info["timerflag"] = True +        else: +            self.restart() + +    def checkFailed(self, pyfile): +        # self.logDebug("self.checkFailed") +        self.info["dlfailed"] += 1 +        curr = self.info["dlfailed"] +        max = self.getConfig("dlFail_n") +        if curr >= max: +            self.checkInterval() + +    def addEvent(self, event, handler): +        if event in self.manager.events: +            if handler not in self.manager.events[event]: +                self.manager.events[event].append(handler) +                # self.logDebug("self.addEvent: " + event + ": added handler") +            else: +                # self.logDebug("self.addEvent: " + event + ": NOT added handler") +                return False +        else: +            self.manager.events[event] = [handler] +            # self.logDebug("self.addEvent: " + event + ": added event and handler") +        return True + +    def removeEvent(self, event, handler): +        if event in self.manager.events and handler in self.manager.events[event]: +            self.manager.events[event].remove(handler) +            # self.logDebug("self.removeEvent: " + event + ": removed handler") +            return True +        else: +            # self.logDebug("self.removeEvent: " + event + ": NOT removed handler") +            return False + +    def configEvents(self, plugin=None, name=None, value=None): +        # self.logDebug("self.configEvents") +        self.interval = self.getConfig("dlFail_i") * 60 +        dlFail = self.getConfig("dlFail") +        dlPrcs = self.getConfig("dlPrcs") +        recnt = self.getConfig("recnt") +        if dlPrcs: +            self.addEvent("allDownloadsProcessed", self.checkInterval) +        else: +            self.removeEvent("allDownloadsProcessed", self.checkInterval) +            if not dlFail: +                self.info["timerflag"] = False +        if recnt: +            self.addEvent("afterReconnecting", self.restart) +        else: +            self.removeEvent("afterReconnecting", self.restart) + +    def unload(self): +        # self.logDebug("self.unload") +        self.removeEvent("pluginConfigChanged", self.configEvents) +        self.removeEvent("downloadFailed", self.checkFailed) +        self.removeEvent("allDownloadsProcessed", self.checkInterval) +        self.removeEvent("afterReconnecting", self.restart) + +    def coreReady(self): +        # self.logDebug("self.coreReady") +        self.info = {"dlfailed": 0, "lastrstime": 0, "timerflag": False} +        if self.getConfig("rsLoad"): +            self.restart() +        self.addEvent("downloadFailed", self.checkFailed) +        self.addEvent("pluginConfigChanged", self.configEvents) +        self.configEvents() diff --git a/module/plugins/crypter/DownloadVimeoCom.py b/module/plugins/crypter/DownloadVimeoCom.py new file mode 100644 index 000000000..88310915b --- /dev/null +++ b/module/plugins/crypter/DownloadVimeoCom.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import re +import HTMLParser +from module.plugins.Crypter import Crypter + +class DownloadVimeoCom(Crypter): +	__name__ = 'DownloadVimeoCom' +	__type__ = 'crypter' +	__pattern__ = r'(?:http://vimeo\.com/\d*|http://smotri\.com/video/view/\?id=.*)' +	## The download from dailymotion failed with a 403 +	__version__ = '0.1' +	__description__ = """Video Download Plugin based on downloadvimeo.com""" +	__author_name__ = ('4Christopher') +	__author_mail__ = ('4Christopher@gmx.de') +	BASE_URL = 'http://downloadvimeo.com' + +	def decrypt(self, pyfile): +		self.package = pyfile.package() +		html = self.load('%s/generate?url=%s' % (self.BASE_URL, pyfile.url)) +		h = HTMLParser.HTMLParser() +		try: +			f = re.search(r'cmd quality="(?P<quality>[^"]+?)">\s*?(?P<URL>[^<]*?)</cmd>', html) +		except: +			self.logDebug('Failed to find the URL') +		else: +			url = h.unescape(f.group('URL')) +			self.logDebug('Quality: %s, URL: %s' % (f.group('quality'), url)) +			self.packages.append((self.package.name, [url], self.package.folder)) diff --git a/module/plugins/crypter/EasybytezComFolder.py b/module/plugins/crypter/EasybytezComFolder.py new file mode 100644 index 000000000..1b887e421 --- /dev/null +++ b/module/plugins/crypter/EasybytezComFolder.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 Affero 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 Affero General Public License for more details.                      # +#                                                                          # +# You should have received a copy of the GNU Affero General Public License # +# along with this program.  If not, see <http://www.gnu.org/licenses/>.    # +############################################################################ + +import re + +from module.plugins.internal.SimpleCrypter import SimpleCrypter + + +class EasybytezComFolder(SimpleCrypter): +    __name__ = "EasybytezComFolder" +    __type__ = "crypter" +    __pattern__ = r"https?://(www\.)?easybytez\.com/users/\w+/\w+" +    __version__ = "0.01" +    __description__ = """Easybytez Crypter Plugin""" +    __author_name__ = ("stickell") +    __author_mail__ = ("l.stickell@yahoo.it") + +    LINK_PATTERN = r'<div class="link"><a href="(http://www\.easybytez\.com/\w+)" target="_blank">.+</a></div>' +    TITLE_PATTERN = r'<Title>Files of (?P<title>.+) folder</Title>' +    PAGES_PATTERN = r"<a href='[^']+'>(\d+)</a><a href='[^']+'>Next »</a><br><small>\(\d+ total\)</small></div>" + +    def decrypt(self, pyfile): +        self.html = self.load(pyfile.url, decode=True) + +        package_name, folder_name = self.getPackageNameAndFolder() + +        package_links = re.findall(self.LINK_PATTERN, self.html) + +        pages = re.search(self.PAGES_PATTERN, self.html) +        if pages: +            pages = int(pages.group(1)) +        else: +            pages = 1 + +        p = 2 +        while p <= pages: +            self.html = self.load(pyfile.url, get={'page': p}, decode=True) +            package_links += re.findall(self.LINK_PATTERN, self.html) +            p += 1 + +        self.logDebug('Package has %d links' % len(package_links)) + +        if package_links: +            self.packages = [(package_name, package_links, folder_name)] +        else: +            self.fail('Could not extract any links')
\ No newline at end of file diff --git a/module/plugins/crypter/GooGl.py b/module/plugins/crypter/GooGl.py index 07de5e008..bcb1d7494 100644 --- a/module/plugins/crypter/GooGl.py +++ b/module/plugins/crypter/GooGl.py @@ -1,5 +1,20 @@  # -*- coding: utf-8 -*- +############################################################################ +# This program is free software: you can redistribute it and/or modify     # +# it under the terms of the GNU Affero 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 Affero General Public License for more details.                      # +#                                                                          # +# You should have received a copy of the GNU Affero General Public License # +# along with this program.  If not, see <http://www.gnu.org/licenses/>.    # +############################################################################ +  from module.plugins.Crypter import Crypter  from module.common.json_layer import json_loads diff --git a/module/plugins/crypter/MBLinkInfo.py b/module/plugins/crypter/MBLinkInfo.py new file mode 100644 index 000000000..e266c7722 --- /dev/null +++ b/module/plugins/crypter/MBLinkInfo.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- + +import re + +from module.plugins.Crypter import Crypter + + +class MBLinkInfo(Crypter): +    __name__ = "MBLinkInfo" +    __type__ = "container" +    __pattern__ = r"http://(?:www\.)?mblink\.info/?\?id=(\d+)" +    __version__ = "0.02" +    __description__ = """MBLink.Info Container Plugin""" +    __author_name__ = ("Gummibaer", "stickell") +    __author_mail__ = ("Gummibaer@wiki-bierkiste.de", "l.stickell@yahoo.it") + +    URL_PATTERN = r'<meta[^;]+; URL=(.*)["\']>' + +    def decrypt(self, pyfile): +        src = self.load(pyfile.url) +        found = re.search(self.URL_PATTERN, src) +        if found: +            link = found.group(1) +            self.logDebug("Redirected to " + link) +            self.core.files.addLinks([link], self.pyfile.package().id) +        else: +            self.fail('Unable to detect valid link') diff --git a/module/plugins/crypter/Movie2kTo.py b/module/plugins/crypter/Movie2kTo.py index f5800b498..097cb702e 100644 --- a/module/plugins/crypter/Movie2kTo.py +++ b/module/plugins/crypter/Movie2kTo.py @@ -9,11 +9,12 @@ class Movie2kTo(Crypter):  	__name__ = 'Movie2kTo'  	__type__ = 'container'  	__pattern__ = r'http://(?:www\.)?movie2k\.to/(.*)\.html' -	__version__ = '0.3' -	__config__ = [('accepted_hosters', 'str', 'List of accepted hosters', 'Xvidstage, '), +	__version__ = '0.5' +	__config__ = [('accepted_hosters', 'str', 'List of accepted hosters', 'Xvidstage, Putlocker, '), +				('dir_quality', 'bool', 'Show the quality of the footage in the folder name', 'True'),  				('whole_season', 'bool', 'Download whole season', 'False'),  				('everything', 'bool', 'Download everything', 'False'), -				('firstN', 'int', 'Download the first N files for each episode. The first file is probably all you will need.', '1')] +				('firstN', 'int', 'Download the first N files for each episode (the first file is probably all you will need)', '1')]  	__description__ = """Movie2k.to Container Plugin"""  	__author_name__ = ('4Christopher')  	__author_mail__ = ('4Christopher@gmx.de') @@ -47,21 +48,26 @@ class Movie2kTo(Crypter):  							season_links += self.getInfoAndLinks('%s/%s' % (self.BASE_URL, url_path))  					self.logDebug(season_links) -					self.packages.append(('%s: Season %s (%s)' -						% (self.name, season, self.qStat()), season_links, 'Season %s' % season)) +					folder = '%s: Season %s' % (self.name, season) +					name = '%s%s' % (folder, self.qStat()) +					self.packages.append((name, season_links, folder))  					self.qStatReset()  		else:  			links = self.getLinks() -			self.package.name = '%s%s' % (self.package.name, self.qStat()) -			self.packages.append((self.package.name, links , self.package.folder)) +			name = '%s%s' % (self.package.name, self.qStat()) +			self.packages.append((name, links , self.package.folder))  	def qStat(self):  		if len(self.q) == 0: return '' +		if not self.getConfig('dir_quality'): return '' +		if len(self.q) == 1: return (' (Quality: %d, max (all hosters): %d)' % (self.q[0], self.max_q))  		return (' (Average quality: %d, min: %d, max: %d, %s, max (all hosters): %d)'  			% (sum(self.q) / float(len(self.q)), min(self.q), max(self.q), self.q, self.max_q)) +  	def qStatReset(self): -		self.q = [] ## to calculate the average, min and max of the quality -		self.max_q = None +		self.q = []		## to calculate the average, min and max of the quality +		self.max_q = None	## maximum quality of all hosters +  	def tvshow_number(self, number):  		if int(number) < 10:  			return '0%s' % number @@ -81,8 +87,6 @@ class Movie2kTo(Crypter):  		elif re.search(self.FILM_URL_PATH_PATTERN, self.url_path):  			self.format = 'film'  			pattern_re = re.search(self.FILM_URL_PATH_PATTERN, self.url_path) - -  		self.name = pattern_re.group('name')  		self.id = pattern_re.group('id')  		self.logDebug('URL Path: %s (ID: %s, Name: %s, Format: %s)' @@ -100,8 +104,8 @@ class Movie2kTo(Crypter):  		re_quality = re.compile(r'.+?Quality:.+?smileys/(\d)\.gif')  		## The quality is one digit. 0 is the worst and 5 is the best.  		## Is not always there … -		re_hoster_id_html = re.compile(r'(?:<td height|<tr id).+?<a href=".*?(\d{7}).*?".+? ([^<>]+?)</a>(.+?)</tr>')  		re_hoster_id_js = re.compile(r'links\[(\d+?)\].+ (.+?)</a>(.+?)</tr>') +		re_hoster_id_html = re.compile(r'(?:<td height|<tr id).+?<a href=".*?(\d{7}).*?".+? ([^<>]+?)</a>(.+?)</tr>')  		## I assume that the ID is 7 digits longs  		count = defaultdict(int)  		matches = re_hoster_id_html.findall(self.html) @@ -112,10 +116,10 @@ class Movie2kTo(Crypter):  			match_q = re_quality.search(q_html)  			if match_q:  				quality = int(match_q.group(1)) -				if self.max_q: -					if self.max_q < quality: self.max_q = quality -				else: ## was None before +				if self.max_q == None:  					self.max_q = quality +				else: +					if self.max_q < quality: self.max_q = quality  				q_s = ', Quality: %d' % quality  			else:  				q_s = ', unknown quality' @@ -128,14 +132,20 @@ class Movie2kTo(Crypter):  						self.html = self.load('%s/tvshows-%s-%s.html' % (self.BASE_URL, h_id, self.name))  					else:  						self.logDebug('This is already the right ID') -					try: -						url = re.search(r'<a target="_blank" href="(http://.*?)"', self.html).group(1) -						self.logDebug('id: %s, %s: %s' % (h_id, hoster, url)) -						links.append(url) -					except: -						self.logDebug('Failed to find the URL') +					# The iframe tag must continue with a width. There where +					# two iframes in the site and I try to make sure that it +					# matches the right one. This is not (yet) nessesary +					# because the right iframe happens to be the first iframe. +					for pattern in (r'<a target="_blank" href="(http://[^"]*?)"', r'<iframe src="(http://[^"]*?)" width'): +						try: +							url = re.search(pattern, self.html).group(1) +						except: +							self.logDebug('Failed to find the URL (pattern %s)' % pattern) +						else: +							self.logDebug('id: %s, %s: %s' % (h_id, hoster, url)) +							links.append(url) +							break  			else:  				self.logDebug('Not accepted: %s, ID: %s%s' % (hoster, h_id, q_s)) -  		# self.logDebug(links)  		return links diff --git a/module/plugins/crypter/NCryptIn.py b/module/plugins/crypter/NCryptIn.py index a8eaac631..5e1ea347c 100644 --- a/module/plugins/crypter/NCryptIn.py +++ b/module/plugins/crypter/NCryptIn.py @@ -50,7 +50,8 @@ class NCryptIn(Crypter):          package_links = []
          package_links.extend(self.handleWebLinks())
          package_links.extend(self.handleContainers())
 -        package_links.extend(self.handleCNL2())
 +        package_links.extend(self.handleCNL2()) 
 +        package_links = self.removeContainers(package_links)
          package_links = set(package_links)
          # Pack
 @@ -65,7 +66,20 @@ class NCryptIn(Crypter):              rexpr = re.compile(pattern, re.DOTALL)
              content = re.sub(rexpr, "", content)
          return content
 -        
 +
 +    def removeContainers(self,package_links):
 +        tmp_package_links = package_links[:]      
 +        for link in tmp_package_links:
 +            self.logDebug(link)
 +            if ".dlc" in link or ".ccf" in link or ".rsdf" in link:
 +                self.logDebug("Removing [%s] from package_links" % link)
 +                package_links.remove(link)
 +
 +        if len(package_links) > 0:
 +            return package_links
 +        else:
 +            return tmp_package_links
 +
      def isOnline(self):        
          if "Your folder does not exist" in self.cleanedHtml:
              self.logDebug("File not found")
 @@ -121,6 +135,19 @@ class NCryptIn(Crypter):              challenge, code = recaptcha.challenge(id)
              postData['recaptcha_challenge_field'] = challenge
              postData['recaptcha_response_field'] = code
 +
 +        # Resolve circlecaptcha
 +        if "circlecaptcha" in form:
 +            self.captcha = True
 +            self.logDebug("Captcha protected")
 +            captcha_img_url = "http://ncrypt.in/classes/captcha/circlecaptcha.php"
 +            coords = self.decryptCaptcha(captcha_img_url, forceUser=True, imgtype="png", result_type='positional')
 +            self.logDebug("Captcha resolved, coords [%s]" % str(coords))
 +            self.captcha_post_url = self.pyfile.url
 +
 +            postData['circle.x'] = coords[0]
 +            postData['circle.y'] = coords[1]
 +
          # Unlock protection
          postData['submit_protected'] = 'Continue to folder '
 @@ -221,4 +248,4 @@ class NCryptIn(Crypter):          # Log and return
          self.logDebug("Block has %d links" % len(links))
 -        return links
\ No newline at end of file +        return links
 diff --git a/module/plugins/crypter/NetfolderIn.py b/module/plugins/crypter/NetfolderIn.py index d71a73d0a..c5c602c27 100644 --- a/module/plugins/crypter/NetfolderIn.py +++ b/module/plugins/crypter/NetfolderIn.py @@ -1,22 +1,25 @@  # -*- coding: utf-8 -*- -from module.plugins.Crypter import Crypter  import re -class NetfolderIn(Crypter): +from module.plugins.internal.SimpleCrypter import SimpleCrypter + + +class NetfolderIn(SimpleCrypter):      __name__ = "NetfolderIn"      __type__ = "crypter"      __pattern__ = r"http://(?:www\.)?netfolder.in/((?P<id1>\w+)/\w+|folder.php\?folder_id=(?P<id2>\w+))" -    __version__ = "0.4" +    __version__ = "0.6"      __description__ = """NetFolder Crypter Plugin"""      __author_name__ = ("RaNaN", "fragonib")      __author_mail__ = ("RaNaN@pyload.org", "fragonib[AT]yahoo[DOT]es") +    TITLE_PATTERN = r'<div class="Text">Inhalt des Ordners <span(.*)>(?P<title>.+)</span></div>' +      def decrypt(self, pyfile): -                  # Request package          self.html = self.load(pyfile.url) -         +          # Check for password protection              if self.isPasswordProtected():              self.html = self.submitPassword() @@ -31,54 +34,37 @@ class NetfolderIn(Crypter):          # Set package          self.packages = [(package_name, package_links, folder_name)] -         -         +      def isPasswordProtected(self): -         +          if '<input type="password" name="password"' in self.html:              self.logDebug("Links are password protected")              return True          return False -      def submitPassword(self):          # Gather data          try:              m = re.match(self.__pattern__, self.pyfile.url) -            id = max(m.group('id1'), m.group('id2'))  +            id = max(m.group('id1'), m.group('id2'))          except AttributeError:              self.logDebug("Unable to get package id from url [%s]" % self.pyfile.url)              return          url = "http://netfolder.in/folder.php?folder_id=" + id          password = self.getPassword() -                    +          # Submit package password      -        post = { 'password' : password, 'save' : 'Absenden' } +        post = {'password': password, 'save': 'Absenden'}          self.logDebug("Submitting password [%s] for protected links with id [%s]" % (password, id))          html = self.load(url, {}, post) -         +          # Check for invalid password          if '<div class="InPage_Error">' in html:              self.logDebug("Incorrect password, please set right password on Edit package form and retry")              return None -         -        return html  -     -     -    def getPackageNameAndFolder(self): -        title_re = r'<div class="Text">Inhalt des Ordners <span(.*)>(?P<title>.+)</span></div>' -        m = re.search(title_re, self.html) -        if m is not None: -            name = folder = m.group('title') -            self.logDebug("Found name [%s] and folder [%s] in package info" % (name, folder)) -            return name, folder -        else: -            name = self.pyfile.package().name -            folder = self.pyfile.package().folder -            self.logDebug("Package info not found, defaulting to pyfile name [%s] and folder [%s]" % (name, folder)) -            return name, folder -         -         + +        return html +      def getLinks(self):          links = re.search(r'name="list" value="(.*?)"', self.html).group(1).split(",")          self.logDebug("Package has %d links" % len(links)) diff --git a/module/plugins/crypter/SerienjunkiesOrg.py b/module/plugins/crypter/SerienjunkiesOrg.py index dfe34ff6e..3fcc12e36 100644 --- a/module/plugins/crypter/SerienjunkiesOrg.py +++ b/module/plugins/crypter/SerienjunkiesOrg.py @@ -11,13 +11,13 @@ class SerienjunkiesOrg(Crypter):      __name__ = "SerienjunkiesOrg"      __type__ = "container"      __pattern__ = r"http://.*?(serienjunkies.org|dokujunkies.org)/.*?" -    __version__ = "0.36" +    __version__ = "0.38"      __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"), +        ("hosterList", "str", "Preferred Hoster list (comma separated)", "RapidshareCom,UploadedTo,NetloadIn,FilefactoryCom,FreakshareNet,FilebaseTo,HotfileCom,DepositfilesCom,EasyshareCom,KickloadCom"),          ("ignoreList", "str", "Ignored Hoster list (comma separated)", "MegauploadCom")          ]      __description__ = """serienjunkies.org Container Plugin""" @@ -30,6 +30,8 @@ class SerienjunkiesOrg(Crypter):      def getSJSrc(self, url):          src = self.req.load(str(url)) +        if "This website is not available in your country" in src: +            self.fail("Not available in your country")          if not src.find("Enter Serienjunkies") == -1:              sleep(1)              src = self.req.load(str(url)) diff --git a/module/plugins/crypter/SpeedLoadOrgFolder.py b/module/plugins/crypter/SpeedLoadOrgFolder.py index 5b350787f..f85ede6f3 100644 --- a/module/plugins/crypter/SpeedLoadOrgFolder.py +++ b/module/plugins/crypter/SpeedLoadOrgFolder.py @@ -1,5 +1,20 @@  # -*- coding: utf-8 -*- +############################################################################ +# This program is free software: you can redistribute it and/or modify     # +# it under the terms of the GNU Affero 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 Affero General Public License for more details.                      # +#                                                                          # +# You should have received a copy of the GNU Affero General Public License # +# along with this program.  If not, see <http://www.gnu.org/licenses/>.    # +############################################################################ +  from module.plugins.internal.SimpleCrypter import SimpleCrypter  class SpeedLoadOrgFolder(SimpleCrypter): diff --git a/module/plugins/crypter/UploadedToFolder.py b/module/plugins/crypter/UploadedToFolder.py index d4534297e..c514f23d0 100644 --- a/module/plugins/crypter/UploadedToFolder.py +++ b/module/plugins/crypter/UploadedToFolder.py @@ -1,13 +1,30 @@  # -*- coding: utf-8 -*-
 -from module.plugins.Crypter import Crypter
 +############################################################################
 +# This program is free software: you can redistribute it and/or modify     #
 +# it under the terms of the GNU Affero 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 Affero General Public License for more details.                      #
 +#                                                                          #
 +# You should have received a copy of the GNU Affero General Public License #
 +# along with this program.  If not, see <http://www.gnu.org/licenses/>.    #
 +############################################################################
 +
  import re
 -class UploadedToFolder(Crypter):
 +from module.plugins.internal.SimpleCrypter import SimpleCrypter
 +
 +
 +class UploadedToFolder(SimpleCrypter):
      __name__ = "UploadedToFolder"
      __type__ = "crypter"
 -    __pattern__ = r"http://(?:www\.)?(uploaded|ul)\.(to|net)/(f|list)/(?P<id>\w+)"
 -    __version__ = "0.1"
 +    __pattern__ = r"http://(?:www\.)?(uploaded|ul)\.(to|net)/(f|folder|list)/(?P<id>\w+)"
 +    __version__ = "0.3"
      __description__ = """UploadedTo Crypter Plugin"""
      __author_name__ = ("stickell")
      __author_mail__ = ("l.stickell@yahoo.it")
 @@ -31,15 +48,3 @@ class UploadedToFolder(Crypter):          self.logDebug('Package has %d links' % len(package_links))
          self.packages = [(package_name, package_links, folder_name)]
 -
 -    def getPackageNameAndFolder(self):
 -        m = re.search(self.TITLE_PATTERN, self.html)
 -        if m:
 -            name = folder = m.group('title')
 -            self.logDebug("Found name [%s] and folder [%s] in package info" % (name, folder))
 -            return name, folder
 -        else:
 -            name = self.pyfile.package().name
 -            folder = self.pyfile.package().folder
 -            self.logDebug("Package info not found, defaulting to pyfile name [%s] and folder [%s]" % (name, folder))
 -            return name, folder
 diff --git a/module/plugins/crypter/YoutubeBatch.py b/module/plugins/crypter/YoutubeBatch.py index 2e68dfe02..72b72aab7 100644 --- a/module/plugins/crypter/YoutubeBatch.py +++ b/module/plugins/crypter/YoutubeBatch.py @@ -2,26 +2,41 @@  # -*- coding: utf-8 -*-  import re +import json  from module.plugins.Crypter import Crypter +API_KEY = "AIzaSyCKnWLNlkX-L4oD1aEzqqhRw1zczeD6_k0" +  class YoutubeBatch(Crypter):      __name__ = "YoutubeBatch"      __type__ = "container" -    __pattern__ = r"http://(?:[^/]*?)youtube\.com/((?:view_play_list|playlist|.*?feature=PlayList).*?[\?&](?:list|p)=|user/)(\w+)" -    __version__ = "0.92" +    __pattern__ = r"https?://(?:[^/]*?)youtube\.com/(?:(?:view_play_list|playlist|.*?feature=PlayList).*?[?&](?:list|p)=)([a-zA-Z0-9-_]+)" +    __version__ = "0.93"      __description__ = """Youtube.com Channel Download Plugin""" -    __author_name__ = ("RaNaN", "Spoob", "zoidberg") -    __author_mail__ = ("RaNaN@pyload.org", "spoob@pyload.org", "zoidberg@mujmail.cz") +    __author_name__ = ("RaNaN", "Spoob", "zoidberg", "roland") +    __author_mail__ = ("RaNaN@pyload.org", "spoob@pyload.org", "zoidberg@mujmail.cz", "roland@enkore.de") + +    def get_videos(self, playlist_id, token=None): +        url = "https://www.googleapis.com/youtube/v3/playlistItems?playlistId=%s&part=snippet&key=%s&maxResults=50" % (playlist_id, API_KEY) +        if token: +            url += "&pageToken=" + token + +        response = json.loads(self.load(url)) + +        for item in response["items"]: +            if item["kind"] == "youtube#playlistItem" and item["snippet"]["resourceId"]["kind"] == "youtube#video": +                yield "http://youtube.com/watch?v=" + item["snippet"]["resourceId"]["videoId"] + +        if "nextPageToken" in response: +            for item in self.get_videos(playlist_id, response["nextPageToken"]): +                yield item      def decrypt(self, pyfile):          match_id = re.match(self.__pattern__, self.pyfile.url) -        if match_id.group(1) == "user/": -            url = "http://gdata.youtube.com/feeds/api/users/%s/uploads?v=2" % match_id.group(2) -        else: -            url = "http://gdata.youtube.com/feeds/api/playlists/%s?v=2" % match_id.group(2) - -        rep = self.load(url)          new_links = [] -        new_links.extend(re.findall(r"href\='(http:\/\/www.youtube.com\/watch\?v\=[^']+)&", rep)) +        playlist_id = match_id.group(1) + +        new_links.extend(self.get_videos(playlist_id)) +          self.packages.append((self.pyfile.package().name, new_links, self.pyfile.package().name)) diff --git a/module/plugins/hooks/Captcha9kw.py b/module/plugins/hooks/Captcha9kw.py index a01ce9576..bb2b8c862 100755 --- a/module/plugins/hooks/Captcha9kw.py +++ b/module/plugins/hooks/Captcha9kw.py @@ -30,17 +30,22 @@ from module.plugins.Hook import Hook  class Captcha9kw(Hook):
      __name__ = "Captcha9kw"
 -    __version__ = "0.03"
 +    __version__ = "0.04"
      __description__ = """send captchas to 9kw.eu"""
      __config__ = [("activated", "bool", "Activated", True),
                    ("force", "bool", "Force CT even if client is connected", True),
 +                  ("https", "bool", "Enable HTTPS", "False"),
 +                  ("confirm", "bool", "Confirm Captcha", "False"),
 +                  ("captchaperhour", "int", "Captcha per hour", "9999"),
 +                  ("prio", "int", "Prio (1-10)", "0"),
                    ("passkey", "password", "API key", ""),]
      __author_name__ = ("RaNaN")
      __author_mail__ = ("RaNaN@pyload.org")
 -    API_URL = "http://www.9kw.eu/index.cgi"
 +    API_URL = "://www.9kw.eu/index.cgi"
      def setup(self):
 +        self.API_URL = "https"+self.API_URL if self.getConfig("https") else "http"+self.API_URL
          self.info = {}
      def getCredits(self):
 @@ -68,6 +73,10 @@ class Captcha9kw(Hook):          response = getURL(self.API_URL, post = { 
                            "apikey": self.getConfig("passkey"), 
 +                          "prio": self.getConfig("prio"),
 +                          "confirm": self.getConfig("confirm"),
 +                          "captchaperhour": self.getConfig("captchaperhour"),
 +                          "maxtimeout": "220",
                            "pyload": "1", 
                            "source": "pyload", 
                            "base64": "1", 
 @@ -78,7 +87,7 @@ class Captcha9kw(Hook):          if response.isdigit():
              self.logInfo(_("NewCaptchaID from upload: %s : %s" % (response,task.captchaFile)))
 -            for i in range(1, 200, 2): 
 +            for i in range(1, 220, 1): 
                  response2 = getURL(self.API_URL, get = { "apikey": self.getConfig("passkey"), "id": response,"pyload": "1","source": "pyload", "action": "usercaptchacorrectdata" })
                  if(response2 != ""):
 diff --git a/module/plugins/hoster/ARD.py b/module/plugins/hoster/ARD.py new file mode 100644 index 000000000..5ab65cd4b --- /dev/null +++ b/module/plugins/hoster/ARD.py @@ -0,0 +1,80 @@ + +import subprocess +import re +import os.path +import os + +from module.utils import save_join, save_path +from module.plugins.Hoster import Hoster + +# Requires rtmpdump +# by Roland Beermann + +class RTMP: +    # TODO: Port to some RTMP-library like rtmpy or similar +    # TODO?: Integrate properly into the API of pyLoad + +    command = "rtmpdump" + +    @classmethod +    def download_rtmp_stream(cls, url, output_file, playpath=None): +        opts = [ +            "-r", url, +            "-o", output_file, +        ] +        if playpath: +            opts.append("--playpath") +            opts.append(playpath) + +        cls._invoke_rtmpdump(opts) + +    @classmethod +    def _invoke_rtmpdump(cls, opts): +        args = [ +            cls.command +        ] +        args.extend(opts) + +        return subprocess.check_call(args) + +class ARD(Hoster): +    __name__ = "ARD Mediathek" +    __version__ = "0.1" +    __pattern__ = r"http://www\.ardmediathek\.de/.*" +    __config__ = [] + +    def process(self, pyfile): +        site = self.load(pyfile.url) + +        avail_videos = re.findall(r"""mediaCollection.addMediaStream\(0, ([0-9]*), "([^\"]*)", "([^\"]*)", "[^\"]*"\);""", site) +        avail_videos.sort(key=lambda videodesc: int(videodesc[0]), reverse=True) # The higher the number, the better the quality + +        quality, url, playpath = avail_videos[0] + +        pyfile.name = re.search(r"<h1>([^<]*)</h1>", site).group(1) + +        if url.startswith("http"): +            # Best quality is available over HTTP. Very rare. +            self.download(url) +        else: +            pyfile.setStatus("downloading") + +            download_folder = self.config['general']['download_folder'] + +            location = save_join(download_folder, pyfile.package().folder) + +            if not os.path.exists(location): +                os.makedirs(location, int(self.core.config["permission"]["folder"], 8)) + +                if self.core.config["permission"]["change_dl"] and os.name != "nt": +                    try: +                        uid = getpwnam(self.config["permission"]["user"])[2] +                        gid = getgrnam(self.config["permission"]["group"])[2] + +                        chown(location, uid, gid) +                    except Exception, e: +                        self.log.warning(_("Setting User and Group failed: %s") % str(e)) + +            output_file = save_join(location, save_path(pyfile.name)) + os.path.splitext(playpath)[1] + +            RTMP.download_rtmp_stream(url, playpath=playpath, output_file=output_file) diff --git a/module/plugins/hoster/CloudzerNet.py b/module/plugins/hoster/CloudzerNet.py index 08a54d509..7608b193d 100644 --- a/module/plugins/hoster/CloudzerNet.py +++ b/module/plugins/hoster/CloudzerNet.py @@ -20,7 +20,7 @@ class CloudzerNet(SimpleHoster):      __name__ = "CloudzerNet"      __type__ = "hoster"      __pattern__ = r"http://(www\.)?(cloudzer\.net/file/|clz\.to/(file/)?)(?P<ID>\w+).*" -    __version__ = "0.01" +    __version__ = "0.02"      __description__ = """Cloudzer.net hoster plugin"""      __author_name__ = ("gs", "z00nx")      __author_mail__ = ("I-_-I-_-I@web.de", "z00nx0@gmail.com") @@ -56,7 +56,7 @@ class CloudzerNet(SimpleHoster):                  self.retry()              elif "Sie haben die max" in response["err"] or "You have reached the max" in response["err"]:                  self.logDebug("Download limit reached, waiting an hour") -                self.setWait(3600) +                self.setWait(3600, True)                  self.wait()          if "type" in response:              if response["type"] == "download": diff --git a/module/plugins/hoster/CzshareCom.py b/module/plugins/hoster/CzshareCom.py index a4a811e82..347427586 100644 --- a/module/plugins/hoster/CzshareCom.py +++ b/module/plugins/hoster/CzshareCom.py @@ -16,6 +16,9 @@      @author: zoidberg  """ +# Test links (random.bin): +# http://czshare.com/5278880/random.bin +  import re  from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, PluginParseError  from module.utils import parseFileSize @@ -24,7 +27,7 @@ class CzshareCom(SimpleHoster):      __name__ = "CzshareCom"      __type__ = "hoster"      __pattern__ = r"http://(\w*\.)*czshare\.(com|cz)/(\d+/|download.php\?).*" -    __version__ = "0.92" +    __version__ = "0.93"      __description__ = """CZshare.com"""      __author_name__ = ("zoidberg") @@ -80,7 +83,7 @@ class CzshareCom(SimpleHoster):              self.resetAccount()          # download the file, destination is determined by pyLoad -        self.download("http://czshare.com/profi_down.php", cookies=True, post=inputs) +        self.download("http://czshare.com/profi_down.php", post=inputs, disposition=True)          self.checkDownloadedFile()      def handleFree(self): diff --git a/module/plugins/hoster/DebridItaliaCom.py b/module/plugins/hoster/DebridItaliaCom.py index 121a141b3..470c4ae5d 100644 --- a/module/plugins/hoster/DebridItaliaCom.py +++ b/module/plugins/hoster/DebridItaliaCom.py @@ -47,7 +47,7 @@ class DebridItaliaCom(Hoster):              self.logDebug("XML data: %s" % page)              if 'File not available' in page: -                self.offline() +                self.fail('File not available')              else:                  new_url = re.search(r'<a href="(?:[^"]+)">(?P<direct>[^<]+)</a>', page).group('direct') diff --git a/module/plugins/hoster/EasybytezCom.py b/module/plugins/hoster/EasybytezCom.py index 0deaa782e..96e3d93d2 100644 --- a/module/plugins/hoster/EasybytezCom.py +++ b/module/plugins/hoster/EasybytezCom.py @@ -16,16 +16,14 @@      @author: zoidberg  """ -import re -from random import random -from pycurl import LOW_SPEED_TIME  from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +  class EasybytezCom(XFileSharingPro):      __name__ = "EasybytezCom"      __type__ = "hoster"      __pattern__ = r"http://(?:\w*\.)?easybytez.com/(\w+).*" -    __version__ = "0.12" +    __version__ = "0.14"      __description__ = """easybytez.com"""      __author_name__ = ("zoidberg")      __author_mail__ = ("zoidberg@mujmail.cz") @@ -33,52 +31,17 @@ class EasybytezCom(XFileSharingPro):      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'<h1>File not available</h1>'     -     -    DIRECT_LINK_PATTERN = r'(http://(\w+\.easybytez\.com|\d+\.\d+\.\d+\.\d+)/files/\d+/\w+/[^"<]+)' +    FILE_OFFLINE_PATTERN = r'<h1>File not available</h1>' + +    DIRECT_LINK_PATTERN = r'(http://(\w+\.(easybytez|zingload)\.com|\d+\.\d+\.\d+\.\d+)/files/\d+/\w+/[^"<]+)'      OVR_DOWNLOAD_LINK_PATTERN = r'<h2>Download Link</h2>\s*<textarea[^>]*>([^<]+)'      OVR_KILL_LINK_PATTERN = r'<h2>Delete Link</h2>\s*<textarea[^>]*>([^<]+)'      ERROR_PATTERN = r'(?:class=["\']err["\'][^>]*>|<Center><b>)(.*?)</' -     +      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()) -        found = re.search(self.DIRECT_LINK_PATTERN, self.html) -        if not found: self.parseError('DIRECT LINK') -        self.startDownload(found.group(1)) - -    def handleOverriden(self): -        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(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(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() -getInfo = create_getInfo(EasybytezCom)
\ No newline at end of file +getInfo = create_getInfo(EasybytezCom) diff --git a/module/plugins/hoster/EgoFilesCom.py b/module/plugins/hoster/EgoFilesCom.py index ad278e60f..7e6673210 100644 --- a/module/plugins/hoster/EgoFilesCom.py +++ b/module/plugins/hoster/EgoFilesCom.py @@ -28,12 +28,12 @@ class EgoFilesCom(SimpleHoster):      __name__ = "EgoFilesCom"
      __type__ = "hoster"
      __pattern__ = r"https?://(www\.)?egofiles.com/(\w+)"
 -    __version__ = "0.11"
 +    __version__ = "0.13"
      __description__ = """Egofiles.com Download Hoster"""
      __author_name__ = ("stickell")
      __author_mail__ = ("l.stickell@yahoo.it")
 -    FILE_INFO_PATTERN = r'<div class="down-file">\s+(?P<N>\S+)\s+<div class="file-properties">\s+(File size|Rozmiar): (?P<S>[\w.]+) (?P<U>\w+) \|'
 +    FILE_INFO_PATTERN = r'<div class="down-file">\s+(?P<N>[^\t]+)\s+<div class="file-properties">\s+(File size|Rozmiar): (?P<S>[\w.]+) (?P<U>\w+) \|'
      FILE_OFFLINE_PATTERN = r'(File size|Rozmiar): 0 KB'
      WAIT_TIME_PATTERN = r'For next free download you have to wait <strong>((?P<m>\d*)m)? ?((?P<s>\d+)s)?</strong>'
      DIRECT_LINK_PATTERN = r'<a href="(?P<link>[^"]+)">Download ></a>'
 diff --git a/module/plugins/hoster/ExtabitCom.py b/module/plugins/hoster/ExtabitCom.py index 718423986..fd91bb023 100644 --- a/module/plugins/hoster/ExtabitCom.py +++ b/module/plugins/hoster/ExtabitCom.py @@ -17,15 +17,17 @@  """  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" +    __pattern__ = r"http://(\w+\.)*extabit\.com/(file|go|fid)/(?P<ID>\w+)" +    __version__ = "0.3"      __description__ = """Extabit.com"""      __author_name__ = ("zoidberg") @@ -33,34 +35,34 @@ class ExtabitCom(SimpleHoster):      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):         +    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()   +            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')               -          +        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)) +                response = json_loads(self.load("http://extabit.com/file/%s/" % fileID, get=get_data))                  if "ok" in response:                      self.correctCaptcha()                      break @@ -70,15 +72,16 @@ class ExtabitCom(SimpleHoster):                  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)       +        self.download(url) + -getInfo = create_getInfo(ExtabitCom)
\ No newline at end of file +getInfo = create_getInfo(ExtabitCom) diff --git a/module/plugins/hoster/FastshareCz.py b/module/plugins/hoster/FastshareCz.py index cc0b18c96..1dbf9fe8f 100644 --- a/module/plugins/hoster/FastshareCz.py +++ b/module/plugins/hoster/FastshareCz.py @@ -16,27 +16,39 @@      @author: zoidberg  """ +# Test links (random.bin): +# http://www.fastshare.cz/2141189/random.bin +  import re -from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo +from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, replace_patterns +  class FastshareCz(SimpleHoster):      __name__ = "FastshareCz"      __type__ = "hoster"      __pattern__ = r"http://(?:\w*\.)?fastshare.cz/\d+/.+" -    __version__ = "0.14" +    __version__ = "0.15"      __description__ = """FastShare.cz""" -    __author_name__ = ("zoidberg") +    __author_name__ = ("zoidberg", "stickell") -    FILE_NAME_PATTERN = r'<h[23]><b><span style=color:black;>(?P<N>[^<]+)</b></h[23]>' -    FILE_SIZE_PATTERN = r'<tr><td>Velikost: </td><td style=font-weight:bold>(?P<S>[^<]+)</td></tr>' +    FILE_INFO_PATTERN = r'<h1 class="dwp">(?P<N>[^<]+)</h1>\s*<div class="fileinfo">\s*(?:Velikost|Size)\s*: (?P<S>[^,]+),'      FILE_OFFLINE_PATTERN = ur'<td align=center>Tento soubor byl smazán' -    SH_COOKIES = [("fastshare.cz","lang","cs")]      FILE_URL_REPLACEMENTS = [('#.*','')]      FREE_URL_PATTERN = ur'<form method=post action=(/free/.*?)><b>Stáhnout FREE.*?<img src="([^"]*)">'      PREMIUM_URL_PATTERN = r'(http://data\d+\.fastshare\.cz/download\.php\?id=\d+\&[^\s\"\'<>]+)'      NOT_ENOUGH_CREDIC_PATTERN = "Nem.te dostate.n. kredit pro sta.en. tohoto souboru" +    def process(self, pyfile): +        pyfile.url = replace_patterns(pyfile.url, self.FILE_URL_REPLACEMENTS) +        self.req.setOption("timeout", 120) +        if self.premium and (not self.SH_CHECK_TRAFFIC or self.checkTrafficLeft()): +            self.handlePremium() +        else: +            self.html = self.load(pyfile.url, decode = not self.SH_BROKEN_ENCODING, cookies = self.SH_COOKIES) +            self.getFileInfo() +            self.handleFree() +      def handleFree(self):          if u">100% FREE slotů je plných.<" in self.html:              self.setWait(60, False) @@ -60,13 +72,20 @@ class FastshareCz(SimpleHoster):              self.retry(6, "Paralell download")      def handlePremium(self): -        if self.NOT_ENOUGH_CREDIC_PATTERN in self.html: -            self.logWarning('Not enough traffic left') -            self.resetAccount() +        header = self.load(self.pyfile.url, just_header=True) +        if 'location' in header: +            url = header['location'] +        else: +            self.html = self.load(self.pyfile.url) +            self.getFileInfo() +            if self.NOT_ENOUGH_CREDIC_PATTERN in self.html: +                self.logWarning('Not enough traffic left') +                self.resetAccount() + +            found = re.search(self.PREMIUM_URL_PATTERN, self.html) +            if not found: self.parseError("Premium URL") +            url = found.group(1) -        found = re.search(self.PREMIUM_URL_PATTERN, self.html) -        if not found: self.parseError("Premium URL") -        url = found.group(1)          self.logDebug("PREMIUM URL: %s" % url)          self.download(url) diff --git a/module/plugins/hoster/FilefactoryCom.py b/module/plugins/hoster/FilefactoryCom.py index 66d26c999..fdde1f9d7 100644 --- a/module/plugins/hoster/FilefactoryCom.py +++ b/module/plugins/hoster/FilefactoryCom.py @@ -1,149 +1,133 @@  # -*- coding: utf-8 -*- + +############################################################################ +# This program is free software: you can redistribute it and/or modify     # +# it under the terms of the GNU Affero 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 Affero General Public License for more details.                      # +#                                                                          # +# You should have received a copy of the GNU Affero General Public License # +# along with this program.  If not, see <http://www.gnu.org/licenses/>.    # +############################################################################ + +# Test links (random.bin): +# http://www.filefactory.com/file/ymxkmdud2o3/n/random.bin + +import re + +from module.plugins.internal.SimpleHoster import SimpleHoster  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 checkFile(plugin, urls): -    url_dict = {} -     +def getInfo(urls): +    file_info = list() +    list_ids = dict() + +    # Create a dict id:url. Will be used to retrieve original url      for url in urls: -        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) - -    html = getURL("http://www.filefactory.com/tool/links.php", post = {"func": "links", "links": "\n".join(urls)}, decode=True)    -         -    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]) -     -    file_info = url_dict.values() -     +        m = re.search(FilefactoryCom.__pattern__, url) +        list_ids[m.group('id')] = url + +    # WARN: There could be a limit of urls for request +    post_data = {'func': 'links', 'links': '\n'.join(urls)} +    rep = getURL('http://www.filefactory.com/tool/links.php', post=post_data, decode=True) + +    # Online links +    for m in re.finditer( +            r'innerText">\s*<h1 class="name">(?P<N>.+) \((?P<S>[\w.]+) (?P<U>\w+)\)</h1>\s*<p>http://www.filefactory.com/file/(?P<ID>\w+).*</p>\s*<p class="hidden size">', +            rep): +        file_info.append((m.group('N'), parseFileSize(m.group('S'), m.group('U')), 2, list_ids[m.group('ID')])) + +    # Offline links +    for m in re.finditer( +            r'innerText">\s*<h1>(http://www.filefactory.com/file/(?P<ID>\w+)/)</h1>\s*<p>\1</p>\s*<p class="errorResponse">Error: file not found</p>', +            rep): +        file_info.append((list_ids[m.group('ID')], 0, 1, list_ids[m.group('ID')])) +      return file_info -    -class FilefactoryCom(Hoster): + + +class FilefactoryCom(SimpleHoster):      __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.36" +    __pattern__ = r"https?://(?:www\.)?filefactory\.com/file/(?P<id>[a-zA-Z0-9]+)" +    __version__ = "0.41"      __description__ = """Filefactory.Com File Download Hoster""" -    __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:\s*\'(?P<check>.*?)\'' -    CAPTCHA_KEY_PATTERN = r'Recaptcha.create\(\s*"(.*?)",'  -    WAIT_PATTERN = r'id="startWait" value="(?P<wait>\d+)"' -    FILE_URL_PATTERN = r'<p[^>]*?id="downloadLinkTarget"[^>]*>\s*<a href="(?P<url>.*?)"'  -             -    def setup(self): -        self.multiDL = self.resumeDownloads = self.premium +    __author_name__ = ("stickell") +    __author_mail__ = ("l.stickell@yahoo.it") + +    DIRECT_LINK_PATTERN = r'<section id="downloadLink">\s*<p class="textAlignCenter">\s*<a href="([^"]+)">[^<]+</a>\s*</p>\s*</section>'      def process(self, 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))  -         -        # 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 not re.match(self.__pattern__ + r'/n/.+', pyfile.url):  # Not in standard format +            header = self.load(pyfile.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 -         -        return False                                 -     +                self.pyfile.url = 'http://www.filefactory.com' + header['location'] + +        if self.premium and (not self.SH_CHECK_TRAFFIC or self.checkTrafficLeft()): +            self.handlePremium() +        else: +            self.handleFree() +      def handleFree(self): +        self.html = self.load(self.pyfile.url, decode=True)          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 -        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):            -            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 -            else: -                self.invalidCaptcha()                             -        else: -            self.fail("No valid captcha after 5 attempts") - -        # This will take us to a wait screen -        waiturl = "http://www.filefactory.com" + response['path'] -        self.logDebug("Fetching wait with url [%s]" % waiturl) -        waithtml = self.load(waiturl, decode=True) -        found = re.search(r'<a href="(http://www.filefactory.com/dlf/.*?)"', waithtml) -        waithtml = self.load(found.group(1), decode=True) - -        # Find the wait value and wait -        wait = int(re.search(self.WAIT_PATTERN, waithtml).group('wait')) -        self.logDebug("Waiting %d seconds." % wait) -        self.setWait(wait, True) + +        # Load the page that contains the direct link +        url = re.search(r"document\.location\.host \+\s*'(.+)';", self.html) +        if not url: +            self.parseError('Unable to detect free link') +        url = 'http://www.filefactory.com' + url.group(1) +        self.html = self.load(url, decode=True) + +        # Free downloads wait time +        waittime = re.search(r'id="startWait" value="(\d+)"', self.html) +        if not waittime: +            self.parseError('Unable to detect wait time') +        self.setWait(int(waittime.group(1)))          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.logDebug("Download URL: %s" % url) -        self.download(url) -         +        # Parse the direct link and download it +        direct = re.search(r'data-href-direct="(.*)" class="button', self.html) +        if not direct: +            self.parseError('Unable to detect free direct link') +        direct = direct.group(1) +        self.logDebug('DIRECT LINK: ' + direct) +        self.download(direct, disposition=True) +          check = self.checkDownload({"multiple": "You are currently downloading too many files at once.",                                      "error": '<div id="errorMessage">'})          if check == "multiple": -            self.setWait(15*60)              self.logDebug("Parallel downloads detected; waiting 15 minutes") -            self.wait() -            self.retry() +            self.retry(wait_time=15 * 60, reason='Parallel downloads')          elif check == "error":              self.fail("Unknown error") -     +      def handlePremium(self): -        self.fail('Please enable direct downloads') -         -def getInfo(urls): -    for chunk in chunks(urls, 100): yield checkFile(FilefactoryCom, chunk) +        header = self.load(self.pyfile.url, just_header=True) +        if 'location' in header: +            url = header['location'].strip() +            if not url.startswith("http://"): +                url = "http://www.filefactory.com" + url +        elif 'content-disposition' in header: +            url = self.pyfile.url +        else: +            html = self.load(self.pyfile.url) +            found = re.search(self.DIRECT_LINK_PATTERN, html) +            if found: +                url = found.group(1) +            else: +                self.parseError('Unable to detect premium direct link') + +        self.logDebug('DIRECT PREMIUM LINK: ' + url) +        self.download(url, disposition=True) diff --git a/module/plugins/hoster/MediafireCom.py b/module/plugins/hoster/MediafireCom.py index 0e405930f..1e856c41d 100644 --- a/module/plugins/hoster/MediafireCom.py +++ b/module/plugins/hoster/MediafireCom.py @@ -18,21 +18,23 @@  import re  from module.plugins.internal.SimpleHoster import SimpleHoster, parseFileInfo -from module.plugins.ReCaptcha import ReCaptcha +from module.plugins.internal.CaptchaService import SolveMedia  from module.network.RequestFactory import getURL +  def replace_eval(js_expr):      return js_expr.replace(r'eval("', '').replace(r"\'", r"'").replace(r'\"', r'"') +  def checkHTMLHeader(url):      try:          for i in range(3): -            header = getURL(url, just_header = True) +            header = getURL(url, just_header=True)              for line in header.splitlines():                  line = line.lower() -                if 'location' in line:  +                if 'location' in line:                      url = line.split(':', 1)[1].strip() -                    if 'error.php?errno=320' in url:  +                    if 'error.php?errno=320' in url:                          return url, 1                      if not url.startswith('http://'): url = 'http://www.mediafire.com' + url                      break @@ -42,9 +44,10 @@ def checkHTMLHeader(url):                  break      except:          return url, 3 -         +      return url, 0 +  def getInfo(urls):      for url in urls:          location, status = checkHTMLHeader(url) @@ -52,52 +55,53 @@ def getInfo(urls):              file_info = (url, 0, status, url)          else:              file_info = parseFileInfo(MediafireCom, url, getURL(url, decode=True)) -        yield file_info    +        yield file_info +  class MediafireCom(SimpleHoster):      __name__ = "MediafireCom"      __type__ = "hoster"      __pattern__ = r"http://(?:\w*\.)*mediafire\.com/(file/|(view/?|download.php)?\?)(\w{11}|\w{15})($|/)" -    __version__ = "0.78" +    __version__ = "0.79"      __description__ = """Mediafire.com plugin - free only""" -    __author_name__ = ("zoidberg") -    __author_mail__ = ("zoidberg@mujmail.cz") +    __author_name__ = ("zoidberg", "stickell") +    __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it")      DOWNLOAD_LINK_PATTERN = r'<div class="download_link"[^>]*(?:z-index:(?P<zindex>\d+))?[^>]*>\s*<a href="(?P<href>http://[^"]+)"'      JS_KEY_PATTERN = r"DoShow\('mfpromo1'\);[^{]*{((\w+)='';.*?)eval\(\2\);" -    JS_ZMODULO_PATTERN = r"\('z-index'\)\) \% (\d+)\)\);"  -    RECAPTCHA_PATTERN = r'src="http://(?:api.recaptcha.net|www.google.com/recaptcha/api)/challenge\?k=([^"]+)">' +    JS_ZMODULO_PATTERN = r"\('z-index'\)\) \% (\d+)\)\);" +    SOLVEMEDIA_PATTERN = r'http://api\.solvemedia\.com/papi/challenge\.noscript\?k=([^"]+)'      PAGE1_ACTION_PATTERN = r'<link rel="canonical" href="([^"]+)"/>'      PASSWORD_PATTERN = r'<form name="form_password"'      FILE_NAME_PATTERN = r'<META NAME="description" CONTENT="(?P<N>[^"]+)"/>'      FILE_INFO_PATTERN = r"oFileSharePopup\.ald\('(?P<ID>[^']*)','(?P<N>[^']*)','(?P<S>[^']*)','','(?P<sha256>[^']*)'\)"      FILE_OFFLINE_PATTERN = r'class="error_msg_title"> Invalid or Deleted File. </div>' -     +      def setup(self):          self.multiDL = False      def process(self, pyfile):          pyfile.url = re.sub(r'/view/?\?', '/?', pyfile.url) -     +          self.url, result = checkHTMLHeader(pyfile.url)          self.logDebug('Location (%d): %s' % (result, self.url)) -         +          if result == 0: -            self.html = self.load(self.url, decode = True) -            self.checkCaptcha()             -            self.multiDL = True             +            self.html = self.load(self.url, decode=True) +            self.checkCaptcha() +            self.multiDL = True              self.check_data = self.getFileInfo() -             +              if self.account:                  self.handlePremium()              else:                  self.handleFree()          elif result == 1: -            self.offline()  +            self.offline()          else: -            self.multiDL = True             -            self.download(self.url, disposition = True) +            self.multiDL = True +            self.download(self.url, disposition=True)      def handleFree(self):          passwords = self.getPassword().splitlines() @@ -108,55 +112,23 @@ class MediafireCom(SimpleHoster):                  self.html = self.load(self.url, post={"downloadp": password})              else:                  self.fail("No or incorrect password") -         -        """ -        links = re.findall(self.DOWNLOAD_LINK_PATTERN, self.html) -        link_count = len(links) -        self.logDebug('LINKS ', links) -         -        if link_count == 0: -            self.retry(3, 0, "No links found") -             -        elif link_count > 1: -            found = re.search(self.JS_KEY_PATTERN, self.html) -            try: -                result = self.js.eval(found.group(1)) -                zmodulo = int(re.search(self.JS_ZMODULO_PATTERN, result).group(1)) -                self.logDebug("ZMODULO: %d" % zmodulo) -            except Exception, e: -                self.logDebug(e)                                        -                self.parseError("ZMODULO") -         -            max_index = 0               -            for index, url in links: -                index = int(index) % zmodulo -                if index >= max_index: -                    download_url = url -                     -            self.logDebug("DOWNLOAD LINK:", download_url) -             -        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.logDebug("DOWNLOAD LINK:", download_url) +          self.download(download_url)      def checkCaptcha(self): -        for i in range(5): -            found = re.search(self.RECAPTCHA_PATTERN, self.html) +        for i in xrange(5): +            found = re.search(self.SOLVEMEDIA_PATTERN, self.html)              if found: -                captcha_action = re.search(self.PAGE1_ACTION_PATTERN, self.html).group(1)                  captcha_key = found.group(1) -                recaptcha = ReCaptcha(self) -                captcha_challenge, captcha_response = recaptcha.challenge(captcha_key) -                self.html = self.load(captcha_action, post = { -                    "recaptcha_challenge_field": captcha_challenge, -                    "recaptcha_response_field": captcha_response -                    }, decode = True) +                solvemedia = SolveMedia(self) +                captcha_challenge, captcha_response = solvemedia.challenge(captcha_key) +                self.html = self.load(self.url, post={"adcopy_challenge": captcha_challenge, +                                                      "adcopy_response": captcha_response}, decode=True)              else:                  break          else: diff --git a/module/plugins/hoster/MegaNz.py b/module/plugins/hoster/MegaNz.py index a28ddca9d..e5be4eeb7 100644 --- a/module/plugins/hoster/MegaNz.py +++ b/module/plugins/hoster/MegaNz.py @@ -19,7 +19,7 @@ class MegaNz(Hoster):      __name__ = "MegaNz"      __type__ = "hoster"      __pattern__ = r"https?://([a-z0-9]+\.)?mega\.co\.nz/#!([a-zA-Z0-9!_\-]+)" -    __version__ = "0.11" +    __version__ = "0.12"      __description__ = """mega.co.nz hoster plugin"""      __author_name__ = ("RaNaN", )      __author_mail__ = ("ranan@pyload.org", ) @@ -34,7 +34,7 @@ class MegaNz(Hoster):      def getCipherKey(self, key):          """ Construct the cipher key from the given data """          a = array("I", key) -        key_array = array("I", [a[0] ^ a[4], a[1] ^a[5], a[2] ^ a[6], a[3] ^a[7]]) +        key_array = array("I", [a[0] ^ a[4], a[1] ^ a[5], a[2] ^ a[6], a[3] ^ a[7]])          return key_array      def callApi(self, **kwargs): @@ -69,7 +69,7 @@ class MegaNz(Hoster):          self.pyfile.setStatus("decrypting")          f = open(self.lastDownload, "rb") -        df = open(self.lastDownload.rstrip(self.FILE_SUFFIX), "wb") +        df = open(self.lastDownload.rsplit(self.FILE_SUFFIX)[0], "wb")          # TODO: calculate CBC-MAC for checksum diff --git a/module/plugins/hoster/MovReelCom.py b/module/plugins/hoster/MovReelCom.py new file mode 100644 index 000000000..6f5f1d3f1 --- /dev/null +++ b/module/plugins/hoster/MovReelCom.py @@ -0,0 +1,106 @@ +# -*- coding: utf-8 -*- +import re +from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo +from module.utils import html_unescape +from module.network.RequestFactory import getURL + +class MovReelCom(SimpleHoster): +  __name__ = "MovReelCom" +  __type__ = "hoster" +  __pattern__ = r"http://movreel.com/.*" +  __version__ = "1.00" +  __description__ = """MovReel.com hoster plugin""" +  __author_name__ = ("JorisV83") +  __author_mail__ = ("jorisv83-pyload@yahoo.com") +   +  FILE_INFO_PATTERN = r'You have requested <font color="red">http://movreel.com/.*/(?P<N>.+?)</font>.*\((?P<S>[\d.]+) (?P<U>..)\)</font>' +  FILE_OFFLINE_PATTERN = r'<b>File Not Found</b>' +   +  def setup(self): +    self.resumeDownload = True +    self.multiDL = False +     +  def handleFree(self): +     +    # Define search patterns +    op_pattern = '<input type="hidden" name="op" value="(.*)">' +    id_pattern = '<input type="hidden" name="id" value="(.*)">' +    fn_pattern = '<input type="hidden" name="fname" value="(.*)">' +    re_pattern = '<input type="hidden" name="referer" value="(.*)">' +    ul_pattern = '<input type="hidden" name="usr_login" value="(.*)">' +    rand_pattern = '<input type="hidden" name="rand" value="(.*)">' +    link_pattern = "var file_link = '(.*)';" +    downlimit_pattern = '<br><p class="err">You have reached the download-limit: .*</p>' +     +    # Get HTML source +    self.logDebug("Getting first HTML source") +    html = self.load(self.pyfile.url) +    self.logDebug(" > Done") +     +    op_val = re.search(op_pattern, html).group(1) +    id_val = re.search(id_pattern, html).group(1) +    fn_val = re.search(fn_pattern, html).group(1) +    re_val = re.search(re_pattern, html).group(1) +    ul_val = re.search(ul_pattern, html).group(1) +     +    # Debug values +    self.logDebug(" > Op " + op_val) +    self.logDebug(" > Id " + id_val) +    self.logDebug(" > Fname " + fn_val) +    self.logDebug(" > Referer " + re_val) +    self.logDebug(" > User Login " + ul_val) +     +    # Create post data +    post_data = {"op" : op_val, "usr_login" : ul_val, "id" : id_val, "fname" : fn_val, "referer" : re_val, "method_free" : "+Free+Download"} +     +    # Post and get new HTML source +    self.logDebug("Getting second HTML source") +    html = self.load(self.pyfile.url, post = post_data, decode=True) +    self.logDebug(" > Done") +     +    # Check download limit +    if re.search(downlimit_pattern, html) is not None: +      self.retry(3, 7200, "Download limit reached, wait 2h")  +     +    # Retrieve data +    if re.search(op_pattern, html) is not None: +      op_val = re.search(op_pattern, html).group(1) +    else: +      self.retry(3, 10, "Second html: no op found!!") +     +    if re.search(id_pattern, html) is not None: +      id_val = re.search(id_pattern, html).group(1) +    else: +      self.retry(3, 10, "Second html: no id found!!")    	 +    	 +    if re.search(rand_pattern, html) is not None: +      rand_val = re.search(rand_pattern, html).group(1) +    else: +      self.retry(3, 10, "Second html: no rand found!!") +       +    re_val = self.pyfile.url +     +    # Debug values +    self.logDebug(" > Op " + op_val) +    self.logDebug(" > Id " + id_val) +    self.logDebug(" > Rand " + rand_val) +    self.logDebug(" > Referer " + re_val) +     +    # Create post data +    post_data = {"op" : op_val, "id" : id_val, "rand" : rand_val, "referer" : re_val, "method_free" : "+Free+Download", "method_premium" : "", "down_direct" : "1"} +     +    # Post and get new HTML source +    self.logDebug("Getting third HTML source") +    html = self.load(self.pyfile.url, post = post_data, decode=True) +    self.logDebug(" > Done") +     +    # Get link value +    if re.search(link_pattern, html) is not None: +      link_val = re.search(link_pattern, html).group(1) +      self.logDebug(" > Link " + link_val) +      self.download(link_val) +    else: +      self.logDebug("No link found!!") +      self.retry(3, 10, "No link found!!") +       +getInfo = create_getInfo(MovReelCom)
\ No newline at end of file diff --git a/module/plugins/hoster/MultiDebridCom.py b/module/plugins/hoster/MultiDebridCom.py new file mode 100644 index 000000000..ca98e8a0e --- /dev/null +++ b/module/plugins/hoster/MultiDebridCom.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- + +############################################################################ +# This program is free software: you can redistribute it and/or modify     # +# it under the terms of the GNU Affero 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 Affero General Public License for more details.                      # +#                                                                          # +# You should have received a copy of the GNU Affero 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.common.json_layer import json_loads + + +class MultiDebridCom(Hoster): +    __name__ = "MultiDebridCom" +    __version__ = "0.01" +    __type__ = "hoster" +    __pattern__ = r"http://\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/dl/" +    __description__ = """Multi-debrid.com hoster plugin""" +    __author_name__ = ("stickell") +    __author_mail__ = ("l.stickell@yahoo.it") + +    def init(self): +        self.chunkLimit = -1 +        self.resumeDownload = True + +    def process(self, pyfile): +        if not self.account: +            self.logError("Please enter your Multi-debrid.com account or deactivate this plugin") +            self.fail("No Multi-debrid.com account provided") + +        self.logDebug("Original URL: %s" % pyfile.url) +        if re.match(self.__pattern__, pyfile.url): +            new_url = pyfile.url +        else: +            page = self.req.load('http://multi-debrid.com/api.php', +                                 get={'user': self.user, 'pass': self.account.getAccountData(self.user)['password'], +                                      'link': pyfile.url}) +            self.logDebug("JSON data: " + page) +            page = json_loads(page) +            if page['status'] != 'ok': +                self.fail('Unable to unrestrict link') +            new_url = page['link'] + +        self.logDebug("Unrestricted URL: " + new_url) + +        self.download(new_url, disposition=True) diff --git a/module/plugins/hoster/OneFichierCom.py b/module/plugins/hoster/OneFichierCom.py index 7b87bbe71..c7c3384e9 100644 --- a/module/plugins/hoster/OneFichierCom.py +++ b/module/plugins/hoster/OneFichierCom.py @@ -7,7 +7,7 @@ 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.46" +    __version__ = "0.47"      __description__ = """1fichier.com download hoster"""      __author_name__ = ("fragonib", "the-razer", "zoidberg","imclem")      __author_mail__ = ("fragonib[AT]yahoo[DOT]es", "daniel_ AT gmx DOT net", "zoidberg@mujmail.cz","imclem on github") @@ -19,7 +19,7 @@ class OneFichierCom(SimpleHoster):      DOWNLOAD_LINK_PATTERN = r'<br/> <br/> <br/> \s+<a href="(?P<url>http://.*?)"'             PASSWORD_PROTECTED_TOKEN = "protected by password" -    WAITING_PATTERN = "Warning ! Without premium status, you can download only one file at a time and you must wait at least (\d+) minutes between each downloads." +    WAITING_PATTERN = "Warning ! Without premium status, you can download only one file at a time and you must wait up to (\d+) minutes between each downloads."      def process(self, pyfile):          found = re.search(self.__pattern__, pyfile.url)          file_id = found.group(2)       diff --git a/module/plugins/hoster/Premium4Me.py b/module/plugins/hoster/Premium4Me.py index 2679916e9..5dd907b9f 100644 --- a/module/plugins/hoster/Premium4Me.py +++ b/module/plugins/hoster/Premium4Me.py @@ -2,20 +2,22 @@  # -*- coding: utf-8 -*-
  from urllib import quote
 -from module.plugins.Hoster import Hoster
 -from module.utils import fs_encode
  from os.path import exists
  from os import remove
 +from module.plugins.Hoster import Hoster
 +from module.utils import fs_encode
 +
 +
  class Premium4Me(Hoster):
      __name__ = "Premium4Me"
 -    __version__ = "0.04"
 +    __version__ = "0.05"
      __type__ = "hoster"
      __pattern__ = r"http://premium4.me/.*"
      __description__ = """premium4.me hoster plugin"""
 -    __author_name__ = ("RaNaN", "zoidberg")
 -    __author_mail__ = ("RaNaN@pyload.org", "zoidberg@mujmail.cz")
 +    __author_name__ = ("RaNaN", "zoidberg", "stickell")
 +    __author_mail__ = ("RaNaN@pyload.org", "zoidberg@mujmail.cz", "l.stickell@yahoo.it")
      def setup(self):
          self.resumeDownload = True
 @@ -29,33 +31,40 @@ class Premium4Me(Hoster):          self.logDebug("premium4.me: Old URL: %s" % pyfile.url)
          tra = self.getTraffic()
 -        
 +
          #raise timeout to 2min
          self.req.setOption("timeout", 120)
 -        
 -        self.download("http://premium4.me/api/getfile.php?authcode=%s&link=%s" % (self.account.authcode, quote(pyfile.url, "")), disposition=True)
 -        
 -        err = ''       
 +
 +        self.download(
 +            "http://premium4.me/api/getfile.php?authcode=%s&link=%s" % (self.account.authcode, quote(pyfile.url, "")),
 +            disposition=True)
 +
 +        check = self.checkDownload({"nopremium": "No premium account available"})
 +
 +        if check == "nopremium":
 +            self.retry(3, 60, 'No premium account available')
 +
 +        err = ''
          if self.req.http.code == '420':
              # Custom error code send - fail
              lastDownload = fs_encode(self.lastDownload)
 -            
 -            if exists(lastDownload): 
 +
 +            if exists(lastDownload):
                  f = open(lastDownload, "rb")
                  err = f.read(256).strip()
                  f.close()
                  remove(lastDownload)
              else:
                  err = 'File does not exist'
 -        
 +
          trb = self.getTraffic()
 -        self.logInfo("Filesize: %d, Traffic used %d, traffic left %d" % (pyfile.size, tra-trb, trb))
 -                    
 +        self.logInfo("Filesize: %d, Traffic used %d, traffic left %d" % (pyfile.size, tra - trb, trb))
 +
          if err: self.fail(err)
 -        
 +
      def getTraffic(self):
          try:
 -            traffic = int(self.load ("http://premium4.me/api/traffic.php?authcode=%s" % self.account.authcode))
 +            traffic = int(self.load("http://premium4.me/api/traffic.php?authcode=%s" % self.account.authcode))
          except:
 -            traffic = 0 
 +            traffic = 0
          return traffic       
 diff --git a/module/plugins/hoster/PutlockerCom.py b/module/plugins/hoster/PutlockerCom.py index 9eff0dc2b..b2016472d 100644 --- a/module/plugins/hoster/PutlockerCom.py +++ b/module/plugins/hoster/PutlockerCom.py @@ -28,7 +28,7 @@ class PutlockerCom(SimpleHoster):      __name__ = "PutlockerCom"      __type__ = "hoster"      __pattern__ = r'http://(www\.)?putlocker\.com/(file|embed)/[A-Z0-9]+' -    __version__ = "0.24" +    __version__ = "0.25"      __description__ = """Putlocker.Com"""      __author_name__ = ("jeix", "stickell")      __author_mail__ = ("l.stickell@yahoo.it") @@ -37,6 +37,8 @@ class PutlockerCom(SimpleHoster):      FILE_INFO_PATTERN = r'site-content">\s*<h1>(?P<N>.+)<strong>\( (?P<S>[^)]+) \)</strong></h1>'      def handleFree(self): +        self.pyfile.url = re.sub(r'http://putlocker\.com', r'http://www.putlocker.com', self.pyfile.url) +          self.html = self.load(self.pyfile.url, decode=True)          link = self._getLink() diff --git a/module/plugins/hoster/RapidgatorNet.py b/module/plugins/hoster/RapidgatorNet.py index 1cc3ff8ae..d2ca77e0f 100644 --- a/module/plugins/hoster/RapidgatorNet.py +++ b/module/plugins/hoster/RapidgatorNet.py @@ -29,9 +29,9 @@ class RapidgatorNet(SimpleHoster):      __name__ = "RapidgatorNet"      __type__ = "hoster"      __pattern__ = r"http://(?:www\.)?(rapidgator.net)/file/(\w+)" -    __version__ = "0.16" +    __version__ = "0.17"      __description__ = """rapidgator.net""" -    __author_name__ = ("zoidberg","chrox") +    __author_name__ = ("zoidberg", "chrox", "stickell")      API_URL = 'http://rapidgator.net/api/file' @@ -39,7 +39,7 @@ class RapidgatorNet(SimpleHoster):      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 = '([^']+)';\s*}\s*return false;" +    DOWNLOAD_LINK_PATTERN = r"return '(http[^']+)';\s*}\s*}\s*}\);"      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=(.*?)"' diff --git a/module/plugins/hoster/RyushareCom.py b/module/plugins/hoster/RyushareCom.py index c2ff54e0c..7bfe4e8fe 100644 --- a/module/plugins/hoster/RyushareCom.py +++ b/module/plugins/hoster/RyushareCom.py @@ -7,7 +7,7 @@ class RyushareCom(XFileSharingPro):      __name__ = "RyushareCom"      __type__ = "hoster"      __pattern__ = r"http://(?:\w*\.)*?ryushare.com/\w{11,}" -    __version__ = "0.10" +    __version__ = "0.11"      __description__ = """ryushare.com hoster plugin"""      __author_name__ = ("zoidberg", "stickell")      __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it") @@ -18,7 +18,9 @@ class RyushareCom(XFileSharingPro):      DIRECT_LINK_PATTERN = r'<a href="([^"]+)">Click here to download</a>'      def setup(self): -        self.resumeDownload = self.multiDL = self.premium +        self.resumeDownload = self.multiDL = True +        if not self.premium: +            self.limitDL = 2          # Up to 3 chunks allowed in free downloads. Unknown for premium          self.chunkLimit = 3 diff --git a/module/plugins/hoster/UploadedTo.py b/module/plugins/hoster/UploadedTo.py index 739f997fe..5aa08891e 100644 --- a/module/plugins/hoster/UploadedTo.py +++ b/module/plugins/hoster/UploadedTo.py @@ -1,6 +1,11 @@  # -*- coding: utf-8 -*- +# Test links (random.bin): +# http://ul.to/044yug9o +# http://ul.to/gzfhd0xs +  import re +from time import sleep  from module.utils import html_unescape, parseFileSize, chunks @@ -13,7 +18,7 @@ key = "bGhGMkllZXByd2VEZnU5Y2NXbHhYVlZ5cEE1bkEzRUw=".decode('base64')  def getID(url):      """ returns id from file url""" -    m = re.match(r"http://[\w\.-]*?(uploaded\.(to|net)|ul\.to)(/file/|/?\?id=|.*?&id=)(?P<ID>\w+)", url) +    m = re.match(UploadedTo.__pattern__, url)      return m.group('ID') @@ -27,7 +32,12 @@ def getAPIData(urls):          post["id_%s" % i] = id          idMap[id] = url -    api = unicode(getURL("http://uploaded.net/api/filemultiple", post=post, decode=False), 'iso-8859-1') +    for i in xrange(5): +        api = unicode(getURL("http://uploaded.net/api/filemultiple", post=post, decode=False), 'iso-8859-1') +        if api != "can't find request": +            break +        else: +            sleep(3)      result = {} @@ -76,8 +86,8 @@ def getInfo(urls):  class UploadedTo(Hoster):      __name__ = "UploadedTo"      __type__ = "hoster" -    __pattern__ = r"http://[\w\.-]*?(uploaded\.(to|net)(/file/|/?\?id=|.*?&id=)|ul\.to/)\w+" -    __version__ = "0.65" +    __pattern__ = r"https?://[\w\.-]*?(uploaded\.(to|net)|ul\.to)(/file/|/?\?id=|.*?&id=|/)(?P<ID>\w+)" +    __version__ = "0.70"      __description__ = """Uploaded.net Download Hoster"""      __author_name__ = ("spoob", "mkaay", "zoidberg", "netpok", "stickell")      __author_mail__ = ("spoob@pyload.org", "mkaay@mkaay.de", "zoidberg@mujmail.cz", "netpok@gmail.com", "l.stickell@yahoo.it") @@ -204,7 +214,7 @@ class UploadedTo(Hoster):              elif "limit-parallel" in result:                  self.fail("Cannot download in parallel")              elif self.DL_LIMIT_PATTERN in result:  # limit-dl -                self.setWait(60 * 60, True) +                self.setWait(3 * 60 * 60, True)                  self.wait()                  self.retry()              elif 'err:"captcha"' in result: @@ -220,9 +230,9 @@ class UploadedTo(Hoster):          if not downloadURL:              self.fail("No Download url retrieved/all captcha attempts failed") -        self.download(downloadURL) +        self.download(downloadURL, disposition=True)          check = self.checkDownload({"limit-dl": self.DL_LIMIT_PATTERN})          if check == "limit-dl": -            self.setWait(60 * 60, True) +            self.setWait(3 * 60 * 60, True)              self.wait()              self.retry() diff --git a/module/plugins/hoster/UploadheroCom.py b/module/plugins/hoster/UploadheroCom.py index eb7b5fb23..502f849af 100644 --- a/module/plugins/hoster/UploadheroCom.py +++ b/module/plugins/hoster/UploadheroCom.py @@ -22,8 +22,8 @@ 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" +    __pattern__ = r"http://(?:www\.)?uploadhero\.com?/dl/\w+" +    __version__ = "0.13"      __description__ = """UploadHero.com plugin"""      __author_name__ = ("mcmyst", "zoidberg")      __author_mail__ = ("mcmyst@hotmail.fr", "zoidberg@mujmail.cz") @@ -81,4 +81,4 @@ class UploadheroCom(SimpleHoster):              self.wait()              self.retry() -getInfo = create_getInfo(UploadheroCom)
\ No newline at end of file +getInfo = create_getInfo(UploadheroCom) diff --git a/module/plugins/hoster/XVideosCom.py b/module/plugins/hoster/XVideosCom.py new file mode 100644 index 000000000..b7f3f7b58 --- /dev/null +++ b/module/plugins/hoster/XVideosCom.py @@ -0,0 +1,19 @@ + +import re +import urllib + +from module.plugins.Hoster import Hoster + +class XVideosCom(Hoster): +    __name__ = "XVideos.com" +    __version__ = "0.1" +    __pattern__ = r"http://www\.xvideos\.com/video([0-9]+)/.*" +    __config__ = [] + +    def process(self, pyfile): +        site = self.load(pyfile.url) +        pyfile.name = "%s (%s).flv" %( +            re.search(r"<h2>([^<]+)<span", site).group(1), +            re.search(self.__pattern__, pyfile.url).group(1), +        ) +        self.download(urllib.unquote(re.search(r"flv_url=([^&]+)&", site).group(1))) diff --git a/module/plugins/hoster/XvidstageCom.py b/module/plugins/hoster/XvidstageCom.py index 14079df43..4962c05af 100644 --- a/module/plugins/hoster/XvidstageCom.py +++ b/module/plugins/hoster/XvidstageCom.py @@ -1,105 +1,114 @@  # -*- 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 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. +    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/>. +    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: 4Christopher +    @author: 4Christopher  """ -from module.plugins.Hoster import Hoster -from module.network.RequestFactory import getURL  import re  import HTMLParser +from module.plugins.Hoster import Hoster +from module.network.RequestFactory import getURL + +  def setup(self): -	self.wantReconnect = False -	self.resumeDownload = True -	self.multiDL = True +    self.wantReconnect = False +    self.resumeDownload = True +    self.multiDL = True +  def getInfo(urls): -	result = [] - -	for url in urls: -		result.append(parseFileInfo(url, getInfoMode = True)) -	yield result - -def parseFileInfo(url, getInfoMode = False): -	html = getURL(url) -	info = {"name" : url, "size" : 0, "status" : 3} -	try: -		info['name'] = re.search(r'(?:Filename|Dateiname):</b></td><td nowrap[^>]*?>(.*?)<', html).group(1) -		info['size'] = re.search(r'(?:Size|Größe):</b></td><td>.*? <small>\((\d+?) bytes\)', html).group(1) -	except: ## The file is offline -		info['status'] = 1 -	else: -		info['status'] = 2 - -	if getInfoMode: -		return info['name'], info['size'], info['status'], url -	else: -		return info['name'], info['size'], info['status'], html +    result = [] + +    for url in urls: +        result.append(parseFileInfo(url, getInfoMode=True)) +    yield result + + +def parseFileInfo(url, getInfoMode=False): +    html = getURL(url) +    info = {"name": url, "size": 0, "status": 3} +    try: +        info['name'] = re.search(r'(?:Filename|Dateiname):</b></td><td nowrap[^>]*?>(.*?)<', html).group(1) +        info['size'] = re.search(r'(?:Size|Größe):</b></td><td>.*? <small>\((\d+?) bytes\)', html).group(1) +    except: ## The file is offline +        info['status'] = 1 +    else: +        info['status'] = 2 + +    if getInfoMode: +        return info['name'], info['size'], info['status'], url +    else: +        return info['name'], info['size'], info['status'], html +  class XvidstageCom(Hoster): -	__name__ = 'XvidstageCom' -	__version__ = '0.3' -	__pattern__ = r'http://(?:www.)?xvidstage.com/(?P<id>[0-9A-Za-z]+)' -	__type__ = 'hoster' -	__description__ = """A Plugin that allows you to download files from http://xvidstage.com""" -	__author_name__ = ('4Christopher') -	__author_mail__ = ('4Christopher@gmx.de') - - -	def process(self, pyfile): -		pyfile.name, pyfile.size, pyfile.status, self.html = parseFileInfo(pyfile.url) -		self.logDebug('Name: %s' % pyfile.name) -		if pyfile.status == 1: ## offline -			self.fail() -		self.id = re.search(self.__pattern__, pyfile.url).group('id') - -		wait_sec = int(re.search(r'countdown_str">.+?>(\d+?)<', self.html).group(1)) -		self.setWait(wait_sec, reconnect=False) -		self.logDebug('Waiting %d seconds before submitting the captcha' % wait_sec) -		self.wait() - -		rand = re.search(r'<input type="hidden" name="rand" value="(.*?)">', self.html).group(1) -		self.logDebug('rand: %s, id: %s' % (rand, self.id)) -		self.html = self.req.load(pyfile.url, post={'op': 'download2', 'id' : self.id, 'rand' : rand, 'code': self.get_captcha()}) -		file_url = re.search(r'<a href="(?P<url>.*?)">(?P=url)</a>', self.html).group('url') -		try: -			hours_file_available = int(re.search(r'This direct link will be available for your IP next (?P<hours>\d+?) hours', self.html).group('hours')) -			self.logDebug('You have %d hours to download this file with your current IP address.' % hours_file_available) -		except: -			self.logDebug('Failed') -		self.logDebug('Download file: %s' % file_url) -		self.download(file_url) -		check = self.checkDownload({'empty': re.compile(r'^$')}) - -		if check == 'empty': -			self.logInfo('Downloaded File was empty') -			# self.retry() - -	def get_captcha(self): -		## <span style='position:absolute;padding-left:7px;padding-top:6px;'>1 … -		cap_chars = {} -		for pad_left, char in re.findall(r"position:absolute;padding-left:(\d+?)px;.*?;'>(.*?)<", self.html): -			cap_chars[int(pad_left)] = char - -		h = HTMLParser.HTMLParser() -		## Sorting after padding-left -		captcha = '' -		for pad_left in sorted(cap_chars): -			captcha += h.unescape(cap_chars[pad_left]) - -		self.logDebug('The captcha is: %s' % captcha) -		return captcha +    __name__ = 'XvidstageCom' +    __version__ = '0.4' +    __pattern__ = r'http://(?:www.)?xvidstage.com/(?P<id>[0-9A-Za-z]+)' +    __type__ = 'hoster' +    __description__ = """A Plugin that allows you to download files from http://xvidstage.com""" +    __author_name__ = ('4Christopher') +    __author_mail__ = ('4Christopher@gmx.de') + + +    def process(self, pyfile): +        pyfile.name, pyfile.size, pyfile.status, self.html = parseFileInfo(pyfile.url) +        self.logDebug('Name: %s' % pyfile.name) +        if pyfile.status == 1: ## offline +            self.offline() +        self.id = re.search(self.__pattern__, pyfile.url).group('id') + +        wait_sec = int(re.search(r'countdown_str">.+?>(\d+?)<', self.html).group(1)) +        self.setWait(wait_sec, reconnect=False) +        self.logDebug('Waiting %d seconds before submitting the captcha' % wait_sec) +        self.wait() + +        rand = re.search(r'<input type="hidden" name="rand" value="(.*?)">', self.html).group(1) +        self.logDebug('rand: %s, id: %s' % (rand, self.id)) +        self.html = self.req.load(pyfile.url, +                                  post={'op': 'download2', 'id': self.id, 'rand': rand, 'code': self.get_captcha()}) +        file_url = re.search(r'<a href="(?P<url>.*?)">(?P=url)</a>', self.html).group('url') +        try: +            hours_file_available = int( +                re.search(r'This direct link will be available for your IP next (?P<hours>\d+?) hours', +                          self.html).group('hours')) +            self.logDebug( +                'You have %d hours to download this file with your current IP address.' % hours_file_available) +        except: +            self.logDebug('Failed') +        self.logDebug('Download file: %s' % file_url) +        self.download(file_url) +        check = self.checkDownload({'empty': re.compile(r'^$')}) + +        if check == 'empty': +            self.logInfo('Downloaded File was empty') +        # self.retry() + +    def get_captcha(self): +        ## <span style='position:absolute;padding-left:7px;padding-top:6px;'>1 … +        cap_chars = {} +        for pad_left, char in re.findall(r"position:absolute;padding-left:(\d+?)px;.*?;'>(.*?)<", self.html): +            cap_chars[int(pad_left)] = char + +        h = HTMLParser.HTMLParser() +        ## Sorting after padding-left +        captcha = '' +        for pad_left in sorted(cap_chars): +            captcha += h.unescape(cap_chars[pad_left]) + +        self.logDebug('The captcha is: %s' % captcha) +        return captcha diff --git a/module/plugins/hoster/YoutubeCom.py b/module/plugins/hoster/YoutubeCom.py index 2fb1e5264..70db597cf 100644 --- a/module/plugins/hoster/YoutubeCom.py +++ b/module/plugins/hoster/YoutubeCom.py @@ -33,8 +33,8 @@ def which(program):  class YoutubeCom(Hoster):      __name__ = "YoutubeCom"      __type__ = "hoster" -    __pattern__ = r"(http|https)://(www\.)?(de\.)?\youtube\.com/watch\?v=.*" -    __version__ = "0.30" +    __pattern__ = r"https?://(?:[^/]*?)youtube\.com/watch.*?[?&]v=.*" +    __version__ = "0.32"      __config__ = [("quality", "sd;hd;fullhd;240p;360p;480p;720p;1080p;3072p", "Quality Setting", "hd"),          ("fmt", "int", "FMT/ITAG Number (5-102, 0 for auto)", 0),          (".mp4", "bool", "Allow .mp4", True), @@ -47,9 +47,9 @@ class YoutubeCom(Hoster):      __author_mail__ = ("spoob@pyload.org", "zoidberg@mujmail.cz")      # name, width, height, quality ranking, 3D -    formats = {5: (".flv", 400, 240, 1, False),  +    formats = {5: (".flv", 400, 240, 1, False),                  6: (".flv", 640, 400, 4, False), -               17: (".3gp", 176, 144, 0, False),  +               17: (".3gp", 176, 144, 0, False),                 18: (".mp4", 480, 360, 2, False),                 22: (".mp4", 1280, 720, 8, False),                 43: (".webm", 640, 360, 3, False), @@ -59,7 +59,7 @@ class YoutubeCom(Hoster):                 37: (".mp4", 1920, 1080, 9, False),                 38: (".mp4", 4096, 3072, 10, False),                 44: (".webm", 854, 480, 5, False), -               45: (".webm", 1280, 720, 7, False),  +               45: (".webm", 1280, 720, 7, False),                  46: (".webm", 1920, 1080, 9, False),                  82: (".mp4", 640, 360, 3, True),                  83: (".mp4", 400, 240, 1, True), @@ -76,54 +76,54 @@ class YoutubeCom(Hoster):      def process(self, pyfile):          html = self.load(pyfile.url, decode=True) -        if "watch-player-unavailable" in html: +        if '<h1 id="unavailable-message" class="message">' in html:              self.offline()          if "We have been receiving a large volume of requests from your network." in html:              self.tempOffline() -         +          #get config          use3d = self.getConf("3d")          if use3d: -            quality = {"sd":82,"hd":84,"fullhd":85,"240p":83,"360p":82,"480p":82,"720p":84,"1080p":85,"3072p":85}  +            quality = {"sd":82,"hd":84,"fullhd":85,"240p":83,"360p":82,"480p":82,"720p":84,"1080p":85,"3072p":85}          else: -            quality = {"sd":18,"hd":22,"fullhd":37,"240p":5,"360p":18,"480p":35,"720p":22,"1080p":37,"3072p":38}  +            quality = {"sd":18,"hd":22,"fullhd":37,"240p":5,"360p":18,"480p":35,"720p":22,"1080p":37,"3072p":38}          desired_fmt = self.getConf("fmt")          if desired_fmt and desired_fmt not in self.formats: -            self.logWarning("FMT %d unknown - using default." % desired_fmt)  -            desired_fmt = 0  +            self.logWarning("FMT %d unknown - using default." % desired_fmt) +            desired_fmt = 0          if not desired_fmt: -            desired_fmt = quality.get(self.getConf("quality"), 18)         -         +            desired_fmt = quality.get(self.getConf("quality"), 18) +          #parse available streams          streams = re.search(r'"url_encoded_fmt_stream_map": "(.*?)",', html).group(1)          streams = [x.split('\u0026') for x in streams.split(',')]          streams = [dict((y.split('=',1)) for y in x) for x in streams]          streams = [(int(x['itag']), "%s&signature=%s" % (unquote(x['url']), x['sig'])) for x in streams] -        #self.logDebug("Found links: %s" % streams)  -        self.logDebug("AVAILABLE STREAMS: %s" % [x[0] for x in streams])                     -         +        #self.logDebug("Found links: %s" % streams) +        self.logDebug("AVAILABLE STREAMS: %s" % [x[0] for x in streams]) +          #build dictionary of supported itags (3D/2D) -        allowed = lambda x: self.getConfig(self.formats[x][0])         +        allowed = lambda x: self.getConfig(self.formats[x][0])          streams = [x for x in streams if x[0] in self.formats and allowed(x[0])]          if not streams:              self.fail("No available stream meets your preferences") -        fmt_dict = dict([x for x in streams if self.formats[x[0]][4] == use3d] or streams)               -                 -        self.logDebug("DESIRED STREAM: ITAG:%d (%s) %sfound, %sallowed" %  -                          (desired_fmt,  +        fmt_dict = dict([x for x in streams if self.formats[x[0]][4] == use3d] or streams) + +        self.logDebug("DESIRED STREAM: ITAG:%d (%s) %sfound, %sallowed" % +                          (desired_fmt,                             "%s %dx%d Q:%d 3D:%s" % self.formats[desired_fmt], -                           "" if desired_fmt in fmt_dict else "NOT ",  +                           "" if desired_fmt in fmt_dict else "NOT ",                             "" if allowed(desired_fmt) else "NOT ") -                      )         +                      ) -        #return fmt nearest to quality index         +        #return fmt nearest to quality index          if desired_fmt in fmt_dict and allowed(desired_fmt):              fmt = desired_fmt          else:              sel = lambda x: self.formats[x][3] #select quality index              comp = lambda x, y: abs(sel(x) - sel(y)) -         +              self.logDebug("Choosing nearest fmt: %s" % [(x, allowed(x), comp(x, desired_fmt)) for x in fmt_dict.keys()])              fmt = reduce(lambda x, y: x if comp(x, desired_fmt) <= comp(y, desired_fmt) and                                         sel(x) > sel(y) else y, fmt_dict.keys()) @@ -132,7 +132,7 @@ class YoutubeCom(Hoster):          url = fmt_dict[fmt]          self.logDebug("URL: %s" % url) -        #set file name         +        #set file name          file_suffix = self.formats[fmt][0] if fmt in self.formats else ".flv"          file_name_pattern = '<meta name="title" content="(.+?)">'          name = re.search(file_name_pattern, html).group(1).replace("/", "") diff --git a/module/plugins/internal/SimpleCrypter.py b/module/plugins/internal/SimpleCrypter.py index b2cc03985..d935bf1da 100644 --- a/module/plugins/internal/SimpleCrypter.py +++ b/module/plugins/internal/SimpleCrypter.py @@ -20,6 +20,7 @@  import re  from module.plugins.Crypter import Crypter +from module.utils import html_unescape  class SimpleCrypter(Crypter): @@ -57,7 +58,7 @@ class SimpleCrypter(Crypter):          if hasattr(self, 'TITLE_PATTERN'):              m = re.search(self.TITLE_PATTERN, self.html)              if m: -                name = folder = m.group('title') +                name = folder = html_unescape(m.group('title').strip())                  self.logDebug("Found name [%s] and folder [%s] in package info" % (name, folder))                  return name, folder  | 
