From 1bd8de6bebb3f76bc5c09566aec682374150f2f8 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Sun, 28 Sep 2014 21:32:34 +0200 Subject: Changed XFileSharingPro and UpdateManager to internal plugins --- pyload/plugins/hooks/ExternalScripts.py | 2 +- pyload/plugins/hooks/UpdateManager.py | 281 ------------------- pyload/plugins/hoster/BillionuploadsCom.py | 2 +- pyload/plugins/hoster/CramitIn.py | 2 +- pyload/plugins/hoster/DuploadOrg.py | 2 +- pyload/plugins/hoster/EasybytezCom.py | 2 +- pyload/plugins/hoster/EpicShareNet.py | 2 +- pyload/plugins/hoster/File4safeCom.py | 2 +- pyload/plugins/hoster/FileParadoxIn.py | 2 +- pyload/plugins/hoster/FileomCom.py | 2 +- pyload/plugins/hoster/FilerioCom.py | 2 +- pyload/plugins/hoster/HugefilesNet.py | 2 +- pyload/plugins/hoster/HundredEightyUploadCom.py | 2 +- pyload/plugins/hoster/LemUploadsCom.py | 2 +- pyload/plugins/hoster/MegaFilesSe.py | 2 +- pyload/plugins/hoster/MegareleaseOrg.py | 2 +- pyload/plugins/hoster/MovReelCom.py | 2 +- pyload/plugins/hoster/NosuploadCom.py | 2 +- pyload/plugins/hoster/NovafileCom.py | 2 +- pyload/plugins/hoster/PandaPlanet.py | 2 +- pyload/plugins/hoster/PotloadCom.py | 2 +- pyload/plugins/hoster/RarefileNet.py | 2 +- pyload/plugins/hoster/RyushareCom.py | 2 +- pyload/plugins/hoster/SecureUploadEu.py | 2 +- pyload/plugins/hoster/SendmywayCom.py | 2 +- pyload/plugins/hoster/StreamcloudEu.py | 2 +- pyload/plugins/hoster/TusfilesNet.py | 2 +- pyload/plugins/hoster/UptoboxCom.py | 2 +- pyload/plugins/hoster/VidPlayNet.py | 2 +- pyload/plugins/hoster/XFileSharingPro.py | 352 ------------------------ pyload/plugins/internal/UpdateManager.py | 281 +++++++++++++++++++ pyload/plugins/internal/XFileSharingPro.py | 352 ++++++++++++++++++++++++ 32 files changed, 661 insertions(+), 661 deletions(-) delete mode 100644 pyload/plugins/hooks/UpdateManager.py delete mode 100644 pyload/plugins/hoster/XFileSharingPro.py create mode 100644 pyload/plugins/internal/UpdateManager.py create mode 100644 pyload/plugins/internal/XFileSharingPro.py (limited to 'pyload/plugins') diff --git a/pyload/plugins/hooks/ExternalScripts.py b/pyload/plugins/hooks/ExternalScripts.py index 2e8dace14..3b32b5068 100644 --- a/pyload/plugins/hooks/ExternalScripts.py +++ b/pyload/plugins/hooks/ExternalScripts.py @@ -113,7 +113,7 @@ class ExternalScripts(Hook): def package_extracted(self, pypack): download_folder = self.config['general']['download_folder'] for script in self.scripts['package_extracted']: - folder = save_join(download_folder, pypack.folder) + folder = safe_join(download_folder, pypack.folder) self.callScript(script, pypack.name, folder, pypack.password, pypack.id) diff --git a/pyload/plugins/hooks/UpdateManager.py b/pyload/plugins/hooks/UpdateManager.py deleted file mode 100644 index 6da39b239..000000000 --- a/pyload/plugins/hooks/UpdateManager.py +++ /dev/null @@ -1,281 +0,0 @@ -# -*- coding: utf-8 -*- - -import re -import sys - -from operator import itemgetter -from os import path, remove, stat - -from pyload.network.RequestFactory import getURL -from pyload.plugins.Hook import Expose, Hook, threaded -from pyload.utils import safe_join - - -class UpdateManager(Hook): - __name__ = "UpdateManager" - __type__ = "hook" - __version__ = "0.35" - - __config__ = [("activated", "bool", "Activated", True), - ("mode", "pyLoad + plugins;plugins only", "Check updates for", "pyLoad + plugins"), - ("interval", "int", "Check interval in hours", 8), - ("reloadplugins", "bool", "Monitor plugins for code changes (debug mode only)", True), - ("nodebugupdate", "bool", "Don't check for updates in debug mode", True)] - - __description__ = """ Check for updates """ - __author_name__ = "Walter Purcaro" - __author_mail__ = "vuolter@gmail.com" - - - event_list = ["pluginConfigChanged"] - - SERVER_URL = "http://updatemanager.pyload.org" - MIN_INTERVAL = 3 * 60 * 60 #: 3h minimum check interval (value is in seconds) - - - def pluginConfigChanged(self, plugin, name, value): - if name == "interval": - interval = value * 60 * 60 - if self.MIN_INTERVAL <= interval != self.interval: - self.core.scheduler.removeJob(self.cb) - self.interval = interval - self.initPeriodical() - else: - self.logDebug("Invalid interval value, kept current") - elif name == "reloadplugins": - if self.cb2: - self.core.scheduler.removeJob(self.cb2) - if value is True and self.core.debug: - self.periodical2() - - def coreReady(self): - self.pluginConfigChanged(self.__name__, "interval", self.getConfig("interval")) - x = lambda: self.pluginConfigChanged(self.__name__, "reloadplugins", self.getConfig("reloadplugins")) - self.core.scheduler.addJob(10, x, threaded=False) - - def unload(self): - self.pluginConfigChanged(self.__name__, "reloadplugins", False) - - def setup(self): - self.cb2 = None - self.interval = self.MIN_INTERVAL - self.updating = False - self.info = {'pyload': False, 'version': None, 'plugins': False} - self.mtimes = {} #: store modification time for each plugin - - def periodical2(self): - if not self.updating: - self.autoreloadPlugins() - self.cb2 = self.core.scheduler.addJob(4, self.periodical2, threaded=False) - - @Expose - def autoreloadPlugins(self): - """ reload and reindex all modified plugins """ - modules = filter( - lambda m: m and (m.__name__.startswith("pyload.plugins.") or - m.__name__.startswith("userplugins.")) and - m.__name__.count(".") >= 2, sys.modules.itervalues() - ) - - reloads = [] - - for m in modules: - root, type, name = m.__name__.rsplit(".", 2) - id = (type, name) - if type in self.core.pluginManager.plugins: - f = m.__file__.replace(".pyc", ".py") - if not path.isfile(f): - continue - - mtime = stat(f).st_mtime - - if id not in self.mtimes: - self.mtimes[id] = mtime - elif self.mtimes[id] < mtime: - reloads.append(id) - self.mtimes[id] = mtime - - return True if self.core.pluginManager.reloadPlugins(reloads) else False - - def periodical(self): - if not self.info['pyload'] and not (self.getConfig("nodebugupdate") and self.core.debug): - self.updateThread() - - def server_request(self): - try: - return getURL(self.SERVER_URL, get={'v': self.core.api.getServerVersion()}).splitlines() - except: - self.logWarning(_("Unable to contact server to get updates")) - - @threaded - def updateThread(self): - self.updating = True - status = self.update(onlyplugin=self.getConfig("mode") == "plugins only") - if status == 2: - self.core.api.restart() - else: - self.updating = False - - @Expose - def updatePlugins(self): - """ simple wrapper for calling plugin update quickly """ - return self.update(onlyplugin=True) - - @Expose - def update(self, onlyplugin=False): - """ check for updates """ - data = self.server_request() - if not data: - exitcode = 0 - elif data[0] == "None": - self.logInfo(_("No new pyLoad version available")) - updates = data[1:] - exitcode = self._updatePlugins(updates) - elif onlyplugin: - exitcode = 0 - else: - newversion = data[0] - self.logInfo(_("*** New pyLoad Version %s available ***") % newversion) - self.logInfo(_("*** Get it here: https://github.com/pyload/pyload/releases ***")) - exitcode = 3 - self.info['pyload'] = True - self.info['version'] = newversion - return exitcode #: 0 = No plugins updated; 1 = Plugins updated; 2 = Plugins updated, but restart required; 3 = No plugins updated, new pyLoad version available - - def _updatePlugins(self, updates): - """ check for plugin updates """ - - if self.info['plugins']: - return False #: plugins were already updated - - updated = [] - - vre = re.compile(r'__version__.*=.*("|\')([0-9.]+)') - url = updates[0] - schema = updates[1].split('|') - if "BLACKLIST" in updates: - blacklist = updates[updates.index('BLACKLIST') + 1:] - updates = updates[2:updates.index('BLACKLIST')] - else: - blacklist = None - updates = updates[2:] - - upgradable = sorted(map(lambda x: dict(zip(schema, x.split('|'))), updates), key=itemgetter("type", "name")) - for plugin in upgradable: - filename = plugin['name'] - prefix = plugin['type'] - version = plugin['version'] - - if filename.endswith(".pyc"): - name = filename[:filename.find("_")] - else: - name = filename.replace(".py", "") - - #@TODO: obsolete after 0.4.10 - if prefix.endswith("s"): - type = prefix[:-1] - else: - type = prefix - - plugins = getattr(self.core.pluginManager, "%sPlugins" % type) - - oldver = float(plugins[name]['v']) if name in plugins else None - newver = float(version) - - if not oldver: - msg = "New [%(type)s] %(name)s (v%(newver)s)" - elif newver > oldver: - msg = "New version of [%(type)s] %(name)s (v%(oldver)s -> v%(newver)s)" - else: - continue - - self.logInfo(_(msg) % { - 'type': type, - 'name': name, - 'oldver': oldver, - 'newver': newver, - }) - - try: - content = getURL(url % plugin) - m = vre.search(content) - if m and m.group(2) == version: - f = open(safe_join("userplugins", prefix, filename), "wb") - f.write(content) - f.close() - updated.append((prefix, name)) - else: - raise Exception, _("Version mismatch") - except Exception, e: - self.logError(_("Error updating plugin %s") % filename, e) - - if blacklist: - blacklisted = sorted(map(lambda x: (x.split('|')[0], x.split('|')[1].rsplit('.', 1)[0]), blacklist)) - - # Always protect UpdateManager from self-removing - try: - blacklisted.remove(("hook", "UpdateManager")) - except: - pass - - removed = self.removePlugins(blacklisted) - for t, n in removed: - self.logInfo(_("Removed blacklisted plugin [%(type)s] %(name)s") % { - 'type': t, - 'name': n, - }) - - if updated: - reloaded = self.core.pluginManager.reloadPlugins(updated) - if reloaded: - self.logInfo(_("Plugins updated and reloaded")) - exitcode = 1 - else: - self.logInfo(_("*** Plugins have been updated, but need a pyLoad restart to be reloaded ***")) - self.info['plugins'] = True - exitcode = 2 - else: - self.logInfo(_("No plugin updates available")) - exitcode = 0 - - return exitcode #: 0 = No plugins updated; 1 = Plugins updated; 2 = Plugins updated, but restart required - - @Expose - def removePlugins(self, type_plugins): - """ delete plugins from disk """ - - if not type_plugins: - return - - self.logDebug("Requested deletion of plugins", type_plugins) - - removed = [] - - for type, name in type_plugins: - err = False - file = name + ".py" - - for root in ("userplugins", path.join(pypath, "pyload", "plugins")): - - filename = safe_join(root, type, file) - try: - remove(filename) - except Exception, e: - self.logDebug("Error deleting", path.basename(filename), e) - err = True - - filename += "c" - if path.isfile(filename): - try: - if type == "hook": - self.manager.deactivateHook(name) - remove(filename) - except Exception, e: - self.logDebug("Error deleting", path.basename(filename), e) - err = True - - if not err: - id = (type, name) - removed.append(id) - - return removed #: return a list of the plugins successfully removed diff --git a/pyload/plugins/hoster/BillionuploadsCom.py b/pyload/plugins/hoster/BillionuploadsCom.py index d6f39b61c..08d3bb1e5 100644 --- a/pyload/plugins/hoster/BillionuploadsCom.py +++ b/pyload/plugins/hoster/BillionuploadsCom.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class BillionuploadsCom(XFileSharingPro): diff --git a/pyload/plugins/hoster/CramitIn.py b/pyload/plugins/hoster/CramitIn.py index 7091e02c2..6b492f6ed 100644 --- a/pyload/plugins/hoster/CramitIn.py +++ b/pyload/plugins/hoster/CramitIn.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class CramitIn(XFileSharingPro): diff --git a/pyload/plugins/hoster/DuploadOrg.py b/pyload/plugins/hoster/DuploadOrg.py index 8c2430c87..071759017 100644 --- a/pyload/plugins/hoster/DuploadOrg.py +++ b/pyload/plugins/hoster/DuploadOrg.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class DuploadOrg(XFileSharingPro): diff --git a/pyload/plugins/hoster/EasybytezCom.py b/pyload/plugins/hoster/EasybytezCom.py index e010aee2a..cdb07de0e 100644 --- a/pyload/plugins/hoster/EasybytezCom.py +++ b/pyload/plugins/hoster/EasybytezCom.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class EasybytezCom(XFileSharingPro): diff --git a/pyload/plugins/hoster/EpicShareNet.py b/pyload/plugins/hoster/EpicShareNet.py index a4a6008ae..bf746ce2a 100644 --- a/pyload/plugins/hoster/EpicShareNet.py +++ b/pyload/plugins/hoster/EpicShareNet.py @@ -3,7 +3,7 @@ # Test links: # BigBuckBunny_320x180.mp4 - 61.7 Mb - http://epicshare.net/fch3m2bk6ihp/BigBuckBunny_320x180.mp4.html -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class EpicShareNet(XFileSharingPro): diff --git a/pyload/plugins/hoster/File4safeCom.py b/pyload/plugins/hoster/File4safeCom.py index a86ed033e..a67c90014 100644 --- a/pyload/plugins/hoster/File4safeCom.py +++ b/pyload/plugins/hoster/File4safeCom.py @@ -4,7 +4,7 @@ import re from pycurl import FOLLOWLOCATION -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class File4safeCom(XFileSharingPro): diff --git a/pyload/plugins/hoster/FileParadoxIn.py b/pyload/plugins/hoster/FileParadoxIn.py index 436fed357..80a58bdf5 100644 --- a/pyload/plugins/hoster/FileParadoxIn.py +++ b/pyload/plugins/hoster/FileParadoxIn.py @@ -2,7 +2,7 @@ import re -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class FileParadoxIn(XFileSharingPro): diff --git a/pyload/plugins/hoster/FileomCom.py b/pyload/plugins/hoster/FileomCom.py index a5de24a3f..a7c91106a 100644 --- a/pyload/plugins/hoster/FileomCom.py +++ b/pyload/plugins/hoster/FileomCom.py @@ -3,7 +3,7 @@ # Test links: # http://fileom.com/gycaytyzdw3g/random.bin.html -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class FileomCom(XFileSharingPro): diff --git a/pyload/plugins/hoster/FilerioCom.py b/pyload/plugins/hoster/FilerioCom.py index 5c62b0da8..c9c63c38e 100644 --- a/pyload/plugins/hoster/FilerioCom.py +++ b/pyload/plugins/hoster/FilerioCom.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class FilerioCom(XFileSharingPro): diff --git a/pyload/plugins/hoster/HugefilesNet.py b/pyload/plugins/hoster/HugefilesNet.py index 8a960c7fa..6450141ca 100644 --- a/pyload/plugins/hoster/HugefilesNet.py +++ b/pyload/plugins/hoster/HugefilesNet.py @@ -3,7 +3,7 @@ # Test links: # http://hugefiles.net/prthf9ya4w6s -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class HugefilesNet(XFileSharingPro): diff --git a/pyload/plugins/hoster/HundredEightyUploadCom.py b/pyload/plugins/hoster/HundredEightyUploadCom.py index fa3dd8de3..eef6e045c 100644 --- a/pyload/plugins/hoster/HundredEightyUploadCom.py +++ b/pyload/plugins/hoster/HundredEightyUploadCom.py @@ -3,7 +3,7 @@ # Test links: # http://180upload.com/js9qdm6kjnrs -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class HundredEightyUploadCom(XFileSharingPro): diff --git a/pyload/plugins/hoster/LemUploadsCom.py b/pyload/plugins/hoster/LemUploadsCom.py index 08d999478..432154981 100644 --- a/pyload/plugins/hoster/LemUploadsCom.py +++ b/pyload/plugins/hoster/LemUploadsCom.py @@ -3,7 +3,7 @@ # Test links: # BigBuckBunny_320x180.mp4 - 61.7 Mb - http://lemuploads.com/uwol0aly9dld -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class LemUploadsCom(XFileSharingPro): diff --git a/pyload/plugins/hoster/MegaFilesSe.py b/pyload/plugins/hoster/MegaFilesSe.py index 48306cd7f..ae2244e94 100644 --- a/pyload/plugins/hoster/MegaFilesSe.py +++ b/pyload/plugins/hoster/MegaFilesSe.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class MegaFilesSe(XFileSharingPro): diff --git a/pyload/plugins/hoster/MegareleaseOrg.py b/pyload/plugins/hoster/MegareleaseOrg.py index adfe68026..979fb60a6 100644 --- a/pyload/plugins/hoster/MegareleaseOrg.py +++ b/pyload/plugins/hoster/MegareleaseOrg.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class MegareleaseOrg(XFileSharingPro): diff --git a/pyload/plugins/hoster/MovReelCom.py b/pyload/plugins/hoster/MovReelCom.py index 8a754f6c8..d85337e46 100644 --- a/pyload/plugins/hoster/MovReelCom.py +++ b/pyload/plugins/hoster/MovReelCom.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class MovReelCom(XFileSharingPro): diff --git a/pyload/plugins/hoster/NosuploadCom.py b/pyload/plugins/hoster/NosuploadCom.py index 83e018355..e7ea7e56b 100644 --- a/pyload/plugins/hoster/NosuploadCom.py +++ b/pyload/plugins/hoster/NosuploadCom.py @@ -2,7 +2,7 @@ import re -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class NosuploadCom(XFileSharingPro): diff --git a/pyload/plugins/hoster/NovafileCom.py b/pyload/plugins/hoster/NovafileCom.py index 8f3f78de1..4f897d1b4 100644 --- a/pyload/plugins/hoster/NovafileCom.py +++ b/pyload/plugins/hoster/NovafileCom.py @@ -4,7 +4,7 @@ # http://novafile.com/vfun4z6o2cit # http://novafile.com/s6zrr5wemuz4 -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class NovafileCom(XFileSharingPro): diff --git a/pyload/plugins/hoster/PandaPlanet.py b/pyload/plugins/hoster/PandaPlanet.py index 8b26202df..0ba09eb53 100644 --- a/pyload/plugins/hoster/PandaPlanet.py +++ b/pyload/plugins/hoster/PandaPlanet.py @@ -4,7 +4,7 @@ # test.bin - 214 B - http://pandapla.net/pew1cz3ot586 # BigBuckBunny_320x180.mp4 - 61.7 Mb - http://pandapla.net/tz0rgjfyyoh7 -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class PandaPlanet(XFileSharingPro): diff --git a/pyload/plugins/hoster/PotloadCom.py b/pyload/plugins/hoster/PotloadCom.py index 6a97d0289..dc8009bdf 100644 --- a/pyload/plugins/hoster/PotloadCom.py +++ b/pyload/plugins/hoster/PotloadCom.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class PotloadCom(XFileSharingPro): diff --git a/pyload/plugins/hoster/RarefileNet.py b/pyload/plugins/hoster/RarefileNet.py index 7082dc19e..5366b475f 100644 --- a/pyload/plugins/hoster/RarefileNet.py +++ b/pyload/plugins/hoster/RarefileNet.py @@ -2,7 +2,7 @@ import re -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo from pyload.utils import html_unescape diff --git a/pyload/plugins/hoster/RyushareCom.py b/pyload/plugins/hoster/RyushareCom.py index 326c55e0c..9641bf6e5 100644 --- a/pyload/plugins/hoster/RyushareCom.py +++ b/pyload/plugins/hoster/RyushareCom.py @@ -5,7 +5,7 @@ import re -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo from pyload.plugins.internal.CaptchaService import SolveMedia diff --git a/pyload/plugins/hoster/SecureUploadEu.py b/pyload/plugins/hoster/SecureUploadEu.py index 0edc1860d..afe839f51 100644 --- a/pyload/plugins/hoster/SecureUploadEu.py +++ b/pyload/plugins/hoster/SecureUploadEu.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class SecureUploadEu(XFileSharingPro): diff --git a/pyload/plugins/hoster/SendmywayCom.py b/pyload/plugins/hoster/SendmywayCom.py index 0306206ca..be9d5854e 100644 --- a/pyload/plugins/hoster/SendmywayCom.py +++ b/pyload/plugins/hoster/SendmywayCom.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class SendmywayCom(XFileSharingPro): diff --git a/pyload/plugins/hoster/StreamcloudEu.py b/pyload/plugins/hoster/StreamcloudEu.py index 875766fd7..57ddabb98 100644 --- a/pyload/plugins/hoster/StreamcloudEu.py +++ b/pyload/plugins/hoster/StreamcloudEu.py @@ -5,7 +5,7 @@ import re from time import sleep from pyload.network.HTTPRequest import HTTPRequest -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class StreamcloudEu(XFileSharingPro): diff --git a/pyload/plugins/hoster/TusfilesNet.py b/pyload/plugins/hoster/TusfilesNet.py index bbed62a6a..4ba847d96 100644 --- a/pyload/plugins/hoster/TusfilesNet.py +++ b/pyload/plugins/hoster/TusfilesNet.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class TusfilesNet(XFileSharingPro): diff --git a/pyload/plugins/hoster/UptoboxCom.py b/pyload/plugins/hoster/UptoboxCom.py index 2786deb5a..5ef2ad69b 100644 --- a/pyload/plugins/hoster/UptoboxCom.py +++ b/pyload/plugins/hoster/UptoboxCom.py @@ -2,7 +2,7 @@ import re -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class UptoboxCom(XFileSharingPro): diff --git a/pyload/plugins/hoster/VidPlayNet.py b/pyload/plugins/hoster/VidPlayNet.py index 82afde07d..c52b43d1f 100644 --- a/pyload/plugins/hoster/VidPlayNet.py +++ b/pyload/plugins/hoster/VidPlayNet.py @@ -3,7 +3,7 @@ # Test links: # BigBuckBunny_320x180.mp4 - 61.7 Mb - http://vidplay.net/38lkev0h3jv0 -from pyload.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo +from pyload.plugins.internal.XFileSharingPro import XFileSharingPro, create_getInfo class VidPlayNet(XFileSharingPro): diff --git a/pyload/plugins/hoster/XFileSharingPro.py b/pyload/plugins/hoster/XFileSharingPro.py deleted file mode 100644 index 212ef23ef..000000000 --- a/pyload/plugins/hoster/XFileSharingPro.py +++ /dev/null @@ -1,352 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from pycurl import FOLLOWLOCATION, LOW_SPEED_TIME -from random import random -from urllib import unquote -from urlparse import urlparse - -from pyload.network.RequestFactory import getURL -from pyload.plugins.internal.CaptchaService import ReCaptcha, SolveMedia -from pyload.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, PluginParseError, replace_patterns -from pyload.utils import html_unescape - - -class XFileSharingPro(SimpleHoster): - """ - Common base for XFileSharingPro hosters like EasybytezCom, CramitIn, FiledinoCom... - Some hosters may work straight away when added to __pattern__ - However, most of them will NOT work because they are either down or running a customized version - """ - __name__ = "XFileSharingPro" - __type__ = "hoster" - __version__ = "0.36" - - __pattern__ = r'^unmatchable$' - - __description__ = """XFileSharingPro base hoster plugin""" - __author_name__ = ("zoidberg", "stickell", "Walter Purcaro") - __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it", "vuolter@gmail.com") - - - HOSTER_NAME = None - - FILE_URL_REPLACEMENTS = [(r'/embed-(\w{12}).*', r'/\1')] #: support embedded files - - COOKIES = [(HOSTER_NAME, "lang", "english")] - - FILE_INFO_PATTERN = r'Filename:(?P[^<]+)\s*.*?\((?P[^<]+)\)' - FILE_NAME_PATTERN = r'[\d\.\,]+) ?(?P\w+)?\)' - - OFFLINE_PATTERN = r'>\w+ (Not Found|file (was|has been) removed)' - - WAIT_PATTERN = r'.*?>(\d+)' - - OVR_LINK_PATTERN = r'

