From 681deb7ff09956be0bee04453e33ac6e9d6dab4a Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Mon, 8 Jun 2015 05:56:10 +0200 Subject: Move base plugins to internal folder --- module/plugins/internal/Plugin.py | 617 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 617 insertions(+) create mode 100644 module/plugins/internal/Plugin.py (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py new file mode 100644 index 000000000..15bf3971f --- /dev/null +++ b/module/plugins/internal/Plugin.py @@ -0,0 +1,617 @@ +# -*- coding: utf-8 -*- + +""" + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . + + @author: RaNaN, spoob, mkaay +""" + +from time import time, sleep +from random import randint + +import os +from os import remove, makedirs, chmod, stat +from os.path import exists, join + +if os.name != "nt": + from os import chown + from pwd import getpwnam + from grp import getgrnam + +from itertools import islice + +from module.utils import save_join, save_path, fs_encode, fs_decode + +def chunks(iterable, size): + it = iter(iterable) + item = list(islice(it, size)) + while item: + yield item + item = list(islice(it, size)) + + +class Abort(Exception): + """ raised when aborted """ + + +class Fail(Exception): + """ raised when failed """ + + +class Reconnect(Exception): + """ raised when reconnected """ + + +class Retry(Exception): + """ raised when start again from beginning """ + + +class SkipDownload(Exception): + """ raised when download should be skipped """ + + +class Base(object): + """ + A Base class with log/config/db methods *all* plugin types can use + """ + + def __init__(self, core): + #: Core instance + self.core = core + #: logging instance + self.log = core.log + #: core config + self.config = core.config + + #log functions + def logInfo(self, *args): + self.log.info("%s: %s" % (self.__name__, " | ".join([a if isinstance(a, basestring) else str(a) for a in args]))) + + def logWarning(self, *args): + self.log.warning("%s: %s" % (self.__name__, " | ".join([a if isinstance(a, basestring) else str(a) for a in args]))) + + def logError(self, *args): + self.log.error("%s: %s" % (self.__name__, " | ".join([a if isinstance(a, basestring) else str(a) for a in args]))) + + def logDebug(self, *args): + self.log.debug("%s: %s" % (self.__name__, " | ".join([a if isinstance(a, basestring) else str(a) for a in args]))) + + + def setConf(self, option, value): + """ see `setConfig` """ + self.core.config.setPlugin(self.__name__, option, value) + + def setConfig(self, option, value): + """ Set config value for current plugin + + :param option: + :param value: + :return: + """ + self.setConf(option, value) + + def getConf(self, option): + """ see `getConfig` """ + return self.core.config.getPlugin(self.__name__, option) + + def getConfig(self, option): + """ Returns config value for current plugin + + :param option: + :return: + """ + return self.getConf(option) + + def setStorage(self, key, value): + """ Saves a value persistently to the database """ + self.core.db.setStorage(self.__name__, key, value) + + def store(self, key, value): + """ same as `setStorage` """ + self.core.db.setStorage(self.__name__, key, value) + + def getStorage(self, key=None, default=None): + """ Retrieves saved value or dict of all saved entries if key is None """ + if key is not None: + return self.core.db.getStorage(self.__name__, key) or default + return self.core.db.getStorage(self.__name__, key) + + def retrieve(self, *args, **kwargs): + """ same as `getStorage` """ + return self.getStorage(*args, **kwargs) + + def delStorage(self, key): + """ Delete entry in db """ + self.core.db.delStorage(self.__name__, key) + + +class Plugin(Base): + """ + Base plugin for hoster/crypter. + Overwrite `process` / `decrypt` in your subclassed plugin. + """ + __name__ = "Plugin" + __version__ = "0.4" + __pattern__ = None + __type__ = "hoster" + __config__ = [("name", "type", "desc", "default")] + __description__ = """Base Plugin""" + __author_name__ = ("RaNaN", "spoob", "mkaay") + __author_mail__ = ("RaNaN@pyload.org", "spoob@pyload.org", "mkaay@mkaay.de") + + def __init__(self, pyfile): + Base.__init__(self, pyfile.m.core) + + self.wantReconnect = False + #: enables simultaneous processing of multiple downloads + self.multiDL = True + self.limitDL = 0 + #: chunk limit + self.chunkLimit = 1 + self.resumeDownload = False + + #: time() + wait in seconds + self.waitUntil = 0 + self.waiting = False + + self.ocr = None #captcha reader instance + #: account handler instance, see :py:class:`Account` + self.account = pyfile.m.core.accountManager.getAccountPlugin(self.__name__) + + #: premium status + self.premium = False + #: username/login + self.user = None + + if self.account and not self.account.canUse(): self.account = None + if self.account: + self.user, data = self.account.selectAccount() + #: Browser instance, see `network.Browser` + self.req = self.account.getAccountRequest(self.user) + self.chunkLimit = -1 # chunk limit, -1 for unlimited + #: enables resume (will be ignored if server dont accept chunks) + self.resumeDownload = True + self.multiDL = True #every hoster with account should provide multiple downloads + #: premium status + self.premium = self.account.isPremium(self.user) + else: + self.req = pyfile.m.core.requestFactory.getRequest(self.__name__) + + #: associated pyfile instance, see `PyFile` + self.pyfile = pyfile + self.thread = None # holds thread in future + + #: location where the last call to download was saved + self.lastDownload = "" + #: re match of the last call to `checkDownload` + self.lastCheck = None + #: js engine, see `JsEngine` + self.js = self.core.js + self.cTask = None #captcha task + + self.retries = 0 # amount of retries already made + self.html = None # some plugins store html code here + + self.init() + + def getChunkCount(self): + if self.chunkLimit <= 0: + return self.config["download"]["chunks"] + return min(self.config["download"]["chunks"], self.chunkLimit) + + def __call__(self): + return self.__name__ + + def init(self): + """initialize the plugin (in addition to `__init__`)""" + pass + + def setup(self): + """ setup for enviroment and other things, called before downloading (possibly more than one time)""" + pass + + def preprocessing(self, thread): + """ handles important things to do before starting """ + self.thread = thread + + if self.account: + self.account.checkLogin(self.user) + else: + self.req.clearCookies() + + self.setup() + + self.pyfile.setStatus("starting") + + return self.process(self.pyfile) + + + def process(self, pyfile): + """the 'main' method of every plugin, you **have to** overwrite it""" + raise NotImplementedError + + def resetAccount(self): + """ dont use account and retry download """ + self.account = None + self.req = self.core.requestFactory.getRequest(self.__name__) + self.retry() + + def checksum(self, local_file=None): + """ + return codes: + 0 - checksum ok + 1 - checksum wrong + 5 - can't get checksum + 10 - not implemented + 20 - unknown error + """ + #@TODO checksum check hook + + return True, 10 + + + def setWait(self, seconds, reconnect=False): + """Set a specific wait time later used with `wait` + + :param seconds: wait time in seconds + :param reconnect: True if a reconnect would avoid wait time + """ + if reconnect: + self.wantReconnect = True + self.pyfile.waitUntil = time() + int(seconds) + + def wait(self): + """ waits the time previously set """ + self.waiting = True + self.pyfile.setStatus("waiting") + + while self.pyfile.waitUntil > time(): + self.thread.m.reconnecting.wait(2) + + if self.pyfile.abort: raise Abort + if self.thread.m.reconnecting.isSet(): + self.waiting = False + self.wantReconnect = False + raise Reconnect + + self.waiting = False + self.pyfile.setStatus("starting") + + def fail(self, reason): + """ fail and give reason """ + raise Fail(reason) + + def offline(self): + """ fail and indicate file is offline """ + raise Fail("offline") + + def tempOffline(self): + """ fail and indicates file ist temporary offline, the core may take consequences """ + raise Fail("temp. offline") + + def retry(self, max_tries=3, wait_time=1, reason=""): + """Retries and begin again from the beginning + + :param max_tries: number of maximum retries + :param wait_time: time to wait in seconds + :param reason: reason for retrying, will be passed to fail if max_tries reached + """ + if 0 < max_tries <= self.retries: + if not reason: reason = "Max retries reached" + raise Fail(reason) + + self.wantReconnect = False + self.setWait(wait_time) + self.wait() + + self.retries += 1 + raise Retry(reason) + + def invalidCaptcha(self): + if self.cTask: + self.cTask.invalid() + + def correctCaptcha(self): + if self.cTask: + self.cTask.correct() + + def decryptCaptcha(self, url, get={}, post={}, cookies=False, forceUser=False, imgtype='jpg', + result_type='textual'): + """ Loads a captcha and decrypts it with ocr, plugin, user input + + :param url: url of captcha image + :param get: get part for request + :param post: post part for request + :param cookies: True if cookies should be enabled + :param forceUser: if True, ocr is not used + :param imgtype: Type of the Image + :param result_type: 'textual' if text is written on the captcha\ + or 'positional' for captcha where the user have to click\ + on a specific region on the captcha + + :return: result of decrypting + """ + + img = self.load(url, get=get, post=post, cookies=cookies) + + id = ("%.2f" % time())[-6:].replace(".", "") + temp_file = open(join("tmp", "tmpCaptcha_%s_%s.%s" % (self.__name__, id, imgtype)), "wb") + temp_file.write(img) + temp_file.close() + + has_plugin = self.__name__ in self.core.pluginManager.captchaPlugins + + if self.core.captcha: + Ocr = self.core.pluginManager.loadClass("captcha", self.__name__) + else: + Ocr = None + + if Ocr and not forceUser: + sleep(randint(3000, 5000) / 1000.0) + if self.pyfile.abort: raise Abort + + ocr = Ocr() + result = ocr.get_captcha(temp_file.name) + else: + captchaManager = self.core.captchaManager + task = captchaManager.newTask(img, imgtype, temp_file.name, result_type) + self.cTask = task + captchaManager.handleCaptcha(task) + + while task.isWaiting(): + if self.pyfile.abort: + captchaManager.removeTask(task) + raise Abort + sleep(1) + + captchaManager.removeTask(task) + + if task.error and has_plugin: #ignore default error message since the user could use OCR + self.fail(_("Pil and tesseract not installed and no Client connected for captcha decrypting")) + elif task.error: + self.fail(task.error) + elif not task.result: + self.fail(_("No captcha result obtained in appropiate time by any of the plugins.")) + + result = task.result + self.log.debug("Received captcha result: %s" % str(result)) + + if not self.core.debug: + try: + remove(temp_file.name) + except: + pass + + return result + + + def load(self, url, get={}, post={}, ref=True, cookies=True, just_header=False, decode=False): + """Load content at url and returns it + + :param url: + :param get: + :param post: + :param ref: + :param cookies: + :param just_header: if True only the header will be retrieved and returned as dict + :param decode: Wether to decode the output according to http header, should be True in most cases + :return: Loaded content + """ + if self.pyfile.abort: raise Abort + #utf8 vs decode -> please use decode attribute in all future plugins + if type(url) == unicode: url = str(url) + + res = self.req.load(url, get, post, ref, cookies, just_header, decode=decode) + + if self.core.debug: + from inspect import currentframe + + frame = currentframe() + if not exists(join("tmp", self.__name__)): + makedirs(join("tmp", self.__name__)) + + f = open( + join("tmp", self.__name__, "%s_line%s.dump.html" % (frame.f_back.f_code.co_name, frame.f_back.f_lineno)) + , "wb") + del frame # delete the frame or it wont be cleaned + + try: + tmp = res.encode("utf8") + except: + tmp = res + + f.write(tmp) + f.close() + + if just_header: + #parse header + header = {"code": self.req.code} + for line in res.splitlines(): + line = line.strip() + if not line or ":" not in line: continue + + key, none, value = line.partition(":") + key = key.lower().strip() + value = value.strip() + + if key in header: + if type(header[key]) == list: + header[key].append(value) + else: + header[key] = [header[key], value] + else: + header[key] = value + res = header + + return res + + def download(self, url, get={}, post={}, ref=True, cookies=True, disposition=False): + """Downloads the content at url to download folder + + :param url: + :param get: + :param post: + :param ref: + :param cookies: + :param disposition: if True and server provides content-disposition header\ + the filename will be changed if needed + :return: The location where the file was saved + """ + + self.checkForSameFiles() + + self.pyfile.setStatus("downloading") + + download_folder = self.config['general']['download_folder'] + + location = save_join(download_folder, self.pyfile.package().folder) + + if not exists(location): + makedirs(location, int(self.core.config["permission"]["folder"], 8)) + + if self.core.config["permission"]["change_dl"] and os.name != "nt": + try: + uid = getpwnam(self.config["permission"]["user"])[2] + gid = getgrnam(self.config["permission"]["group"])[2] + + chown(location, uid, gid) + except Exception, e: + self.log.warning(_("Setting User and Group failed: %s") % str(e)) + + # convert back to unicode + location = fs_decode(location) + name = save_path(self.pyfile.name) + + filename = join(location, name) + + self.core.hookManager.dispatchEvent("downloadStarts", self.pyfile, url, filename) + + try: + newname = self.req.httpDownload(url, filename, get=get, post=post, ref=ref, cookies=cookies, + chunks=self.getChunkCount(), resume=self.resumeDownload, + progressNotify=self.pyfile.setProgress, disposition=disposition) + finally: + self.pyfile.size = self.req.size + + if disposition and newname and newname != name: #triple check, just to be sure + self.log.info("%(name)s saved as %(newname)s" % {"name": name, "newname": newname}) + self.pyfile.name = newname + filename = join(location, newname) + + fs_filename = fs_encode(filename) + + if self.core.config["permission"]["change_file"]: + chmod(fs_filename, int(self.core.config["permission"]["file"], 8)) + + if self.core.config["permission"]["change_dl"] and os.name != "nt": + try: + uid = getpwnam(self.config["permission"]["user"])[2] + gid = getgrnam(self.config["permission"]["group"])[2] + + chown(fs_filename, uid, gid) + except Exception, e: + self.log.warning(_("Setting User and Group failed: %s") % str(e)) + + self.lastDownload = filename + return self.lastDownload + + def checkDownload(self, rules, api_size=0, max_size=50000, delete=True, read_size=0): + """ checks the content of the last downloaded file, re match is saved to `lastCheck` + + :param rules: dict with names and rules to match (compiled regexp or strings) + :param api_size: expected file size + :param max_size: if the file is larger then it wont be checked + :param delete: delete if matched + :param read_size: amount of bytes to read from files larger then max_size + :return: dictionary key of the first rule that matched + """ + lastDownload = fs_encode(self.lastDownload) + if not exists(lastDownload): return None + + size = stat(lastDownload) + size = size.st_size + + if api_size and api_size <= size: return None + elif size > max_size and not read_size: return None + self.log.debug("Download Check triggered") + f = open(lastDownload, "rb") + content = f.read(read_size if read_size else -1) + f.close() + #produces encoding errors, better log to other file in the future? + #self.log.debug("Content: %s" % content) + for name, rule in rules.iteritems(): + if type(rule) in (str, unicode): + if rule in content: + if delete: + remove(lastDownload) + return name + elif hasattr(rule, "search"): + m = rule.search(content) + if m: + if delete: + remove(lastDownload) + self.lastCheck = m + return name + + + def getPassword(self): + """ get the password the user provided in the package""" + password = self.pyfile.package().password + if not password: return "" + return password + + + def checkForSameFiles(self, starting=False): + """ checks if same file was/is downloaded within same package + + :param starting: indicates that the current download is going to start + :raises SkipDownload: + """ + + pack = self.pyfile.package() + + for pyfile in self.core.files.cache.values(): + if pyfile != self.pyfile and pyfile.name == self.pyfile.name and pyfile.package().folder == pack.folder: + if pyfile.status in (0, 12): #finished or downloading + raise SkipDownload(pyfile.pluginname) + elif pyfile.status in ( + 5, 7) and starting: #a download is waiting/starting and was appenrently started before + raise SkipDownload(pyfile.pluginname) + + download_folder = self.config['general']['download_folder'] + location = save_join(download_folder, pack.folder, self.pyfile.name) + + if starting and self.core.config['download']['skip_existing'] and exists(location): + size = os.stat(location).st_size + if size >= self.pyfile.size: + raise SkipDownload("File exists.") + + pyfile = self.core.db.findDuplicates(self.pyfile.id, self.pyfile.package().folder, self.pyfile.name) + if pyfile: + if exists(location): + raise SkipDownload(pyfile[0]) + + self.log.debug("File %s not skipped, because it does not exists." % self.pyfile.name) + + def clean(self): + """ clean everything and remove references """ + if hasattr(self, "pyfile"): + del self.pyfile + if hasattr(self, "req"): + self.req.close() + del self.req + if hasattr(self, "thread"): + del self.thread + if hasattr(self, "html"): + del self.html -- cgit v1.2.3 From 0e1ef9bc01579328e17e79416fa3c1c7b77adcc8 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Mon, 8 Jun 2015 06:08:01 +0200 Subject: Update everything --- module/plugins/internal/Plugin.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 15bf3971f..e1de48f72 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -142,7 +142,7 @@ class Plugin(Base): Overwrite `process` / `decrypt` in your subclassed plugin. """ __name__ = "Plugin" - __version__ = "0.4" + __version__ = "0.04" __pattern__ = None __type__ = "hoster" __config__ = [("name", "type", "desc", "default")] @@ -263,7 +263,7 @@ class Plugin(Base): def setWait(self, seconds, reconnect=False): """Set a specific wait time later used with `wait` - + :param seconds: wait time in seconds :param reconnect: True if a reconnect would avoid wait time """ @@ -339,7 +339,7 @@ class Plugin(Base): :param result_type: 'textual' if text is written on the captcha\ or 'positional' for captcha where the user have to click\ on a specific region on the captcha - + :return: result of decrypting """ @@ -528,7 +528,7 @@ class Plugin(Base): def checkDownload(self, rules, api_size=0, max_size=50000, delete=True, read_size=0): """ checks the content of the last downloaded file, re match is saved to `lastCheck` - + :param rules: dict with names and rules to match (compiled regexp or strings) :param api_size: expected file size :param max_size: if the file is larger then it wont be checked -- cgit v1.2.3 From aa2db98aab37450a20b3640cf5df0e12236acaec Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Wed, 10 Jun 2015 10:46:04 +0200 Subject: Fix https://github.com/pyload/pyload/issues/1473 --- module/plugins/internal/Plugin.py | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index e1de48f72..228685ee5 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -31,6 +31,7 @@ if os.name != "nt": from itertools import islice +from module.plugins.Plugin import Abort, Fail, Reconnect, Retry, SkipDownload from module.utils import save_join, save_path, fs_encode, fs_decode def chunks(iterable, size): @@ -41,26 +42,6 @@ def chunks(iterable, size): item = list(islice(it, size)) -class Abort(Exception): - """ raised when aborted """ - - -class Fail(Exception): - """ raised when failed """ - - -class Reconnect(Exception): - """ raised when reconnected """ - - -class Retry(Exception): - """ raised when start again from beginning """ - - -class SkipDownload(Exception): - """ raised when download should be skipped """ - - class Base(object): """ A Base class with log/config/db methods *all* plugin types can use @@ -142,7 +123,7 @@ class Plugin(Base): Overwrite `process` / `decrypt` in your subclassed plugin. """ __name__ = "Plugin" - __version__ = "0.04" + __version__ = "0.05" __pattern__ = None __type__ = "hoster" __config__ = [("name", "type", "desc", "default")] -- cgit v1.2.3 From ea27af7361bb75d665c29120d9cdc254a209afa8 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Sun, 14 Jun 2015 17:43:31 +0200 Subject: Move new log functions to Plugin --- module/plugins/internal/Plugin.py | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 228685ee5..aef8fd450 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -31,8 +31,8 @@ if os.name != "nt": from itertools import islice -from module.plugins.Plugin import Abort, Fail, Reconnect, Retry, SkipDownload -from module.utils import save_join, save_path, fs_encode, fs_decode +from module.plugins.Plugin import Abort, Fail, Reconnect, Retry, SkipDownload #@TODO: Remove in 0.4.10 +from module.utils import decode, save_join, save_path, fs_encode, fs_decode def chunks(iterable, size): it = iter(iterable) @@ -55,18 +55,35 @@ class Base(object): #: core config self.config = core.config - #log functions + # Log functions + def _log(self, level, args): + log = getattr(self.core.log, level) + msg = " | ".join((fs_encode(a) if isinstance(a, unicode) else #@NOTE: `fs_encode` -> `encode` in 0.4.10 + str(a)).strip() for a in args if a) + log("%(plugin)s[%(id)s]: %(msg)s" % {'plugin': self.__name__, + 'id' : self.pyfile.id, + 'msg' : msg or _(level.upper() + " MARK")}) + + + def logDebug(self, *args): + if self.core.debug: + return self._log("debug", args) + + def logInfo(self, *args): - self.log.info("%s: %s" % (self.__name__, " | ".join([a if isinstance(a, basestring) else str(a) for a in args]))) + return self._log("info", args) + def logWarning(self, *args): - self.log.warning("%s: %s" % (self.__name__, " | ".join([a if isinstance(a, basestring) else str(a) for a in args]))) + return self._log("warning", args) + def logError(self, *args): - self.log.error("%s: %s" % (self.__name__, " | ".join([a if isinstance(a, basestring) else str(a) for a in args]))) + return self._log("error", args) - def logDebug(self, *args): - self.log.debug("%s: %s" % (self.__name__, " | ".join([a if isinstance(a, basestring) else str(a) for a in args]))) + + def logCritical(self, *args): + return self._log("critical", args) def setConf(self, option, value): @@ -123,7 +140,7 @@ class Plugin(Base): Overwrite `process` / `decrypt` in your subclassed plugin. """ __name__ = "Plugin" - __version__ = "0.05" + __version__ = "0.06" __pattern__ = None __type__ = "hoster" __config__ = [("name", "type", "desc", "default")] -- cgit v1.2.3 From bae390c536f643932581b6be00c11cc32e84c171 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Sun, 14 Jun 2015 19:11:26 +0200 Subject: Fix https://github.com/pyload/pyload/issues/1492 and https://github.com/pyload/pyload/issues/1493 --- module/plugins/internal/Plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index aef8fd450..bbf3191c3 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -61,7 +61,7 @@ class Base(object): msg = " | ".join((fs_encode(a) if isinstance(a, unicode) else #@NOTE: `fs_encode` -> `encode` in 0.4.10 str(a)).strip() for a in args if a) log("%(plugin)s[%(id)s]: %(msg)s" % {'plugin': self.__name__, - 'id' : self.pyfile.id, + 'id' : self.pyfile.id if hasattr(self, 'pyfile') else "", 'msg' : msg or _(level.upper() + " MARK")}) @@ -140,7 +140,7 @@ class Plugin(Base): Overwrite `process` / `decrypt` in your subclassed plugin. """ __name__ = "Plugin" - __version__ = "0.06" + __version__ = "0.07" __pattern__ = None __type__ = "hoster" __config__ = [("name", "type", "desc", "default")] -- cgit v1.2.3 From 312f6decf9f0f07d46a3470c97707dd74698172c Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Sun, 14 Jun 2015 19:46:30 +0200 Subject: Hook back to Base class --- module/plugins/internal/Plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index bbf3191c3..c13d94aac 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -32,7 +32,7 @@ if os.name != "nt": from itertools import islice from module.plugins.Plugin import Abort, Fail, Reconnect, Retry, SkipDownload #@TODO: Remove in 0.4.10 -from module.utils import decode, save_join, save_path, fs_encode, fs_decode +from module.utils import save_join, save_path, fs_encode, fs_decode def chunks(iterable, size): it = iter(iterable) -- cgit v1.2.3 From 71d5584e82050a66aa5306ce99e43e7cbc3a62a7 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Mon, 15 Jun 2015 00:17:49 +0200 Subject: Fix new internal plugins --- module/plugins/internal/Plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index c13d94aac..950879c6e 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -60,8 +60,8 @@ class Base(object): log = getattr(self.core.log, level) msg = " | ".join((fs_encode(a) if isinstance(a, unicode) else #@NOTE: `fs_encode` -> `encode` in 0.4.10 str(a)).strip() for a in args if a) - log("%(plugin)s[%(id)s]: %(msg)s" % {'plugin': self.__name__, - 'id' : self.pyfile.id if hasattr(self, 'pyfile') else "", + log("%(plugin)s%(id)s: %(msg)s" % {'plugin': self.__name__, + 'id' : ("[%s]" % self.pyfile.id) if hasattr(self, 'pyfile') else "", 'msg' : msg or _(level.upper() + " MARK")}) -- cgit v1.2.3 From 8319d31956f7c1a09684009b7ec8c64bd0f3f631 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Mon, 15 Jun 2015 05:36:33 +0200 Subject: Update Base --- module/plugins/internal/Plugin.py | 125 +++++++++++++++++++++++--------------- 1 file changed, 77 insertions(+), 48 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 950879c6e..70bd8574d 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -31,7 +31,7 @@ if os.name != "nt": from itertools import islice -from module.plugins.Plugin import Abort, Fail, Reconnect, Retry, SkipDownload #@TODO: Remove in 0.4.10 +from module.plugins.Plugin import Abort, Fail, Reconnect, Retry, SkipDownload as Skip #@TODO: Remove in 0.4.10 from module.utils import save_join, save_path, fs_encode, fs_decode def chunks(iterable, size): @@ -55,7 +55,8 @@ class Base(object): #: core config self.config = core.config - # Log functions + + #: Log functions def _log(self, level, args): log = getattr(self.core.log, level) msg = " | ".join((fs_encode(a) if isinstance(a, unicode) else #@NOTE: `fs_encode` -> `encode` in 0.4.10 @@ -86,67 +87,96 @@ class Base(object): return self._log("critical", args) - def setConf(self, option, value): - """ see `setConfig` """ - self.core.config.setPlugin(self.__name__, option, value) - def setConfig(self, option, value): - """ Set config value for current plugin + """ + Set config value for current plugin :param option: :param value: :return: """ - self.setConf(option, value) + self.core.config.setPlugin(self.__name__, option, value) + + + #: Deprecated method + def setConf(self, *args, **kwargs): + """See `setConfig`""" + return self.setConfig(*args, **kwargs) - def getConf(self, option): - """ see `getConfig` """ - return self.core.config.getPlugin(self.__name__, option) def getConfig(self, option): - """ Returns config value for current plugin + """ + Returns config value for current plugin :param option: :return: """ - return self.getConf(option) + return self.core.config.getPlugin(self.__name__, option) + + + #: Deprecated method + def getConf(self, *args, **kwargs): + """See `getConfig`""" + return self.getConfig(*args, **kwargs) - def setStorage(self, key, value): - """ Saves a value persistently to the database """ - self.core.db.setStorage(self.__name__, key, value) def store(self, key, value): - """ same as `setStorage` """ + """Saves a value persistently to the database""" self.core.db.setStorage(self.__name__, key, value) - def getStorage(self, key=None, default=None): - """ Retrieves saved value or dict of all saved entries if key is None """ - if key is not None: - return self.core.db.getStorage(self.__name__, key) or default - return self.core.db.getStorage(self.__name__, key) - def retrieve(self, *args, **kwargs): - """ same as `getStorage` """ - return self.getStorage(*args, **kwargs) + #: Deprecated method + def setStorage(self, *args, **kwargs): + """Same as `setStorage`""" + return self.store(*args, **kwargs) + + + def retrieve(self, key, default=None): + """Retrieves saved value or dict of all saved entries if key is None""" + return self.core.db.getStorage(self.__name__, key) or default + + + #: Deprecated method + def getStorage(self, *args, **kwargs): + """Same as `getStorage`""" + return self.retrieve(*args, **kwargs) + def delStorage(self, key): - """ Delete entry in db """ + """Delete entry in db""" self.core.db.delStorage(self.__name__, key) + def fail(self, reason): + """Fail and give reason""" + raise Fail(reason) + + + def error(self, reason="", type=_("Parse")): + if not reason and not type: + type = _("Unknown") + + msg = _("%s error") % type.strip().capitalize() if type else _("Error") + msg += (": %s" % reason.strip()) if reason else "" + msg += _(" | Plugin may be out of date") + + raise Fail(msg) + + class Plugin(Base): - """ - Base plugin for hoster/crypter. - Overwrite `process` / `decrypt` in your subclassed plugin. - """ - __name__ = "Plugin" - __version__ = "0.07" - __pattern__ = None - __type__ = "hoster" - __config__ = [("name", "type", "desc", "default")] - __description__ = """Base Plugin""" - __author_name__ = ("RaNaN", "spoob", "mkaay") - __author_mail__ = ("RaNaN@pyload.org", "spoob@pyload.org", "mkaay@mkaay.de") + __name__ = "Plugin" + __type__ = "hoster" + __version__ = "0.08" + + __pattern__ = r'^unmatchable$' + __config__ = [] #: [("name", "type", "desc", "default")] + + __description__ = """Base plugin""" + __license__ = "GPLv3" + __authors__ = [("RaNaN", "RaNaN@pyload.org"), + ("spoob", "spoob@pyload.org"), + ("mkaay", "mkaay@mkaay.de" )] + def __init__(self, pyfile): Base.__init__(self, pyfile.m.core) @@ -286,10 +316,6 @@ class Plugin(Base): self.waiting = False self.pyfile.setStatus("starting") - def fail(self, reason): - """ fail and give reason """ - raise Fail(reason) - def offline(self): """ fail and indicate file is offline """ raise Fail("offline") @@ -298,6 +324,9 @@ class Plugin(Base): """ fail and indicates file ist temporary offline, the core may take consequences """ raise Fail("temp. offline") + def skip(self, reason) + raise Skip(reason) + def retry(self, max_tries=3, wait_time=1, reason=""): """Retries and begin again from the beginning @@ -574,7 +603,7 @@ class Plugin(Base): """ checks if same file was/is downloaded within same package :param starting: indicates that the current download is going to start - :raises SkipDownload: + :raises Skip: """ pack = self.pyfile.package() @@ -582,10 +611,10 @@ class Plugin(Base): for pyfile in self.core.files.cache.values(): if pyfile != self.pyfile and pyfile.name == self.pyfile.name and pyfile.package().folder == pack.folder: if pyfile.status in (0, 12): #finished or downloading - raise SkipDownload(pyfile.pluginname) + self.skip(pyfile.pluginname) elif pyfile.status in ( 5, 7) and starting: #a download is waiting/starting and was appenrently started before - raise SkipDownload(pyfile.pluginname) + self.skip(pyfile.pluginname) download_folder = self.config['general']['download_folder'] location = save_join(download_folder, pack.folder, self.pyfile.name) @@ -593,14 +622,14 @@ class Plugin(Base): if starting and self.core.config['download']['skip_existing'] and exists(location): size = os.stat(location).st_size if size >= self.pyfile.size: - raise SkipDownload("File exists.") + self.skip("File exists") pyfile = self.core.db.findDuplicates(self.pyfile.id, self.pyfile.package().folder, self.pyfile.name) if pyfile: if exists(location): - raise SkipDownload(pyfile[0]) + self.skip(pyfile[0]) - self.log.debug("File %s not skipped, because it does not exists." % self.pyfile.name) + self.log.debug("File %s not skipped, because it does not exists" % self.pyfile.name) def clean(self): """ clean everything and remove references """ -- cgit v1.2.3 From 743fb50e0f6e33077b8d1ea661f80c2f34e2711a Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Mon, 15 Jun 2015 05:41:47 +0200 Subject: [Plugin] Typo --- module/plugins/internal/Plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 70bd8574d..b89772052 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -166,7 +166,7 @@ class Base(object): class Plugin(Base): __name__ = "Plugin" __type__ = "hoster" - __version__ = "0.08" + __version__ = "0.09" __pattern__ = r'^unmatchable$' __config__ = [] #: [("name", "type", "desc", "default")] @@ -324,7 +324,7 @@ class Plugin(Base): """ fail and indicates file ist temporary offline, the core may take consequences """ raise Fail("temp. offline") - def skip(self, reason) + def skip(self, reason): raise Skip(reason) def retry(self, max_tries=3, wait_time=1, reason=""): -- cgit v1.2.3 From 2b1399197d6090e8672edabbbfaa59d0ecb4ce8d Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Mon, 15 Jun 2015 06:54:39 +0200 Subject: Fix https://github.com/pyload/pyload/issues/1498 --- module/plugins/internal/Plugin.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index b89772052..16aa9cc45 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -104,14 +104,18 @@ class Base(object): return self.setConfig(*args, **kwargs) - def getConfig(self, option): + def getConfig(self, option, default=""): """ Returns config value for current plugin :param option: :return: """ - return self.core.config.getPlugin(self.__name__, option) + try: + return self.core.config.getPlugin(self.__name__, option) + + except KeyError: + return default #: Deprecated method @@ -166,7 +170,7 @@ class Base(object): class Plugin(Base): __name__ = "Plugin" __type__ = "hoster" - __version__ = "0.09" + __version__ = "0.10" __pattern__ = r'^unmatchable$' __config__ = [] #: [("name", "type", "desc", "default")] -- cgit v1.2.3 From 5a139055ae658d3a05cbb658cbd66aeae0d01db5 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Mon, 15 Jun 2015 21:06:10 +0200 Subject: Spare code cosmetics --- module/plugins/internal/Plugin.py | 44 ++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 24 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 16aa9cc45..da597ef42 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -32,7 +32,7 @@ if os.name != "nt": from itertools import islice from module.plugins.Plugin import Abort, Fail, Reconnect, Retry, SkipDownload as Skip #@TODO: Remove in 0.4.10 -from module.utils import save_join, save_path, fs_encode, fs_decode +from module.utils import save_join as fs_join, save_path as safe_filename, fs_encode, fs_decode def chunks(iterable, size): it = iter(iterable) @@ -50,10 +50,6 @@ class Base(object): def __init__(self, core): #: Core instance self.core = core - #: logging instance - self.log = core.log - #: core config - self.config = core.config #: Log functions @@ -183,7 +179,7 @@ class Plugin(Base): def __init__(self, pyfile): - Base.__init__(self, pyfile.m.core) + super(Plugin, self).__init__(pyfile.m.core) self.wantReconnect = False #: enables simultaneous processing of multiple downloads @@ -239,8 +235,8 @@ class Plugin(Base): def getChunkCount(self): if self.chunkLimit <= 0: - return self.config["download"]["chunks"] - return min(self.config["download"]["chunks"], self.chunkLimit) + return self.core.config["download"]["chunks"] + return min(self.core.config["download"]["chunks"], self.chunkLimit) def __call__(self): return self.__name__ @@ -416,7 +412,7 @@ class Plugin(Base): self.fail(_("No captcha result obtained in appropiate time by any of the plugins.")) result = task.result - self.log.debug("Received captcha result: %s" % str(result)) + self.core.log.debug("Received captcha result: %s" % str(result)) if not self.core.debug: try: @@ -504,25 +500,25 @@ class Plugin(Base): self.pyfile.setStatus("downloading") - download_folder = self.config['general']['download_folder'] + download_folder = self.core.config['general']['download_folder'] - location = save_join(download_folder, self.pyfile.package().folder) + location = fs_join(download_folder, self.pyfile.package().folder) if not exists(location): makedirs(location, int(self.core.config["permission"]["folder"], 8)) if self.core.config["permission"]["change_dl"] and os.name != "nt": try: - uid = getpwnam(self.config["permission"]["user"])[2] - gid = getgrnam(self.config["permission"]["group"])[2] + uid = getpwnam(self.core.config["permission"]["user"])[2] + gid = getgrnam(self.core.config["permission"]["group"])[2] chown(location, uid, gid) except Exception, e: - self.log.warning(_("Setting User and Group failed: %s") % str(e)) + self.core.log.warning(_("Setting User and Group failed: %s") % str(e)) # convert back to unicode location = fs_decode(location) - name = save_path(self.pyfile.name) + name = safe_filename(self.pyfile.name) filename = join(location, name) @@ -536,7 +532,7 @@ class Plugin(Base): self.pyfile.size = self.req.size if disposition and newname and newname != name: #triple check, just to be sure - self.log.info("%(name)s saved as %(newname)s" % {"name": name, "newname": newname}) + self.core.log.info("%(name)s saved as %(newname)s" % {"name": name, "newname": newname}) self.pyfile.name = newname filename = join(location, newname) @@ -547,12 +543,12 @@ class Plugin(Base): if self.core.config["permission"]["change_dl"] and os.name != "nt": try: - uid = getpwnam(self.config["permission"]["user"])[2] - gid = getgrnam(self.config["permission"]["group"])[2] + uid = getpwnam(self.core.config["permission"]["user"])[2] + gid = getgrnam(self.core.config["permission"]["group"])[2] chown(fs_filename, uid, gid) except Exception, e: - self.log.warning(_("Setting User and Group failed: %s") % str(e)) + self.core.log.warning(_("Setting User and Group failed: %s") % str(e)) self.lastDownload = filename return self.lastDownload @@ -575,12 +571,12 @@ class Plugin(Base): if api_size and api_size <= size: return None elif size > max_size and not read_size: return None - self.log.debug("Download Check triggered") + self.core.log.debug("Download Check triggered") f = open(lastDownload, "rb") content = f.read(read_size if read_size else -1) f.close() #produces encoding errors, better log to other file in the future? - #self.log.debug("Content: %s" % content) + #self.core.log.debug("Content: %s" % content) for name, rule in rules.iteritems(): if type(rule) in (str, unicode): if rule in content: @@ -620,8 +616,8 @@ class Plugin(Base): 5, 7) and starting: #a download is waiting/starting and was appenrently started before self.skip(pyfile.pluginname) - download_folder = self.config['general']['download_folder'] - location = save_join(download_folder, pack.folder, self.pyfile.name) + download_folder = self.core.config['general']['download_folder'] + location = fs_join(download_folder, pack.folder, self.pyfile.name) if starting and self.core.config['download']['skip_existing'] and exists(location): size = os.stat(location).st_size @@ -633,7 +629,7 @@ class Plugin(Base): if exists(location): self.skip(pyfile[0]) - self.log.debug("File %s not skipped, because it does not exists" % self.pyfile.name) + self.core.log.debug("File %s not skipped, because it does not exists" % self.pyfile.name) def clean(self): """ clean everything and remove references """ -- cgit v1.2.3 From c1764e2fea0bb05164c83a876e8cd58b97f58f25 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Tue, 16 Jun 2015 17:31:38 +0200 Subject: Update all --- module/plugins/internal/Plugin.py | 608 ++++++++------------------------------ 1 file changed, 126 insertions(+), 482 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index da597ef42..0d4c3b165 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -1,65 +1,108 @@ # -*- coding: utf-8 -*- -""" - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. +from __future__ import with_statement - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU General Public License for more details. +import os +import re +import urllib - You should have received a copy of the GNU General Public License - along with this program; if not, see . +from module.plugins.Plugin import Abort, Fail, Reconnect, Retry, SkipDownload as Skip #@TODO: Remove in 0.4.10 +from module.utils import fs_encode, fs_decode, html_unescape, save_join as fs_join - @author: RaNaN, spoob, mkaay -""" -from time import time, sleep -from random import randint +def replace_patterns(string, ruleslist): + for r in ruleslist: + rf, rt = r + string = re.sub(rf, rt, string) + return string -import os -from os import remove, makedirs, chmod, stat -from os.path import exists, join -if os.name != "nt": - from os import chown - from pwd import getpwnam - from grp import getgrnam +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) -from itertools import islice -from module.plugins.Plugin import Abort, Fail, Reconnect, Retry, SkipDownload as Skip #@TODO: Remove in 0.4.10 -from module.utils import save_join as fs_join, save_path as safe_filename, fs_encode, fs_decode +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={}): + for form in re.finditer(r"(?P]*%s[^>]*>)(?P.*?)]*>" % attr_str, + html, re.S | re.I): + inputs = {} + action = parseHtmlTagAttrValue("action", form.group('TAG')) + + for inputtag in re.finditer(r'(<(input|textarea)[^>]*>)([^<]*(?= `encode` in 0.4.10 - str(a)).strip() for a in args if a) + msg = fs_encode(" | ".join((a if isinstance(a, basestring) else str(a)).strip() for a in args if a)) #@NOTE: `fs_encode` -> `encode` in 0.4.10 log("%(plugin)s%(id)s: %(msg)s" % {'plugin': self.__name__, - 'id' : ("[%s]" % self.pyfile.id) if hasattr(self, 'pyfile') else "", - 'msg' : msg or _(level.upper() + " MARK")}) + 'id' : ("[%s]" % self.pyfile.id) if hasattr(self, 'pyfile') else "", + 'msg' : msg or _(level.upper() + " MARK")}) def logDebug(self, *args): @@ -100,7 +143,7 @@ class Base(object): return self.setConfig(*args, **kwargs) - def getConfig(self, option, default=""): + def getConfig(self, option, default="", plugin=None): """ Returns config value for current plugin @@ -108,9 +151,10 @@ class Base(object): :return: """ try: - return self.core.config.getPlugin(self.__name__, option) + return self.core.config.getPlugin(plugin or self.__name__, option) except KeyError: + self.logWarning(_("Config option or plugin not found")) return default @@ -149,11 +193,11 @@ class Base(object): def fail(self, reason): """Fail and give reason""" - raise Fail(reason) + raise Fail(fs_encode(reason)) def error(self, reason="", type=_("Parse")): - if not reason and not type: + if not reason: type = _("Unknown") msg = _("%s error") % type.strip().capitalize() if type else _("Error") @@ -163,313 +207,73 @@ class Base(object): raise Fail(msg) -class Plugin(Base): - __name__ = "Plugin" - __type__ = "hoster" - __version__ = "0.10" + def fixurl(self, url): + return html_unescape(urllib.unquote(url.decode('unicode-escape'))).strip() - __pattern__ = r'^unmatchable$' - __config__ = [] #: [("name", "type", "desc", "default")] - __description__ = """Base plugin""" - __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org"), - ("spoob", "spoob@pyload.org"), - ("mkaay", "mkaay@mkaay.de" )] - - - def __init__(self, pyfile): - super(Plugin, self).__init__(pyfile.m.core) - - self.wantReconnect = False - #: enables simultaneous processing of multiple downloads - self.multiDL = True - self.limitDL = 0 - #: chunk limit - self.chunkLimit = 1 - self.resumeDownload = False - - #: time() + wait in seconds - self.waitUntil = 0 - self.waiting = False - - self.ocr = None #captcha reader instance - #: account handler instance, see :py:class:`Account` - self.account = pyfile.m.core.accountManager.getAccountPlugin(self.__name__) - - #: premium status - self.premium = False - #: username/login - self.user = None - - if self.account and not self.account.canUse(): self.account = None - if self.account: - self.user, data = self.account.selectAccount() - #: Browser instance, see `network.Browser` - self.req = self.account.getAccountRequest(self.user) - self.chunkLimit = -1 # chunk limit, -1 for unlimited - #: enables resume (will be ignored if server dont accept chunks) - self.resumeDownload = True - self.multiDL = True #every hoster with account should provide multiple downloads - #: premium status - self.premium = self.account.isPremium(self.user) - else: - self.req = pyfile.m.core.requestFactory.getRequest(self.__name__) - - #: associated pyfile instance, see `PyFile` - self.pyfile = pyfile - self.thread = None # holds thread in future - - #: location where the last call to download was saved - self.lastDownload = "" - #: re match of the last call to `checkDownload` - self.lastCheck = None - #: js engine, see `JsEngine` - self.js = self.core.js - self.cTask = None #captcha task - - self.retries = 0 # amount of retries already made - self.html = None # some plugins store html code here - - self.init() - - def getChunkCount(self): - if self.chunkLimit <= 0: - return self.core.config["download"]["chunks"] - return min(self.core.config["download"]["chunks"], self.chunkLimit) - - def __call__(self): - return self.__name__ - - def init(self): - """initialize the plugin (in addition to `__init__`)""" - pass - - def setup(self): - """ setup for enviroment and other things, called before downloading (possibly more than one time)""" - pass - - def preprocessing(self, thread): - """ handles important things to do before starting """ - self.thread = thread - - if self.account: - self.account.checkLogin(self.user) - else: - self.req.clearCookies() - - self.setup() - - self.pyfile.setStatus("starting") - - return self.process(self.pyfile) - - - def process(self, pyfile): - """the 'main' method of every plugin, you **have to** overwrite it""" - raise NotImplementedError - - def resetAccount(self): - """ dont use account and retry download """ - self.account = None - self.req = self.core.requestFactory.getRequest(self.__name__) - self.retry() - - def checksum(self, local_file=None): - """ - return codes: - 0 - checksum ok - 1 - checksum wrong - 5 - can't get checksum - 10 - not implemented - 20 - unknown error - """ - #@TODO checksum check hook - - return True, 10 - - - def setWait(self, seconds, reconnect=False): - """Set a specific wait time later used with `wait` - - :param seconds: wait time in seconds - :param reconnect: True if a reconnect would avoid wait time + def load(self, url, get={}, post={}, ref=True, cookies=True, just_header=False, decode=True, req=None): """ - if reconnect: - self.wantReconnect = True - self.pyfile.waitUntil = time() + int(seconds) - - def wait(self): - """ waits the time previously set """ - self.waiting = True - self.pyfile.setStatus("waiting") - - while self.pyfile.waitUntil > time(): - self.thread.m.reconnecting.wait(2) - - if self.pyfile.abort: raise Abort - if self.thread.m.reconnecting.isSet(): - self.waiting = False - self.wantReconnect = False - raise Reconnect - - self.waiting = False - self.pyfile.setStatus("starting") - - def offline(self): - """ fail and indicate file is offline """ - raise Fail("offline") - - def tempOffline(self): - """ fail and indicates file ist temporary offline, the core may take consequences """ - raise Fail("temp. offline") - - def skip(self, reason): - raise Skip(reason) - - def retry(self, max_tries=3, wait_time=1, reason=""): - """Retries and begin again from the beginning - - :param max_tries: number of maximum retries - :param wait_time: time to wait in seconds - :param reason: reason for retrying, will be passed to fail if max_tries reached - """ - if 0 < max_tries <= self.retries: - if not reason: reason = "Max retries reached" - raise Fail(reason) - - self.wantReconnect = False - self.setWait(wait_time) - self.wait() - - self.retries += 1 - raise Retry(reason) - - def invalidCaptcha(self): - if self.cTask: - self.cTask.invalid() - - def correctCaptcha(self): - if self.cTask: - self.cTask.correct() - - def decryptCaptcha(self, url, get={}, post={}, cookies=False, forceUser=False, imgtype='jpg', - result_type='textual'): - """ Loads a captcha and decrypts it with ocr, plugin, user input - - :param url: url of captcha image - :param get: get part for request - :param post: post part for request - :param cookies: True if cookies should be enabled - :param forceUser: if True, ocr is not used - :param imgtype: Type of the Image - :param result_type: 'textual' if text is written on the captcha\ - or 'positional' for captcha where the user have to click\ - on a specific region on the captcha - - :return: result of decrypting - """ - - img = self.load(url, get=get, post=post, cookies=cookies) - - id = ("%.2f" % time())[-6:].replace(".", "") - temp_file = open(join("tmp", "tmpCaptcha_%s_%s.%s" % (self.__name__, id, imgtype)), "wb") - temp_file.write(img) - temp_file.close() - - has_plugin = self.__name__ in self.core.pluginManager.captchaPlugins - - if self.core.captcha: - Ocr = self.core.pluginManager.loadClass("captcha", self.__name__) - else: - Ocr = None - - if Ocr and not forceUser: - sleep(randint(3000, 5000) / 1000.0) - if self.pyfile.abort: raise Abort - - ocr = Ocr() - result = ocr.get_captcha(temp_file.name) - else: - captchaManager = self.core.captchaManager - task = captchaManager.newTask(img, imgtype, temp_file.name, result_type) - self.cTask = task - captchaManager.handleCaptcha(task) - - while task.isWaiting(): - if self.pyfile.abort: - captchaManager.removeTask(task) - raise Abort - sleep(1) - - captchaManager.removeTask(task) - - if task.error and has_plugin: #ignore default error message since the user could use OCR - self.fail(_("Pil and tesseract not installed and no Client connected for captcha decrypting")) - elif task.error: - self.fail(task.error) - elif not task.result: - self.fail(_("No captcha result obtained in appropiate time by any of the plugins.")) - - result = task.result - self.core.log.debug("Received captcha result: %s" % str(result)) - - if not self.core.debug: - try: - remove(temp_file.name) - except: - pass - - return result - - - def load(self, url, get={}, post={}, ref=True, cookies=True, just_header=False, decode=False): - """Load content at url and returns it + Load content at url and returns it :param url: :param get: :param post: :param ref: :param cookies: - :param just_header: if True only the header will be retrieved and returned as dict + :param just_header: If True only the header will be retrieved and returned as dict :param decode: Wether to decode the output according to http header, should be True in most cases :return: Loaded content """ - if self.pyfile.abort: raise Abort - #utf8 vs decode -> please use decode attribute in all future plugins - if type(url) == unicode: url = str(url) + if hasattr(self, 'pyfile') and self.pyfile.abort: + self.abort() + + url = self.fixurl(url) - res = self.req.load(url, get, post, ref, cookies, just_header, decode=decode) + if not url or not isinstance(url, basestring): + self.fail(_("No url given")) if self.core.debug: - from inspect import currentframe + self.logDebug("Load url: " + url, *["%s=%s" % (key, val) for key, val in locals().iteritems() if key not in ("self", "url")]) + + if req is None: + if hasattr(self, "req"): + req = self.req + else: + req = self.core.requestFactory.getRequest(self.__name__) - frame = currentframe() - if not exists(join("tmp", self.__name__)): - makedirs(join("tmp", self.__name__)) + res = req.load(url, get, post, ref, cookies, just_header, True, bool(decode)) - f = open( - join("tmp", self.__name__, "%s_line%s.dump.html" % (frame.f_back.f_code.co_name, frame.f_back.f_lineno)) - , "wb") - del frame # delete the frame or it wont be cleaned + if decode: + res = html_unescape(res) + if isinstance(decode, basestring): + res = res.decode(decode) + + if self.core.debug: + import inspect + + frame = inspect.currentframe() + framefile = fs_join("tmp", self.__name__, "%s_line%s.dump.html" % (frame.f_back.f_code.co_name, frame.f_back.f_lineno)) try: - tmp = res.encode("utf8") - except: - tmp = res + if not os.path.exists(os.path.join("tmp", self.__name__)): + os.makedirs(os.path.join("tmp", self.__name__)) - f.write(tmp) - f.close() + with open(framefile, "wb") as f: + del frame #: delete the frame or it wont be cleaned + f.write(res.encode('utf8')) + except IOError, e: + self.logError(e) if just_header: - #parse header - header = {"code": self.req.code} + # parse header + header = {"code": req.code} for line in res.splitlines(): line = line.strip() - if not line or ":" not in line: continue + if not line or ":" not in line: + continue key, none, value = line.partition(":") - key = key.lower().strip() + key = key.strip().lower() value = value.strip() if key in header: @@ -481,164 +285,4 @@ class Plugin(Base): header[key] = value res = header - return res - - def download(self, url, get={}, post={}, ref=True, cookies=True, disposition=False): - """Downloads the content at url to download folder - - :param url: - :param get: - :param post: - :param ref: - :param cookies: - :param disposition: if True and server provides content-disposition header\ - the filename will be changed if needed - :return: The location where the file was saved - """ - - self.checkForSameFiles() - - self.pyfile.setStatus("downloading") - - download_folder = self.core.config['general']['download_folder'] - - location = fs_join(download_folder, self.pyfile.package().folder) - - if not exists(location): - makedirs(location, int(self.core.config["permission"]["folder"], 8)) - - if self.core.config["permission"]["change_dl"] and os.name != "nt": - try: - uid = getpwnam(self.core.config["permission"]["user"])[2] - gid = getgrnam(self.core.config["permission"]["group"])[2] - - chown(location, uid, gid) - except Exception, e: - self.core.log.warning(_("Setting User and Group failed: %s") % str(e)) - - # convert back to unicode - location = fs_decode(location) - name = safe_filename(self.pyfile.name) - - filename = join(location, name) - - self.core.hookManager.dispatchEvent("downloadStarts", self.pyfile, url, filename) - - try: - newname = self.req.httpDownload(url, filename, get=get, post=post, ref=ref, cookies=cookies, - chunks=self.getChunkCount(), resume=self.resumeDownload, - progressNotify=self.pyfile.setProgress, disposition=disposition) - finally: - self.pyfile.size = self.req.size - - if disposition and newname and newname != name: #triple check, just to be sure - self.core.log.info("%(name)s saved as %(newname)s" % {"name": name, "newname": newname}) - self.pyfile.name = newname - filename = join(location, newname) - - fs_filename = fs_encode(filename) - - if self.core.config["permission"]["change_file"]: - chmod(fs_filename, int(self.core.config["permission"]["file"], 8)) - - if self.core.config["permission"]["change_dl"] and os.name != "nt": - try: - uid = getpwnam(self.core.config["permission"]["user"])[2] - gid = getgrnam(self.core.config["permission"]["group"])[2] - - chown(fs_filename, uid, gid) - except Exception, e: - self.core.log.warning(_("Setting User and Group failed: %s") % str(e)) - - self.lastDownload = filename - return self.lastDownload - - def checkDownload(self, rules, api_size=0, max_size=50000, delete=True, read_size=0): - """ checks the content of the last downloaded file, re match is saved to `lastCheck` - - :param rules: dict with names and rules to match (compiled regexp or strings) - :param api_size: expected file size - :param max_size: if the file is larger then it wont be checked - :param delete: delete if matched - :param read_size: amount of bytes to read from files larger then max_size - :return: dictionary key of the first rule that matched - """ - lastDownload = fs_encode(self.lastDownload) - if not exists(lastDownload): return None - - size = stat(lastDownload) - size = size.st_size - - if api_size and api_size <= size: return None - elif size > max_size and not read_size: return None - self.core.log.debug("Download Check triggered") - f = open(lastDownload, "rb") - content = f.read(read_size if read_size else -1) - f.close() - #produces encoding errors, better log to other file in the future? - #self.core.log.debug("Content: %s" % content) - for name, rule in rules.iteritems(): - if type(rule) in (str, unicode): - if rule in content: - if delete: - remove(lastDownload) - return name - elif hasattr(rule, "search"): - m = rule.search(content) - if m: - if delete: - remove(lastDownload) - self.lastCheck = m - return name - - - def getPassword(self): - """ get the password the user provided in the package""" - password = self.pyfile.package().password - if not password: return "" - return password - - - def checkForSameFiles(self, starting=False): - """ checks if same file was/is downloaded within same package - - :param starting: indicates that the current download is going to start - :raises Skip: - """ - - pack = self.pyfile.package() - - for pyfile in self.core.files.cache.values(): - if pyfile != self.pyfile and pyfile.name == self.pyfile.name and pyfile.package().folder == pack.folder: - if pyfile.status in (0, 12): #finished or downloading - self.skip(pyfile.pluginname) - elif pyfile.status in ( - 5, 7) and starting: #a download is waiting/starting and was appenrently started before - self.skip(pyfile.pluginname) - - download_folder = self.core.config['general']['download_folder'] - location = fs_join(download_folder, pack.folder, self.pyfile.name) - - if starting and self.core.config['download']['skip_existing'] and exists(location): - size = os.stat(location).st_size - if size >= self.pyfile.size: - self.skip("File exists") - - pyfile = self.core.db.findDuplicates(self.pyfile.id, self.pyfile.package().folder, self.pyfile.name) - if pyfile: - if exists(location): - self.skip(pyfile[0]) - - self.core.log.debug("File %s not skipped, because it does not exists" % self.pyfile.name) - - def clean(self): - """ clean everything and remove references """ - if hasattr(self, "pyfile"): - del self.pyfile - if hasattr(self, "req"): - self.req.close() - del self.req - if hasattr(self, "thread"): - del self.thread - if hasattr(self, "html"): - del self.html + return res \ No newline at end of file -- cgit v1.2.3 From 164512b6a74c94a731fcee7435dce1ccfa2f71e7 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Wed, 17 Jun 2015 18:29:50 +0200 Subject: Spare code cosmetics --- module/plugins/internal/Plugin.py | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 0d4c3b165..68169e077 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -139,7 +139,9 @@ class Plugin(object): #: Deprecated method def setConf(self, *args, **kwargs): - """See `setConfig`""" + """ + See `setConfig` + """ return self.setConfig(*args, **kwargs) @@ -160,39 +162,53 @@ class Plugin(object): #: Deprecated method def getConf(self, *args, **kwargs): - """See `getConfig`""" + """ + See `getConfig` + """ return self.getConfig(*args, **kwargs) def store(self, key, value): - """Saves a value persistently to the database""" + """ + Saves a value persistently to the database + """ self.core.db.setStorage(self.__name__, key, value) #: Deprecated method def setStorage(self, *args, **kwargs): - """Same as `setStorage`""" + """ + Same as `setStorage` + """ return self.store(*args, **kwargs) def retrieve(self, key, default=None): - """Retrieves saved value or dict of all saved entries if key is None""" + """ + Retrieves saved value or dict of all saved entries if key is None + """ return self.core.db.getStorage(self.__name__, key) or default #: Deprecated method def getStorage(self, *args, **kwargs): - """Same as `getStorage`""" + """ + Same as `getStorage` + """ return self.retrieve(*args, **kwargs) def delStorage(self, key): - """Delete entry in db""" + """ + Delete entry in db + """ self.core.db.delStorage(self.__name__, key) def fail(self, reason): - """Fail and give reason""" + """ + Fail and give reason + """ raise Fail(fs_encode(reason)) -- cgit v1.2.3 From 20b6a2ec022202b0efb6cb69415239fb8f4d1445 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Wed, 17 Jun 2015 18:59:20 +0200 Subject: Spare code cosmetics (2) --- module/plugins/internal/Plugin.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 68169e077..1f86214c4 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -45,7 +45,7 @@ def parseHtmlForm(attr_str, html, input_names={}): inputs[name] = value if input_names: - # check input attributes + #: check input attributes for key, val in input_names.iteritems(): if key in inputs: if isinstance(val, basestring) and inputs[key] == val: @@ -60,7 +60,7 @@ def parseHtmlForm(attr_str, html, input_names={}): else: return action, inputs #: passed attribute check else: - # no attribute check + #: no attribute check return action, inputs return {}, None #: no matching form found @@ -281,7 +281,7 @@ class Plugin(object): self.logError(e) if just_header: - # parse header + #: parse header header = {"code": req.code} for line in res.splitlines(): line = line.strip() -- cgit v1.2.3 From fe70307e0b6916cc5a4273c73cdd355dee02546a Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Sun, 5 Jul 2015 13:14:40 +0200 Subject: [Plugin] Fix decoding in load method --- module/plugins/internal/Plugin.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 1f86214c4..9b110280e 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -2,6 +2,7 @@ from __future__ import with_statement +import inspect import os import re import urllib @@ -260,14 +261,9 @@ class Plugin(object): res = req.load(url, get, post, ref, cookies, just_header, True, bool(decode)) if decode: - res = html_unescape(res) - - if isinstance(decode, basestring): - res = res.decode(decode) + res = html_unescape(res).decode(decode if isinstance(decode, basestring) else 'utf8') if self.core.debug: - import inspect - frame = inspect.currentframe() framefile = fs_join("tmp", self.__name__, "%s_line%s.dump.html" % (frame.f_back.f_code.co_name, frame.f_back.f_lineno)) try: -- cgit v1.2.3 From b1759bc440cd6013837697eb8de540914f693ffd Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Tue, 7 Jul 2015 01:23:55 +0200 Subject: No camelCase style anymore --- module/plugins/internal/Plugin.py | 58 ++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 25 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 9b110280e..0b08858f3 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -25,12 +25,12 @@ def set_cookies(cj, cookies): cj.setCookie(domain, name, value) -def parseHtmlTagAttrValue(attr_name, tag): +def parse_html_tag_attr_value(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={}): +def parse_html_form(attr_str, html, input_names={}): for form in re.finditer(r"(?P]*%s[^>]*>)(?P.*?)]*>" % attr_str, html, re.S | re.I): inputs = {} @@ -78,7 +78,7 @@ def chunks(iterable, size): class Plugin(object): __name__ = "Plugin" __type__ = "hoster" - __version__ = "0.11" + __version__ = "0.12" __pattern__ = r'^unmatchable$' __config__ = [] #: [("name", "type", "desc", "default")] @@ -106,28 +106,28 @@ class Plugin(object): 'msg' : msg or _(level.upper() + " MARK")}) - def logDebug(self, *args): + def log_debug(self, *args): if self.core.debug: return self._log("debug", args) - def logInfo(self, *args): + def log_info(self, *args): return self._log("info", args) - def logWarning(self, *args): + def log_warning(self, *args): return self._log("warning", args) - def logError(self, *args): + def log_error(self, *args): return self._log("error", args) - def logCritical(self, *args): + def log_critical(self, *args): return self._log("critical", args) - def setConfig(self, option, value): + def set_config(self, option, value): """ Set config value for current plugin @@ -138,15 +138,15 @@ class Plugin(object): self.core.config.setPlugin(self.__name__, option, value) - #: Deprecated method + #: Deprecated method, use `set_config` instead def setConf(self, *args, **kwargs): """ - See `setConfig` + See `set_config` """ - return self.setConfig(*args, **kwargs) + return self.set_config(*args, **kwargs) - def getConfig(self, option, default="", plugin=None): + def get_config(self, option, default="", plugin=None): """ Returns config value for current plugin @@ -157,16 +157,16 @@ class Plugin(object): return self.core.config.getPlugin(plugin or self.__name__, option) except KeyError: - self.logWarning(_("Config option or plugin not found")) + self.log_warning(_("Config option or plugin not found")) return default - #: Deprecated method + #: Deprecated method, use `get_config` instead def getConf(self, *args, **kwargs): """ - See `getConfig` + See `get_config` """ - return self.getConfig(*args, **kwargs) + return self.get_config(*args, **kwargs) def store(self, key, value): @@ -176,10 +176,10 @@ class Plugin(object): self.core.db.setStorage(self.__name__, key, value) - #: Deprecated method + #: Deprecated method, use `store` instead def setStorage(self, *args, **kwargs): """ - Same as `setStorage` + Same as `store` """ return self.store(*args, **kwargs) @@ -191,21 +191,29 @@ class Plugin(object): return self.core.db.getStorage(self.__name__, key) or default - #: Deprecated method + #: Deprecated method, use `retrieve` instead def getStorage(self, *args, **kwargs): """ - Same as `getStorage` + Same as `retrieve` """ return self.retrieve(*args, **kwargs) - def delStorage(self, key): + def delete(self, key): """ Delete entry in db """ self.core.db.delStorage(self.__name__, key) + #: Deprecated method, use `delete` instead + def delStorage(self, *args, **kwargs): + """ + Same as `delete` + """ + return self.delete(*args, **kwargs) + + def fail(self, reason): """ Fail and give reason @@ -250,7 +258,7 @@ class Plugin(object): self.fail(_("No url given")) if self.core.debug: - self.logDebug("Load url: " + url, *["%s=%s" % (key, val) for key, val in locals().iteritems() if key not in ("self", "url")]) + self.log_debug("Load url: " + url, *["%s=%s" % (key, val) for key, val in locals().iteritems() if key not in ("self", "url")]) if req is None: if hasattr(self, "req"): @@ -274,7 +282,7 @@ class Plugin(object): del frame #: delete the frame or it wont be cleaned f.write(res.encode('utf8')) except IOError, e: - self.logError(e) + self.log_error(e) if just_header: #: parse header @@ -297,4 +305,4 @@ class Plugin(object): header[key] = value res = header - return res \ No newline at end of file + return res -- cgit v1.2.3 From d2e2b127651a5a44b56337eb6d9ca246c97a208a Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Fri, 17 Jul 2015 03:03:26 +0200 Subject: Spare fixes and code cosmetics --- module/plugins/internal/Plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 0b08858f3..01294ea92 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -236,7 +236,7 @@ class Plugin(object): return html_unescape(urllib.unquote(url.decode('unicode-escape'))).strip() - def load(self, url, get={}, post={}, ref=True, cookies=True, just_header=False, decode=True, req=None): + def load(self, url, get={}, post={}, ref=True, cookies=True, just_header=False, decode=True, multipart=True, req=None): """ Load content at url and returns it @@ -266,7 +266,7 @@ class Plugin(object): else: req = self.core.requestFactory.getRequest(self.__name__) - res = req.load(url, get, post, ref, cookies, just_header, True, bool(decode)) + res = req.load(url, get, post, ref, cookies, just_header, multipart, bool(decode)) if decode: res = html_unescape(res).decode(decode if isinstance(decode, basestring) else 'utf8') -- cgit v1.2.3 From ce3788f41d400e486c13126891641ad45740020c Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Sat, 18 Jul 2015 19:19:51 +0200 Subject: Reorder some functions --- module/plugins/internal/Plugin.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 01294ea92..d1b8bb1cf 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -11,6 +11,29 @@ from module.plugins.Plugin import Abort, Fail, Reconnect, Retry, SkipDownload as from module.utils import fs_encode, fs_decode, html_unescape, save_join as fs_join +#@TODO: Move to utils in 0.4.10 +def timestamp(): + return int(time.time() * 1000) + + +def seconds_to_midnight(gmt=0): + now = datetime.datetime.utcnow() + datetime.timedelta(hours=gmt) + + if now.hour is 0 and now.minute < 10: + midnight = now + else: + midnight = now + datetime.timedelta(days=1) + + td = midnight.replace(hour=0, minute=10, second=0, microsecond=0) - now + + if hasattr(td, 'total_seconds'): + res = td.total_seconds() + else: #@NOTE: work-around for python 2.5 and 2.6 missing datetime.timedelta.total_seconds + res = (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6 + + return int(res) + + def replace_patterns(string, ruleslist): for r in ruleslist: rf, rt = r @@ -67,6 +90,7 @@ def parse_html_form(attr_str, html, input_names={}): return {}, None #: no matching form found +#@TODO: Move to utils in 0.4.10 def chunks(iterable, size): it = iter(iterable) item = list(islice(it, size)) @@ -78,7 +102,7 @@ def chunks(iterable, size): class Plugin(object): __name__ = "Plugin" __type__ = "hoster" - __version__ = "0.12" + __version__ = "0.13" __pattern__ = r'^unmatchable$' __config__ = [] #: [("name", "type", "desc", "default")] -- cgit v1.2.3 From 9e5d813d7721e351ac02ba72bdc473a7d77ba6b7 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Sat, 18 Jul 2015 20:04:36 +0200 Subject: Code cosmetics --- module/plugins/internal/Plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index d1b8bb1cf..dc5995e65 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -282,7 +282,7 @@ class Plugin(object): self.fail(_("No url given")) if self.core.debug: - self.log_debug("Load url: " + url, *["%s=%s" % (key, val) for key, val in locals().iteritems() if key not in ("self", "url")]) + self.log_debug("Load url " + url, *["%s=%s" % (key, val) for key, val in locals().iteritems() if key not in ("self", "url")]) if req is None: if hasattr(self, "req"): -- cgit v1.2.3 From dad722ac7255640e7e0541c4094a4d2e4de79cd3 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Sun, 19 Jul 2015 00:05:58 +0200 Subject: Code cosmetics (2) --- module/plugins/internal/Plugin.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index dc5995e65..51f952b40 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -69,7 +69,7 @@ def parse_html_form(attr_str, html, input_names={}): inputs[name] = value if input_names: - #: check input attributes + #: Check input attributes for key, val in input_names.iteritems(): if key in inputs: if isinstance(val, basestring) and inputs[key] == val: @@ -78,16 +78,16 @@ def parse_html_form(attr_str, html, input_names={}): continue elif hasattr(val, "search") and re.match(val, inputs[key]): continue - break #: attibute value does not match + break #: Attibute value does not match else: - break #: attibute name does not match + break #: Attibute name does not match else: - return action, inputs #: passed attribute check + return action, inputs #: Passed attribute check else: - #: no attribute check + #: No attribute check return action, inputs - return {}, None #: no matching form found + return {}, None #: No matching form found #@TODO: Move to utils in 0.4.10 @@ -303,13 +303,13 @@ class Plugin(object): os.makedirs(os.path.join("tmp", self.__name__)) with open(framefile, "wb") as f: - del frame #: delete the frame or it wont be cleaned + del frame #: Delete the frame or it wont be cleaned f.write(res.encode('utf8')) except IOError, e: self.log_error(e) if just_header: - #: parse header + #: Parse header header = {"code": req.code} for line in res.splitlines(): line = line.strip() -- cgit v1.2.3 From a0e2459f2d1506912ac4a5d0c330c8dae01a4768 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Sun, 19 Jul 2015 00:28:18 +0200 Subject: Improve fixurl method --- module/plugins/internal/Plugin.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 51f952b40..93dd2ecbe 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -11,6 +11,11 @@ from module.plugins.Plugin import Abort, Fail, Reconnect, Retry, SkipDownload as from module.utils import fs_encode, fs_decode, html_unescape, save_join as fs_join +#@TODO: Move to utils in 0.4.10 +def fixurl(url): + return html_unescape(urllib.unquote(url.decode('unicode-escape'))).strip() + + #@TODO: Move to utils in 0.4.10 def timestamp(): return int(time.time() * 1000) @@ -256,10 +261,6 @@ class Plugin(object): raise Fail(msg) - def fixurl(self, url): - return html_unescape(urllib.unquote(url.decode('unicode-escape'))).strip() - - def load(self, url, get={}, post={}, ref=True, cookies=True, just_header=False, decode=True, multipart=True, req=None): """ Load content at url and returns it @@ -276,7 +277,7 @@ class Plugin(object): if hasattr(self, 'pyfile') and self.pyfile.abort: self.abort() - url = self.fixurl(url) + url = fixurl(url) if not url or not isinstance(url, basestring): self.fail(_("No url given")) -- cgit v1.2.3 From 502517f37c7540b0bddb092e69386d9d6f08800c Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Sun, 19 Jul 2015 09:42:34 +0200 Subject: Fix addons --- module/plugins/internal/Plugin.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 93dd2ecbe..d0f75a8a3 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -122,9 +122,7 @@ class Plugin(object): def __init__(self, core): self.core = core - - #: Provide information in dict here - self.info = {} + self.info = {} #: Provide information in dict here def _log(self, level, args): -- cgit v1.2.3 From ff9383bfe06d14d23bc0ed6af79aa8967965d078 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Sun, 19 Jul 2015 10:59:52 +0200 Subject: Code cosmetics (3) --- module/plugins/internal/Plugin.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index d0f75a8a3..7dec6344e 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -123,6 +123,14 @@ class Plugin(object): def __init__(self, core): self.core = core self.info = {} #: Provide information in dict here + self.init() + + + def init(self): + """ + Initialize the plugin (in addition to `__init__`) + """ + pass def _log(self, level, args): @@ -309,7 +317,7 @@ class Plugin(object): if just_header: #: Parse header - header = {"code": req.code} + header = {'code': req.code} for line in res.splitlines(): line = line.strip() if not line or ":" not in line: -- cgit v1.2.3 From 56389e28ba5d2f5658278bc7f486d73be747f135 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Sun, 19 Jul 2015 11:44:49 +0200 Subject: Rename self.core to self.pyload (plugins only) --- module/plugins/internal/Plugin.py | 66 ++++++++------------------------------- 1 file changed, 13 insertions(+), 53 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 7dec6344e..74f5e7c6d 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -121,8 +121,8 @@ class Plugin(object): def __init__(self, core): - self.core = core - self.info = {} #: Provide information in dict here + self.pyload = core + self.info = {} #: Provide information in dict here self.init() @@ -134,7 +134,7 @@ class Plugin(object): def _log(self, level, args): - log = getattr(self.core.log, level) + log = getattr(self.pyload.log, level) msg = fs_encode(" | ".join((a if isinstance(a, basestring) else str(a)).strip() for a in args if a)) #@NOTE: `fs_encode` -> `encode` in 0.4.10 log("%(plugin)s%(id)s: %(msg)s" % {'plugin': self.__name__, 'id' : ("[%s]" % self.pyfile.id) if hasattr(self, 'pyfile') else "", @@ -142,7 +142,7 @@ class Plugin(object): def log_debug(self, *args): - if self.core.debug: + if self.pyload.debug: return self._log("debug", args) @@ -170,15 +170,7 @@ class Plugin(object): :param value: :return: """ - self.core.config.setPlugin(self.__name__, option, value) - - - #: Deprecated method, use `set_config` instead - def setConf(self, *args, **kwargs): - """ - See `set_config` - """ - return self.set_config(*args, **kwargs) + self.pyload.config.setPlugin(self.__name__, option, value) def get_config(self, option, default="", plugin=None): @@ -189,64 +181,32 @@ class Plugin(object): :return: """ try: - return self.core.config.getPlugin(plugin or self.__name__, option) + return self.pyload.config.getPlugin(plugin or self.__name__, option) except KeyError: self.log_warning(_("Config option or plugin not found")) return default - #: Deprecated method, use `get_config` instead - def getConf(self, *args, **kwargs): - """ - See `get_config` - """ - return self.get_config(*args, **kwargs) - - def store(self, key, value): """ Saves a value persistently to the database """ - self.core.db.setStorage(self.__name__, key, value) - - - #: Deprecated method, use `store` instead - def setStorage(self, *args, **kwargs): - """ - Same as `store` - """ - return self.store(*args, **kwargs) + self.pyload.db.setStorage(self.__name__, key, value) def retrieve(self, key, default=None): """ Retrieves saved value or dict of all saved entries if key is None """ - return self.core.db.getStorage(self.__name__, key) or default - - - #: Deprecated method, use `retrieve` instead - def getStorage(self, *args, **kwargs): - """ - Same as `retrieve` - """ - return self.retrieve(*args, **kwargs) + return self.pyload.db.getStorage(self.__name__, key) or default def delete(self, key): """ Delete entry in db """ - self.core.db.delStorage(self.__name__, key) - - - #: Deprecated method, use `delete` instead - def delStorage(self, *args, **kwargs): - """ - Same as `delete` - """ - return self.delete(*args, **kwargs) + self.pyload.db.delStorage(self.__name__, key) def fail(self, reason): @@ -288,21 +248,21 @@ class Plugin(object): if not url or not isinstance(url, basestring): self.fail(_("No url given")) - if self.core.debug: - self.log_debug("Load url " + url, *["%s=%s" % (key, val) for key, val in locals().iteritems() if key not in ("self", "url")]) + if self.pyload.debug: + self.log_debug("LOAD URL " + url, *["%s=%s" % (key, val) for key, val in locals().iteritems() if key not in ("self", "url")]) if req is None: if hasattr(self, "req"): req = self.req else: - req = self.core.requestFactory.getRequest(self.__name__) + req = self.pyload.requestFactory.getRequest(self.__name__) res = req.load(url, get, post, ref, cookies, just_header, multipart, bool(decode)) if decode: res = html_unescape(res).decode(decode if isinstance(decode, basestring) else 'utf8') - if self.core.debug: + if self.pyload.debug: frame = inspect.currentframe() framefile = fs_join("tmp", self.__name__, "%s_line%s.dump.html" % (frame.f_back.f_code.co_name, frame.f_back.f_lineno)) try: -- cgit v1.2.3 From d38e830b7c0b3c6561a0072c74bbccb5fcdf4a61 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Sun, 19 Jul 2015 14:43:42 +0200 Subject: New __status__ magic key --- module/plugins/internal/Plugin.py | 1 + 1 file changed, 1 insertion(+) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 74f5e7c6d..030c372aa 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -108,6 +108,7 @@ class Plugin(object): __name__ = "Plugin" __type__ = "hoster" __version__ = "0.13" + __status__ = "stable" __pattern__ = r'^unmatchable$' __config__ = [] #: [("name", "type", "desc", "default")] -- cgit v1.2.3 From 8f7e3150dcf97c2137514d72af69cc253d8c0aed Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Fri, 24 Jul 2015 00:16:08 +0200 Subject: [Plugin] Another fix about page decoding --- module/plugins/internal/Plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 030c372aa..35541f903 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -258,7 +258,7 @@ class Plugin(object): else: req = self.pyload.requestFactory.getRequest(self.__name__) - res = req.load(url, get, post, ref, cookies, just_header, multipart, bool(decode)) + res = req.load(url, get, post, ref, cookies, just_header, multipart, decode is True) if decode: res = html_unescape(res).decode(decode if isinstance(decode, basestring) else 'utf8') -- cgit v1.2.3 From f7df6ef48a7c0a8ab6351e046cd12160257c4ef5 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Fri, 24 Jul 2015 02:15:31 +0200 Subject: Hotfixes --- module/plugins/internal/Plugin.py | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 35541f903..01cc1ce8a 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -11,6 +11,24 @@ from module.plugins.Plugin import Abort, Fail, Reconnect, Retry, SkipDownload as from module.utils import fs_encode, fs_decode, html_unescape, save_join as fs_join +#@TODO: Move to utils in 0.4.10 +def decode(string, encoding='utf8'): + """ Decode string to unicode with utf8 """ + if type(string) is str: + return string.decode(encoding, "replace") + else: + return string + + +#@TODO: Move to utils in 0.4.10 +def encode(string, encoding='utf8'): + """ Decode string to utf8 """ + if type(string) is unicode: + return string.encode(encoding, "replace") + else: + return string + + #@TODO: Move to utils in 0.4.10 def fixurl(url): return html_unescape(urllib.unquote(url.decode('unicode-escape'))).strip() @@ -136,7 +154,7 @@ class Plugin(object): def _log(self, level, args): log = getattr(self.pyload.log, level) - msg = fs_encode(" | ".join((a if isinstance(a, basestring) else str(a)).strip() for a in args if a)) #@NOTE: `fs_encode` -> `encode` in 0.4.10 + msg = encode(" | ".join((a if isinstance(a, basestring) else str(a)).strip() for a in args if a)) #@NOTE: `fs_encode` -> `encode` in 0.4.10 log("%(plugin)s%(id)s: %(msg)s" % {'plugin': self.__name__, 'id' : ("[%s]" % self.pyfile.id) if hasattr(self, 'pyfile') else "", 'msg' : msg or _(level.upper() + " MARK")}) @@ -214,7 +232,7 @@ class Plugin(object): """ Fail and give reason """ - raise Fail(fs_encode(reason)) + raise Fail(encode(reason)) #: Move to manager in 0.4.10 def error(self, reason="", type=_("Parse")): @@ -260,8 +278,11 @@ class Plugin(object): res = req.load(url, get, post, ref, cookies, just_header, multipart, decode is True) - if decode: - res = html_unescape(res).decode(decode if isinstance(decode, basestring) else 'utf8') + if decode: #@TODO: Move to network in 0.4.10 + res = html_unescape(res) + + if isinstance(decode, basestring): #@TODO: Move to network in 0.4.10 + res = decode(res, decode) if self.pyload.debug: frame = inspect.currentframe() @@ -272,7 +293,7 @@ class Plugin(object): with open(framefile, "wb") as f: del frame #: Delete the frame or it wont be cleaned - f.write(res.encode('utf8')) + f.write(encode(res)) except IOError, e: self.log_error(e) -- cgit v1.2.3 From 94d017cd2a5c1f194960827a8c7e46afc3682008 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Fri, 24 Jul 2015 06:55:49 +0200 Subject: Hotfixes (2) --- module/plugins/internal/Plugin.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 01cc1ce8a..e70c099b1 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -66,7 +66,7 @@ def replace_patterns(string, ruleslist): def set_cookies(cj, cookies): for cookie in cookies: - if isinstance(cookie, tuple) and len(cookie) == 3: + if isinstance(cookie, tuple) and len(cookie) is 3: domain, name, value = cookie cj.setCookie(domain, name, value) @@ -95,7 +95,7 @@ def parse_html_form(attr_str, html, input_names={}): #: Check input attributes for key, val in input_names.iteritems(): if key in inputs: - if isinstance(val, basestring) and inputs[key] == val: + if isinstance(val, basestring) and inputs[key] is val: continue elif isinstance(val, tuple) and inputs[key] in val: continue @@ -126,7 +126,7 @@ class Plugin(object): __name__ = "Plugin" __type__ = "hoster" __version__ = "0.13" - __status__ = "stable" + __status__ = "testing" __pattern__ = r'^unmatchable$' __config__ = [] #: [("name", "type", "desc", "default")] @@ -232,7 +232,7 @@ class Plugin(object): """ Fail and give reason """ - raise Fail(encode(reason)) #: Move to manager in 0.4.10 + raise Fail(encode(reason)) #: Move `encode(reason)` to manager in 0.4.10 def error(self, reason="", type=_("Parse")): @@ -246,7 +246,7 @@ class Plugin(object): raise Fail(msg) - def load(self, url, get={}, post={}, ref=True, cookies=True, just_header=False, decode=True, multipart=True, req=None): + def load(self, url, get={}, post={}, ref=True, cookies=True, just_header=False, decode=True, req=None): """ Load content at url and returns it @@ -276,7 +276,7 @@ class Plugin(object): else: req = self.pyload.requestFactory.getRequest(self.__name__) - res = req.load(url, get, post, ref, cookies, just_header, multipart, decode is True) + res = req.load(url, get, post, ref, cookies, just_header, isinstance(post, dict), decode is True) #@TODO: Fix network multipart in 0.4.10 if decode: #@TODO: Move to network in 0.4.10 res = html_unescape(res) @@ -310,7 +310,7 @@ class Plugin(object): value = value.strip() if key in header: - if type(header[key]) == list: + if type(header[key]) is list: header[key].append(value) else: header[key] = [header[key], value] -- cgit v1.2.3 From 761ca5c66e07559925ebbdbc6531f9ca658b12ce Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Fri, 24 Jul 2015 16:11:58 +0200 Subject: Code cosmetics --- module/plugins/internal/Plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index e70c099b1..9ac89501c 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -42,7 +42,7 @@ def timestamp(): def seconds_to_midnight(gmt=0): now = datetime.datetime.utcnow() + datetime.timedelta(hours=gmt) - if now.hour is 0 and now.minute < 10: + if now.hour == 0 and now.minute < 10: midnight = now else: midnight = now + datetime.timedelta(days=1) @@ -66,7 +66,7 @@ def replace_patterns(string, ruleslist): def set_cookies(cj, cookies): for cookie in cookies: - if isinstance(cookie, tuple) and len(cookie) is 3: + if isinstance(cookie, tuple) and len(cookie) == 3: domain, name, value = cookie cj.setCookie(domain, name, value) -- cgit v1.2.3 From a95c217627a1cb651b24e69f20640df40797aff9 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Sat, 25 Jul 2015 09:34:18 +0200 Subject: Account rewritten (2) --- module/plugins/internal/Plugin.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 9ac89501c..02ef326d6 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -5,6 +5,7 @@ from __future__ import with_statement import inspect import os import re +import traceback import urllib from module.plugins.Plugin import Abort, Fail, Reconnect, Retry, SkipDownload as Skip #@TODO: Remove in 0.4.10 @@ -80,12 +81,12 @@ def parse_html_form(attr_str, html, input_names={}): for form in re.finditer(r"(?P]*%s[^>]*>)(?P.*?)]*>" % attr_str, html, re.S | re.I): inputs = {} - action = parseHtmlTagAttrValue("action", form.group('TAG')) + action = parse_html_tag_attr_value("action", form.group('TAG')) for inputtag in re.finditer(r'(<(input|textarea)[^>]*>)([^<]*(?= `encode` in 0.4.10 - log("%(plugin)s%(id)s: %(msg)s" % {'plugin': self.__name__, - 'id' : ("[%s]" % self.pyfile.id) if hasattr(self, 'pyfile') else "", - 'msg' : msg or _(level.upper() + " MARK")}) + log("%(type)s %(plugin)s%(id)s: %(msg)s" % {'type': self.__type__.upper(), + 'plugin': self.__name__, + 'id' : ("[%s]" % self.pyfile.id) if hasattr(self, 'pyfile') else "", + 'msg' : msg or _(level.upper() + " MARK")}) def log_debug(self, *args): @@ -204,6 +206,7 @@ class Plugin(object): except KeyError: self.log_warning(_("Config option or plugin not found")) + traceback.print_exc() return default -- cgit v1.2.3 From 952001324e1faf584b1adcb01c4a0406a3722932 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Sat, 25 Jul 2015 09:42:49 +0200 Subject: =?UTF-8?q?Don't=20user=20dictionary=E2=80=99s=20iterator=20method?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module/plugins/internal/Plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 02ef326d6..7b3d03752 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -94,7 +94,7 @@ def parse_html_form(attr_str, html, input_names={}): if input_names: #: Check input attributes - for key, val in input_names.iteritems(): + for key, val in input_names.items(): if key in inputs: if isinstance(val, basestring) and inputs[key] is val: continue @@ -271,7 +271,7 @@ class Plugin(object): self.fail(_("No url given")) if self.pyload.debug: - self.log_debug("LOAD URL " + url, *["%s=%s" % (key, val) for key, val in locals().iteritems() if key not in ("self", "url")]) + self.log_debug("LOAD URL " + url, *["%s=%s" % (key, val) for key, val in locals().items() if key not in ("self", "url")]) if req is None: if hasattr(self, "req"): -- cgit v1.2.3 From f83389333ec10376452aa5f6d5ccd3963c6bafa1 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Mon, 27 Jul 2015 10:28:30 +0200 Subject: Update internal plugins --- module/plugins/internal/Plugin.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 7b3d03752..f88660f24 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -5,7 +5,6 @@ from __future__ import with_statement import inspect import os import re -import traceback import urllib from module.plugins.Plugin import Abort, Fail, Reconnect, Retry, SkipDownload as Skip #@TODO: Remove in 0.4.10 @@ -126,7 +125,7 @@ def chunks(iterable, size): class Plugin(object): __name__ = "Plugin" __type__ = "hoster" - __version__ = "0.13" + __version__ = "0.14" __status__ = "testing" __pattern__ = r'^unmatchable$' @@ -155,11 +154,11 @@ class Plugin(object): def _log(self, level, args): log = getattr(self.pyload.log, level) - msg = encode(" | ".join((a if isinstance(a, basestring) else str(a)).strip() for a in args if a)) #@NOTE: `fs_encode` -> `encode` in 0.4.10 - log("%(type)s %(plugin)s%(id)s: %(msg)s" % {'type': self.__type__.upper(), - 'plugin': self.__name__, - 'id' : ("[%s]" % self.pyfile.id) if hasattr(self, 'pyfile') else "", - 'msg' : msg or _(level.upper() + " MARK")}) + msg = encode(" | ".join((a if isinstance(a, basestring) else str(a)).strip() for a in args if a)) + log("%(type)s %(plugin)s%(id)s : %(msg)s" % {'type': self.__type__.upper(), + 'plugin': self.__name__, + 'id' : ("[%s]" % self.pyfile.id) if hasattr(self, 'pyfile') else "", + 'msg' : msg or "---------- MARK ----------"}) def log_debug(self, *args): @@ -205,8 +204,7 @@ class Plugin(object): return self.pyload.config.getPlugin(plugin or self.__name__, option) except KeyError: - self.log_warning(_("Config option or plugin not found")) - traceback.print_exc() + self.log_warning(_("Config option `%s` not found, use default `%s`") % (option, default or None)) return default @@ -271,7 +269,8 @@ class Plugin(object): self.fail(_("No url given")) if self.pyload.debug: - self.log_debug("LOAD URL " + url, *["%s=%s" % (key, val) for key, val in locals().items() if key not in ("self", "url")]) + self.log_debug("LOAD URL " + url, + *["%s=%s" % (key, val) for key, val in locals().items() if key not in ("self", "url")]) if req is None: if hasattr(self, "req"): -- cgit v1.2.3 From 34f48259060656077b5cb45edd8f9d92bb0282de Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Mon, 27 Jul 2015 20:19:03 +0200 Subject: Bunch of fixups --- module/plugins/internal/Plugin.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index f88660f24..e781ca297 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -29,6 +29,18 @@ def encode(string, encoding='utf8'): return string +#@TODO: Move to utils in 0.4.10 +def exists(path): + if os.path.exists(path): + if os.name == "nt": + dir, name = os.path.split(path) + return name in os.listdir(dir) + else: + return True + else: + return False + + #@TODO: Move to utils in 0.4.10 def fixurl(url): return html_unescape(urllib.unquote(url.decode('unicode-escape'))).strip() @@ -158,7 +170,7 @@ class Plugin(object): log("%(type)s %(plugin)s%(id)s : %(msg)s" % {'type': self.__type__.upper(), 'plugin': self.__name__, 'id' : ("[%s]" % self.pyfile.id) if hasattr(self, 'pyfile') else "", - 'msg' : msg or "---------- MARK ----------"}) + 'msg' : msg}) def log_debug(self, *args): @@ -290,7 +302,7 @@ class Plugin(object): frame = inspect.currentframe() framefile = fs_join("tmp", self.__name__, "%s_line%s.dump.html" % (frame.f_back.f_code.co_name, frame.f_back.f_lineno)) try: - if not os.path.exists(os.path.join("tmp", self.__name__)): + if not exists(os.path.join("tmp", self.__name__)): os.makedirs(os.path.join("tmp", self.__name__)) with open(framefile, "wb") as f: -- cgit v1.2.3 From 95ed76d34290e08876dccce6840c3e09138a2047 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Mon, 27 Jul 2015 23:47:47 +0200 Subject: Spare code fixes --- module/plugins/internal/Plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index e781ca297..52c22b527 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -245,7 +245,7 @@ class Plugin(object): """ Fail and give reason """ - raise Fail(encode(reason)) #: Move `encode(reason)` to manager in 0.4.10 + raise Fail(encode(reason)) #@TODO: Remove `encode` in 0.4.10 def error(self, reason="", type=_("Parse")): @@ -256,7 +256,7 @@ class Plugin(object): msg += (": %s" % reason.strip()) if reason else "" msg += _(" | Plugin may be out of date") - raise Fail(msg) + raise Fail(encode(msg)) #@TODO: Remove `encode` in 0.4.10 def load(self, url, get={}, post={}, ref=True, cookies=True, just_header=False, decode=True, req=None): -- cgit v1.2.3 From 6f387ff66b93e24cc52db7a5ea277265d35f051d Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Tue, 28 Jul 2015 00:29:19 +0200 Subject: Missed to bump up some plugin __version__ --- module/plugins/internal/Plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 52c22b527..fb62712fa 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -137,7 +137,7 @@ def chunks(iterable, size): class Plugin(object): __name__ = "Plugin" __type__ = "hoster" - __version__ = "0.14" + __version__ = "0.15" __status__ = "testing" __pattern__ = r'^unmatchable$' -- cgit v1.2.3 From ecf37227de05c73b7ffe2da89a5eda1259a72543 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Tue, 28 Jul 2015 01:09:59 +0200 Subject: Improve _log method --- module/plugins/internal/Plugin.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index fb62712fa..638a1ee1f 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -137,7 +137,7 @@ def chunks(iterable, size): class Plugin(object): __name__ = "Plugin" __type__ = "hoster" - __version__ = "0.15" + __version__ = "0.16" __status__ = "testing" __pattern__ = r'^unmatchable$' @@ -164,34 +164,35 @@ class Plugin(object): pass - def _log(self, level, args): + def _log(self, level, plugintype, pluginname, messages): log = getattr(self.pyload.log, level) - msg = encode(" | ".join((a if isinstance(a, basestring) else str(a)).strip() for a in args if a)) - log("%(type)s %(plugin)s%(id)s : %(msg)s" % {'type': self.__type__.upper(), - 'plugin': self.__name__, - 'id' : ("[%s]" % self.pyfile.id) if hasattr(self, 'pyfile') else "", - 'msg' : msg}) + msg = encode(" | ".join((a if isinstance(a, basestring) else str(a)).strip() for a in messages if a)) + log("%(plugintype)s %(pluginname)s%(id)s : %(msg)s" + % {'plugintype': plugintype.upper(), + 'pluginname': pluginname, + 'id' : ("[%s]" % self.pyfile.id) if hasattr(self, 'pyfile') else "", + 'msg' : msg}) def log_debug(self, *args): if self.pyload.debug: - return self._log("debug", args) + return self._log("debug", self.__type__, self.__name__, args) def log_info(self, *args): - return self._log("info", args) + return self._log("info", self.__type__, self.__name__, args) def log_warning(self, *args): - return self._log("warning", args) + return self._log("warning", self.__type__, self.__name__, args) def log_error(self, *args): - return self._log("error", args) + return self._log("error", self.__type__, self.__name__, args) def log_critical(self, *args): - return self._log("critical", args) + return self._log("critical", self.__type__, self.__name__, args) def set_config(self, option, value): -- cgit v1.2.3 From e42f5783442fcbaa53e6c0faf943dd33c397e0b3 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Wed, 29 Jul 2015 08:40:17 +0200 Subject: Fix _log method --- module/plugins/internal/Plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 638a1ee1f..84dd5bdd4 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -137,7 +137,7 @@ def chunks(iterable, size): class Plugin(object): __name__ = "Plugin" __type__ = "hoster" - __version__ = "0.16" + __version__ = "0.17" __status__ = "testing" __pattern__ = r'^unmatchable$' @@ -167,7 +167,7 @@ class Plugin(object): def _log(self, level, plugintype, pluginname, messages): log = getattr(self.pyload.log, level) msg = encode(" | ".join((a if isinstance(a, basestring) else str(a)).strip() for a in messages if a)) - log("%(plugintype)s %(pluginname)s%(id)s : %(msg)s" + log("%(plugintype)s %(pluginname)s%(id)s: %(msg)s" % {'plugintype': plugintype.upper(), 'pluginname': pluginname, 'id' : ("[%s]" % self.pyfile.id) if hasattr(self, 'pyfile') else "", -- cgit v1.2.3 From e91d1b7b50c97fdbec0f99c071d3fd19b25e57bc Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Wed, 29 Jul 2015 12:23:29 +0200 Subject: [Plugin] Fix set_cookies --- module/plugins/internal/Plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 84dd5bdd4..0049826da 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -80,7 +80,7 @@ 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) + cj.setCookie(domain, name, encode(value)) #@TODO: Remove `encode` in 0.4.10 def parse_html_tag_attr_value(attr_name, tag): @@ -137,7 +137,7 @@ def chunks(iterable, size): class Plugin(object): __name__ = "Plugin" __type__ = "hoster" - __version__ = "0.17" + __version__ = "0.18" __status__ = "testing" __pattern__ = r'^unmatchable$' -- cgit v1.2.3 From dc27f688159b11188f5db4914ff8324e0d633dec Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Wed, 29 Jul 2015 17:38:15 +0200 Subject: Fix https://github.com/pyload/pyload/issues/1602 --- module/plugins/internal/Plugin.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 0049826da..76056c66d 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -2,6 +2,7 @@ from __future__ import with_statement +import datetime import inspect import os import re @@ -137,7 +138,7 @@ def chunks(iterable, size): class Plugin(object): __name__ = "Plugin" __type__ = "hoster" - __version__ = "0.18" + __version__ = "0.19" __status__ = "testing" __pattern__ = r'^unmatchable$' -- cgit v1.2.3 From 91e0803c1f47444072ca7381d789a8e98160ae78 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Wed, 29 Jul 2015 21:11:29 +0200 Subject: Still improving _log methods --- module/plugins/internal/Plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 76056c66d..59528a441 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -168,7 +168,7 @@ class Plugin(object): def _log(self, level, plugintype, pluginname, messages): log = getattr(self.pyload.log, level) msg = encode(" | ".join((a if isinstance(a, basestring) else str(a)).strip() for a in messages if a)) - log("%(plugintype)s %(pluginname)s%(id)s: %(msg)s" + log("%(plugintype)s %(pluginname)s%(id)s : %(msg)s" % {'plugintype': plugintype.upper(), 'pluginname': pluginname, 'id' : ("[%s]" % self.pyfile.id) if hasattr(self, 'pyfile') else "", -- cgit v1.2.3 From 88f98ab3bd6e091c1b6ca6ac9fddc37b2e29694c Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Thu, 30 Jul 2015 14:37:44 +0200 Subject: Fix get_code call in captcha hooks --- module/plugins/internal/Plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 59528a441..76056c66d 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -168,7 +168,7 @@ class Plugin(object): def _log(self, level, plugintype, pluginname, messages): log = getattr(self.pyload.log, level) msg = encode(" | ".join((a if isinstance(a, basestring) else str(a)).strip() for a in messages if a)) - log("%(plugintype)s %(pluginname)s%(id)s : %(msg)s" + log("%(plugintype)s %(pluginname)s%(id)s: %(msg)s" % {'plugintype': plugintype.upper(), 'pluginname': pluginname, 'id' : ("[%s]" % self.pyfile.id) if hasattr(self, 'pyfile') else "", -- cgit v1.2.3 From 092112b44af84c7a59b1fa2cfff5c5875e778a8f Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Fri, 31 Jul 2015 02:21:35 +0200 Subject: Fix https://github.com/pyload/pyload/issues/1625 --- module/plugins/internal/Plugin.py | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 76056c66d..70494561c 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -138,7 +138,7 @@ def chunks(iterable, size): class Plugin(object): __name__ = "Plugin" __type__ = "hoster" - __version__ = "0.19" + __version__ = "0.20" __status__ = "testing" __pattern__ = r'^unmatchable$' @@ -196,6 +196,37 @@ class Plugin(object): return self._log("critical", self.__type__, self.__name__, args) + def set_permissions(self, path): + if not os.path.exists(path): + return + + try: + if self.pyload.config.get("permission", "change_file"): + if os.path.isfile(path): + os.chmod(path, int(self.pyload.config.get("permission", "file"), 8)) + + elif os.path.isdir(path): + os.chmod(path, int(self.pyload.config.get("permission", "folder"), 8)) + + except OSError, e: + self.log_warning(_("Setting path mode failed"), e) + + try: + if os.name != "nt" and self.pyload.config.get("permission", "change_dl"): + uid = pwd.getpwnam(self.pyload.config.get("permission", "user"))[2] + gid = grp.getgrnam(self.pyload.config.get("permission", "group"))[2] + os.chown(path, uid, gid) + + except OSError, e: + self.log_warning(_("Setting owner and group failed"), e) + + + def get_chunk_count(self): + if self.chunk_limit <= 0: + return self.pyload.config.get("download", "chunks") + return min(self.pyload.config.get("download", "chunks"), self.chunk_limit) + + def set_config(self, option, value): """ Set config value for current plugin -- cgit v1.2.3 From e3799bcb0731e8cdf4d3f86ae6ee67e9cc5e4d80 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Fri, 31 Jul 2015 06:35:21 +0200 Subject: Fix https://github.com/pyload/pyload/issues/1601 --- module/plugins/internal/Plugin.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 70494561c..159668c28 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -138,7 +138,7 @@ def chunks(iterable, size): class Plugin(object): __name__ = "Plugin" __type__ = "hoster" - __version__ = "0.20" + __version__ = "0.21" __status__ = "testing" __pattern__ = r'^unmatchable$' @@ -292,7 +292,7 @@ class Plugin(object): raise Fail(encode(msg)) #@TODO: Remove `encode` in 0.4.10 - def load(self, url, get={}, post={}, ref=True, cookies=True, just_header=False, decode=True, req=None): + def load(self, url, get={}, post={}, ref=True, cookies=True, just_header=False, decode=True, multipart=False, req=None): """ Load content at url and returns it @@ -323,7 +323,7 @@ class Plugin(object): else: req = self.pyload.requestFactory.getRequest(self.__name__) - res = req.load(url, get, post, ref, cookies, just_header, isinstance(post, dict), decode is True) #@TODO: Fix network multipart in 0.4.10 + res = req.load(url, get, post, ref, cookies, just_header, multipart, decode is True) #@TODO: Fix network multipart in 0.4.10 if decode: #@TODO: Move to network in 0.4.10 res = html_unescape(res) -- cgit v1.2.3 From 8a8323f3fd86985a5ca876e8d54f1699e75b24a8 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Fri, 31 Jul 2015 07:37:10 +0200 Subject: Fix https://github.com/pyload/pyload/issues/1628 --- module/plugins/internal/Plugin.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 159668c28..fa0ccaadd 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -8,6 +8,10 @@ import os import re import urllib +if os.name != "nt": + import grp + import pwd + from module.plugins.Plugin import Abort, Fail, Reconnect, Retry, SkipDownload as Skip #@TODO: Remove in 0.4.10 from module.utils import fs_encode, fs_decode, html_unescape, save_join as fs_join @@ -138,7 +142,7 @@ def chunks(iterable, size): class Plugin(object): __name__ = "Plugin" __type__ = "hoster" - __version__ = "0.21" + __version__ = "0.22" __status__ = "testing" __pattern__ = r'^unmatchable$' -- cgit v1.2.3 From 6108c417fa3eb049c839310d0894b11511d3f986 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Fri, 31 Jul 2015 10:57:49 +0200 Subject: Fix https://github.com/pyload/pyload/issues/1632 --- module/plugins/internal/Plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index fa0ccaadd..d3cc4bbc4 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -142,7 +142,7 @@ def chunks(iterable, size): class Plugin(object): __name__ = "Plugin" __type__ = "hoster" - __version__ = "0.22" + __version__ = "0.23" __status__ = "testing" __pattern__ = r'^unmatchable$' @@ -253,7 +253,7 @@ class Plugin(object): return self.pyload.config.getPlugin(plugin or self.__name__, option) except KeyError: - self.log_warning(_("Config option `%s` not found, use default `%s`") % (option, default or None)) + self.log_debug("Config option `%s` not found, use default `%s`" % (option, default or None)) #@TODO: Restore to `log_warning` in 0.4.10 return default -- cgit v1.2.3 From b0d9532f675854a6a32d22f7b6b7b4cd32683443 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Sun, 2 Aug 2015 07:10:51 +0200 Subject: Fix https://github.com/pyload/pyload/issues/1640 --- module/plugins/internal/Plugin.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index d3cc4bbc4..3d53b7d2d 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -142,7 +142,7 @@ def chunks(iterable, size): class Plugin(object): __name__ = "Plugin" __type__ = "hoster" - __version__ = "0.23" + __version__ = "0.24" __status__ = "testing" __pattern__ = r'^unmatchable$' @@ -159,6 +159,7 @@ class Plugin(object): def __init__(self, core): self.pyload = core self.info = {} #: Provide information in dict here + self.req = None self.init() @@ -322,10 +323,7 @@ class Plugin(object): *["%s=%s" % (key, val) for key, val in locals().items() if key not in ("self", "url")]) if req is None: - if hasattr(self, "req"): - req = self.req - else: - req = self.pyload.requestFactory.getRequest(self.__name__) + req = self.req or self.pyload.requestFactory.getRequest(self.__name__) res = req.load(url, get, post, ref, cookies, just_header, multipart, decode is True) #@TODO: Fix network multipart in 0.4.10 @@ -370,3 +368,17 @@ class Plugin(object): res = header return res + + + def clean(self): + """ + Clean everything and remove references + """ + for a in ("pyfile", "thread", "html"): + if hasattr(self, a): + setattr(self, a, None) + + try: + self.req.close() + finally: + self.req = None -- cgit v1.2.3 From 84f2193d76f7c6f47c834dc8902d8ead8e45a11a Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Sun, 2 Aug 2015 07:44:07 +0200 Subject: Fix https://github.com/pyload/pyload/issues/1640 (2) --- module/plugins/internal/Plugin.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 3d53b7d2d..601acd491 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -142,7 +142,7 @@ def chunks(iterable, size): class Plugin(object): __name__ = "Plugin" __type__ = "hoster" - __version__ = "0.24" + __version__ = "0.25" __status__ = "testing" __pattern__ = r'^unmatchable$' @@ -157,10 +157,14 @@ class Plugin(object): def __init__(self, core): + self._init(core) + self.init() + + + def _init(self, core): self.pyload = core self.info = {} #: Provide information in dict here self.req = None - self.init() def init(self): -- cgit v1.2.3 From 539d2bc721a7363786da06b43de065f1405a61a0 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Sun, 2 Aug 2015 09:25:41 +0200 Subject: Fix https://github.com/pyload/pyload/issues/1640 (3) --- module/plugins/internal/Plugin.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 601acd491..570c984ac 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -142,7 +142,7 @@ def chunks(iterable, size): class Plugin(object): __name__ = "Plugin" __type__ = "hoster" - __version__ = "0.25" + __version__ = "0.26" __status__ = "testing" __pattern__ = r'^unmatchable$' @@ -378,11 +378,11 @@ class Plugin(object): """ Clean everything and remove references """ - for a in ("pyfile", "thread", "html"): - if hasattr(self, a): - setattr(self, a, None) - try: self.req.close() - finally: - self.req = None + except Exception: + pass + + for a in ("pyfile", "thread", "html", "req"): + if hasattr(self, a): + setattr(self, a, None) -- cgit v1.2.3 From 5e15580202c44628f2fbfabad0c3f693975fb3c9 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Sun, 2 Aug 2015 17:13:17 +0200 Subject: Fix https://github.com/pyload/pyload/issues/1663 --- module/plugins/internal/Plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 570c984ac..ac6b4a57e 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -48,7 +48,7 @@ def exists(path): #@TODO: Move to utils in 0.4.10 def fixurl(url): - return html_unescape(urllib.unquote(url.decode('unicode-escape'))).strip() + return html_unescape(urllib.unquote(url.decode('unicode-escape'))).strip().rstrip('/') #@TODO: Move to utils in 0.4.10 @@ -142,7 +142,7 @@ def chunks(iterable, size): class Plugin(object): __name__ = "Plugin" __type__ = "hoster" - __version__ = "0.26" + __version__ = "0.27" __status__ = "testing" __pattern__ = r'^unmatchable$' -- cgit v1.2.3 From 9cb6b5d05ddcc15148bd5fab0fe02978159cfef5 Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Sun, 2 Aug 2015 17:23:46 +0200 Subject: Tiny fixes --- module/plugins/internal/Plugin.py | 1 + 1 file changed, 1 insertion(+) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index ac6b4a57e..62eb17aa6 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -347,6 +347,7 @@ class Plugin(object): with open(framefile, "wb") as f: del frame #: Delete the frame or it wont be cleaned f.write(encode(res)) + except IOError, e: self.log_error(e) -- cgit v1.2.3 From e5ce0acf056dc96c40d5616ab6d2b82f998eefbe Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Mon, 3 Aug 2015 00:37:57 +0200 Subject: Use set_cookie instead cj.setCookie --- module/plugins/internal/Plugin.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 62eb17aa6..99b5751e5 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -81,11 +81,15 @@ def replace_patterns(string, ruleslist): return string +#@TODO: Remove in 0.4.10 and fix CookieJar.setCookie +def set_cookie(cj, domain, name, value): + return cj.setCookie(domain, name, encode(value)) + + 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, encode(value)) #@TODO: Remove `encode` in 0.4.10 + set_cookie(cj, *cookie) def parse_html_tag_attr_value(attr_name, tag): @@ -142,7 +146,7 @@ def chunks(iterable, size): class Plugin(object): __name__ = "Plugin" __type__ = "hoster" - __version__ = "0.27" + __version__ = "0.28" __status__ = "testing" __pattern__ = r'^unmatchable$' @@ -329,12 +333,18 @@ class Plugin(object): if req is None: req = self.req or self.pyload.requestFactory.getRequest(self.__name__) - res = req.load(url, get, post, ref, cookies, just_header, multipart, decode is True) #@TODO: Fix network multipart in 0.4.10 + #@TODO: Move to network in 0.4.10 + if isinstance(self.COOKIES, list): + set_cookies(req.cj, cookies) + + res = req.load(url, get, post, ref, bool(cookies), just_header, multipart, decode is True) #@TODO: Fix network multipart in 0.4.10 - if decode: #@TODO: Move to network in 0.4.10 + #@TODO: Move to network in 0.4.10 + if decode: res = html_unescape(res) - if isinstance(decode, basestring): #@TODO: Move to network in 0.4.10 + #@TODO: Move to network in 0.4.10 + if isinstance(decode, basestring): res = decode(res, decode) if self.pyload.debug: -- cgit v1.2.3 From f2416468c89af6064b07ee51384818502ae54b05 Mon Sep 17 00:00:00 2001 From: GammaC0de Date: Mon, 3 Aug 2015 21:27:55 +0300 Subject: Update Plugin.py --- module/plugins/internal/Plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 99b5751e5..7d1fea1e3 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -146,7 +146,7 @@ def chunks(iterable, size): class Plugin(object): __name__ = "Plugin" __type__ = "hoster" - __version__ = "0.28" + __version__ = "0.29" __status__ = "testing" __pattern__ = r'^unmatchable$' @@ -334,7 +334,7 @@ class Plugin(object): req = self.req or self.pyload.requestFactory.getRequest(self.__name__) #@TODO: Move to network in 0.4.10 - if isinstance(self.COOKIES, list): + if hasattr(self, COOKIES) and isinstance(self.COOKIES, list): set_cookies(req.cj, cookies) res = req.load(url, get, post, ref, bool(cookies), just_header, multipart, decode is True) #@TODO: Fix network multipart in 0.4.10 -- cgit v1.2.3 From 967f6d917fa1c7a70958528d0de918a13f91d16b Mon Sep 17 00:00:00 2001 From: GammaC0de Date: Mon, 3 Aug 2015 21:35:31 +0300 Subject: Update Plugin.py --- module/plugins/internal/Plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 7d1fea1e3..971bf7bed 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -334,7 +334,7 @@ class Plugin(object): req = self.req or self.pyload.requestFactory.getRequest(self.__name__) #@TODO: Move to network in 0.4.10 - if hasattr(self, COOKIES) and isinstance(self.COOKIES, list): + if hasattr(self, 'COOKIES') and isinstance(self.COOKIES, list): set_cookies(req.cj, cookies) res = req.load(url, get, post, ref, bool(cookies), just_header, multipart, decode is True) #@TODO: Fix network multipart in 0.4.10 -- cgit v1.2.3 From 459bd7482a67334e91a753adba1741181d634291 Mon Sep 17 00:00:00 2001 From: GammaC0de Date: Mon, 3 Aug 2015 23:22:15 +0300 Subject: Update Plugin.py --- module/plugins/internal/Plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 971bf7bed..5f70a292d 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -335,7 +335,7 @@ class Plugin(object): #@TODO: Move to network in 0.4.10 if hasattr(self, 'COOKIES') and isinstance(self.COOKIES, list): - set_cookies(req.cj, cookies) + set_cookies(req.cj, self.COOKIES) res = req.load(url, get, post, ref, bool(cookies), just_header, multipart, decode is True) #@TODO: Fix network multipart in 0.4.10 -- cgit v1.2.3 From 2cf928db10224b5327f918dceaa13273753620ac Mon Sep 17 00:00:00 2001 From: Walter Purcaro Date: Tue, 4 Aug 2015 18:06:42 +0200 Subject: Some fixes --- module/plugins/internal/Plugin.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'module/plugins/internal/Plugin.py') diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 5f70a292d..7b45c40a8 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -146,7 +146,7 @@ def chunks(iterable, size): class Plugin(object): __name__ = "Plugin" __type__ = "hoster" - __version__ = "0.29" + __version__ = "0.30" __status__ = "testing" __pattern__ = r'^unmatchable$' @@ -334,8 +334,8 @@ class Plugin(object): req = self.req or self.pyload.requestFactory.getRequest(self.__name__) #@TODO: Move to network in 0.4.10 - if hasattr(self, 'COOKIES') and isinstance(self.COOKIES, list): - set_cookies(req.cj, self.COOKIES) + if isinstance(cookies, list): + set_cookies(req.cj, cookies) res = req.load(url, get, post, ref, bool(cookies), just_header, multipart, decode is True) #@TODO: Fix network multipart in 0.4.10 -- cgit v1.2.3