diff options
Diffstat (limited to 'module/plugins/internal')
-rw-r--r-- | module/plugins/internal/AbstractExtractor.py | 101 | ||||
-rw-r--r-- | module/plugins/internal/CaptchaService.py | 210 | ||||
-rw-r--r-- | module/plugins/internal/DeadCrypter.py | 20 | ||||
-rw-r--r-- | module/plugins/internal/DeadHoster.py | 28 | ||||
-rw-r--r-- | module/plugins/internal/MultiHoster.py | 191 | ||||
-rw-r--r-- | module/plugins/internal/SimpleCrypter.py | 138 | ||||
-rw-r--r-- | module/plugins/internal/SimpleHoster.py | 301 | ||||
-rw-r--r-- | module/plugins/internal/UnRar.py | 221 | ||||
-rw-r--r-- | module/plugins/internal/UnZip.py | 38 | ||||
-rw-r--r-- | module/plugins/internal/XFSPAccount.py | 75 | ||||
-rw-r--r-- | module/plugins/internal/__init__.py | 0 |
11 files changed, 0 insertions, 1323 deletions
diff --git a/module/plugins/internal/AbstractExtractor.py b/module/plugins/internal/AbstractExtractor.py deleted file mode 100644 index d1d1a09cb..000000000 --- a/module/plugins/internal/AbstractExtractor.py +++ /dev/null @@ -1,101 +0,0 @@ -# -*- coding: utf-8 -*- - -class ArchiveError(Exception): - pass - - -class CRCError(Exception): - pass - - -class WrongPassword(Exception): - pass - - -class AbtractExtractor: - __name__ = "AbtractExtractor" - __version__ = "0.1" - - __description__ = """Abtract extractor plugin""" - __author_name__ = "pyLoad Team" - __author_mail__ = "admin@pyload.org" - - - @staticmethod - def checkDeps(): - """ Check if system statisfy dependencies - :return: boolean - """ - return True - - @staticmethod - def getTargets(files_ids): - """ Filter suited targets from list of filename id tuple list - :param files_ids: List of filepathes - :return: List of targets, id tuple list - """ - raise NotImplementedError - - def __init__(self, m, file, out, fullpath, overwrite, excludefiles, renice): - """Initialize extractor for specific file - - :param m: ExtractArchive Hook plugin - :param file: Absolute filepath - :param out: Absolute path to destination directory - :param fullpath: extract to fullpath - :param overwrite: Overwrite existing archives - :param renice: Renice value - """ - self.m = m - self.file = file - self.out = out - self.fullpath = fullpath - self.overwrite = overwrite - self.excludefiles = excludefiles - self.renice = renice - 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. - - :return: boolean - :raises ArchiveError - """ - return False - - def checkPassword(self, password): - """ Check if the given password is/might be correct. - If it can not be decided at this point return true. - - :param password: - :return: boolean - """ - return True - - def extract(self, progress, password=None): - """Extract the archive. Raise specific errors in case of failure. - - :param progress: Progress function, call this to update status - :param password password to use - :raises WrongPassword - :raises CRCError - :raises ArchiveError - :return: - """ - raise NotImplementedError - - def getDeleteFiles(self): - """Return list of files to delete, do *not* delete them here. - - :return: List with paths of files to delete - """ - raise NotImplementedError - - def getExtractedFiles(self): - """Populate self.files at some point while extracting""" - return self.files diff --git a/module/plugins/internal/CaptchaService.py b/module/plugins/internal/CaptchaService.py deleted file mode 100644 index 35074bc63..000000000 --- a/module/plugins/internal/CaptchaService.py +++ /dev/null @@ -1,210 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from random import random - - -class CaptchaService: - __name__ = "CaptchaService" - __version__ = "0.09" - - __description__ = """Base captcha service plugin""" - __author_name__ = "pyLoad Team" - __author_mail__ = "admin@pyload.org" - - KEY_PATTERN = None - - key = None - - - def __init__(self, plugin): - self.plugin = plugin - - - def detect_key(self, html=None): - if not html: - if hasattr(self.plugin, "html") and self.plugin.html: - html = self.plugin.html - else: - errmsg = "%s html missing" % self.__name__ - self.plugin.fail(errmsg) - raise TypeError(errmsg) - - m = re.search(self.KEY_PATTERN, html) - if m: - self.key = m.group("KEY") - self.plugin.logDebug("%s key: %s" % (self.__name__, self.key)) - return self.key - else: - self.plugin.logDebug("%s key not found" % self.__name__) - return None - - - def challenge(self, key=None): - raise NotImplementedError - - - def result(self, server, challenge): - raise NotImplementedError - - -class ReCaptcha(CaptchaService): - __name__ = "ReCaptcha" - __version__ = "0.02" - - __description__ = """ReCaptcha captcha service plugin""" - __author_name__ = "pyLoad Team" - __author_mail__ = "admin@pyload.org" - - - KEY_PATTERN = r"https?://(?:www\.)?google\.com/recaptcha/api/challenge\?k=(?P<KEY>\w+?)" - KEY_AJAX_PATTERN = r"Recaptcha\.create\s*\(\s*[\"'](?P<KEY>\w+)[\"']\s*," - - - def detect_key(self, html=None): - if not html: - if hasattr(self.plugin, "html") and self.plugin.html: - html = self.plugin.html - else: - errmsg = "ReCaptcha html missing" - self.plugin.fail(errmsg) - raise TypeError(errmsg) - - m = re.search(self.KEY_PATTERN, html) - if m is None: - m = re.search(self.KEY_AJAX_PATTERN, html) - if m: - self.key = m.group("KEY") - self.plugin.logDebug("ReCaptcha key: %s" % self.key) - return self.key - else: - self.plugin.logDebug("ReCaptcha key not found") - return None - - - def challenge(self, key=None): - if not key: - if self.key: - key = self.key - else: - errmsg = "ReCaptcha key missing" - self.plugin.fail(errmsg) - raise TypeError(errmsg) - - js = self.plugin.load("http://www.google.com/recaptcha/api/challenge", get={'k': key}, cookies=True) - - try: - challenge = re.search("challenge : '(.+?)',", js).group(1) - server = re.search("server : '(.+?)',", js).group(1) - except: - self.plugin.parseError("ReCaptcha challenge pattern not found") - - result = self.result(server, challenge) - - return challenge, result - - - def result(self, server, challenge): - return self.plugin.decryptCaptcha("%simage" % server, get={'c': challenge}, - cookies=True, forceUser=True, imgtype="jpg") - - -class AdsCaptcha(CaptchaService): - __name__ = "AdsCaptcha" - __version__ = "0.02" - - __description__ = """AdsCaptcha captcha service plugin""" - __author_name__ = "pyLoad Team" - __author_mail__ = "admin@pyload.org" - - - ID_PATTERN = r'http://api\.adscaptcha\.com/Get\.aspx\?[^"\']*CaptchaId=(?P<ID>\d+)' - KEY_PATTERN = r'http://api\.adscaptcha\.com/Get\.aspx\?[^"\']*PublicKey=(?P<KEY>[\w-]+)' - - - def detect_key(self, html=None): - if not html: - if hasattr(self.plugin, "html") and self.plugin.html: - html = self.plugin.html - else: - errmsg = "AdsCaptcha html missing" - self.plugin.fail(errmsg) - raise TypeError(errmsg) - - m = re.search(self.ID_PATTERN, html) - n = re.search(self.KEY_PATTERN, html) - if m and n: - self.key = (m.group("ID"), m.group("KEY")) - self.plugin.logDebug("AdsCaptcha id|key: %s | %s" % self.key) - return self.key - else: - self.plugin.logDebug("AdsCaptcha id or key not found") - return None - - - def challenge(self, key=None): #: key is tuple(CaptchaId, PublicKey) - if not key: - if self.key: - key = self.key - else: - errmsg = "AdsCaptcha key missing" - self.plugin.fail(errmsg) - raise TypeError(errmsg) - - CaptchaId, PublicKey = key - - js = self.plugin.load("http://api.adscaptcha.com/Get.aspx", get={'CaptchaId': CaptchaId, 'PublicKey': PublicKey}, cookies=True) - - try: - challenge = re.search("challenge: '(.+?)',", js).group(1) - server = re.search("server: '(.+?)',", js).group(1) - except: - self.plugin.parseError("AdsCaptcha challenge pattern not found") - - 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): - __name__ = "SolveMedia" - __version__ = "0.02" - - __description__ = """SolveMedia captcha service plugin""" - __author_name__ = "pyLoad Team" - __author_mail__ = "admin@pyload.org" - - - KEY_PATTERN = r'http://api\.solvemedia\.com/papi/challenge\.(no)?script\?k=(?P<KEY>.+?)"' - - - def challenge(self, key=None): - if not key: - if self.key: - key = self.key - else: - errmsg = "SolveMedia key missing" - self.plugin.fail(errmsg) - raise TypeError(errmsg) - - html = self.plugin.load("http://api.solvemedia.com/papi/challenge.noscript", get={'k': key}, cookies=True) - try: - challenge = re.search(r'<input type=hidden name="adcopy_challenge" id="adcopy_challenge" value="([^"]+)">', - html).group(1) - server = "http://api.solvemedia.com/papi/media" - except: - self.plugin.parseError("SolveMedia challenge pattern not found") - - result = self.result(server, challenge) - - return challenge, result - - - def result(self, server, challenge): - return self.plugin.decryptCaptcha(server, get={'c': challenge}, imgtype="gif") diff --git a/module/plugins/internal/DeadCrypter.py b/module/plugins/internal/DeadCrypter.py deleted file mode 100644 index 1e6fb7d9f..000000000 --- a/module/plugins/internal/DeadCrypter.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.Crypter import Crypter as _Crypter - - -class DeadCrypter(_Crypter): - __name__ = "DeadCrypter" - __type__ = "crypter" - __version__ = "0.02" - - __pattern__ = None - - __description__ = """ Crypter is no longer available """ - __author_name__ = "stickell" - __author_mail__ = "l.stickell@yahoo.it" - - - def setup(self): - self.pyfile.error = "Crypter is no longer available" - self.offline() #@TODO: self.offline("Crypter is no longer available") diff --git a/module/plugins/internal/DeadHoster.py b/module/plugins/internal/DeadHoster.py deleted file mode 100644 index 37cd3cf17..000000000 --- a/module/plugins/internal/DeadHoster.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.plugins.Hoster import Hoster as _Hoster - - -def create_getInfo(plugin): - - def getInfo(urls): - yield map(lambda url: ('#N/A: ' + url, 0, 1, url), urls) - - return getInfo - - -class DeadHoster(_Hoster): - __name__ = "DeadHoster" - __type__ = "hoster" - __version__ = "0.12" - - __pattern__ = None - - __description__ = """ Hoster is no longer available """ - __author_name__ = "zoidberg" - __author_mail__ = "zoidberg@mujmail.cz" - - - def setup(self): - self.pyfile.error = "Hoster is no longer available" - self.offline() #@TODO: self.offline("Hoster is no longer available") diff --git a/module/plugins/internal/MultiHoster.py b/module/plugins/internal/MultiHoster.py deleted file mode 100644 index 7f1bb5103..000000000 --- a/module/plugins/internal/MultiHoster.py +++ /dev/null @@ -1,191 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.plugins.Hook import Hook -from module.utils import remove_chars - - -class MultiHoster(Hook): - __name__ = "AbtractExtractor" - __version__ = "0.19" - - __description__ = """Generic MultiHoster plugin""" - __author_name__ = "pyLoad Team" - __author_mail__ = "admin@pyload.org" - - 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")] - ignored = [] - 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""" - try: - return self.getConf(option) - except KeyError: - return default - - def getHosterCached(self): - if not self.hosters: - - try: - hosterSet = self.toHosterSet(self.getHoster()) - set(self.ignored) - except Exception, e: - self.logError(e) - return [] - - try: - configMode = self.getConfig('hosterListMode', 'all') - if configMode in ("listed", "unlisted"): - configSet = self.toHosterSet(self.getConfig('hosterList', '').replace('|', ',').replace(';', ',').split(',')) - - if configMode == "listed": - hosterSet &= configSet - else: - hosterSet -= configSet - - except Exception, e: - self.logError(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('') - return hosters - - def getHoster(self): - """Load list of supported hoster - - :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 - if cfg_interval is not None: - self.interval = cfg_interval * 60 * 60 - - if self.interval: - self._periodical() - else: - self.periodical() - - def initPeriodical(self): - 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", ", ".join(old_supported)) - for hoster in old_supported: - self.unloadHoster(hoster) - - def overridePlugins(self): - 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] - excludedList = [] - - for hoster in self.getHosterCached(): - name = remove_chars(hoster.lower(), "-.") - - if name in accountList: - excludedList.append(hoster) - else: - if name in pluginMap: - self.supported.append(pluginMap[name]) - else: - self.new_supported.append(hoster) - - if not self.supported and not self.new_supported: - self.logError(_("No Hoster loaded")) - return - - module = self.core.pluginManager.getPlugin(self.__name__) - klass = getattr(module, self.__name__) - - # inject plugin plugin - self.logDebug("Overwritten Hosters", ", ".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"), ", ".join(sorted(excludedList))) - - if self.new_supported: - self.logDebug("New Hosters", ", ".join(sorted(self.new_supported))) - - # create new regexp - 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", regexp) - - dict = self.core.pluginManager.hosterPlugins[self.__name__] - dict['pattern'] = regexp - dict['re'] = re.compile(regexp) - - def unloadHoster(self, hoster): - dict = self.core.pluginManager.hosterPlugins[hoster] - if "module" in dict: - del dict['module'] - - if "new_module" in dict: - del dict['new_module'] - del dict['new_name'] - - def unload(self): - """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']) - - def downloadFailed(self, pyfile): - """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.unloadHoster(pyfile.pluginname) - pyfile.setStatus("queued") diff --git a/module/plugins/internal/SimpleCrypter.py b/module/plugins/internal/SimpleCrypter.py deleted file mode 100644 index 2873a7fa7..000000000 --- a/module/plugins/internal/SimpleCrypter.py +++ /dev/null @@ -1,138 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.plugins.Crypter import Crypter -from module.plugins.internal.SimpleHoster import PluginParseError, replace_patterns, set_cookies -from module.utils import html_unescape - - -class SimpleCrypter(Crypter): - __name__ = "SimpleCrypter" - __type__ = "crypter" - __version__ = "0.12" - - __pattern__ = None - - __description__ = """Simple decrypter plugin""" - __author_name__ = ("stickell", "zoidberg", "Walter Purcaro") - __author_mail__ = ("l.stickell@yahoo.it", "zoidberg@mujmail.cz", "vuolter@gmail.com") - - """ - Following patterns should be defined by each crypter: - - LINK_PATTERN: group(1) must be a download link or a regex to catch more links - example: LINK_PATTERN = r'<div class="link"><a href="(http://speedload.org/\w+)' - - TITLE_PATTERN: (optional) The group defined by 'title' should be the folder name or the webpage title - example: TITLE_PATTERN = r'<title>Files of: (?P<title>[^<]+) folder</title>' - - OFFLINE_PATTERN: (optional) Checks if the file is yet available online - example: OFFLINE_PATTERN = r'File (deleted|not found)' - - TEMP_OFFLINE_PATTERN: (optional) Checks if the file is temporarily offline - example: TEMP_OFFLINE_PATTERN = r'Server maintainance' - - - You can override the getLinks method if you need a more sophisticated way to extract the links. - - - If the links are splitted on multiple pages you can define the PAGES_PATTERN regex: - - PAGES_PATTERN: (optional) The group defined by 'pages' should be the number of overall pages containing the links - example: PAGES_PATTERN = r'Pages: (?P<pages>\d+)' - - and its loadPage method: - - def loadPage(self, page_n): - return the html of the page number page_n - """ - - - URL_REPLACEMENTS = [] - - TEXT_ENCODING = False #: Set to True or encoding name if encoding in http header is not correct - COOKIES = True #: or False or list of tuples [(domain, name, value)] - - LOGIN_ACCOUNT = False - LOGIN_PREMIUM = False - - - def prepare(self): - if self.LOGIN_ACCOUNT and not self.account: - self.fail('Required account not found!') - - if self.LOGIN_PREMIUM and not self.premium: - self.fail('Required premium account not found!') - - if isinstance(self.COOKIES, list): - set_cookies(self.req.cj, self.COOKIES) - - - def decrypt(self, pyfile): - self.prepare() - - pyfile.url = replace_patterns(pyfile.url, self.URL_REPLACEMENTS) - - self.html = self.load(pyfile.url, decode=not self.TEXT_ENCODING) - - self.checkOnline() - - package_name, folder_name = self.getPackageNameAndFolder() - - self.package_links = self.getLinks() - - if hasattr(self, 'PAGES_PATTERN') and hasattr(self, 'loadPage'): - self.handleMultiPages() - - self.logDebug("Package has %d links" % len(self.package_links)) - - if self.package_links: - self.packages = [(package_name, self.package_links, folder_name)] - else: - self.fail('Could not extract any links') - - - def getLinks(self): - """ - Returns the links extracted from self.html - You should override this only if it's impossible to extract links using only the LINK_PATTERN. - """ - return re.findall(self.LINK_PATTERN, self.html) - - - def checkOnline(self): - if hasattr(self, "OFFLINE_PATTERN") and re.search(self.OFFLINE_PATTERN, self.html): - self.offline() - elif hasattr(self, "TEMP_OFFLINE_PATTERN") and re.search(self.TEMP_OFFLINE_PATTERN, self.html): - self.tempOffline() - - - def getPackageNameAndFolder(self): - if hasattr(self, 'TITLE_PATTERN'): - m = re.search(self.TITLE_PATTERN, self.html) - if m: - name = folder = html_unescape(m.group('title').strip()) - self.logDebug("Found name [%s] and folder [%s] in package info" % (name, folder)) - return name, folder - - name = self.pyfile.package().name - folder = self.pyfile.package().folder - self.logDebug("Package info not found, defaulting to pyfile name [%s] and folder [%s]" % (name, folder)) - return name, folder - - - def handleMultiPages(self): - pages = re.search(self.PAGES_PATTERN, self.html) - if pages: - pages = int(pages.group('pages')) - else: - pages = 1 - - for p in xrange(2, pages + 1): - self.html = self.loadPage(p) - self.package_links += self.getLinks() - - - def parseError(self, msg): - raise PluginParseError(msg) diff --git a/module/plugins/internal/SimpleHoster.py b/module/plugins/internal/SimpleHoster.py deleted file mode 100644 index 3625f171e..000000000 --- a/module/plugins/internal/SimpleHoster.py +++ /dev/null @@ -1,301 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from time import time -from urlparse import urlparse - -from module.network.CookieJar import CookieJar -from module.network.RequestFactory import getURL -from module.plugins.Hoster import Hoster -from module.utils import fixup, html_unescape, parseFileSize - - -def replace_patterns(string, ruleslist): - for r in ruleslist: - rf, rt = r - string = re.sub(rf, rt, string) - return string - - -def set_cookies(cj, cookies): - for cookie in cookies: - if isinstance(cookie, tuple) and len(cookie) == 3: - domain, name, value = cookie - cj.setCookie(domain, name, value) - - -def parseHtmlTagAttrValue(attr_name, tag): - m = re.search(r"%s\s*=\s*([\"']?)((?<=\")[^\"]+|(?<=')[^']+|[^>\s\"'][^>\s]*)\1" % attr_name, tag, re.I) - return m.group(2) if m else None - - -def parseHtmlForm(attr_str, html, input_names=None): - for form in re.finditer(r"(?P<tag><form[^>]*%s[^>]*>)(?P<content>.*?)</?(form|body|html)[^>]*>" % attr_str, - html, re.S | re.I): - inputs = {} - action = parseHtmlTagAttrValue("action", form.group('tag')) - for inputtag in re.finditer(r'(<(input|textarea)[^>]*>)([^<]*(?=</\2)|)', form.group('content'), re.S | re.I): - name = parseHtmlTagAttrValue("name", inputtag.group(1)) - if name: - value = parseHtmlTagAttrValue("value", inputtag.group(1)) - if not value: - inputs[name] = inputtag.group(3) or '' - else: - inputs[name] = value - - if isinstance(input_names, dict): - # check input attributes - for key, val in input_names.items(): - if key in inputs: - if isinstance(val, basestring) and inputs[key] == val: - continue - elif isinstance(val, tuple) and inputs[key] in val: - continue - elif hasattr(val, "search") and re.match(val, inputs[key]): - continue - break # attibute value does not match - else: - break # attibute name does not match - else: - return action, inputs # passed attribute check - else: - # no attribute check - return action, inputs - - return {}, None # no matching form found - - -def parseFileInfo(self, url='', html=''): - info = {"name": url, "size": 0, "status": 3} - - if hasattr(self, "pyfile"): - url = self.pyfile.url - - if hasattr(self, "req") and self.req.http.code == '404': - info['status'] = 1 - else: - if not html and hasattr(self, "html"): - html = self.html - if isinstance(self.TEXT_ENCODING, basestring): - html = unicode(html, self.TEXT_ENCODING) - if hasattr(self, "html"): - self.html = html - - if hasattr(self, "OFFLINE_PATTERN") and re.search(self.OFFLINE_PATTERN, html): - info['status'] = 1 - elif hasattr(self, "FILE_OFFLINE_PATTERN") and re.search(self.FILE_OFFLINE_PATTERN, html): #@TODO: Remove in 0.4.10 - info['status'] = 1 - elif hasattr(self, "TEMP_OFFLINE_PATTERN") and re.search(self.TEMP_OFFLINE_PATTERN, html): - info['status'] = 6 - else: - online = False - try: - info.update(re.match(self.__pattern__, url).groupdict()) - except: - pass - - for pattern in ("FILE_INFO_PATTERN", "FILE_NAME_PATTERN", "FILE_SIZE_PATTERN"): - try: - info.update(re.search(getattr(self, pattern), html).groupdict()) - online = True - except AttributeError: - continue - - if online: - # File online, return name and size - info['status'] = 2 - if 'N' in info: - info['name'] = replace_patterns(info['N'], self.FILE_NAME_REPLACEMENTS) - if 'S' in info: - size = replace_patterns(info['S'] + info['U'] if 'U' in info else info['S'], - self.FILE_SIZE_REPLACEMENTS) - info['size'] = parseFileSize(size) - elif isinstance(info['size'], basestring): - if 'units' in info: - info['size'] += info['units'] - info['size'] = parseFileSize(info['size']) - - if hasattr(self, "file_info"): - self.file_info = info - - return info['name'], info['size'], info['status'], url - - -def create_getInfo(plugin): - - def getInfo(urls): - for url in urls: - cj = CookieJar(plugin.__name__) - if isinstance(plugin.COOKIES, list): - set_cookies(cj, plugin.COOKIES) - file_info = parseFileInfo(plugin, url, getURL(replace_patterns(url, plugin.FILE_URL_REPLACEMENTS), - decode=not plugin.TEXT_ENCODING, cookies=cj)) - yield file_info - - return getInfo - - -def timestamp(): - return int(time() * 1000) - - -class PluginParseError(Exception): - - def __init__(self, msg): - Exception.__init__(self) - self.value = 'Parse error (%s) - plugin may be out of date' % msg - - def __str__(self): - return repr(self.value) - - -class SimpleHoster(Hoster): - __name__ = "SimpleHoster" - __type__ = "hoster" - __version__ = "0.36" - - __pattern__ = None - - __description__ = """Simple hoster plugin""" - __author_name__ = ("zoidberg", "stickell", "Walter Purcaro") - __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it", "vuolter@gmail.com") - - """ - Following patterns should be defined by each hoster: - - FILE_INFO_PATTERN: Name and Size of the file - example: FILE_INFO_PATTERN = r'(?P<N>file_name) (?P<S>file_size) (?P<U>size_unit)' - or - FILE_NAME_PATTERN: Name that will be set for the file - example: FILE_NAME_PATTERN = r'(?P<N>file_name)' - FILE_SIZE_PATTERN: Size that will be checked for the file - example: FILE_SIZE_PATTERN = r'(?P<S>file_size) (?P<U>size_unit)' - - OFFLINE_PATTERN: Checks if the file is yet available online - example: OFFLINE_PATTERN = r'File (deleted|not found)' - - TEMP_OFFLINE_PATTERN: Checks if the file is temporarily offline - example: TEMP_OFFLINE_PATTERN = r'Server (maintenance|maintainance)' - - PREMIUM_ONLY_PATTERN: (optional) Checks if the file can be downloaded only with a premium account - example: PREMIUM_ONLY_PATTERN = r'Premium account required' - """ - - FILE_NAME_REPLACEMENTS = [("&#?\w+;", fixup)] - FILE_SIZE_REPLACEMENTS = [] - FILE_URL_REPLACEMENTS = [] - - TEXT_ENCODING = False #: Set to True or encoding name if encoding in http header is not correct - COOKIES = True #: or False or list of tuples [(domain, name, value)] - FORCE_CHECK_TRAFFIC = False #: Set to True to force checking traffic left for premium account - - - def init(self): - self.file_info = {} - - - def setup(self): - self.resumeDownload = self.multiDL = self.premium - - - def prepare(self): - if isinstance(self.COOKIES, list): - set_cookies(self.req.cj, self.COOKIES) - self.req.setOption("timeout", 120) - - - def process(self, pyfile): - self.prepare() - - pyfile.url = replace_patterns(pyfile.url, self.FILE_URL_REPLACEMENTS) - - # Due to a 0.4.9 core bug self.load would keep previous cookies even if overridden by cookies parameter. - # Workaround using getURL. Can be reverted in 0.4.10 as the cookies bug has been fixed. - self.html = getURL(pyfile.url, decode=not self.TEXT_ENCODING, cookies=self.COOKIES) - premium_only = hasattr(self, 'PREMIUM_ONLY_PATTERN') and re.search(self.PREMIUM_ONLY_PATTERN, self.html) - if not premium_only: # Usually premium only pages doesn't show the file information - self.getFileInfo() - - if self.premium and (not self.FORCE_CHECK_TRAFFIC or self.checkTrafficLeft()): - self.handlePremium() - elif premium_only: - self.fail("This link require a premium account") - else: - # This line is required due to the getURL workaround. Can be removed in 0.4.10 - self.html = self.load(pyfile.url, decode=not self.TEXT_ENCODING) - self.handleFree() - - - def getFileInfo(self): - self.logDebug("URL", self.pyfile.url) - - name, size, status = parseFileInfo(self)[:3] - - if status == 1: - self.offline() - elif status == 6: - self.tempOffline() - elif status != 2: - self.logDebug(self.file_info) - self.parseError('File info') - - if name: - self.pyfile.name = name - else: - self.pyfile.name = html_unescape(urlparse(self.pyfile.url).path.split("/")[-1]) - - if size: - self.pyfile.size = size - else: - self.logError(_("File size not parsed")) - - self.logDebug("FILE NAME: %s FILE SIZE: %s" % (self.pyfile.name, self.pyfile.size)) - return self.file_info - - - def handleFree(self): - self.fail("Free download not implemented") - - - def handlePremium(self): - self.fail("Premium download not implemented") - - - def parseError(self, msg): - raise PluginParseError(msg) - - - def longWait(self, wait_time=None, max_tries=3): - if wait_time and isinstance(wait_time, (int, long, float)): - time_str = "%dh %dm" % divmod(wait_time / 60, 60) - else: - wait_time = 900 - time_str = "(unknown time)" - max_tries = 100 - - self.logInfo(_("Download limit reached, reconnect or wait %s") % time_str) - - self.setWait(wait_time, True) - self.wait() - self.retry(max_tries=max_tries, reason="Download limit reached") - - - def parseHtmlForm(self, attr_str='', input_names=None): - return parseHtmlForm(attr_str, self.html, input_names) - - - def checkTrafficLeft(self): - traffic = self.account.getAccountInfo(self.user, True)['trafficleft'] - if traffic == -1: - return True - size = self.pyfile.size / 1024 - self.logInfo(_("Filesize: %i KiB, Traffic left for user %s: %i KiB") % (size, self.user, traffic)) - return size <= traffic - - - #@TODO: Remove in 0.4.10 - def wait(self, seconds=False, reconnect=False): - if seconds: - self.setWait(seconds, reconnect) - super(SimpleHoster, self).wait() diff --git a/module/plugins/internal/UnRar.py b/module/plugins/internal/UnRar.py deleted file mode 100644 index c93b18435..000000000 --- a/module/plugins/internal/UnRar.py +++ /dev/null @@ -1,221 +0,0 @@ -# -*- coding: utf-8 -*- - -import os -import re - -from glob import glob -from os.path import basename, join -from string import digits -from subprocess import Popen, PIPE - -from module.plugins.internal.AbstractExtractor import AbtractExtractor, WrongPassword, ArchiveError, CRCError -from module.utils import save_join, decode - - -def renice(pid, value): - if os.name != "nt" and value: - try: - Popen(["renice", str(value), str(pid)], stdout=PIPE, stderr=PIPE, bufsize=-1) - except: - print "Renice failed" - - -class UnRar(AbtractExtractor): - __name__ = "UnRar" - __version__ = "0.18" - - __description__ = """Rar extractor plugin""" - __author_name__ = "RaNaN" - __author_mail__ = "RaNaN@pyload.org" - - - CMD = "unrar" - - # there are some more uncovered rar formats - re_version = re.compile(r"(UNRAR 5[\.\d]+(.*?)freeware)") - re_splitfile = re.compile(r"(.*)\.part(\d+)\.rar$", re.I) - re_partfiles = re.compile(r".*\.(rar|r[0-9]+)", re.I) - re_filelist = re.compile(r"(.+)\s+(\d+)\s+(\d+)\s+") - re_filelist5 = re.compile(r"(.+)\s+(\d+)\s+\d\d-\d\d-\d\d\s+\d\d:\d\d\s+(.+)") - re_wrongpwd = re.compile("(Corrupt file or wrong password|password incorrect)", re.I) - - - @staticmethod - def checkDeps(): - if os.name == "nt": - UnRar.CMD = join(pypath, "UnRAR.exe") - p = Popen([UnRar.CMD], stdout=PIPE, stderr=PIPE) - p.communicate() - else: - try: - p = Popen([UnRar.CMD], stdout=PIPE, stderr=PIPE) - p.communicate() - except OSError: - - # fallback to rar - UnRar.CMD = "rar" - p = Popen([UnRar.CMD], stdout=PIPE, stderr=PIPE) - p.communicate() - - return True - - - @staticmethod - def getTargets(files_ids): - result = [] - - for file, id in files_ids: - if not file.endswith(".rar"): - continue - - match = UnRar.re_splitfile.findall(file) - if match: - # only add first parts - if int(match[0][1]) == 1: - result.append((file, id)) - else: - result.append((file, id)) - - 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 - - - def checkArchive(self): - p = self.call_unrar("l", "-v", self.file) - out, err = p.communicate() - if self.re_wrongpwd.search(err): - self.passwordProtected = True - self.headerProtected = True - return True - - # output only used to check if passworded files are present - if self.re_version.search(out): - for attr, size, name in self.re_filelist5.findall(out): - if attr.startswith("*"): - self.passwordProtected = True - return True - else: - for name, size, packed in self.re_filelist.findall(out): - if name.startswith("*"): - self.passwordProtected = True - return True - - self.listContent() - if not self.files: - raise ArchiveError("Empty Archive") - - return False - - - def checkPassword(self, password): - # 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() - if self.re_wrongpwd.search(err): - return False - - return True - - - def extract(self, progress, password=None): - command = "x" if self.fullpath else "e" - - p = self.call_unrar(command, self.file, self.out, password=password) - renice(p.pid, self.renice) - - progress(0) - progressstring = "" - while True: - c = p.stdout.read(1) - # quit loop on eof - if not c: - break - # reading a percentage sign -> set progress and restart - if c == '%': - progress(int(progressstring)) - progressstring = "" - # not reading a digit -> therefore restart - elif c not in digits: - progressstring = "" - # add digit to progressstring - else: - progressstring = progressstring + c - progress(100) - - # retrieve stderr - err = p.stderr.read() - - if "CRC failed" in err and not password and not self.passwordProtected: - raise CRCError - elif "CRC failed" in err: - raise WrongPassword - if err.strip(): #: raise error if anything is on stderr - raise ArchiveError(err.strip()) - if p.returncode: - raise ArchiveError("Process terminated") - - if not self.files: - self.password = password - self.listContent() - - - def getDeleteFiles(self): - if ".part" in basename(self.file): - return glob(re.sub("(?<=\.part)([01]+)", "*", self.file, re.IGNORECASE)) - # get files which matches .r* and filter unsuited files out - parts = glob(re.sub(r"(?<=\.r)ar$", "*", self.file, re.IGNORECASE)) - return filter(lambda x: self.re_partfiles.match(x), parts) - - - def listContent(self): - command = "vb" if self.fullpath else "lb" - p = self.call_unrar(command, "-v", self.file, password=self.password) - out, err = p.communicate() - - if "Cannot open" in err: - raise ArchiveError("Cannot open file") - - if err.strip(): #: only log error at this point - self.m.logError(err.strip()) - - result = set() - - for f in decode(out).splitlines(): - f = f.strip() - result.add(save_join(self.out, f)) - - self.files = result - - - def call_unrar(self, command, *xargs, **kwargs): - args = [] - # 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) - - # assume yes on all queries - args.append("-y") - - # 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 - call = [self.CMD, command] + args + list(xargs) - self.m.logDebug(" ".join(call)) - - p = Popen(call, stdout=PIPE, stderr=PIPE) - - return p diff --git a/module/plugins/internal/UnZip.py b/module/plugins/internal/UnZip.py deleted file mode 100644 index e339434f9..000000000 --- a/module/plugins/internal/UnZip.py +++ /dev/null @@ -1,38 +0,0 @@ -# -*- coding: utf-8 -*- - -import sys -import zipfile - -from module.plugins.internal.AbstractExtractor import AbtractExtractor - - -class UnZip(AbtractExtractor): - __name__ = "UnZip" - __version__ = "0.1" - - __description__ = """Zip extractor plugin""" - __author_name__ = "RaNaN" - __author_mail__ = "RaNaN@pyload.org" - - - @staticmethod - def checkDeps(): - return sys.version_info[:2] >= (2, 6) - - @staticmethod - def getTargets(files_ids): - result = [] - - for file, id in files_ids: - if file.endswith(".zip"): - result.append((file, id)) - - return result - - def extract(self, progress, password=None): - z = zipfile.ZipFile(self.file) - self.files = z.namelist() - z.extractall(self.out) - - def getDeleteFiles(self): - return [self.file] diff --git a/module/plugins/internal/XFSPAccount.py b/module/plugins/internal/XFSPAccount.py deleted file mode 100644 index b93fb5d30..000000000 --- a/module/plugins/internal/XFSPAccount.py +++ /dev/null @@ -1,75 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from time import mktime, strptime - -from module.plugins.Account import Account -from module.plugins.internal.SimpleHoster import parseHtmlForm, set_cookies -from module.utils import parseFileSize - - -class XFSPAccount(Account): - __name__ = "XFSPAccount" - __type__ = "account" - __version__ = "0.07" - - __description__ = """XFileSharingPro base account plugin""" - __author_name__ = "zoidberg" - __author_mail__ = "zoidberg@mujmail.cz" - - - HOSTER_URL = None - - COOKIES = None #: or list of tuples [(domain, name, value)] - - VALID_UNTIL_PATTERN = r'>Premium.[Aa]ccount expire:</TD><TD><b>([^<]+)</b>' - TRAFFIC_LEFT_PATTERN = r'>Traffic available today:</TD><TD><b>([^<]+)</b>' - LOGIN_FAIL_PATTERN = r'Incorrect Login or Password|>Error<' - PREMIUM_PATTERN = r'>Renew premium<' - - - def loadAccountInfo(self, user, req): - html = req.load(self.HOSTER_URL + "?op=my_account", decode=True) - - validuntil = trafficleft = None - premium = True if re.search(self.PREMIUM_PATTERN, html) else False - - m = re.search(self.VALID_UNTIL_PATTERN, html) - if m: - premium = True - trafficleft = -1 - try: - self.logDebug(m.group(1)) - validuntil = mktime(strptime(m.group(1), "%d %B %Y")) - except Exception, e: - self.logError(e) - else: - m = re.search(self.TRAFFIC_LEFT_PATTERN, html) - if m: - trafficleft = m.group(1) - if "Unlimited" in trafficleft: - premium = True - else: - trafficleft = parseFileSize(trafficleft) / 1024 - - return {"validuntil": validuntil, "trafficleft": trafficleft, "premium": premium} - - - def login(self, user, data, req): - set_cookies(req.cj, self.COOKIES) - - html = req.load('%slogin.html' % self.HOSTER_URL, decode=True) - - action, inputs = parseHtmlForm('name="FL"', html) - if not inputs: - inputs = {"op": "login", - "redirect": self.HOSTER_URL} - - inputs.update({"login": user, - "password": data['password']}) - - html = req.load(self.HOSTER_URL, post=inputs, decode=True) - - if re.search(self.LOGIN_FAIL_PATTERN, html): - self.wrongPassword() diff --git a/module/plugins/internal/__init__.py b/module/plugins/internal/__init__.py deleted file mode 100644 index e69de29bb..000000000 --- a/module/plugins/internal/__init__.py +++ /dev/null |