From ce1c2b6b05c08b669357947e61ae40efce7fc50f Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Mon, 16 Feb 2015 10:46:28 +0100 Subject: module temp --- module/plugins/internal/AbstractExtractor.py | 109 ++++++ module/plugins/internal/BasePlugin.py | 106 ++++++ module/plugins/internal/DeadCrypter.py | 32 ++ module/plugins/internal/DeadHoster.py | 32 ++ module/plugins/internal/MultiHoster.py | 202 ++++++++++ module/plugins/internal/SimpleCrypter.py | 152 ++++++++ module/plugins/internal/SimpleHoster.py | 530 +++++++++++++++++++++++++++ module/plugins/internal/UnRar.py | 221 +++++++++++ module/plugins/internal/UnZip.py | 41 +++ module/plugins/internal/UpdateManager.py | 300 +++++++++++++++ module/plugins/internal/XFSAccount.py | 155 ++++++++ module/plugins/internal/XFSCrypter.py | 29 ++ module/plugins/internal/XFSHoster.py | 339 +++++++++++++++++ module/plugins/internal/__init__.py | 1 + 14 files changed, 2249 insertions(+) create mode 100644 module/plugins/internal/AbstractExtractor.py create mode 100644 module/plugins/internal/BasePlugin.py create mode 100644 module/plugins/internal/DeadCrypter.py create mode 100644 module/plugins/internal/DeadHoster.py create mode 100644 module/plugins/internal/MultiHoster.py create mode 100644 module/plugins/internal/SimpleCrypter.py create mode 100644 module/plugins/internal/SimpleHoster.py create mode 100644 module/plugins/internal/UnRar.py create mode 100644 module/plugins/internal/UnZip.py create mode 100644 module/plugins/internal/UpdateManager.py create mode 100644 module/plugins/internal/XFSAccount.py create mode 100644 module/plugins/internal/XFSCrypter.py create mode 100644 module/plugins/internal/XFSHoster.py create mode 100644 module/plugins/internal/__init__.py (limited to 'module/plugins/internal') diff --git a/module/plugins/internal/AbstractExtractor.py b/module/plugins/internal/AbstractExtractor.py new file mode 100644 index 000000000..5e09c6755 --- /dev/null +++ b/module/plugins/internal/AbstractExtractor.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- + +class ArchiveError(Exception): + pass + + +class CRCError(Exception): + pass + + +class WrongPassword(Exception): + pass + + +class AbtractExtractor(object): + __name__ = "AbtractExtractor" + __version__ = "0.10" + + __description__ = """Abtract extractor plugin""" + __license__ = "GPLv3" + __authors__ = [("pyLoad Team", "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 Addon 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/BasePlugin.py b/module/plugins/internal/BasePlugin.py new file mode 100644 index 000000000..954fe4e22 --- /dev/null +++ b/module/plugins/internal/BasePlugin.py @@ -0,0 +1,106 @@ +# -*- coding: utf-8 -*- + +import re + +from urllib import unquote +from urlparse import urljoin, urlparse + +from pyload.network.HTTPRequest import BadHeader +from pyload.plugin.internal.SimpleHoster import create_getInfo +from pyload.plugin.Hoster import Hoster + + +class BasePlugin(Hoster): + __name__ = "BasePlugin" + __type__ = "hoster" + __version__ = "0.25" + + __pattern__ = r'^unmatchable$' + + __description__ = """Base plugin when any other didnt fit""" + __license__ = "GPLv3" + __authors__ = [("RaNaN", "RaNaN@pyload.org"), + ("Walter Purcaro", "vuolter@gmail.com")] + + + @classmethod + def getInfo(cls, url="", html=""): #@TODO: Move to hoster class in 0.4.10 + return {'name': urlparse(unquote(url)).path.split('/')[-1] or _("Unknown"), 'size': 0, 'status': 3 if url else 1, 'url': unquote(url) or ""} + + + def setup(self): + self.chunkLimit = -1 + self.resumeDownload = True + + + def process(self, pyfile): + """main function""" + + pyfile.name = self.getInfo(pyfile.url)['name'] + + if not pyfile.url.startswith("http"): + self.fail(_("No plugin matched")) + + for _i in xrange(5): + try: + self.downloadFile(pyfile) + + except BadHeader, e: + if e.code is 404: + self.offline() + + elif e.code in (401, 403): + self.logDebug("Auth required", "Received HTTP status code: %d" % e.code) + + account = self.core.accountManager.getAccountPlugin('Http') + servers = [x['login'] for x in account.getAllAccounts()] + server = urlparse(pyfile.url).netloc + + if server in servers: + self.logDebug("Logging on to %s" % server) + self.req.addAuth(account.accounts[server]['password']) + else: + for pwd in self.getPassword().splitlines(): + if ":" in pwd: + self.req.addAuth(pwd.strip()) + break + else: + self.fail(_("Authorization required")) + else: + self.fail(e) + else: + break + else: + self.fail(_("No file downloaded")) #@TODO: Move to hoster class in 0.4.10 + + if self.checkDownload({'empty': re.compile(r"^$")}) is "empty": #@TODO: Move to hoster in 0.4.10 + self.fail(_("Empty file")) + + + def downloadFile(self, pyfile): + url = pyfile.url + + for i in xrange(1, 7): #@TODO: retrieve the pycurl.MAXREDIRS value set by req + header = self.load(url, ref=True, cookies=True, just_header=True, decode=True) + + if 'location' not in header or not header['location']: + if 'code' in header and header['code'] not in (200, 201, 203, 206): + self.logDebug("Received HTTP status code: %d" % header['code']) + self.fail(_("File not found")) + else: + break + + location = header['location'] + + self.logDebug("Redirect #%d to: %s" % (i, location)) + + if urlparse(location).scheme: + url = location + else: + p = urlparse(url) + base = "%s://%s" % (p.scheme, p.netloc) + url = urljoin(base, location) + else: + self.fail(_("Too many redirects")) + + self.download(unquote(url), disposition=True) diff --git a/module/plugins/internal/DeadCrypter.py b/module/plugins/internal/DeadCrypter.py new file mode 100644 index 000000000..97d99021e --- /dev/null +++ b/module/plugins/internal/DeadCrypter.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- + +from urllib import unquote +from urlparse import urlparse + +from pyload.plugin.Crypter import Crypter as _Crypter +from pyload.plugin.internal.SimpleCrypter import create_getInfo + + +class DeadCrypter(_Crypter): + __name__ = "DeadCrypter" + __type__ = "crypter" + __version__ = "0.04" + + __pattern__ = r'^unmatchable$' + + __description__ = """Crypter is no longer available""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it")] + + + @classmethod + def getInfo(cls, url="", html=""): + return {'name': urlparse(unquote(url)).path.split('/')[-1] or _("Unknown"), 'size': 0, 'status': 1, 'url': url} + + + def setup(self): + self.pyfile.error = "Crypter is no longer available" + self.offline() #@TODO: self.offline("Crypter is no longer available") + + +getInfo = create_getInfo(DeadCrypter) diff --git a/module/plugins/internal/DeadHoster.py b/module/plugins/internal/DeadHoster.py new file mode 100644 index 000000000..27036a139 --- /dev/null +++ b/module/plugins/internal/DeadHoster.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- + +from urllib import unquote +from urlparse import urlparse + +from pyload.plugin.Hoster import Hoster as _Hoster +from pyload.plugin.internal.SimpleHoster import create_getInfo + + +class DeadHoster(_Hoster): + __name__ = "DeadHoster" + __type__ = "hoster" + __version__ = "0.14" + + __pattern__ = r'^unmatchable$' + + __description__ = """Hoster is no longer available""" + __license__ = "GPLv3" + __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] + + + @classmethod + def getInfo(cls, url="", html=""): + return {'name': urlparse(unquote(url)).path.split('/')[-1] or _("Unknown"), 'size': 0, 'status': 1, 'url': url} + + + def setup(self): + self.pyfile.error = "Hoster is no longer available" + self.offline() #@TODO: self.offline("Hoster is no longer available") + + +getInfo = create_getInfo(DeadHoster) diff --git a/module/plugins/internal/MultiHoster.py b/module/plugins/internal/MultiHoster.py new file mode 100644 index 000000000..3b45801f8 --- /dev/null +++ b/module/plugins/internal/MultiHoster.py @@ -0,0 +1,202 @@ +# -*- coding: utf-8 -*- + +import re + +from pyload.plugin.Addon import Addon +from pyload.utils import remove_chars + + +class MultiHoster(Addon): + __name__ = "MultiHoster" + __type__ = "addon" + __version__ = "0.20" + + __description__ = """Base multi-hoster plugin""" + __license__ = "GPLv3" + __authors__ = [("pyLoad Team", "admin@pyload.org")] + + + HOSTER_REPLACEMENTS = [("1fichier.com", "onefichier.com"), ("2shared.com", "twoshared.com"), + ("4shared.com", "fourshared.com"), ("cloudnator.com", "shragle.com"), + ("easy-share.com", "crocko.com"), ("freakshare.net", "freakshare.com"), + ("hellshare.com", "hellshare.cz"), ("ifile.it", "filecloud.io"), + ("putlocker.com", "firedrive.com"), ("share-rapid.cz", "multishare.cz"), + ("sharerapid.cz", "multishare.cz"), ("ul.to", "uploaded.to"), + ("uploaded.net", "uploaded.to")] + HOSTER_EXCLUDED = [] + + + def setup(self): + self.interval = 12 * 60 * 60 #: reload hosters every 12h + 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.HOSTER_EXCLUDED) + 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.HOSTER_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 activate(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 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 = dict((name.lower(), name) for name in self.core.pluginManager.hosterPlugins.keys()) + accountList = [name.lower() for name, data in self.core.accountManager.accounts.iteritems() 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.__type__, 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 deactivate(self): + """Remove override for all hosters. Scheduler job is removed by AddonManager""" + for hoster in self.supported: + self.unloadHoster(hoster) + + # reset pattern + klass = getattr(self.core.pluginManager.getPlugin(self.__type__, 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 new file mode 100644 index 000000000..5115692ad --- /dev/null +++ b/module/plugins/internal/SimpleCrypter.py @@ -0,0 +1,152 @@ +# -*- coding: utf-8 -*- + +import re + +from urlparse import urlparse + +from pyload.plugin.Crypter import Crypter +from pyload.plugin.internal.SimpleHoster import SimpleHoster, create_getInfo, replace_patterns, set_cookies +from pyload.utils import fixup + + +class SimpleCrypter(Crypter, SimpleHoster): + __name__ = "SimpleCrypter" + __type__ = "crypter" + __version__ = "0.32" + + __pattern__ = r'^unmatchable$' + __config__ = [("use_subfolder", "bool", "Save package to subfolder", True), #: Overrides core.config['general']['folder_per_package'] + ("subfolder_per_package", "bool", "Create a subfolder for each package", True)] + + __description__ = """Simple decrypter plugin""" + __license__ = "GPLv3" + __authors__ = [("stickell", "l.stickell@yahoo.it"), + ("zoidberg", "zoidberg@mujmail.cz"), + ("Walter Purcaro", "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'