From 68d662e689cd42687341c550fb6ebb74e6968d21 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Mon, 8 Sep 2014 00:29:57 +0200 Subject: module -> pyload --- pyload/plugins/internal/AbstractExtractor.py | 101 +++++++++ pyload/plugins/internal/CaptchaService.py | 96 +++++++++ pyload/plugins/internal/DeadCrypter.py | 19 ++ pyload/plugins/internal/DeadHoster.py | 27 +++ pyload/plugins/internal/MultiHoster.py | 192 ++++++++++++++++++ pyload/plugins/internal/SimpleCrypter.py | 118 +++++++++++ pyload/plugins/internal/SimpleHoster.py | 292 +++++++++++++++++++++++++++ pyload/plugins/internal/UnRar.py | 212 +++++++++++++++++++ pyload/plugins/internal/UnZip.py | 38 ++++ pyload/plugins/internal/XFSPAccount.py | 69 +++++++ pyload/plugins/internal/__init__.py | 0 11 files changed, 1164 insertions(+) create mode 100644 pyload/plugins/internal/AbstractExtractor.py create mode 100644 pyload/plugins/internal/CaptchaService.py create mode 100644 pyload/plugins/internal/DeadCrypter.py create mode 100644 pyload/plugins/internal/DeadHoster.py create mode 100644 pyload/plugins/internal/MultiHoster.py create mode 100644 pyload/plugins/internal/SimpleCrypter.py create mode 100644 pyload/plugins/internal/SimpleHoster.py create mode 100644 pyload/plugins/internal/UnRar.py create mode 100644 pyload/plugins/internal/UnZip.py create mode 100644 pyload/plugins/internal/XFSPAccount.py create mode 100644 pyload/plugins/internal/__init__.py (limited to 'pyload/plugins/internal') diff --git a/pyload/plugins/internal/AbstractExtractor.py b/pyload/plugins/internal/AbstractExtractor.py new file mode 100644 index 000000000..d1d1a09cb --- /dev/null +++ b/pyload/plugins/internal/AbstractExtractor.py @@ -0,0 +1,101 @@ +# -*- 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/pyload/plugins/internal/CaptchaService.py b/pyload/plugins/internal/CaptchaService.py new file mode 100644 index 000000000..b247ba654 --- /dev/null +++ b/pyload/plugins/internal/CaptchaService.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- + +import re + +from random import random + + +class CaptchaService: + __name__ = "CaptchaService" + __version__ = "0.05" + + __description__ = """Captcha service plugin""" + __author_name__ = "pyLoad Team" + __author_mail__ = "admin@pyload.org" + + + def __init__(self, plugin): + self.plugin = plugin + + +class ReCaptcha: + RECAPTCHA_KEY_PATTERN = r"https?://(?:www\.)?google\.com/recaptcha/api/challenge\?k=(?P\w+)" + RECAPTCHA_KEY_AJAX_PATTERN = r"Recaptcha\.create\s*\(\s*[\"'](?P\w+)[\"']\s*," + + recaptcha_key = None + + + def __init__(self, plugin): + self.plugin = plugin + + def detect_key(self, html): + m = re.search(self.RECAPTCHA_KEY_PATTERN, html) + if m is None: + m = re.search(self.RECAPTCHA_KEY_AJAX_PATTERN, html) + if m: + self.recaptcha_key = m.group('key') + return self.recaptcha_key + else: + return None + + def challenge(self, key=None): + if key is None and self.recaptcha_key: + key = self.recaptcha_key + else: + raise TypeError("ReCaptcha key not found") + + js = self.plugin.req.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.fail("recaptcha error") + 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): + + def challenge(self, src): + js = self.plugin.req.load(src, cookies=True) + + try: + challenge = re.search("challenge: '(.*?)',", js).group(1) + server = re.search("server: '(.*?)',", js).group(1) + except: + self.plugin.fail("adscaptcha error") + result = self.result(server, challenge) + + return challenge, result + + def result(self, server, challenge): + return self.plugin.decryptCaptcha("%sChallenge.aspx" % server, get={"cid": challenge, "dummy": random()}, + cookies=True, imgtype="jpg") + + +class SolveMedia(CaptchaService): + + def challenge(self, src): + html = self.plugin.req.load("http://api.solvemedia.com/papi/challenge.noscript?k=%s" % src, cookies=True) + try: + challenge = re.search(r'', + html).group(1) + except: + self.plugin.fail("solvemedia 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") diff --git a/pyload/plugins/internal/DeadCrypter.py b/pyload/plugins/internal/DeadCrypter.py new file mode 100644 index 000000000..ea9c414cb --- /dev/null +++ b/pyload/plugins/internal/DeadCrypter.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.Crypter import Crypter as _Crypter + + +class DeadCrypter(_Crypter): + __name__ = "DeadCrypter" + __type__ = "crypter" + __version__ = "0.01" + + __pattern__ = None + + __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/pyload/plugins/internal/DeadHoster.py b/pyload/plugins/internal/DeadHoster.py new file mode 100644 index 000000000..0b2398020 --- /dev/null +++ b/pyload/plugins/internal/DeadHoster.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- + +from pyload.plugins.Hoster import Hoster as _Hoster + + +def create_getInfo(plugin): + + def getInfo(urls): + yield [('#N/A: ' + url, 0, 1, url) for url in urls] + + return getInfo + + +class DeadHoster(_Hoster): + __name__ = "DeadHoster" + __type__ = "hoster" + __version__ = "0.11" + + __pattern__ = None + + __description__ = """Hoster is no longer available""" + __author_name__ = "zoidberg" + __author_mail__ = "zoidberg@mujmail.cz" + + + def setup(self): + self.fail("Hoster is no longer available") diff --git a/pyload/plugins/internal/MultiHoster.py b/pyload/plugins/internal/MultiHoster.py new file mode 100644 index 000000000..d99ae6ff9 --- /dev/null +++ b/pyload/plugins/internal/MultiHoster.py @@ -0,0 +1,192 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugins.Hook import Hook +from pyload.utils import remove_chars + + +class MultiHoster(Hook): + __name__ = "MultiHoster" + __type__ = "hook" + __version__ = "0.20" + + __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 - subclass may not implements all config options""" + try: + # Fixed loop due to getConf deprecation in 0.4.10 + return super(MultiHoster, self).getConfig(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("%s" % str(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("%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('') + 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: %s" % ", ".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: %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]) + 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) + + 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/pyload/plugins/internal/SimpleCrypter.py b/pyload/plugins/internal/SimpleCrypter.py new file mode 100644 index 000000000..6e639c946 --- /dev/null +++ b/pyload/plugins/internal/SimpleCrypter.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugins.Crypter import Crypter +from pyload.plugins.internal.SimpleHoster import PluginParseError, replace_patterns, set_cookies +from pyload.utils import html_unescape + + +class SimpleCrypter(Crypter): + __name__ = "SimpleCrypter" + __type__ = "crypter" + __version__ = "0.10" + + __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'