Download Link

\s*]*>([^<]+)' - LINK_PATTERN = None #: final download url pattern - - CAPTCHA_URL_PATTERN = r'(http://[^"\']+?/captchas?/[^"\']+)' - RECAPTCHA_URL_PATTERN = r'http://[^"\']+?recaptcha[^"\']+?\?k=([^"\']+)"' - CAPTCHA_DIV_PATTERN = r'>Enter code.*?(.*?)' - SOLVEMEDIA_PATTERN = r'http:\/\/api\.solvemedia\.com\/papi\/challenge\.script\?k=(.*?)"' - - ERROR_PATTERN = r'class=["\']err["\'][^>]*>(.*?)", " ", self.errmsg)) - - if 'wait' in self.errmsg: - wait_time = sum([int(v) * {"hour": 3600, "minute": 60, "second": 1}[u] for v, u in - re.findall(r'(\d+)\s*(hour|minute|second)', self.errmsg)]) - self.wait(wait_time, True) - elif 'captcha' in self.errmsg: - self.invalidCaptcha() - elif 'premium' in self.errmsg and 'require' in self.errmsg: - self.fail("File can be downloaded by premium users only") - elif 'limit' in self.errmsg: - self.wait(1 * 60 * 60, True) - self.retry(25) - elif 'countdown' in self.errmsg or 'Expired' in self.errmsg: - self.retry() - elif 'maintenance' in self.errmsg: - self.tempOffline() - elif 'download files up to' in self.errmsg: - self.fail("File too large for free download") - else: - self.fail(self.errmsg) - - else: - self.errmsg = None - - return self.errmsg - - - def getPostParameters(self): - for _ in xrange(3): - if not self.errmsg: - self.checkErrors() - - if hasattr(self, "FORM_PATTERN"): - action, inputs = self.parseHtmlForm(self.FORM_PATTERN) - else: - action, inputs = self.parseHtmlForm(input_names={"op": re.compile("^download")}) - - if not inputs: - action, inputs = self.parseHtmlForm('F1') - if not inputs: - if self.errmsg: - self.retry() - else: - self.parseError("Form not found") - - self.logDebug(self.HOSTER_NAME, inputs) - - if 'op' in inputs and inputs['op'] in ("download2", "download3"): - if "password" in inputs: - if self.passwords: - inputs['password'] = self.passwords.pop(0) - else: - self.fail("No or invalid passport") - - if not self.premium: - m = re.search(self.WAIT_PATTERN, self.html) - if m: - wait_time = int(m.group(1)) + 1 - self.setWait(wait_time, False) - else: - wait_time = 0 - - self.captcha = self.handleCaptcha(inputs) - - if wait_time: - self.wait() - - self.errmsg = None - return inputs - - else: - inputs['referer'] = self.pyfile.url - - if self.premium: - inputs['method_premium'] = "Premium Download" - if 'method_free' in inputs: - del inputs['method_free'] - else: - inputs['method_free'] = "Free Download" - if 'method_premium' in inputs: - del inputs['method_premium'] - - self.html = self.load(self.pyfile.url, post=inputs, ref=True) - self.errmsg = None - - else: - self.parseError('FORM: %s' % (inputs['op'] if 'op' in inputs else 'UNKNOWN')) - - - def handleCaptcha(self, inputs): - m = re.search(self.RECAPTCHA_URL_PATTERN, self.html) - if m: - recaptcha_key = unquote(m.group(1)) - self.logDebug("RECAPTCHA KEY: %s" % recaptcha_key) - recaptcha = ReCaptcha(self) - inputs['recaptcha_challenge_field'], inputs['recaptcha_response_field'] = recaptcha.challenge(recaptcha_key) - return 1 - else: - m = re.search(self.CAPTCHA_URL_PATTERN, self.html) - if m: - captcha_url = m.group(1) - inputs['code'] = self.decryptCaptcha(captcha_url) - return 2 - else: - m = re.search(self.CAPTCHA_DIV_PATTERN, self.html, re.DOTALL) - if m: - captcha_div = m.group(1) - self.logDebug(captcha_div) - numerals = re.findall(r'(\d)', html_unescape(captcha_div)) - inputs['code'] = "".join([a[1] for a in sorted(numerals, key=lambda num: int(num[0]))]) - self.logDebug("CAPTCHA", inputs['code'], numerals) - return 3 - else: - m = re.search(self.SOLVEMEDIA_PATTERN, self.html) - if m: - captcha_key = m.group(1) - captcha = SolveMedia(self) - inputs['adcopy_challenge'], inputs['adcopy_response'] = captcha.challenge(captcha_key) - return 4 - return 0 - - -getInfo = create_getInfo(XFileSharingPro) diff --git a/pyload/plugins/internal/UpdateManager.py b/pyload/plugins/internal/UpdateManager.py new file mode 100644 index 000000000..eb9411236 --- /dev/null +++ b/pyload/plugins/internal/UpdateManager.py @@ -0,0 +1,281 @@ +# -*- coding: utf-8 -*- + +import re +import sys + +from operator import itemgetter +from os import path, remove, stat + +from pyload.network.RequestFactory import getURL +from pyload.plugins.Hook import Expose, Hook, threaded +from pyload.utils import safe_join + + +class UpdateManager(Hook): + __name__ = "UpdateManager" + __type__ = "hook" + __version__ = "0.35" + + __config__ = [("activated", "bool", "Activated", True), + ("mode", "pyLoad + plugins;plugins only", "Check updates for", "pyLoad + plugins"), + ("interval", "int", "Check interval in hours", 8), + ("reloadplugins", "bool", "Monitor plugins for code changes (debug mode only)", True), + ("nodebugupdate", "bool", "Don't check for updates in debug mode", True)] + + __description__ = """ Check for updates """ + __author_name__ = "Walter Purcaro" + __author_mail__ = "vuolter@gmail.com" + + + event_list = ["pluginConfigChanged"] + + SERVER_URL = "http://updatemanager.pyload.org" + MIN_INTERVAL = 3 * 60 * 60 #: 3h minimum check interval (value is in seconds) + + + def pluginConfigChanged(self, plugin, name, value): + if name == "interval": + interval = value * 60 * 60 + if self.MIN_INTERVAL <= interval != self.interval: + self.core.scheduler.removeJob(self.cb) + self.interval = interval + self.initPeriodical() + else: + self.logDebug("Invalid interval value, kept current") + elif name == "reloadplugins": + if self.cb2: + self.core.scheduler.removeJob(self.cb2) + if value is True and self.core.debug: + self.periodical2() + + def coreReady(self): + self.pluginConfigChanged(self.__name__, "interval", self.getConfig("interval")) + x = lambda: self.pluginConfigChanged(self.__name__, "reloadplugins", self.getConfig("reloadplugins")) + self.core.scheduler.addJob(10, x, threaded=False) + + def unload(self): + self.pluginConfigChanged(self.__name__, "reloadplugins", False) + + def setup(self): + self.cb2 = None + self.interval = self.MIN_INTERVAL + self.updating = False + self.info = {'pyload': False, 'version': None, 'plugins': False} + self.mtimes = {} #: store modification time for each plugin + + def periodical2(self): + if not self.updating: + self.autoreloadPlugins() + self.cb2 = self.core.scheduler.addJob(4, self.periodical2, threaded=False) + + @Expose + def autoreloadPlugins(self): + """ reload and reindex all modified plugins """ + modules = filter( + lambda m: m and (m.__name__.startswith("pyload.plugins.") or + m.__name__.startswith("userplugins.")) and + m.__name__.count(".") >= 2, sys.modules.itervalues() + ) + + reloads = [] + + for m in modules: + root, type, name = m.__name__.rsplit(".", 2) + id = (type, name) + if type in self.core.pluginManager.plugins: + f = m.__file__.replace(".pyc", ".py") + if not path.isfile(f): + continue + + mtime = stat(f).st_mtime + + if id not in self.mtimes: + self.mtimes[id] = mtime + elif self.mtimes[id] < mtime: + reloads.append(id) + self.mtimes[id] = mtime + + return True if self.core.pluginManager.reloadPlugins(reloads) else False + + def periodical(self): + if not self.info['pyload'] and not (self.getConfig("nodebugupdate") and self.core.debug): + self.updateThread() + + def server_request(self): + try: + return getURL(self.SERVER_URL, get={'v': self.core.api.getServerVersion()}).splitlines() + except: + self.logWarning(_("Unable to contact server to get updates")) + + @threaded + def updateThread(self): + self.updating = True + status = self.update(onlyplugin=self.getConfig("mode") == "plugins only") + if status == 2: + self.core.api.restart() + else: + self.updating = False + + @Expose + def updatePlugins(self): + """ simple wrapper for calling plugin update quickly """ + return self.update(onlyplugin=True) + + @Expose + def update(self, onlyplugin=False): + """ check for updates """ + data = self.server_request() + if not data: + exitcode = 0 + elif data[0] == "None": + self.logInfo(_("No new pyLoad version available")) + updates = data[1:] + exitcode = self._updatePlugins(updates) + elif onlyplugin: + exitcode = 0 + else: + newversion = data[0] + self.logInfo(_("*** New pyLoad Version %s available ***") % newversion) + self.logInfo(_("*** Get it here: https://github.com/pyload/pyload/releases ***")) + exitcode = 3 + self.info['pyload'] = True + self.info['version'] = newversion + return exitcode #: 0 = No plugins updated; 1 = Plugins updated; 2 = Plugins updated, but restart required; 3 = No plugins updated, new pyLoad version available + + def _updatePlugins(self, updates): + """ check for plugin updates """ + + if self.info['plugins']: + return False #: plugins were already updated + + updated = [] + + vre = re.compile(r'__version__.*=.*("|\')([0-9.]+)') + url = updates[0] + schema = updates[1].split('|') + if "BLACKLIST" in updates: + blacklist = updates[updates.index('BLACKLIST') + 1:] + updates = updates[2:updates.index('BLACKLIST')] + else: + blacklist = None + updates = updates[2:] + + upgradable = sorted(map(lambda x: dict(zip(schema, x.split('|'))), updates), key=itemgetter("type", "name")) + for plugin in upgradable: + filename = plugin['name'] + prefix = plugin['type'] + version = plugin['version'] + + if filename.endswith(".pyc"): + name = filename[:filename.find("_")] + else: + name = filename.replace(".py", "") + + #@TODO: obsolete after 0.4.10 + if prefix.endswith("s"): + type = prefix[:-1] + else: + type = prefix + + plugins = getattr(self.core.pluginManager, "%sPlugins" % type) + + oldver = float(plugins[name]['v']) if name in plugins else None + newver = float(version) + + if not oldver: + msg = "New [%(type)s] %(name)s (v%(newver)s)" + elif newver > oldver: + msg = "New version of [%(type)s] %(name)s (v%(oldver)s -> v%(newver)s)" + else: + continue + + self.logInfo(_(msg) % { + 'type': type, + 'name': name, + 'oldver': oldver, + 'newver': newver, + }) + + try: + content = getURL(url % plugin) + m = vre.search(content) + if m and m.group(2) == version: + f = open(safe_join("userplugins", prefix, filename), "wb") + f.write(content) + f.close() + updated.append((prefix, name)) + else: + raise Exception, _("Version mismatch") + except Exception, e: + self.logError(_("Error updating plugin %s") % filename, e) + + if blacklist: + blacklisted = sorted(map(lambda x: (x.split('|')[0], x.split('|')[1].rsplit('.', 1)[0]), blacklist)) + + # Always protect UpdateManager from self-removing + try: + blacklisted.remove(("internal", "UpdateManager")) + except: + pass + + removed = self.removePlugins(blacklisted) + for t, n in removed: + self.logInfo(_("Removed blacklisted plugin [%(type)s] %(name)s") % { + 'type': t, + 'name': n, + }) + + if updated: + reloaded = self.core.pluginManager.reloadPlugins(updated) + if reloaded: + self.logInfo(_("Plugins updated and reloaded")) + exitcode = 1 + else: + self.logInfo(_("*** Plugins have been updated, but need a pyLoad restart to be reloaded ***")) + self.info['plugins'] = True + exitcode = 2 + else: + self.logInfo(_("No plugin updates available")) + exitcode = 0 + + return exitcode #: 0 = No plugins updated; 1 = Plugins updated; 2 = Plugins updated, but restart required + + @Expose + def removePlugins(self, type_plugins): + """ delete plugins from disk """ + + if not type_plugins: + return + + self.logDebug("Requested deletion of plugins", type_plugins) + + removed = [] + + for type, name in type_plugins: + err = False + file = name + ".py" + + for root in ("userplugins", path.join(pypath, "pyload", "plugins")): + + filename = safe_join(root, type, file) + try: + remove(filename) + except Exception, e: + self.logDebug("Error deleting", path.basename(filename), e) + err = True + + filename += "c" + if path.isfile(filename): + try: + if type == "hook": + self.manager.deactivateHook(name) + remove(filename) + except Exception, e: + self.logDebug("Error deleting", path.basename(filename), e) + err = True + + if not err: + id = (type, name) + removed.append(id) + + return removed #: return a list of the plugins successfully removed diff --git a/pyload/plugins/internal/XFileSharingPro.py b/pyload/plugins/internal/XFileSharingPro.py new file mode 100644 index 000000000..212ef23ef --- /dev/null +++ b/pyload/plugins/internal/XFileSharingPro.py @@ -0,0 +1,352 @@ +# -*- coding: utf-8 -*- + +import re + +from pycurl import FOLLOWLOCATION, LOW_SPEED_TIME +from random import random +from urllib import unquote +from urlparse import urlparse + +from pyload.network.RequestFactory import getURL +from pyload.plugins.internal.CaptchaService import ReCaptcha, SolveMedia +from pyload.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, PluginParseError, replace_patterns +from pyload.utils import html_unescape + + +class XFileSharingPro(SimpleHoster): + """ + Common base for XFileSharingPro hosters like EasybytezCom, CramitIn, FiledinoCom... + Some hosters may work straight away when added to __pattern__ + However, most of them will NOT work because they are either down or running a customized version + """ + __name__ = "XFileSharingPro" + __type__ = "hoster" + __version__ = "0.36" + + __pattern__ = r'^unmatchable$' + + __description__ = """XFileSharingPro base hoster plugin""" + __author_name__ = ("zoidberg", "stickell", "Walter Purcaro") + __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it", "vuolter@gmail.com") + + + HOSTER_NAME = None + + FILE_URL_REPLACEMENTS = [(r'/embed-(\w{12}).*', r'/\1')] #: support embedded files + + COOKIES = [(HOSTER_NAME, "lang", "english")] + + FILE_INFO_PATTERN = r'Filename:(?P[^<]+)\s*.*?\((?P[^<]+)\)' + FILE_NAME_PATTERN = r'[\d\.\,]+) ?(?P\w+)?\)' + + OFFLINE_PATTERN = r'>\w+ (Not Found|file (was|has been) removed)' + + WAIT_PATTERN = r'.*?>(\d+)' + + OVR_LINK_PATTERN = r'

Download Link

\s*]*>([^<]+)' + LINK_PATTERN = None #: final download url pattern + + CAPTCHA_URL_PATTERN = r'(http://[^"\']+?/captchas?/[^"\']+)' + RECAPTCHA_URL_PATTERN = r'http://[^"\']+?recaptcha[^"\']+?\?k=([^"\']+)"' + CAPTCHA_DIV_PATTERN = r'>Enter code.*?(.*?)' + SOLVEMEDIA_PATTERN = r'http:\/\/api\.solvemedia\.com\/papi\/challenge\.script\?k=(.*?)"' + + ERROR_PATTERN = r'class=["\']err["\'][^>]*>(.*?)", " ", self.errmsg)) + + if 'wait' in self.errmsg: + wait_time = sum([int(v) * {"hour": 3600, "minute": 60, "second": 1}[u] for v, u in + re.findall(r'(\d+)\s*(hour|minute|second)', self.errmsg)]) + self.wait(wait_time, True) + elif 'captcha' in self.errmsg: + self.invalidCaptcha() + elif 'premium' in self.errmsg and 'require' in self.errmsg: + self.fail("File can be downloaded by premium users only") + elif 'limit' in self.errmsg: + self.wait(1 * 60 * 60, True) + self.retry(25) + elif 'countdown' in self.errmsg or 'Expired' in self.errmsg: + self.retry() + elif 'maintenance' in self.errmsg: + self.tempOffline() + elif 'download files up to' in self.errmsg: + self.fail("File too large for free download") + else: + self.fail(self.errmsg) + + else: + self.errmsg = None + + return self.errmsg + + + def getPostParameters(self): + for _ in xrange(3): + if not self.errmsg: + self.checkErrors() + + if hasattr(self, "FORM_PATTERN"): + action, inputs = self.parseHtmlForm(self.FORM_PATTERN) + else: + action, inputs = self.parseHtmlForm(input_names={"op": re.compile("^download")}) + + if not inputs: + action, inputs = self.parseHtmlForm('F1') + if not inputs: + if self.errmsg: + self.retry() + else: + self.parseError("Form not found") + + self.logDebug(self.HOSTER_NAME, inputs) + + if 'op' in inputs and inputs['op'] in ("download2", "download3"): + if "password" in inputs: + if self.passwords: + inputs['password'] = self.passwords.pop(0) + else: + self.fail("No or invalid passport") + + if not self.premium: + m = re.search(self.WAIT_PATTERN, self.html) + if m: + wait_time = int(m.group(1)) + 1 + self.setWait(wait_time, False) + else: + wait_time = 0 + + self.captcha = self.handleCaptcha(inputs) + + if wait_time: + self.wait() + + self.errmsg = None + return inputs + + else: + inputs['referer'] = self.pyfile.url + + if self.premium: + inputs['method_premium'] = "Premium Download" + if 'method_free' in inputs: + del inputs['method_free'] + else: + inputs['method_free'] = "Free Download" + if 'method_premium' in inputs: + del inputs['method_premium'] + + self.html = self.load(self.pyfile.url, post=inputs, ref=True) + self.errmsg = None + + else: + self.parseError('FORM: %s' % (inputs['op'] if 'op' in inputs else 'UNKNOWN')) + + + def handleCaptcha(self, inputs): + m = re.search(self.RECAPTCHA_URL_PATTERN, self.html) + if m: + recaptcha_key = unquote(m.group(1)) + self.logDebug("RECAPTCHA KEY: %s" % recaptcha_key) + recaptcha = ReCaptcha(self) + inputs['recaptcha_challenge_field'], inputs['recaptcha_response_field'] = recaptcha.challenge(recaptcha_key) + return 1 + else: + m = re.search(self.CAPTCHA_URL_PATTERN, self.html) + if m: + captcha_url = m.group(1) + inputs['code'] = self.decryptCaptcha(captcha_url) + return 2 + else: + m = re.search(self.CAPTCHA_DIV_PATTERN, self.html, re.DOTALL) + if m: + captcha_div = m.group(1) + self.logDebug(captcha_div) + numerals = re.findall(r'(\d)', html_unescape(captcha_div)) + inputs['code'] = "".join([a[1] for a in sorted(numerals, key=lambda num: int(num[0]))]) + self.logDebug("CAPTCHA", inputs['code'], numerals) + return 3 + else: + m = re.search(self.SOLVEMEDIA_PATTERN, self.html) + if m: + captcha_key = m.group(1) + captcha = SolveMedia(self) + inputs['adcopy_challenge'], inputs['adcopy_response'] = captcha.challenge(captcha_key) + return 4 + return 0 + + +getInfo = create_getInfo(XFileSharingPro) -- cgit v1.2.3