diff options
| -rw-r--r-- | module/plugins/accounts/FilefactoryCom.py | 57 | ||||
| -rw-r--r-- | module/plugins/accounts/FshareVn.py | 10 | ||||
| -rw-r--r-- | module/plugins/crypter/EasybytezComFolder.py | 6 | ||||
| -rw-r--r-- | module/plugins/crypter/YoutubeBatch.py | 109 | ||||
| -rw-r--r-- | module/plugins/hoster/BayfilesCom.py | 18 | ||||
| -rw-r--r-- | module/plugins/hoster/CrockoCom.py | 8 | ||||
| -rw-r--r-- | module/plugins/hoster/NowDownloadEu.py | 4 | ||||
| -rw-r--r-- | module/plugins/hoster/TurbobitNet.py | 3 | ||||
| -rw-r--r-- | module/plugins/internal/AbstractExtractor.py | 9 | ||||
| -rw-r--r-- | module/plugins/internal/CaptchaService.py | 37 | ||||
| -rw-r--r-- | module/plugins/internal/DeadCrypter.py | 2 | ||||
| -rw-r--r-- | module/plugins/internal/DeadHoster.py | 5 | ||||
| -rw-r--r-- | module/plugins/internal/MultiHoster.py | 97 | ||||
| -rw-r--r-- | module/plugins/internal/SimpleCrypter.py | 7 | ||||
| -rw-r--r-- | module/plugins/internal/SimpleHoster.py | 3 | ||||
| -rw-r--r-- | module/plugins/internal/UnRar.py | 38 | ||||
| -rw-r--r-- | module/plugins/internal/UnZip.py | 5 | ||||
| -rw-r--r-- | module/plugins/internal/XFSPAccount.py | 41 | 
18 files changed, 275 insertions, 184 deletions
| diff --git a/module/plugins/accounts/FilefactoryCom.py b/module/plugins/accounts/FilefactoryCom.py index 679409058..04ba0ea86 100644 --- a/module/plugins/accounts/FilefactoryCom.py +++ b/module/plugins/accounts/FilefactoryCom.py @@ -1,45 +1,46 @@  # -*- coding: utf-8 -*- -""" -    This program is free software; you can redistribute it and/or modify -    it under the terms of the GNU General Public License as published by -    the Free Software Foundation; either version 3 of the License, -    or (at your option) any later version. - -    This program is distributed in the hope that it will be useful, -    but WITHOUT ANY WARRANTY; without even the implied warranty of -    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -    See the GNU General Public License for more details. - -    You should have received a copy of the GNU General Public License -    along with this program; if not, see <http://www.gnu.org/licenses/>. -     -    @author: zoidberg -""" +############################################################################ +# 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 time import mktime, strptime +from pycurl import REFERER +  from module.plugins.Account import Account  class FilefactoryCom(Account):      __name__ = "FilefactoryCom" -    __version__ = "0.13" +    __version__ = "0.14"      __type__ = "account"      __description__ = """filefactory.com account plugin"""      __author_name__ = ("zoidberg", "stickell")      __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it") -    ACCOUNT_INFO_PATTERN = r'<time datetime="([\d-]+)">' +    VALID_UNTIL_PATTERN = r'Premium valid until: <strong>(?P<d>\d{1,2})\w{1,2} (?P<m>\w{3}), (?P<y>\d{4})</strong>'      def loadAccountInfo(self, user, req): -        html = req.load("http://www.filefactory.com/member/") +        html = req.load("http://www.filefactory.com/account/") -        found = re.search(self.ACCOUNT_INFO_PATTERN, html) -        if found: +        m = re.search(self.VALID_UNTIL_PATTERN, html) +        if m:              premium = True -            validuntil = mktime(strptime(found.group(1), "%Y-%m-%d")) +            validuntil = re.sub(self.VALID_UNTIL_PATTERN, '\g<d> \g<m> \g<y>', m.group(0)) +            validuntil = mktime(strptime(validuntil, "%d %b %Y"))          else:              premium = False              validuntil = -1 @@ -47,10 +48,12 @@ class FilefactoryCom(Account):          return {"premium": premium, "trafficleft": -1, "validuntil": validuntil}      def login(self, user, data, req): -        html = req.load("http://www.filefactory.com/member/login.php", post={ -            "email": user, -            "password": data["password"], -            "redirect": "/"}) +        req.http.c.setopt(REFERER, "http://www.filefactory.com/member/login.php") + +        html = req.load("http://www.filefactory.com/member/signin.php", post={ +            "loginEmail": user, +            "loginPassword": data["password"], +            "Submit": "Sign In"}) -        if '/member/login.php?err=1' in req.http.header: +        if req.lastEffectiveURL != "http://www.filefactory.com/account/":              self.wrongPassword() diff --git a/module/plugins/accounts/FshareVn.py b/module/plugins/accounts/FshareVn.py index 75191e74a..11abfa463 100644 --- a/module/plugins/accounts/FshareVn.py +++ b/module/plugins/accounts/FshareVn.py @@ -26,13 +26,13 @@ from module.plugins.Account import Account  class FshareVn(Account):      __name__ = "FshareVn" -    __version__ = "0.04" +    __version__ = "0.05"      __type__ = "account"      __description__ = """fshare.vn account plugin""" -    __author_name__ = ("zoidberg") -    __author_mail__ = ("zoidberg@mujmail.cz") +    __author_name__ = ("zoidberg", "stickell") +    __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it") -    VALID_UNTIL_PATTERN = ur'<dt>Thời hạn dùng:</dt>\s*<dd>([^<]+)</dd>' +    VALID_UNTIL_PATTERN = ur'<dt>Lần đăng nhập trước:</dt>\s*<dd>([^<]+)</dd>'      TRAFFIC_LEFT_PATTERN = ur'<dt>Tổng Dung Lượng Tài Khoản</dt>\s*<dd[^>]*>([0-9.]+) ([kKMG])B</dd>'      DIRECT_DOWNLOAD_PATTERN = ur'<input type="checkbox"\s*([^=>]*)[^>]*/>Kích hoạt download trực tiếp</dt>' @@ -41,7 +41,7 @@ class FshareVn(Account):          found = re.search(self.VALID_UNTIL_PATTERN, html)          if found:              premium = True -            validuntil = mktime(strptime(found.group(1), '%I:%M:%S %p %d-%m-%Y')) +            validuntil = mktime(strptime(found.group(1), '%d-%m-%Y'))              found = re.search(self.TRAFFIC_LEFT_PATTERN, html)              trafficleft = float(found.group(1)) * 1024 ** {                  'k': 0, 'K': 0, 'M': 1, 'G': 2}[found.group(2)] if found else 0 diff --git a/module/plugins/crypter/EasybytezComFolder.py b/module/plugins/crypter/EasybytezComFolder.py index 56be72669..b9cf240a0 100644 --- a/module/plugins/crypter/EasybytezComFolder.py +++ b/module/plugins/crypter/EasybytezComFolder.py @@ -21,12 +21,14 @@ 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.03" +    __pattern__ = r"http://(?:www\.)?easybytez\.com/users/(?P<ID>\d+/\d+)" +    __version__ = "0.04"      __description__ = """Easybytez Crypter Plugin"""      __author_name__ = ("stickell")      __author_mail__ = ("l.stickell@yahoo.it") +    FILE_URL_REPLACEMENTS = [(__pattern__, r"http://www.easybytez.com/users/\g<ID>")] +      LINK_PATTERN = r'<div class="link"><a href="(http://www\.easybytez\.com/\w+)" target="_blank">.+</a></div>'      TITLE_PATTERN = r'<Title>Files of \d+: (?P<title>.+) folder</Title>'      PAGES_PATTERN = r"<a href='[^']+'>(?P<pages>\d+)</a><a href='[^']+'>Next »</a><br><small>\(\d+ total\)</small></div>" diff --git a/module/plugins/crypter/YoutubeBatch.py b/module/plugins/crypter/YoutubeBatch.py index b6178448d..ee84f0528 100644 --- a/module/plugins/crypter/YoutubeBatch.py +++ b/module/plugins/crypter/YoutubeBatch.py @@ -1,10 +1,28 @@  #!/usr/bin/env python  # -*- 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 +""" +  import re  import json  from module.plugins.Crypter import Crypter +from os.path import join  API_KEY = "AIzaSyCKnWLNlkX-L4oD1aEzqqhRw1zczeD6_k0" @@ -12,33 +30,86 @@ API_KEY = "AIzaSyCKnWLNlkX-L4oD1aEzqqhRw1zczeD6_k0"  class YoutubeBatch(Crypter):      __name__ = "YoutubeBatch"      __type__ = "container" -    __pattern__ = r"https?://(?:[^/]*?)youtube\.com/(?:(?:view_play_list|playlist|.*?feature=PlayList).*?[?&](?:list|p)=)([a-zA-Z0-9-_]+)" -    __version__ = "0.93" +    __pattern__ = r"https?://(?:[^/]*?)youtube\.com/(?:(view_play_list|playlist|.*?feature=PlayList|user)(?:.*?[?&](?:list|p)=|/))([a-zA-Z0-9-_]+)" +    __version__ = "0.94"      __description__ = """Youtube.com Channel Download Plugin""" -    __author_name__ = ("RaNaN", "Spoob", "zoidberg", "roland") -    __author_mail__ = ("RaNaN@pyload.org", "spoob@pyload.org", "zoidberg@mujmail.cz", "roland@enkore.de") +    __author_name__ = ("RaNaN", "Spoob", "zoidberg", "roland", "Walter Purcaro") +    __author_mail__ = ("RaNaN@pyload.org", "spoob@pyload.org", "zoidberg@mujmail.cz", "roland@enkore.de", "vuolter@gmail.com") -    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) +    def json_response(self, api, req): +        req.update({"key": API_KEY}) +        url = "https://www.googleapis.com/youtube/v3/" + api +        page = self.load(url, get=req) +        return json.loads(page) + +    def get_playlist_baseinfos(self, playlist_id): +        res = self.json_response("playlists", {"part": "snippet", "id": playlist_id}) + +        snippet = res["items"][0]["snippet"] +        playlist_name = snippet["title"] +        channel_title = snippet["channelTitle"] +        return playlist_name, channel_title + +    def get_channel_id(self, user_name): +        res = self.json_response("channels", {"part": "id", "forUsername": user_name}) +        return res["items"][0]["id"] + +    def get_playlists(self, user_name, token=None): +        channel_id = self.get_channel_id(user_name) +        req = {"part": "id", "maxResults": "50", "channelId": channel_id}          if token: -            url += "&pageToken=" + token +            req.update({"pageToken": token}) +        res = self.json_response("playlists", req) -        response = json.loads(self.load(url)) +        for item in res["items"]: +            yield item["id"] -        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 res: +            for item in self.get_playlists(user_name, res["nextPageToken"]): +                yield item -        if "nextPageToken" in response: -            for item in self.get_videos(playlist_id, response["nextPageToken"]): +    def get_videos(self, playlist_id, token=None): +        req = {"part": "snippet", "maxResults": "50", "playlistId": playlist_id} +        if token: +            req.update({"pageToken": token}) +        res = self.json_response("playlistItems", req) + +        for item in res["items"]: +            yield "http://youtube.com/watch?v=" + item["snippet"]["resourceId"]["videoId"] + +        if "nextPageToken" in res: +            for item in self.get_videos(playlist_id, res["nextPageToken"]):                  yield item      def decrypt(self, pyfile): -        match_id = re.match(self.__pattern__, self.pyfile.url) -        new_links = [] -        playlist_id = match_id.group(1) +        match_obj = re.match(self.__pattern__, pyfile.url) +        match_type, match_result = match_obj.group(1), match_obj.group(2) +        playlist_ids = [] + +        #: is a channel username or just a playlist id? +        if match_type == "user": +            ids = self.get_playlists(match_result) +            playlist_ids.extend(ids) +        else: +            playlist_ids.append(match_result) + +        self.logDebug("Playlist IDs = %s" % playlist_ids) + +        if not playlist_ids: +            self.fail("Wrong url") + +        for id in playlist_ids: +            self.logDebug("Processing playlist id: %s" % id) + +            playlist_name, channel_title = self.get_playlist_baseinfos(id) +            video_links = [x for x in self.get_videos(id)] + +            self.logInfo("%s videos found on playlist \"%s\" (channel \"%s\")" % (len(video_links), playlist_name, channel_title)) + +            if not video_links: +                continue -        new_links.extend(self.get_videos(playlist_id)) +            self.logDebug("Video links = %s" % video_links) -        self.packages.append((self.pyfile.package().name, new_links, self.pyfile.package().name)) +            folder = join(self.config['general']['download_folder'], channel_title, playlist_name) +            self.packages.append((playlist_name, video_links, folder)) #Note: folder is NOT used actually! diff --git a/module/plugins/hoster/BayfilesCom.py b/module/plugins/hoster/BayfilesCom.py index a696bac26..a7a2c75d4 100644 --- a/module/plugins/hoster/BayfilesCom.py +++ b/module/plugins/hoster/BayfilesCom.py @@ -26,11 +26,11 @@ from module.common.json_layer import json_loads  class BayfilesCom(SimpleHoster):      __name__ = "BayfilesCom"      __type__ = "hoster" -    __pattern__ = r"http://(?:www\.)?bayfiles\.(?:com|net)/file/\w+/\w+/.*" -    __version__ = "0.05" +    __pattern__ = r"https?://(?:www\.)?bayfiles\.(com|net)/file/(?P<ID>[a-zA-Z0-9]+/[a-zA-Z0-9]+/[^/]+)" +    __version__ = "0.06"      __description__ = """Bayfiles.com plugin - free only""" -    __author_name__ = ("zoidberg") -    __author_mail__ = ("zoidberg@mujmail.cz") +    __author_name__ = ("zoidberg", "Walter Purcaro") +    __author_mail__ = ("zoidberg@mujmail.cz", "vuolter@gmail.com")      FILE_INFO_PATTERN = r'<p title="(?P<N>[^"]+)">[^<]*<strong>(?P<S>[0-9., ]+)(?P<U>[kKMG])i?B</strong></p>'      FILE_OFFLINE_PATTERN = r'(<p>The requested file could not be found.</p>|<title>404 Not Found</title>)' @@ -53,7 +53,7 @@ class BayfilesCom(SimpleHoster):              self.parseError('VARS')          vfid, delay = found.groups() -        response = json_loads(self.load('http://bayfiles.com/ajax_download', get={ +        response = json_loads(self.load('https://bayfiles.com/ajax_download', get={              "_": time() * 1000,              "action": "startTimer",              "vfid": vfid}, decode=True)) @@ -64,12 +64,12 @@ class BayfilesCom(SimpleHoster):          self.setWait(int(delay))          self.wait() -        self.html = self.load('http://bayfiles.com/ajax_download', get={ +        self.html = self.load('https://bayfiles.com/ajax_download', get={              "token": response['token'],              "action": "getLink",              "vfid": vfid}) -        # Get final link and download         +        # Get final link and download          found = re.search(self.LINK_PATTERN, self.html)          if not found:              self.parseError("Free link") @@ -90,9 +90,9 @@ class BayfilesCom(SimpleHoster):              "notfound": re.compile(r"<title>404 Not Found</title>")          })          if check == "waitforfreeslots": -            self.retry(60, 300, "Wait for free slot") +            self.retry(30, 60 * 5, "Wait for free slot")          elif check == "notfound": -            self.retry(60, 300, "404 Not found") +            self.retry(30, 60 * 5, "404 Not found")  getInfo = create_getInfo(BayfilesCom) diff --git a/module/plugins/hoster/CrockoCom.py b/module/plugins/hoster/CrockoCom.py index 7d5336cd9..77c45ed92 100644 --- a/module/plugins/hoster/CrockoCom.py +++ b/module/plugins/hoster/CrockoCom.py @@ -10,8 +10,8 @@ from module.plugins.internal.CaptchaService import ReCaptcha  class CrockoCom(SimpleHoster):      __name__ = "CrockoCom"      __type__ = "hoster" -    __pattern__ = r"http://(www\.)?(crocko|easy-share).com/.*" -    __version__ = "0.14" +    __pattern__ = r"http://(www\.)?(crocko|easy-share).com/\w+" +    __version__ = "0.15"      __description__ = """Crocko Download Hoster"""      __author_name__ = ("zoidberg")      __author_mail__ = ("zoidberg@mujmail.cz") @@ -32,7 +32,7 @@ class CrockoCom(SimpleHoster):          if "You need Premium membership to download this file." in self.html:              self.fail("You need Premium membership to download this file.") -        for i in range(5): +        for _ in xrange(5):              found = re.search(self.CAPTCHA_URL_PATTERN, self.html)              if found:                  url, wait_time = 'http://crocko.com' + found.group(1), found.group(2) @@ -55,7 +55,7 @@ class CrockoCom(SimpleHoster):          recaptcha = ReCaptcha(self) -        for i in range(5): +        for _ in xrange(5):              inputs['recaptcha_challenge_field'], inputs['recaptcha_response_field'] = recaptcha.challenge(captcha_key)              self.download(action, post=inputs) diff --git a/module/plugins/hoster/NowDownloadEu.py b/module/plugins/hoster/NowDownloadEu.py index ff7d237f5..bd84b58bc 100644 --- a/module/plugins/hoster/NowDownloadEu.py +++ b/module/plugins/hoster/NowDownloadEu.py @@ -24,8 +24,8 @@ from module.utils import fixup  class NowDownloadEu(SimpleHoster):      __name__ = "NowDownloadEu"      __type__ = "hoster" -    __pattern__ = r"http://(?:www\.)?nowdownload\.(ch|eu|co)/(dl/|download\.php\?id=)(?P<ID>[a-zA-Z0-9]+)" -    __version__ = "0.03" +    __pattern__ = r"http://(?:www\.)?nowdownload\.(ch|co|eu|sx)/(dl/|download\.php\?id=)(?P<ID>\w+)" +    __version__ = "0.04"      __description__ = """NowDownloadCh"""      __author_name__ = ("godofdream", "Walter Purcaro")      __author_mail__ = ("", "vuolter@gmail.com") diff --git a/module/plugins/hoster/TurbobitNet.py b/module/plugins/hoster/TurbobitNet.py index d574d1fa7..78d8b3deb 100644 --- a/module/plugins/hoster/TurbobitNet.py +++ b/module/plugins/hoster/TurbobitNet.py @@ -36,7 +36,7 @@ class TurbobitNet(SimpleHoster):      __name__ = "TurbobitNet"      __type__ = "hoster"      __pattern__ = r"http://(?:\w*\.)?(turbobit.net|unextfiles.com)/(?!download/folder/)(?:download/free/)?(?P<ID>\w+).*" -    __version__ = "0.10" +    __version__ = "0.11"      __description__ = """Turbobit.net plugin"""      __author_name__ = ("zoidberg")      __author_mail__ = ("zoidberg@mujmail.cz") @@ -168,6 +168,7 @@ class TurbobitNet(SimpleHoster):      def handlePremium(self):          self.logDebug("Premium download as user %s" % self.user) +        self.html = self.load(self.pyfile.url)  # Useless in 0.5          self.downloadFile()      def downloadFile(self): diff --git a/module/plugins/internal/AbstractExtractor.py b/module/plugins/internal/AbstractExtractor.py index f730a8434..32c137414 100644 --- a/module/plugins/internal/AbstractExtractor.py +++ b/module/plugins/internal/AbstractExtractor.py @@ -1,15 +1,19 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*- +  class ArchiveError(Exception):      pass +  class CRCError(Exception):      pass +  class WrongPassword(Exception):      pass +  class AbtractExtractor:      __version__ = "0.1" @@ -29,7 +33,6 @@ class AbtractExtractor:          """          raise NotImplementedError -      def __init__(self, m, file, out, fullpath, overwrite, excludefiles, renice):          """Initialize extractor for specific file @@ -47,14 +50,12 @@ class AbtractExtractor:          self.overwrite = overwrite          self.excludefiles = excludefiles          self.renice = renice -        self.files = [] # Store extracted files here - +        self.files = []  #: Store extracted files here      def init(self):          """ Initialize additional data structures """          pass -      def checkArchive(self):          """Check if password if needed. Raise ArchiveError if integrity is          questionable. diff --git a/module/plugins/internal/CaptchaService.py b/module/plugins/internal/CaptchaService.py index b912436a7..4aa3f7dad 100644 --- a/module/plugins/internal/CaptchaService.py +++ b/module/plugins/internal/CaptchaService.py @@ -1,4 +1,5 @@  # -*- 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 @@ -18,49 +19,53 @@  import re -class CaptchaService():     + +class CaptchaService():      __version__ = "0.02" -     +      def __init__(self, plugin):          self.plugin = plugin -         + +  class ReCaptcha():      def __init__(self, plugin):          self.plugin = plugin -     +      def challenge(self, id): -        js = self.plugin.req.load("http://www.google.com/recaptcha/api/challenge", get={"k":id}, cookies=True) -         +        js = self.plugin.req.load("http://www.google.com/recaptcha/api/challenge", get={"k": id}, cookies=True) +          try:              challenge = re.search("challenge : '(.*?)',", js).group(1)              server = re.search("server : '(.*?)',", js).group(1)          except:              self.plugin.fail("recaptcha error") -        result = self.result(server,challenge) -         +        result = self.result(server, challenge) +          return challenge, result      def result(self, server, challenge): -        return self.plugin.decryptCaptcha("%simage"%server, get={"c":challenge}, cookies=True, forceUser=True, imgtype="jpg")     +        return self.plugin.decryptCaptcha("%simage" % server, get={"c": challenge}, cookies=True, forceUser=True, imgtype="jpg") +  class AdsCaptcha(CaptchaService):      def challenge(self, src):          js = self.plugin.req.load(src, cookies=True) -         +          try:              challenge = re.search("challenge: '(.*?)',", js).group(1)              server = re.search("server: '(.*?)',", js).group(1)          except:              self.plugin.fail("adscaptcha error") -        result = self.result(server,challenge) -         +        result = self.result(server, challenge) +          return challenge, result      def result(self, server, challenge):          return self.plugin.decryptCaptcha("%sChallenge.aspx" % server, get={"cid": challenge, "dummy": random()}, cookies=True, imgtype="jpg") +  class SolveMedia(CaptchaService): -    def __init__(self,plugin): +    def __init__(self, plugin):          self.plugin = plugin      def challenge(self, src): @@ -70,8 +75,8 @@ class SolveMedia(CaptchaService):          except:              self.plugin.fail("solvmedia error")          result = self.result(challenge) -         +          return challenge, result -    def result(self,challenge): -        return self.plugin.decryptCaptcha("http://api.solvemedia.com/papi/media?c=%s" % challenge,imgtype="gif")
\ No newline at end of file +    def result(self, challenge): +        return self.plugin.decryptCaptcha("http://api.solvemedia.com/papi/media?c=%s" % challenge, imgtype="gif") diff --git a/module/plugins/internal/DeadCrypter.py b/module/plugins/internal/DeadCrypter.py index 805f781af..51e24a00a 100644 --- a/module/plugins/internal/DeadCrypter.py +++ b/module/plugins/internal/DeadCrypter.py @@ -9,6 +9,6 @@ class DeadCrypter(_Crypter):      __description__ = """Crypter is no longer available"""      __author_name__ = ("stickell")      __author_mail__ = ("l.stickell@yahoo.it") -     +      def setup(self):          self.fail("Crypter is no longer available") diff --git a/module/plugins/internal/DeadHoster.py b/module/plugins/internal/DeadHoster.py index e180e2384..ba6abc0c5 100644 --- a/module/plugins/internal/DeadHoster.py +++ b/module/plugins/internal/DeadHoster.py @@ -5,6 +5,7 @@ def create_getInfo(plugin):          yield [('#N/A: ' + url, 0, 1, url) for url in urls]      return getInfo +  class DeadHoster(_Hoster):      __name__ = "DeadHoster"      __type__ = "hoster" @@ -13,6 +14,6 @@ class DeadHoster(_Hoster):      __description__ = """Hoster is no longer available"""      __author_name__ = ("zoidberg")      __author_mail__ = ("zoidberg@mujmail.cz") -     +      def setup(self): -        self.fail("Hoster is no longer available")
\ No newline at end of file +        self.fail("Hoster is no longer available") diff --git a/module/plugins/internal/MultiHoster.py b/module/plugins/internal/MultiHoster.py index a8961aafc..bd6dc7877 100644 --- a/module/plugins/internal/MultiHoster.py +++ b/module/plugins/internal/MultiHoster.py @@ -6,6 +6,7 @@ import re  from module.utils import remove_chars  from module.plugins.Hook import Hook +  class MultiHoster(Hook):      """      Generic MultiHoster plugin @@ -14,19 +15,19 @@ class MultiHoster(Hook):      __version__ = "0.19"      replacements = [("2shared.com", "twoshared.com"), ("4shared.com", "fourshared.com"), ("cloudnator.com", "shragle.com"), -                    ("ifile.it", "filecloud.io"), ("easy-share.com","crocko.com"), ("freakshare.net","freakshare.com"), -                    ("hellshare.com", "hellshare.cz"), ("share-rapid.cz","sharerapid.com"), ("sharerapid.cz","sharerapid.com"), -                    ("ul.to","uploaded.to"), ("uploaded.net","uploaded.to"), ("1fichier.com", "onefichier.com")] +                    ("ifile.it", "filecloud.io"), ("easy-share.com", "crocko.com"), ("freakshare.net", "freakshare.com"), +                    ("hellshare.com", "hellshare.cz"), ("share-rapid.cz", "sharerapid.com"), ("sharerapid.cz", "sharerapid.com"), +                    ("ul.to", "uploaded.to"), ("uploaded.net", "uploaded.to"), ("1fichier.com", "onefichier.com")]      ignored = [] -    interval = 24 * 60 * 60 # reload hosters daily -     +    interval = 24 * 60 * 60  #: reload hosters daily +      def setup(self):          self.hosters = []          self.supported = []          self.new_supported = [] -         -    def getConfig(self, option, default = ''): -        """getConfig with default value - sublass may not implements all config options"""  + +    def getConfig(self, option, default=''): +        """getConfig with default value - sublass may not implements all config options"""          try:              return self.getConf(option)          except KeyError: @@ -40,33 +41,33 @@ class MultiHoster(Hook):              except Exception, e:                  self.logError("%s" % str(e))                  return [] -                 -            try:  + +            try:                  configMode = self.getConfig('hosterListMode', 'all')                  if configMode in ("listed", "unlisted"): -                    configSet = self.toHosterSet(self.getConfig('hosterList', '').replace('|',',').replace(';',',').split(',')) -                     +                    configSet = self.toHosterSet(self.getConfig('hosterList', '').replace('|', ',').replace(';', ',').split(',')) +                      if configMode == "listed":                          hosterSet &= configSet                      else:                          hosterSet -= configSet -                                 +              except Exception, e:                  self.logError("%s" % str(e)) -         +              self.hosters = list(hosterSet)          return self.hosters -         +      def toHosterSet(self, hosters):          hosters = set((str(x).strip().lower() for x in hosters)) -     +          for rep in self.replacements:              if rep[0] in hosters:                  hosters.remove(rep[0])                  hosters.add(rep[1]) -         -        hosters.discard('')       + +        hosters.discard('')          return hosters      def getHoster(self): @@ -75,34 +76,34 @@ class MultiHoster(Hook):          :return: List of domain names          """          raise NotImplementedError -         +      def coreReady(self):          if self.cb:              self.core.scheduler.removeJob(self.cb) -             -        self.setConfig("activated", True) # config not in sync after plugin reload -         -        cfg_interval = self.getConfig("interval", None) # reload interval in hours + +        self.setConfig("activated", True)  #: config not in sync after plugin reload + +        cfg_interval = self.getConfig("interval", None)  #: reload interval in hours          if cfg_interval is not None: -            self.interval = cfg_interval * 60 * 60             -                 +            self.interval = cfg_interval * 60 * 60 +          if self.interval:              self._periodical()          else:              self.periodical() -             +      def initPeriodical(self): -        pass        -         +        pass +      def periodical(self):          """reload hoster list periodically"""          self.logInfo("Reloading supported hoster list") -         +          old_supported = self.supported          self.supported, self.new_supported, self.hosters = [], [], [] -         +          self.overridePlugins() -         +          old_supported = [hoster for hoster in old_supported if hoster not in self.supported]          if old_supported:              self.logDebug("UNLOAD: %s" % ", ".join(old_supported)) @@ -113,15 +114,15 @@ class MultiHoster(Hook):          pluginMap = {}          for name in self.core.pluginManager.hosterPlugins.keys():              pluginMap[name.lower()] = name -         -        accountList = [ name.lower() for name, data in self.core.accountManager.accounts.items() if data ] + +        accountList = [name.lower() for name, data in self.core.accountManager.accounts.items() if data]          excludedList = [] -         +          for hoster in self.getHosterCached():              name = remove_chars(hoster.lower(), "-.")              if name in accountList: -                excludedList.append(hoster)                 +                excludedList.append(hoster)              else:                  if name in pluginMap:                      self.supported.append(pluginMap[name]) @@ -134,27 +135,27 @@ class MultiHoster(Hook):          module = self.core.pluginManager.getPlugin(self.__name__)          klass = getattr(module, self.__name__) -         +          # inject plugin plugin          self.logDebug("Overwritten Hosters: %s" % ", ".join(sorted(self.supported)))          for hoster in self.supported:              dict = self.core.pluginManager.hosterPlugins[hoster]              dict["new_module"] = module              dict["new_name"] = self.__name__ -             +          if excludedList:              self.logInfo("The following hosters were not overwritten - account exists: %s" % ", ".join(sorted(excludedList)))          if self.new_supported:              self.logDebug("New Hosters: %s" % ", ".join(sorted(self.new_supported))) -     +              # create new regexp -            regexp = r".*(%s).*" % "|".join([x.replace(".", "\\.") for x in self.new_supported])             +            regexp = r".*(%s).*" % "|".join([x.replace(".", "\\.") for x in self.new_supported])              if hasattr(klass, "__pattern__") and isinstance(klass.__pattern__, basestring)  and '://' in klass.__pattern__:                  regexp = r"%s|%s" % (klass.__pattern__, regexp) -                 +              self.logDebug("Regexp: %s" % regexp) -     +              dict = self.core.pluginManager.hosterPlugins[self.__name__]              dict["pattern"] = regexp              dict["re"] = re.compile(regexp) @@ -172,18 +173,18 @@ class MultiHoster(Hook):          """Remove override for all hosters. Scheduler job is removed by hookmanager"""          for hoster in self.supported:              self.unloadHoster(hoster) -         +          # reset pattern          klass = getattr(self.core.pluginManager.getPlugin(self.__name__), self.__name__)          dict = self.core.pluginManager.hosterPlugins[self.__name__] -        dict["pattern"] = getattr(klass, '__pattern__', r"^unmatchable$")  -        dict["re"] = re.compile(dict["pattern"])    -             +        dict["pattern"] = getattr(klass, '__pattern__', r"^unmatchable$") +        dict["re"] = re.compile(dict["pattern"]) +      def downloadFailed(self, pyfile): -        """remove plugin override if download fails but not if file is offline/temp.offline"""   +        """remove plugin override if download fails but not if file is offline/temp.offline"""          if pyfile.hasStatus("failed") and self.getConfig("unloadFailing", True):              hdict = self.core.pluginManager.hosterPlugins[pyfile.pluginname]              if "new_name" in hdict and hdict['new_name'] == self.__name__: -                self.logDebug("Unload MultiHoster", pyfile.pluginname, hdict)     +                self.logDebug("Unload MultiHoster", pyfile.pluginname, hdict)                  self.unloadHoster(pyfile.pluginname) -                pyfile.setStatus("queued")
\ No newline at end of file +                pyfile.setStatus("queued") diff --git a/module/plugins/internal/SimpleCrypter.py b/module/plugins/internal/SimpleCrypter.py index f0fe0b764..78c7158bf 100644 --- a/module/plugins/internal/SimpleCrypter.py +++ b/module/plugins/internal/SimpleCrypter.py @@ -21,11 +21,12 @@ import re  from module.plugins.Crypter import Crypter  from module.utils import html_unescape +from module.plugins.internal.SimpleHoster import replace_patterns  class SimpleCrypter(Crypter):      __name__ = "SimpleCrypter" -    __version__ = "0.06" +    __version__ = "0.07"      __pattern__ = None      __type__ = "crypter"      __description__ = """Base crypter plugin""" @@ -52,7 +53,11 @@ class SimpleCrypter(Crypter):      must return the html of the page number 'page_n'      """ +    FILE_URL_REPLACEMENTS = [] +      def decrypt(self, pyfile): +        pyfile.url = replace_patterns(pyfile.url, self.FILE_URL_REPLACEMENTS) +          self.html = self.load(pyfile.url, decode=True)          package_name, folder_name = self.getPackageNameAndFolder() diff --git a/module/plugins/internal/SimpleHoster.py b/module/plugins/internal/SimpleHoster.py index 856d3fde6..962d7639e 100644 --- a/module/plugins/internal/SimpleHoster.py +++ b/module/plugins/internal/SimpleHoster.py @@ -213,7 +213,8 @@ class SimpleHoster(Hoster):              self.handleFree()      def load(self, url, get={}, post={}, ref=True, cookies=True, just_header=False, decode=False): -        if type(url) == unicode: url = url.encode('utf8') +        if type(url) == unicode: +            url = url.encode('utf8')          return Hoster.load(self, url=url, get=get, post=post, ref=ref, cookies=cookies,                             just_header=just_header, decode=decode) diff --git a/module/plugins/internal/UnRar.py b/module/plugins/internal/UnRar.py index 80ee39cdf..ec430c5bc 100644 --- a/module/plugins/internal/UnRar.py +++ b/module/plugins/internal/UnRar.py @@ -13,7 +13,7 @@      You should have received a copy of the GNU General Public License      along with this program; if not, see <http://www.gnu.org/licenses/>. -     +      @author: RaNaN  """ @@ -27,6 +27,7 @@ from string import digits  from module.utils import save_join, decode  from module.plugins.internal.AbstractExtractor import AbtractExtractor, WrongPassword, ArchiveError, CRCError +  class UnRar(AbtractExtractor):      __name__ = "UnRar"      __version__ = "0.14" @@ -50,7 +51,7 @@ class UnRar(AbtractExtractor):                  p.communicate()              except OSError: -                #fallback to rar +                # fallback to rar                  UnRar.CMD = "rar"                  p = Popen([UnRar.CMD], stdout=PIPE, stderr=PIPE)                  p.communicate() @@ -62,11 +63,12 @@ class UnRar(AbtractExtractor):          result = []          for file, id in files_ids: -            if not file.endswith(".rar"): continue +            if not file.endswith(".rar"): +                continue              match = UnRar.re_splitfile.findall(file)              if match: -                #only add first parts +                # only add first parts                  if int(match[0][1]) == 1:                      result.append((file, id))              else: @@ -74,12 +76,11 @@ class UnRar(AbtractExtractor):          return result -      def init(self):          self.passwordProtected = False -        self.headerProtected = False  #list files will not work without password -        self.smallestFile = None  #small file to test passwords -        self.password = ""  #save the correct password +        self.headerProtected = False  #: list files will not work without password +        self.smallestFile = None  #: small file to test passwords +        self.password = ""  #: save the correct password      def checkArchive(self):          p = self.call_unrar("l", "-v", self.file) @@ -102,7 +103,7 @@ class UnRar(AbtractExtractor):          return False      def checkPassword(self, password): -        #at this point we can only verify header protected files +        # at this point we can only verify header protected files          if self.headerProtected:              p = self.call_unrar("l", "-v", self.file, password=password)              out, err = p.communicate() @@ -111,7 +112,6 @@ class UnRar(AbtractExtractor):          return True -      def extract(self, progress, password=None):          command = "x" if self.fullpath else "e" @@ -144,7 +144,7 @@ class UnRar(AbtractExtractor):              raise CRCError          elif "CRC failed" in err:              raise WrongPassword -        if err.strip(): #raise error if anything is on stderr +        if err.strip():  #: raise error if anything is on stderr              raise ArchiveError(err.strip())          if p.returncode:              raise ArchiveError("Process terminated") @@ -153,7 +153,6 @@ class UnRar(AbtractExtractor):              self.password = password              self.listContent() -      def getDeleteFiles(self):          if ".part" in self.file:              return glob(re.sub("(?<=\.part)([01]+)", "*", self.file, re.IGNORECASE)) @@ -169,7 +168,7 @@ class UnRar(AbtractExtractor):          if "Cannot open" in err:              raise ArchiveError("Cannot open file") -        if err.strip(): # only log error at this point +        if err.strip():  #: only log error at this point              self.m.logError(err.strip())          result = set() @@ -180,26 +179,25 @@ class UnRar(AbtractExtractor):          self.files = result -      def call_unrar(self, command, *xargs, **kwargs):          args = [] -        #overwrite flag +        # overwrite flag          args.append("-o+") if self.overwrite else args.append("-o-") -         +          if self.excludefiles:              for word in self.excludefiles.split(';'): -                args.append("-x%s" % word ) -                 +                args.append("-x%s" % word) +          # assume yes on all queries          args.append("-y") -        #set a password +        # set a password          if "password" in kwargs and kwargs["password"]:              args.append("-p%s" % kwargs["password"])          else:              args.append("-p-") -        #NOTE: return codes are not reliable, some kind of threading, cleanup whatever issue +        # NOTE: return codes are not reliable, some kind of threading, cleanup whatever issue          call = [self.CMD, command] + args + list(xargs)          self.m.logDebug(" ".join(call)) diff --git a/module/plugins/internal/UnZip.py b/module/plugins/internal/UnZip.py index 9aa9ac75c..501962442 100644 --- a/module/plugins/internal/UnZip.py +++ b/module/plugins/internal/UnZip.py @@ -13,7 +13,7 @@      You should have received a copy of the GNU General Public License      along with this program; if not, see <http://www.gnu.org/licenses/>. -     +      @author: RaNaN  """ @@ -22,6 +22,7 @@ import sys  from module.plugins.internal.AbstractExtractor import AbtractExtractor +  class UnZip(AbtractExtractor):      __name__ = "UnZip"      __version__ = "0.1" @@ -46,4 +47,4 @@ class UnZip(AbtractExtractor):          z.extractall(self.out)      def getDeleteFiles(self): -        return [self.file]
\ No newline at end of file +        return [self.file] diff --git a/module/plugins/internal/XFSPAccount.py b/module/plugins/internal/XFSPAccount.py index 8333c7265..e4f211216 100644 --- a/module/plugins/internal/XFSPAccount.py +++ b/module/plugins/internal/XFSPAccount.py @@ -13,7 +13,7 @@      You should have received a copy of the GNU General Public License      along with this program; if not, see <http://www.gnu.org/licenses/>. -     +      @author: zoidberg  """ @@ -23,6 +23,7 @@ from module.plugins.Account import Account  from module.plugins.internal.SimpleHoster import parseHtmlForm  from module.utils import parseFileSize +  class XFSPAccount(Account):      __name__ = "XFSPAccount"      __version__ = "0.05" @@ -30,18 +31,18 @@ class XFSPAccount(Account):      __description__ = """XFileSharingPro account base"""      __author_name__ = ("zoidberg")      __author_mail__ = ("zoidberg@mujmail.cz") -     +      MAIN_PAGE = None -       +      VALID_UNTIL_PATTERN = r'>Premium.[Aa]ccount expire:</TD><TD><b>([^<]+)</b>'      TRAFFIC_LEFT_PATTERN = r'>Traffic available today:</TD><TD><b>([^<]+)</b>' -         -    def loadAccountInfo(self, user, req):       -        html = req.load(self.MAIN_PAGE + "?op=my_account", decode = True) -         + +    def loadAccountInfo(self, user, req): +        html = req.load(self.MAIN_PAGE + "?op=my_account", decode=True) +          validuntil = trafficleft = None          premium = True if '>Renew premium<' in html else False -         +          found = re.search(self.VALID_UNTIL_PATTERN, html)          if found:              premium = True @@ -58,22 +59,22 @@ class XFSPAccount(Account):                  if "Unlimited" in trafficleft:                      premium = True                  else: -                    trafficleft = parseFileSize(trafficleft) / 1024                             -         +                    trafficleft = parseFileSize(trafficleft) / 1024 +          return ({"validuntil": validuntil, "trafficleft": trafficleft, "premium": premium}) -     +      def login(self, user, data, req): -        html = req.load('%slogin.html' % self.MAIN_PAGE, decode = True) -         +        html = req.load('%slogin.html' % self.MAIN_PAGE, decode=True) +          action, inputs = parseHtmlForm('name="FL"', html)          if not inputs:              inputs = {"op": "login", -                      "redirect": self.MAIN_PAGE}         -         +                      "redirect": self.MAIN_PAGE} +          inputs.update({"login": user,                         "password": data['password']}) -         -        html = req.load(self.MAIN_PAGE, post = inputs, decode = True) -         -        if 'Incorrect Login or Password' in html or '>Error<' in html:           -            self.wrongPassword()
\ No newline at end of file + +        html = req.load(self.MAIN_PAGE, post=inputs, decode=True) + +        if 'Incorrect Login or Password' in html or '>Error<' in html: +            self.wrongPassword() | 
