diff options
Diffstat (limited to 'module/plugins/hooks')
34 files changed, 566 insertions, 767 deletions
diff --git a/module/plugins/hooks/AndroidPhoneNotify.py b/module/plugins/hooks/AndroidPhoneNotify.py index cc7fe8d6b..5a5188365 100644 --- a/module/plugins/hooks/AndroidPhoneNotify.py +++ b/module/plugins/hooks/AndroidPhoneNotify.py @@ -6,19 +6,22 @@ from module.plugins.internal.Notifier import Notifier class AndroidPhoneNotify(Notifier): __name__ = "AndroidPhoneNotify" __type__ = "hook" - __version__ = "0.13" + __version__ = "0.15" __status__ = "testing" - __config__ = [("activated" , "bool", "Activated" , False), - ("apikey" , "str" , "API key" , "" ), - ("notifycaptcha" , "bool", "Notify captcha request" , True ), - ("notifypackage" , "bool", "Notify package finished" , True ), - ("notifyprocessed", "bool", "Notify packages processed" , True ), - ("notifyupdate" , "bool", "Notify plugin updates" , True ), - ("notifyexit" , "bool", "Notify pyLoad shutdown" , True ), - ("sendtimewait" , "int" , "Timewait in seconds between notifications", 5 ), - ("sendpermin" , "int" , "Max notifications per minute" , 12 ), - ("ignoreclient" , "bool", "Send notifications if client is connected", False)] + __config__ = [("activated" , "bool", "Activated" , False), + ("apikey" , "str" , "API key" , "" ), + ("captcha" , "bool", "Notify captcha request" , True ), + ("reconnection" , "bool", "Notify reconnection request" , False), + ("downloadfinished", "bool", "Notify download finished" , True ), + ("downloadfailed" , "bool", "Notify download failed" , True ), + ("packagefinished" , "bool", "Notify package finished" , True ), + ("packagefailed" , "bool", "Notify package failed" , True ), + ("update" , "bool", "Notify pyLoad update" , False), + ("exit" , "bool", "Notify pyLoad shutdown/restart" , False), + ("sendinterval" , "int" , "Interval in seconds between notifications", 1 ), + ("sendpermin" , "int" , "Max notifications per minute" , 60 ), + ("ignoreclient" , "bool", "Send notifications if client is connected", True )] __description__ = """Send push notifications to your Android Phone using notifymyandroid.com""" __license__ = "GPLv3" @@ -27,7 +30,7 @@ class AndroidPhoneNotify(Notifier): def get_key(self): - return self.get_config('apikey') + return self.config.get('apikey') def send(self, event, msg, key): diff --git a/module/plugins/hooks/AntiStandby.py b/module/plugins/hooks/AntiStandby.py index 5ad95d6e8..2159e5937 100644 --- a/module/plugins/hooks/AntiStandby.py +++ b/module/plugins/hooks/AntiStandby.py @@ -13,7 +13,7 @@ except ImportError: pass from module.plugins.internal.Addon import Addon, Expose -from module.plugins.internal.utils import encode, fs_join +from module.plugins.internal.misc import encode, fsjoin class Kernel32(object): @@ -27,7 +27,7 @@ class Kernel32(object): class AntiStandby(Addon): __name__ = "AntiStandby" __type__ = "hook" - __version__ = "0.13" + __version__ = "0.14" __status__ = "testing" __config__ = [("activated", "bool", "Activated" , True ), @@ -50,12 +50,12 @@ class AntiStandby(Addon): def activate(self): - hdd = self.get_config('hdd') - system = not self.get_config('system') - display = not self.get_config('display') + hdd = self.config.get('hdd') + system = not self.config.get('system') + display = not self.config.get('display') if hdd: - self.start_periodical(self.get_config('interval'), threaded=True) + self.periodical.start(self.config.get('interval'), threaded=True) if os.name is "nt": self.win_standby(system, display) @@ -68,11 +68,7 @@ class AntiStandby(Addon): def deactivate(self): - try: - os.remove(self.TMP_FILE) - - except OSError: - pass + self.remove(self.TMP_FILE, trash=False) if os.name is "nt": self.win_standby(True) @@ -152,22 +148,22 @@ class AntiStandby(Addon): @Expose def max_mtime(self, path): return max(0, 0, - *(os.path.getmtime(fs_join(root, file)) + *(os.path.getmtime(fsjoin(root, file)) for root, dirs, files in os.walk(encode(path), topdown=False) for file in files)) - def periodical(self): - if self.get_config('hdd') is False: + def periodical_task(self): + if self.config.get('hdd') is False: return if (self.pyload.threadManager.pause or - not self.pyload.api.isTimeDownload() or - not self.pyload.threadManager.getActiveFiles()): + not self.pyload.api.isTimeDownload() or + not self.pyload.threadManager.getActiveFiles()): return dl_folder = self.pyload.config.get("general", "download_folder") - if (self.max_mtime(dl_folder) - self.mtime) < self.interval: + if (self.max_mtime(dl_folder) - self.mtime) < self.periodical.interval: return self.touch(self.TMP_FILE) diff --git a/module/plugins/hooks/AntiVirus.py b/module/plugins/hooks/AntiVirus.py index 049e92ab8..1a0f3f8bd 100644 --- a/module/plugins/hooks/AntiVirus.py +++ b/module/plugins/hooks/AntiVirus.py @@ -10,14 +10,14 @@ except ImportError: pass from module.plugins.internal.Addon import Addon, Expose, threaded -from module.plugins.internal.utils import encode, exists, fs_join +from module.plugins.internal.misc import encode, exists, fsjoin class AntiVirus(Addon): __name__ = "AntiVirus" __type__ = "hook" - __version__ = "0.15" - __status__ = "testing" + __version__ = "0.16" + __status__ = "broken" #@TODO: add trash option (use Send2Trash lib) __config__ = [("activated" , "bool" , "Activated" , False ), @@ -38,18 +38,18 @@ class AntiVirus(Addon): @Expose @threaded def scan(self, pyfile, thread): - avfile = encode(self.get_config('avfile')) - avargs = encode(self.get_config('avargs').strip()) + avfile = encode(self.config.get('avfile')) + avargs = encode(self.config.get('avargs').strip()) if not os.path.isfile(avfile): self.fail(_("Antivirus executable not found")) - scanfolder = self.get_config('avtarget') is "folder" + scanfolder = self.config.get('avtarget') is "folder" if scanfolder: dl_folder = self.pyload.config.get("general", "download_folder") package_folder = pyfile.package().folder if self.pyload.config.get("general", "folder_per_package") else "" - target = fs_join(dl_folder, package_folder, pyfile.name) + target = fsjoin(dl_folder, package_folder, pyfile.name) target_repr = "Folder: " + package_folder or dl_folder else: target = encode(pyfile.plugin.last_download) @@ -75,12 +75,12 @@ class AntiVirus(Addon): if err: self.log_warning(target_repr, err) - if not self.get_config('ignore-err'): + if not self.config.get('ignore-err'): self.log_debug("Delete/Quarantine task aborted due scan error") return if p.returncode: - action = self.get_config('action') + action = self.config.get('action') if scanfolder: if action is "Antivirus default": @@ -91,7 +91,7 @@ class AntiVirus(Addon): try: if action is "Delete": - if not self.get_config('deltotrash'): + if not self.config.get('deltotrash'): os.remove(file) else: @@ -101,19 +101,19 @@ class AntiVirus(Addon): except NameError: self.log_warning(_("Send2Trash lib not found, moving to quarantine instead")) pyfile.setCustomStatus(_("file moving")) - shutil.move(file, self.get_config('quardir')) + shutil.move(file, self.config.get('quardir')) except Exception, e: self.log_warning(_("Unable to move file to trash: %s, moving to quarantine instead") % e.message) pyfile.setCustomStatus(_("file moving")) - shutil.move(file, self.get_config('quardir')) + shutil.move(file, self.config.get('quardir')) else: self.log_debug("Successfully moved file to trash") elif action is "Quarantine": pyfile.setCustomStatus(_("file moving")) - shutil.move(file, self.get_config('quardir')) + shutil.move(file, self.config.get('quardir')) except (IOError, shutil.Error), e: self.log_error(target_repr, action + " action failed!", e) @@ -132,5 +132,5 @@ class AntiVirus(Addon): def download_failed(self, pyfile): #: Check if pyfile is still "failed", maybe might has been restarted in meantime - if pyfile.status is 8 and self.get_config('scanfailed'): + if pyfile.status is 8 and self.config.get('scanfailed'): return self.scan(pyfile) diff --git a/module/plugins/hooks/BypassCaptcha.py b/module/plugins/hooks/BypassCaptcha.py index 581d2f6dd..bc28b1469 100644 --- a/module/plugins/hooks/BypassCaptcha.py +++ b/module/plugins/hooks/BypassCaptcha.py @@ -28,7 +28,7 @@ class BypassCaptchaException(Exception): class BypassCaptcha(Addon): __name__ = "BypassCaptcha" __type__ = "hook" - __version__ = "0.09" + __version__ = "0.10" __status__ = "testing" __config__ = [("activated" , "bool" , "Activated" , False), @@ -50,7 +50,7 @@ class BypassCaptcha(Addon): def get_credits(self): - res = self.load(self.GETCREDITS_URL, post={'key': self.get_config('passkey')}) + res = self.load(self.GETCREDITS_URL, post={'key': self.config.get('passkey')}) data = dict(x.split(' ', 1) for x in res.splitlines()) return int(data['Left']) @@ -65,7 +65,7 @@ class BypassCaptcha(Addon): try: res = self.load(self.SUBMIT_URL, post={'vendor_key': self.PYLOAD_KEY, - 'key': self.get_config('passkey'), + 'key': self.config.get('passkey'), 'gen_task_id': "1", 'file': (pycurl.FORM_FILE, captcha)}, req=req) @@ -85,7 +85,7 @@ class BypassCaptcha(Addon): def respond(self, ticket, success): try: - res = self.load(self.RESPOND_URL, post={'task_id': ticket, 'key': self.get_config('passkey'), + res = self.load(self.RESPOND_URL, post={'task_id': ticket, 'key': self.config.get('passkey'), 'cv': 1 if success else 0}) except BadHeader, e: self.log_error(_("Could not send response"), e) @@ -98,10 +98,10 @@ class BypassCaptcha(Addon): if not task.isTextual(): return False - if not self.get_config('passkey'): + if not self.config.get('passkey'): return False - if self.pyload.isClientConnected() and self.get_config('check_client'): + if self.pyload.isClientConnected() and self.config.get('check_client'): return False if self.get_credits() > 0: diff --git a/module/plugins/hooks/Captcha9Kw.py b/module/plugins/hooks/Captcha9Kw.py index c81882f67..714be8bc4 100644 --- a/module/plugins/hooks/Captcha9Kw.py +++ b/module/plugins/hooks/Captcha9Kw.py @@ -2,11 +2,10 @@ from __future__ import with_statement +import base64 import re import time -from base64 import b64encode - from module.network.HTTPRequest import BadHeader from module.plugins.internal.Addon import Addon, threaded @@ -14,7 +13,7 @@ from module.plugins.internal.Addon import Addon, threaded class Captcha9Kw(Addon): __name__ = "Captcha9Kw" __type__ = "hook" - __version__ = "0.31" + __version__ = "0.32" __status__ = "testing" __config__ = [("activated" , "bool" , "Activated" , False ), @@ -40,7 +39,7 @@ class Captcha9Kw(Addon): def get_credits(self): res = self.load(self.API_URL, - get={'apikey': self.get_config('passkey'), + get={'apikey': self.config.get('passkey'), 'pyload': "1", 'source': "pyload", 'action': "usercaptchaguthaben"}) @@ -71,14 +70,14 @@ class Captcha9Kw(Addon): 'numeric' : 0, 'case_sensitive': 0, 'math' : 0, - 'prio' : min(max(self.get_config('prio'), 0), 10), - 'confirm' : self.get_config('confirm'), - 'timeout' : min(max(self.get_config('timeout'), 300), 3999), - 'selfsolve' : self.get_config('selfsolve'), - 'cph' : self.get_config('captchaperhour'), - 'cpm' : self.get_config('captchapermin')} - - for opt in str(self.get_config('hoster_options').split('|')): + 'prio' : min(max(self.config.get('prio'), 0), 10), + 'confirm' : self.config.get('confirm'), + 'timeout' : min(max(self.config.get('timeout'), 300), 3999), + 'selfsolve' : self.config.get('selfsolve'), + 'cph' : self.config.get('captchaperhour'), + 'cpm' : self.config.get('captchapermin')} + + for opt in str(self.config.get('hoster_options').split('|')): details = map(str.strip, opt.split(':')) if not details or details[0].lower() is not pluginname.lower(): @@ -96,7 +95,7 @@ class Captcha9Kw(Addon): break - post_data = {'apikey' : self.get_config('passkey'), + post_data = {'apikey' : self.config.get('passkey'), 'prio' : option['prio'], 'confirm' : option['confirm'], 'maxtimeout' : option['timeout'], @@ -114,7 +113,7 @@ class Captcha9Kw(Addon): 'source' : "pyload", 'base64' : 1, 'mouse' : 1 if task.isPositional() else 0, - 'file-upload-01': b64encode(data), + 'file-upload-01': base64.b64encode(data), 'action' : "usercaptchaupload"} for _i in xrange(5): @@ -136,9 +135,9 @@ class Captcha9Kw(Addon): task.data['ticket'] = res - for _i in xrange(int(self.get_config('timeout') / 5)): + for _i in xrange(int(self.config.get('timeout') / 5)): result = self.load(self.API_URL, - get={'apikey': self.get_config('passkey'), + get={'apikey': self.config.get('passkey'), 'id' : res, 'pyload': "1", 'info' : "1", @@ -163,10 +162,10 @@ class Captcha9Kw(Addon): if not task.isTextual() and not task.isPositional(): return - if not self.get_config('passkey'): + if not self.config.get('passkey'): return - if self.pyload.isClientConnected() and self.get_config('check_client'): + if self.pyload.isClientConnected() and self.config.get('check_client'): return credits = self.get_credits() @@ -175,8 +174,8 @@ class Captcha9Kw(Addon): self.log_error(_("Your captcha 9kw.eu account has not enough credits")) return - queue = min(self.get_config('queue'), 999) - timeout = min(max(self.get_config('timeout'), 300), 3999) + queue = min(self.config.get('queue'), 999) + timeout = min(max(self.config.get('timeout'), 300), 3999) pluginname = re.search(r'_(.+?)_\d+.\w+', task.captchaFile).group(1) for _i in xrange(5): @@ -189,7 +188,7 @@ class Captcha9Kw(Addon): else: self.fail(_("Too many captchas in queue")) - for opt in str(self.get_config('hoster_options').split('|')): + for opt in str(self.config.get('hoster_options').split('|')): details = map(str.strip, opt.split(':')) if not details or details[0].lower() is not pluginname.lower(): @@ -219,7 +218,7 @@ class Captcha9Kw(Addon): self.log_debug("No CaptchaID for %s request (task: %s)" % (type, task)) return - passkey = self.get_config('passkey') + passkey = self.config.get('passkey') for _i in xrange(3): res = self.load(self.API_URL, diff --git a/module/plugins/hooks/CaptchaBrotherhood.py b/module/plugins/hooks/CaptchaBrotherhood.py index 5334c1c5b..15546c63f 100644 --- a/module/plugins/hooks/CaptchaBrotherhood.py +++ b/module/plugins/hooks/CaptchaBrotherhood.py @@ -3,10 +3,11 @@ from __future__ import with_statement import StringIO -import pycurl import time import urllib +import pycurl + try: from PIL import Image @@ -38,7 +39,7 @@ class CaptchaBrotherhoodException(Exception): class CaptchaBrotherhood(Addon): __name__ = "CaptchaBrotherhood" __type__ = "hook" - __version__ = "0.11" + __version__ = "0.12" __status__ = "testing" __config__ = [("activated" , "bool" , "Activated" , False), @@ -57,7 +58,7 @@ class CaptchaBrotherhood(Addon): def get_credits(self): res = self.load(self.API_URL + "askCredits.aspx", - get={'username': self.get_config('username'), 'password': self.get_config('password')}) + get={'username': self.config.get('username'), 'password': self.config.get('password')}) if not res.startswith("OK"): raise CaptchaBrotherhoodException(res) else: @@ -87,8 +88,8 @@ class CaptchaBrotherhood(Addon): req = get_request() url = "%ssendNewCaptcha.aspx?%s" % (self.API_URL, - urllib.urlencode({'username' : self.get_config('username'), - 'password' : self.get_config('password'), + urllib.urlencode({'username' : self.config.get('username'), + 'password' : self.config.get('password'), 'captchaSource': "pyLoad", 'timeout' : "80"})) @@ -122,8 +123,8 @@ class CaptchaBrotherhood(Addon): def api_response(self, api, ticket): res = self.load("%s%s.aspx" % (self.API_URL, api), - get={'username': self.get_config('username'), - 'password': self.get_config('password'), + get={'username': self.config.get('username'), + 'password': self.config.get('password'), 'captchaID': ticket}) if not res.startswith("OK"): raise CaptchaBrotherhoodException("Unknown response: %s" % res) @@ -138,10 +139,10 @@ class CaptchaBrotherhood(Addon): if not task.isTextual(): return False - if not self.get_config('username') or not self.get_config('password'): + if not self.config.get('username') or not self.config.get('password'): return False - if self.pyload.isClientConnected() and self.get_config('check_client'): + if self.pyload.isClientConnected() and self.config.get('check_client'): return False if self.get_credits() > 10: diff --git a/module/plugins/hooks/Checksum.py b/module/plugins/hooks/Checksum.py index cf5ed2147..af6f2f406 100644 --- a/module/plugins/hooks/Checksum.py +++ b/module/plugins/hooks/Checksum.py @@ -8,7 +8,7 @@ import re import zlib from module.plugins.internal.Addon import Addon -from module.plugins.internal.utils import encode, fs_join +from module.plugins.internal.misc import encode, fsjoin def compute_checksum(local_file, algorithm): @@ -38,8 +38,8 @@ def compute_checksum(local_file, algorithm): class Checksum(Addon): __name__ = "Checksum" __type__ = "hook" - __version__ = "0.23" - __status__ = "testing" + __version__ = "0.24" + __status__ = "broken" __config__ = [("activated" , "bool" , "Activated" , False ), ("check_checksum", "bool" , "Check checksum? (If False only size will be verified)", True ), @@ -65,7 +65,7 @@ class Checksum(Addon): def activate(self): - if not self.get_config('check_checksum'): + if not self.config.get('check_checksum'): self.log_info(_("Checksum validation is disabled in plugin configuration")) @@ -105,7 +105,7 @@ class Checksum(Addon): local_file = encode(pyfile.plugin.last_download) # dl_folder = self.pyload.config.get("general", "download_folder") - # local_file = encode(fs_join(dl_folder, pyfile.package().folder, pyfile.name)) + # local_file = encode(fsjoin(dl_folder, pyfile.package().folder, pyfile.name)) if not os.path.isfile(local_file): self.check_failed(pyfile, None, "File does not exist") @@ -122,7 +122,7 @@ class Checksum(Addon): data.pop('size', None) #: Validate checksum - if data and self.get_config('check_checksum'): + if data and self.config.get('check_checksum'): if not 'md5' in data: for type in ("checksum", "hashsum", "hash"): @@ -149,14 +149,14 @@ class Checksum(Addon): def check_failed(self, pyfile, local_file, msg): - check_action = self.get_config('check_action') + check_action = self.config.get('check_action') if check_action == "retry": - max_tries = self.get_config('max_tries') - retry_action = self.get_config('retry_action') + max_tries = self.config.get('max_tries') + retry_action = self.config.get('retry_action') if pyfile.plugin.retries < max_tries: if local_file: os.remove(local_file) - pyfile.plugin.retry(max_tries, self.get_config('wait_time'), msg) + pyfile.plugin.retry(max_tries, self.config.get('wait_time'), msg) elif retry_action == "nothing": return elif check_action == "nothing": @@ -166,17 +166,17 @@ class Checksum(Addon): def package_finished(self, pypack): - dl_folder = fs_join(self.pyload.config.get("general", "download_folder"), pypack.folder, "") + dl_folder = fsjoin(self.pyload.config.get("general", "download_folder"), pypack.folder, "") - for link in pypack.getChildren().values(): - file_type = os.path.splitext(link['name'])[1][1:].lower() + for fid, fdata in pypack.getChildren().items(): + file_type = os.path.splitext(fdata['name'])[1][1:].lower() if file_type not in self.formats: continue - hash_file = encode(fs_join(dl_folder, link['name'])) + hash_file = encode(fsjoin(dl_folder, fdata['name'])) if not os.path.isfile(hash_file): - self.log_warning(_("File not found"), link['name']) + self.log_warning(_("File not found"), fdata['name']) continue with open(hash_file) as f: @@ -184,9 +184,9 @@ class Checksum(Addon): for m in re.finditer(self.regexps.get(file_type, self.regexps['default']), text): data = m.groupdict() - self.log_debug(link['name'], data) + self.log_debug(fdata['name'], data) - local_file = encode(fs_join(dl_folder, data['NAME'])) + local_file = encode(fsjoin(dl_folder, data['NAME'])) algorithm = self.methods.get(file_type, file_type) checksum = compute_checksum(local_file, algorithm) diff --git a/module/plugins/hooks/ClickNLoad.py b/module/plugins/hooks/ClickNLoad.py index 79bf66c09..08b16d221 100644 --- a/module/plugins/hooks/ClickNLoad.py +++ b/module/plugins/hooks/ClickNLoad.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- import socket -import threading import time try: @@ -10,17 +9,7 @@ except ImportError: pass from module.plugins.internal.Addon import Addon, threaded - - -def forward(source, destination): - try: - bufsize = 1024 - bufdata = source.recv(bufsize) - while bufdata: - destination.sendall(bufdata) - bufdata = source.recv(bufsize) - finally: - destination.shutdown(socket.SHUT_WR) +from module.plugins.internal.misc import forward, lock #@TODO: IPv6 support @@ -46,8 +35,8 @@ class ClickNLoad(Addon): if not self.pyload.config.get("webinterface", "activated"): return - cnlip = "" if self.get_config('extern') else "127.0.0.1" - cnlport = self.get_config('port') + cnlip = "" if self.config.get('extern') else "127.0.0.1" + cnlport = self.config.get('port') webip = "127.0.0.1" if any(_ip == self.pyload.config.get("webinterface", "host") for _ip in ("0.0.0.0", "")) \ else self.pyload.config.get("webinterface", "host") webport = self.pyload.config.get("webinterface", "port") @@ -55,6 +44,7 @@ class ClickNLoad(Addon): self.pyload.scheduler.addJob(5, self.proxy, [cnlip, cnlport, webip, webport], threaded=False) + @lock @threaded def forward(self, source, destination, queue=False): if queue: @@ -71,13 +61,8 @@ class ClickNLoad(Addon): @threaded def proxy(self, cnlip, cnlport, webip, webport): self.log_info(_("Proxy listening on %s:%s") % (cnlip or "0.0.0.0", cnlport)) - self._server(cnlip, cnlport, webip, webport) - lock = threading.Lock() - lock.acquire() - lock.acquire() - @threaded def _server(self, cnlip, cnlport, webip, webport): @@ -108,7 +93,7 @@ class ClickNLoad(Addon): server_socket.connect((webip, webport)) - self.forward(client_socket, server_socket, self.get_config('dest') is "queue") + self.forward(client_socket, server_socket, self.config.get('dest') is "queue") self.forward(server_socket, client_socket) except socket.timeout: diff --git a/module/plugins/hooks/DeathByCaptcha.py b/module/plugins/hooks/DeathByCaptcha.py index 5c1c89c88..62cfe7d16 100644 --- a/module/plugins/hooks/DeathByCaptcha.py +++ b/module/plugins/hooks/DeathByCaptcha.py @@ -2,16 +2,16 @@ from __future__ import with_statement -import pycurl +import base64 import re import time -from base64 import b64encode +import pycurl -from module.plugins.internal.utils import json from module.network.HTTPRequest import BadHeader from module.network.RequestFactory import getRequest as get_request from module.plugins.internal.Addon import Addon, threaded +from module.plugins.internal.misc import json class DeathByCaptchaException(Exception): @@ -51,7 +51,7 @@ class DeathByCaptchaException(Exception): class DeathByCaptcha(Addon): __name__ = "DeathByCaptcha" __type__ = "hook" - __version__ = "0.10" + __version__ = "0.11" __status__ = "testing" __config__ = [("activated" , "bool" , "Activated" , False), @@ -75,8 +75,8 @@ class DeathByCaptcha(Addon): if post: if not isinstance(post, dict): post = {} - post.update({'username': self.get_config('username'), - 'password': self.get_config('password')}) + post.update({'username': self.config.get('username'), + 'password': self.config.get('password')}) res = None try: @@ -94,13 +94,13 @@ class DeathByCaptcha(Addon): raise DeathByCaptchaException(str(res)) except BadHeader, e: - if e.code == 403: + if e.code is 403: raise DeathByCaptchaException('not-logged-in') - elif e.code == 413: + elif e.code is 413: raise DeathByCaptchaException('invalid-captcha') - elif e.code == 503: + elif e.code is 503: raise DeathByCaptchaException('service-overload') elif e.code in (400, 405): @@ -135,14 +135,14 @@ class DeathByCaptcha(Addon): def submit(self, captcha, captchaType="file", match=None): #@NOTE: Workaround multipart-post bug in HTTPRequest.py - if re.match("^\w*$", self.get_config('password')): + if re.match("^\w*$", self.config.get('password')): multipart = True data = (pycurl.FORM_FILE, captcha) else: multipart = False with open(captcha, 'rb') as f: data = f.read() - data = "base64:" + b64encode(data) + data = "base64:" + base64.b64encode(data) res = self.api_response("captcha", {'captchafile': data}, multipart) @@ -171,10 +171,10 @@ class DeathByCaptcha(Addon): if not task.isTextual(): return False - if not self.get_config('username') or not self.get_config('password'): + if not self.config.get('username') or not self.config.get('password'): return False - if self.pyload.isClientConnected() and self.get_config('check_client'): + if self.pyload.isClientConnected() and self.config.get('check_client'): return False try: diff --git a/module/plugins/hooks/DeleteFinished.py b/module/plugins/hooks/DeleteFinished.py index 17b85959a..67e1a1056 100644 --- a/module/plugins/hooks/DeleteFinished.py +++ b/module/plugins/hooks/DeleteFinished.py @@ -7,7 +7,7 @@ from module.plugins.internal.Addon import Addon class DeleteFinished(Addon): __name__ = "DeleteFinished" __type__ = "hook" - __version__ = "1.17" + __version__ = "1.18" __status__ = "testing" __config__ = [("activated" , "bool", "Activated" , False), @@ -19,12 +19,9 @@ class DeleteFinished(Addon): __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - PERIODICAL_INTERVAL = 1 * 60 * 60 #: 1 hour - - - def periodical(self): + def periodical_task(self): if not self.info['sleep']: - deloffline = self.get_config('deloffline') + deloffline = self.config.get('deloffline') mode = "0,1,4" if deloffline else "0,4" msg = _('delete all finished packages in queue list (%s packages with offline links)') self.log_info(msg % (_('including') if deloffline else _('excluding'))) @@ -39,8 +36,8 @@ class DeleteFinished(Addon): def activate(self): self.info['sleep'] = True - self.set_interval(self.get_config('interval') * 60 * 60) self.add_event('package_finished', self.wakeup) + self.periodical.start(self.config.get('interval') * 60 * 60) ## own methods ## diff --git a/module/plugins/hooks/DownloadScheduler.py b/module/plugins/hooks/DownloadScheduler.py index 9c644ab20..d4c0356fd 100644 --- a/module/plugins/hooks/DownloadScheduler.py +++ b/module/plugins/hooks/DownloadScheduler.py @@ -9,7 +9,7 @@ from module.plugins.internal.Addon import Addon class DownloadScheduler(Addon): __name__ = "DownloadScheduler" __type__ = "hook" - __version__ = "0.25" + __version__ = "0.26" __status__ = "testing" __config__ = [("activated", "bool", "Activated" , False ), @@ -28,7 +28,7 @@ class DownloadScheduler(Addon): def update_schedule(self, schedule=None): if schedule is None: - schedule = self.get_config('timetable') + schedule = self.config.get('timetable') schedule = re.findall("(\d{1,2}):(\d{2})[\s]*(-?\d+)", schedule.lower().replace("full", "-1").replace("none", "0")) @@ -56,7 +56,7 @@ class DownloadScheduler(Addon): def set_download_speed(self, speed): if speed == 0: - abort = self.get_config('abort') + abort = self.config.get('abort') self.log_info(_("Stopping download server. (Running downloads will %sbe aborted.)") % '' if abort else _('not ')) self.pyload.api.pauseServer() if abort: diff --git a/module/plugins/hooks/EventMapper.py b/module/plugins/hooks/EventMapper.py new file mode 100644 index 000000000..ca1be2bdd --- /dev/null +++ b/module/plugins/hooks/EventMapper.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- + +from module.plugins.internal.Addon import Addon + + +class EventMapper(Addon): + __name__ = "EventMapper" + __type__ = "hook" + __version__ = "0.01" + __status__ = "testing" + + __config__ = [("activated", "bool", "Activated", True)] + + __description__ = """Map old events to new events""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + def activate(self, *args): + self.manager.dispatchEvent("activate", *args) + + + def exit(self, *args): + self.manager.dispatchEvent("exit", *args) + + + def config_changed(self, *args): + self.manager.dispatchEvent("config_changed", *args) + + + def all_downloads_finished(self, *args): + self.manager.dispatchEvent("all_downloads_finished", *args) + + + def all_downloads_processed(self, *args): + self.manager.dispatchEvent("all_downloads_processed", *args) + + + def links_added(self, *args): + self.manager.dispatchEvent("links_added", *args) + + + def download_preparing(self, *args): + self.manager.dispatchEvent("download_preparing", *args) + + + def download_finished(self, *args): + self.manager.dispatchEvent("download_finished", *args) + + + def download_failed(self, *args): + self.manager.dispatchEvent("download_failed", *args) + + + def package_deleted(self, *args): + self.manager.dispatchEvent("package_deleted", *args) + + + def package_finished(self, *args): + self.manager.dispatchEvent("package_finished", *args) + + + def before_reconnect(self, *args): + self.manager.dispatchEvent("before_reconnect", *args) + + + def after_reconnect(self, *args): + self.manager.dispatchEvent("after_reconnect", *args) + + + def captcha_task(self, *args): + self.manager.dispatchEvent("captcha_task", *args) + + + def captcha_correct(self, *args): + self.manager.dispatchEvent("captcha_correct", *args) + + + def captcha_invalid(self, *args): + self.manager.dispatchEvent("captcha_invalid", *args) diff --git a/module/plugins/hooks/ExpertDecoders.py b/module/plugins/hooks/ExpertDecoders.py index 55c07d4b9..9b29aa8c5 100644 --- a/module/plugins/hooks/ExpertDecoders.py +++ b/module/plugins/hooks/ExpertDecoders.py @@ -2,10 +2,10 @@ from __future__ import with_statement -import pycurl +import base64 import uuid -from base64 import b64encode +import pycurl from module.network.HTTPRequest import BadHeader from module.network.RequestFactory import getRequest as get_request @@ -15,7 +15,7 @@ from module.plugins.internal.Addon import Addon, threaded class ExpertDecoders(Addon): __name__ = "ExpertDecoders" __type__ = "hook" - __version__ = "0.07" + __version__ = "0.08" __status__ = "testing" __config__ = [("activated" , "bool" , "Activated" , False), @@ -32,7 +32,7 @@ class ExpertDecoders(Addon): def get_credits(self): - res = self.load(self.API_URL, post={'key': self.get_config('passkey'), 'action': "balance"}) + res = self.load(self.API_URL, post={'key': self.config.get('passkey'), 'action': "balance"}) if res.isdigit(): self.log_info(_("%s credits left") % res) @@ -58,8 +58,8 @@ class ExpertDecoders(Addon): try: result = self.load(self.API_URL, post={'action' : "upload", - 'key' : self.get_config('passkey'), - 'file' : b64encode(data), + 'key' : self.config.get('passkey'), + 'file' : base64.b64encode(data), 'gen_task_id': ticket}, req=req) finally: @@ -73,10 +73,10 @@ class ExpertDecoders(Addon): if not task.isTextual(): return False - if not self.get_config('passkey'): + if not self.config.get('passkey'): return False - if self.pyload.isClientConnected() and self.get_config('check_client'): + if self.pyload.isClientConnected() and self.config.get('check_client'): return False if self.get_credits() > 0: @@ -93,7 +93,7 @@ class ExpertDecoders(Addon): try: res = self.load(self.API_URL, - post={'action': "refund", 'key': self.get_config('passkey'), 'gen_task_id': task.data['ticket']}) + post={'action': "refund", 'key': self.config.get('passkey'), 'gen_task_id': task.data['ticket']}) self.log_info(_("Request refund"), res) except BadHeader, e: diff --git a/module/plugins/hooks/ExternalScripts.py b/module/plugins/hooks/ExternalScripts.py index 99427dfab..3f4fa74db 100644 --- a/module/plugins/hooks/ExternalScripts.py +++ b/module/plugins/hooks/ExternalScripts.py @@ -4,17 +4,17 @@ import os import subprocess from module.plugins.internal.Addon import Addon, Expose -from module.plugins.internal.utils import encode, fs_join +from module.plugins.internal.misc import encode class ExternalScripts(Addon): __name__ = "ExternalScripts" __type__ = "hook" - __version__ = "0.55" + __version__ = "0.60" __status__ = "testing" - __config__ = [("activated", "bool", "Activated" , True ), - ("lock" , "bool", "Wait for script to terminate", False)] + __config__ = [("activated", "bool", "Activated" , True ), + ("unlock" , "bool", "Execute script concurrently", False)] __description__ = """Run external scripts""" __license__ = "GPLv3" @@ -32,8 +32,14 @@ class ExternalScripts(Addon): 'package_extract_failed': "package_extract_failed" , 'package_extracted' : "package_extracted" , 'all_archives_extracted': "all_archives_extracted" , - 'all_archives_processed': "all_archives_processed" } + 'all_archives_processed': "all_archives_processed" , + 'pyload_updated' : "pyload_updated" } + self.periodical.start(60) + self.pyload_start() + + + def make_folders(self): folders = ["pyload_start", "pyload_restart", "pyload_stop", "before_reconnect", "after_reconnect", "download_preparing", "download_failed", "download_finished", @@ -43,176 +49,187 @@ class ExternalScripts(Addon): "all_archives_extracted", "all_archives_processed"] for folder in folders: - path = os.path.join("scripts", folder) - self.init_folder(folder, path) + dir = os.path.join("scripts", folder) - for folder, scripts in self.scripts.items(): - if scripts: - self.log_info(_("Installed scripts in folder `%s`: %s") - % (folder, ", ".join(scripts))) + if os.path.isdir(dir): + continue - self.pyload_start() + try: + os.makedirs(dir) + except OSError, e: + self.log_debug(e, trace=True) - def init_folder(self, name, path): - self.scripts[name] = [] - if not os.path.isdir(path): - try: - os.makedirs(path) + def periodical_task(self): + self.make_folders() - except OSError, e: - self.log_debug(e) - return + folders = [entry for entry in os.listdir("scripts") \ + if os.path.isdir(os.path.join("scripts", entry))] - for filename in os.listdir(path): - file = fs_join(path, filename) - if not os.path.isfile(file): - continue + for folder in folders: + self.scripts[folder] = [] - if file[0] in ("#", "_") or file.endswith("~") or file.endswith(".swp"): - continue + dirname = os.path.join("scripts", folder) + + for entry in os.listdir(dirname): + file = os.path.join(dirname, entry) + + if not os.path.isfile(file): + continue + + if file[0] in ("#", "_") or file.endswith("~") or file.endswith(".swp"): + continue + + if not os.access(file, os.X_OK): + self.log_warning(_("Script `%s` is not executable") % entry) - if not os.access(file, os.X_OK): - self.log_warning(_("Script not executable: [%s] %s") % (name, file)) + self.scripts[folder].append(file) - self.scripts[name].append(file) - self.log_info(_("Registered script: [%s] %s") % (name, file)) + script_names = map(os.path.basename, self.scripts[folder]) + self.log_info(_("Activated %s scripts: %s") + % (folder, ", ".join(script_names) or None)) + + + def call_cmd(self, command, *args, **kwargs): + call = [command] + args + self.log_debug("EXECUTE " + " ".join(call)) + + call = map(encode, call) + p = subprocess.Popen(call, bufsize=-1) #@NOTE: output goes to pyload + + return p @Expose - def call(self, script, args=[], lock=None): - if lock is None: - lock = self.get_config('lock') + def call_script(self, folder, *args, **kwargs): + scripts = self.scripts.get(folder) + + if folder not in scripts: + self.log_debug("Folder `%s` not found" % folder) + return + + scripts = self.scripts.get(folder) + + if not scripts: + self.log_debug("No script found under folder `%s`" % folder) + return + + self.log_info(_("Executing %s scripts...") % folder) - try: - script = os.path.abspath(script) - args = [script] + map(lambda arg: encode(arg) if isinstance(arg, basestring) else encode(str(arg)), args) + for file in scripts: + try: + p = self.call_cmd(file, args) - self.log_info(_("EXECUTE [%s] %s") % (os.path.dirname(script), args)) - p = subprocess.Popen(args, bufsize=-1) #@NOTE: output goes to pyload - if lock: - p.communicate() + except Exception, e: + self.log_error(_("Runtime error: %s") % file, + e or _("Unknown error")) - except Exception, e: - self.log_error(_("Runtime error: %s") % script, - e or _("Unknown error")) + else: + if kwargs.get('lock') or not self.config.get('unlock'): + p.communicate() - def _call(self, folder, args=[], lock=None): - for script in self.scripts[folder]: - self.call(script, args, lock) + def pyload_updated(self, etag): + self.call_script("pyload_updated", etag) def pyload_start(self): - self._call('pyload_start') + self.call_script('pyload_start') def exit(self): - folder = "pyload_restart" if self.pyload.do_restart else "pyload_stop" - self._call(folder, lock=True) + event = "restart" if self.pyload.do_restart else "stop" + self.call_script("pyload_" + event, lock=True) def before_reconnect(self, ip): - args = [ip] - self._call("before_reconnect", args) + self.call_script("before_reconnect", ip) def after_reconnect(self, ip, oldip): - args = [ip, oldip] - self._call("after_reconnect", args) + self.call_script("after_reconnect", ip, oldip) def download_preparing(self, pyfile): args = [pyfile.id, pyfile.name, None, pyfile.pluginname, pyfile.url] - self._call("download_preparing", args) + self.call_script("download_preparing", *args) def download_failed(self, pyfile): - if self.pyload.config.get("general", "folder_per_package"): - dl_folder = fs_join(self.pyload.config.get("general", "download_folder"), pyfile.package().folder) - else: - dl_folder = self.pyload.config.get("general", "download_folder") - - file = fs_join(dl_folder, pyfile.name) + file = pyfile.plugin.last_download args = [pyfile.id, pyfile.name, file, pyfile.pluginname, pyfile.url] - self._call("download_failed", args) + self.call_script("download_failed", *args) def download_finished(self, pyfile): - if self.pyload.config.get("general", "folder_per_package"): - dl_folder = fs_join(self.pyload.config.get("general", "download_folder"), pyfile.package().folder) - else: - dl_folder = self.pyload.config.get("general", "download_folder") - - file = fs_join(dl_folder, pyfile.name) + file = pyfile.plugin.last_download args = [pyfile.id, pyfile.name, file, pyfile.pluginname, pyfile.url] - self._call("download_finished", args) + self.call_script("download_finished", *args) def archive_extract_failed(self, pyfile, archive): args = [pyfile.id, pyfile.name, archive.filename, archive.out, archive.files] - self._call("archive_extract_failed", args) + self.call_script("archive_extract_failed", *args) def archive_extracted(self, pyfile, archive): args = [pyfile.id, pyfile.name, archive.filename, archive.out, archive.files] - self._call("archive_extracted", args) + self.call_script("archive_extracted", *args) def package_finished(self, pypack): + dl_folder = self.pyload.config.get("general", "download_folder") + if self.pyload.config.get("general", "folder_per_package"): - dl_folder = fs_join(self.pyload.config.get("general", "download_folder"), pypack.folder) - else: - dl_folder = self.pyload.config.get("general", "download_folder") + dl_folder = os.path.join(dl_folder, pypack.folder) args = [pypack.id, pypack.name, dl_folder, pypack.password] - self._call("package_finished", args) + self.call_script("package_finished", *args) def package_deleted(self, pid): + dl_folder = self.pyload.config.get("general", "download_folder") pdata = self.pyload.api.getPackageInfo(pid) if self.pyload.config.get("general", "folder_per_package"): - dl_folder = fs_join(self.pyload.config.get("general", "download_folder"), pdata.folder) - else: - dl_folder = self.pyload.config.get("general", "download_folder") + dl_folder = os.path.join(dl_folder, pdata.folder) args = [pdata.pid, pdata.name, dl_folder, pdata.password] - self._call("package_deleted", args) + self.call_script("package_deleted", *args) def package_extract_failed(self, pypack): + dl_folder = self.pyload.config.get("general", "download_folder") + if self.pyload.config.get("general", "folder_per_package"): - dl_folder = fs_join(self.pyload.config.get("general", "download_folder"), pypack.folder) - else: - dl_folder = self.pyload.config.get("general", "download_folder") + dl_folder = os.path.join(dl_folder, pypack.folder) args = [pypack.id, pypack.name, dl_folder, pypack.password] - self._call("package_extract_failed", args) + self.call_script("package_extract_failed", *args) def package_extracted(self, pypack): + dl_folder = self.pyload.config.get("general", "download_folder") + if self.pyload.config.get("general", "folder_per_package"): - dl_folder = fs_join(self.pyload.config.get("general", "download_folder"), pypack.folder) - else: - dl_folder = self.pyload.config.get("general", "download_folder") + dl_folder = os.path.join(dl_folder, pypack.folder) args = [pypack.id, pypack.name, dl_folder] - self._call("package_extracted", args) + self.call_script("package_extracted", *args) def all_downloads_finished(self): - self._call("all_downloads_finished") + self.call_script("all_downloads_finished") def all_downloads_processed(self): - self._call("all_downloads_processed") + self.call_script("all_downloads_processed") def all_archives_extracted(self): - self._call("all_archives_extracted") + self.call_script("all_archives_extracted") def all_archives_processed(self): - self._call("all_archives_processed") + self.call_script("all_archives_processed") diff --git a/module/plugins/hooks/ExtractArchive.py b/module/plugins/hooks/ExtractArchive.py index c001000c8..a60205f20 100644 --- a/module/plugins/hooks/ExtractArchive.py +++ b/module/plugins/hooks/ExtractArchive.py @@ -51,7 +51,7 @@ except ImportError: from module.plugins.internal.Addon import Addon, Expose, threaded from module.plugins.internal.Extractor import ArchiveError, CRCError, PasswordError -from module.plugins.internal.utils import encode, exists, fs_join, replace_patterns, uniqify +from module.plugins.internal.misc import encode, exists, fsjoin, replace_patterns, uniqify class ArchiveQueue(object): @@ -98,8 +98,8 @@ class ArchiveQueue(object): class ExtractArchive(Addon): __name__ = "ExtractArchive" __type__ = "hook" - __version__ = "1.53" - __status__ = "testing" + __version__ = "1.54" + __status__ = "broken" __config__ = [("activated" , "bool" , "Activated" , True ), ("fullpath" , "bool" , "Extract with full paths" , True ), @@ -142,14 +142,14 @@ class ExtractArchive(Addon): def activate(self): - for p in ("UnRar", "SevenZip", "UnZip"): + for p in ("UnRar", "SevenZip", "UnZip", "UnTar"): try: module = self.pyload.pluginManager.loadModule("internal", p) klass = getattr(module, p) if klass.find(): self.extractors.append(klass) if klass.REPAIR: - self.repair = self.get_config('repair') + self.repair = self.config.get('repair') except OSError, e: if e.errno == 2: @@ -206,7 +206,7 @@ class ExtractArchive(Addon): """ for id in ids: self.queue.add(id) - if not self.get_config('waitall') and not self.extracting: + if not self.config.get('waitall') and not self.extracting: self.extract_queued() @@ -216,13 +216,13 @@ class ExtractArchive(Addon): def package_finished(self, pypack): self.queue.add(pypack.id) - if not self.get_config('waitall') and not self.extracting: + if not self.config.get('waitall') and not self.extracting: self.extract_queued() def all_downloads_processed(self): self.last_package = True - if self.get_config('waitall') and not self.extracting: + if self.config.get('waitall') and not self.extracting: self.extract_queued() @@ -237,16 +237,16 @@ class ExtractArchive(Addon): toList = lambda string: string.replace(' ', '').replace(',', '|').replace(';', '|').split('|') - destination = self.get_config('destination') - subfolder = self.get_config('subfolder') - fullpath = self.get_config('fullpath') - overwrite = self.get_config('overwrite') - priority = self.get_config('priority') - recursive = self.get_config('recursive') - keepbroken = self.get_config('keepbroken') + destination = self.config.get('destination') + subfolder = self.config.get('subfolder') + fullpath = self.config.get('fullpath') + overwrite = self.config.get('overwrite') + priority = self.config.get('priority') + recursive = self.config.get('recursive') + keepbroken = self.config.get('keepbroken') - extensions = [x.lstrip('.').lower() for x in toList(self.get_config('extensions'))] - excludefiles = toList(self.get_config('excludefiles')) + extensions = [x.lstrip('.').lower() for x in toList(self.config.get('extensions'))] + excludefiles = toList(self.config.get('excludefiles')) if extensions: self.log_debug("Use for extensions: %s" % "|.".join(extensions)) @@ -267,18 +267,18 @@ class ExtractArchive(Addon): self.log_info(_("Check package: %s") % pypack.name) #: Determine output folder - out = fs_join(dl_folder, pypack.folder, destination, "") #: Force trailing slash + out = fsjoin(dl_folder, pypack.folder, destination, "") #: Force trailing slash if subfolder: - out = fs_join(out, pypack.folder) + out = fsjoin(out, pypack.folder) if not exists(out): os.makedirs(out) matched = False success = True - files_ids = dict((pylink['name'], ((fs_join(dl_folder, pypack.folder, pylink['name'])), pylink['id'], out)) for pylink \ - in sorted(pypack.getChildren().values(), key=lambda k: k['name'])).values() #: Remove duplicates + files_ids = dict((fdata['name'], ((fsjoin(dl_folder, pypack.folder, fdata['name'])), fid, out)) for fid, fdata \ + in sorted(pypack.getChildren().values(), key=lambda k: k['name'])).items() #: Remove duplicates #: Check as long there are unseen files while files_ids: @@ -338,7 +338,7 @@ class ExtractArchive(Addon): self.set_permissions(file) for filename in new_files: - file = encode(fs_join(os.path.dirname(archive.filename), filename)) + file = encode(fsjoin(os.path.dirname(archive.filename), filename)) if not exists(file): self.log_debug("New file %s does not exists" % filename) continue @@ -383,7 +383,7 @@ class ExtractArchive(Addon): encrypted = False try: self.log_debug("Password: %s" % (password or "None provided")) - passwords = uniqify([password] + self.get_passwords(False)) if self.get_config('usepasswordfile') else [password] + passwords = uniqify([password] + self.get_passwords(False)) if self.config.get('usepasswordfile') else [password] for pw in passwords: try: pyfile.setCustomStatus(_("archive testing")) @@ -410,7 +410,7 @@ class ExtractArchive(Addon): repaired = archive.repair() pyfile.setProgress(100) - if not repaired and not self.get_config('keepbroken'): + if not repaired and not self.config.get('keepbroken'): raise CRCError("Archive damaged") else: @@ -427,7 +427,7 @@ class ExtractArchive(Addon): pyfile.setCustomStatus(_("archive extracting")) pyfile.setProgress(0) - if not encrypted or not self.get_config('usepasswordfile'): + if not encrypted or not self.config.get('usepasswordfile'): self.log_debug("Extracting using password: %s" % (password or "None")) archive.extract(password) else: @@ -450,10 +450,10 @@ class ExtractArchive(Addon): delfiles = archive.items() self.log_debug("Would delete: " + ", ".join(delfiles)) - if self.get_config('delete'): + if self.config.get('delete'): self.log_info(_("Deleting %s files") % len(delfiles)) - deltotrash = self.get_config('deltotrash') + deltotrash = self.config.get('deltotrash') for f in delfiles: file = encode(f) if not exists(file): @@ -523,7 +523,7 @@ class ExtractArchive(Addon): try: passwords = [] - file = encode(self.get_config('passwordfile')) + file = encode(self.config.get('passwordfile')) with open(file) as f: for pw in f.read().splitlines(): passwords.append(pw) @@ -552,7 +552,7 @@ class ExtractArchive(Addon): try: self.passwords = uniqify([password] + self.passwords) - file = encode(self.get_config('passwordfile')) + file = encode(self.config.get('passwordfile')) with open(file, "wb") as f: for pw in self.passwords: f.write(pw + '\n') diff --git a/module/plugins/hooks/HotFolder.py b/module/plugins/hooks/HotFolder.py index c89083fb1..26217c0f8 100644 --- a/module/plugins/hooks/HotFolder.py +++ b/module/plugins/hooks/HotFolder.py @@ -3,17 +3,16 @@ from __future__ import with_statement import os -import shutil import time from module.plugins.internal.Addon import Addon -from module.plugins.internal.utils import encode, fs_join +from module.plugins.internal.misc import encode, fsjoin, move_tree class HotFolder(Addon): __name__ = "HotFolder" __type__ = "hook" - __version__ = "0.20" + __version__ = "0.21" __status__ = "testing" __config__ = [("activated", "bool", "Activated" , False ), @@ -28,18 +27,18 @@ class HotFolder(Addon): def activate(self): - self.start_periodical(30, threaded=True) + self.periodical.start(30, threaded=True) - def periodical(self): - folder = encode(self.get_config('folder')) - file = encode(self.get_config('file')) + def periodical_task(self): + folder = encode(self.config.get('folder')) + file = encode(self.config.get('file')) try: if not os.path.isdir(os.path.join(folder, "finished")): os.makedirs(os.path.join(folder, "finished")) - if self.get_config('watchfile'): + if self.config.get('watchfile'): with open(file, "a+") as f: f.seek(0) content = f.read().strip() @@ -50,7 +49,7 @@ class HotFolder(Addon): name = "%s_%s.txt" % (file, time.strftime("%H-%M-%S_%d%b%Y")) - with open(fs_join(folder, "finished", name), "wb") as f: + with open(fsjoin(folder, "finished", name), "wb") as f: f.write(content) self.pyload.api.addPackage(f.name, [f.name], 1) @@ -61,8 +60,8 @@ class HotFolder(Addon): if not os.path.isfile(path) or f.endswith("~") or f.startswith("#") or f.startswith("."): continue - newpath = os.path.join(folder, "finished", "tmp_" + f if self.get_config('delete') else f) - shutil.move(path, newpath) + newpath = os.path.join(folder, "finished", "tmp_" + f if self.config.get('delete') else f) + move_tree(path, newpath) self.log_info(_("Added %s from HotFolder") % f) self.pyload.api.addPackage(f, [newpath], 1) diff --git a/module/plugins/hooks/IRCInterface.py b/module/plugins/hooks/IRC.py index 1f337d686..7dec4b798 100644 --- a/module/plugins/hooks/IRCInterface.py +++ b/module/plugins/hooks/IRC.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- -import pycurl import re import select import socket @@ -8,17 +7,19 @@ import ssl import time import traceback +import pycurl + from threading import Thread from module.Api import PackageDoesNotExists, FileDoesNotExists -from module.plugins.internal.Addon import Addon -from module.utils import formatSize +from module.plugins.internal.Notifier import Notifier +from module.internal.misc import formatSize -class IRCInterface(Thread, Addon): - __name__ = "IRCInterface" +class IRC(Thread, Notifier): + __name__ = "IRC" __type__ = "hook" - __version__ = "0.18" + __version__ = "0.19" __status__ = "testing" __config__ = [("activated", "bool", "Activated" , False ), @@ -54,7 +55,7 @@ class IRCInterface(Thread, Addon): def package_finished(self, pypack): try: - if self.get_config('info_pack'): + if self.config.get('info_pack'): self.response(_("Package finished: %s") % pypack.name) except Exception: @@ -63,7 +64,7 @@ class IRCInterface(Thread, Addon): def download_finished(self, pyfile): try: - if self.get_config('info_file'): + if self.config.get('info_file'): self.response( _("Download finished: %(name)s @ %(plugin)s ") % {'name': pyfile.name, 'plugin': pyfile.pluginname}) @@ -72,7 +73,7 @@ class IRCInterface(Thread, Addon): def captcha_task(self, task): - if self.get_config('captcha') and task.isTextual(): + if self.config.get('captcha') and task.isTextual(): task.handler.append(self) task.setWaiting(60) @@ -87,16 +88,16 @@ class IRCInterface(Thread, Addon): def run(self): #: Connect to IRC etc. self.sock = socket.socket() - host = self.get_config('host') - self.sock.connect((host, self.get_config('port'))) + host = self.config.get('host') + self.sock.connect((host, self.config.get('port'))) - if self.get_config('ssl'): + if self.config.get('ssl'): self.sock = ssl.wrap_socket(self.sock, cert_reqs=ssl.CERT_NONE) #@TODO: support certificate - nick = self.get_config('nick') + nick = self.config.get('nick') self.sock.send("NICK %s\r\n" % nick) self.sock.send("USER %s %s bla :%s\r\n" % (nick, host, nick)) - for t in self.get_config('owner').split(): + for t in self.config.get('owner').split(): if t.strip().startswith("#"): self.sock.send("JOIN %s\r\n" % t.strip()) self.log_info(_("Connected to"), host) @@ -151,10 +152,10 @@ class IRCInterface(Thread, Addon): def handle_events(self, msg): - if not msg['origin'].split("!", 1)[0] in self.get_config('owner').split(): + if not msg['origin'].split("!", 1)[0] in self.config.get('owner').split(): return - if msg['target'].split("!", 1)[0] is not self.get_config('nick'): + if msg['target'].split("!", 1)[0] is not self.config.get('nick'): return if msg['action'] != "PRIVMSG": @@ -197,7 +198,7 @@ class IRCInterface(Thread, Addon): def response(self, msg, origin=""): if origin == "": - for t in self.get_config('owner').split(): + for t in self.config.get('owner').split(): self.sock.send("PRIVMSG %s :%s\r\n" % (t.strip(), msg)) else: self.sock.send("PRIVMSG %s :%s\r\n" % (origin.split("!", 1)[0], msg)) @@ -218,7 +219,7 @@ class IRCInterface(Thread, Addon): lines = ["ID - Name - Status - Speed - ETA - Progress"] for data in downloads: - if data.status == 5: + if data.status is 5: temp_progress = data.format_wait else: temp_progress = "%d%% (%s)" % (data.percent, data.format_size) @@ -236,25 +237,25 @@ class IRCInterface(Thread, Addon): def event_queue(self, args): - ps = self.pyload.api.getQueueData() + pdata = self.pyload.api.getQueueData() - if not ps: + if not pdata: return ["INFO: There are no packages in queue."] lines = [] - for pack in ps: + for pack in pdata: lines.append('PACKAGE #%s: "%s" with %d links.' % (pack.pid, pack.name, len(pack.links))) return lines def event_collector(self, args): - ps = self.pyload.api.getCollectorData() - if not ps: + pdata = self.pyload.api.getCollectorData() + if not pdata: return ["INFO: No packages in collector!"] lines = [] - for pack in ps: + for pack in pdata: lines.append('PACKAGE #%s: "%s" with %d links.' % (pack.pid, pack.name, len(pack.links))) return lines diff --git a/module/plugins/hooks/ImageTyperz.py b/module/plugins/hooks/ImageTyperz.py index 656ad0c25..5afeb4a78 100644 --- a/module/plugins/hooks/ImageTyperz.py +++ b/module/plugins/hooks/ImageTyperz.py @@ -2,10 +2,10 @@ from __future__ import with_statement -import pycurl +import base64 import re -from base64 import b64encode +import pycurl from module.network.RequestFactory import getRequest as get_request from module.plugins.internal.Addon import Addon, threaded @@ -32,7 +32,7 @@ class ImageTyperzException(Exception): class ImageTyperz(Addon): __name__ = "ImageTyperz" __type__ = "hook" - __version__ = "0.09" + __version__ = "0.10" __status__ = "testing" __config__ = [("activated" , "bool" , "Activated" , False), @@ -54,8 +54,8 @@ class ImageTyperz(Addon): def get_credits(self): res = self.load(self.GETCREDITS_URL, post={'action': "REQUESTBALANCE", - 'username': self.get_config('username'), - 'password': self.get_config('password')}) + 'username': self.config.get('username'), + 'password': self.config.get('password')}) if res.startswith('ERROR'): raise ImageTyperzException(res) @@ -77,19 +77,19 @@ class ImageTyperz(Addon): try: #@NOTE: Workaround multipart-post bug in HTTPRequest.py - if re.match("^\w*$", self.get_config('password')): + if re.match("^\w*$", self.config.get('password')): multipart = True data = (pycurl.FORM_FILE, captcha) else: multipart = False with open(captcha, 'rb') as f: data = f.read() - data = b64encode(data) + data = base64.b64encode(data) res = self.load(self.SUBMIT_URL, post={'action': "UPLOADCAPTCHA", - 'username': self.get_config('username'), - 'password': self.get_config('password'), 'file': data}, + 'username': self.config.get('username'), + 'password': self.config.get('password'), 'file': data}, multipart=multipart, req=req) finally: @@ -99,7 +99,7 @@ class ImageTyperz(Addon): raise ImageTyperzException(res) else: data = res.split('|') - if len(data) == 2: + if len(data) is 2: ticket, result = data else: raise ImageTyperzException("Unknown response: %s" % res) @@ -114,10 +114,10 @@ class ImageTyperz(Addon): if not task.isTextual(): return False - if not self.get_config('username') or not self.get_config('password'): + if not self.config.get('username') or not self.config.get('password'): return False - if self.pyload.isClientConnected() and self.get_config('check_client'): + if self.pyload.isClientConnected() and self.config.get('check_client'): return False if self.get_credits() > 0: @@ -134,8 +134,8 @@ class ImageTyperz(Addon): if task.data['service'] is self.classname and "ticket" in task.data: res = self.load(self.RESPOND_URL, post={'action': "SETBADIMAGE", - 'username': self.get_config('username'), - 'password': self.get_config('password'), + 'username': self.config.get('username'), + 'password': self.config.get('password'), 'imageid': task.data['ticket']}) if res == "SUCCESS": diff --git a/module/plugins/hooks/JustPremium.py b/module/plugins/hooks/JustPremium.py index 3f7388020..2492498cb 100644 --- a/module/plugins/hooks/JustPremium.py +++ b/module/plugins/hooks/JustPremium.py @@ -8,7 +8,7 @@ from module.plugins.internal.Addon import Addon class JustPremium(Addon): __name__ = "JustPremium" __type__ = "hook" - __version__ = "0.25" + __version__ = "0.26" __status__ = "testing" __config__ = [("activated", "bool", "Activated" , False), @@ -37,9 +37,9 @@ class JustPremium(Addon): and hosterdict[hoster]['new_name'] in premiumplugins) excluded = map(lambda domain: "".join(part.capitalize() for part in re.split(r'(\.|\d+)', domain) if part != '.'), - self.get_config('excluded').replace(' ', '').replace(',', '|').replace(';', '|').split('|')) + self.config.get('excluded').replace(' ', '').replace(',', '|').replace(';', '|').split('|')) included = map(lambda domain: "".join(part.capitalize() for part in re.split(r'(\.|\d+)', domain) if part != '.'), - self.get_config('included').replace(' ', '').replace(',', '|').replace(';', '|').split('|')) + self.config.get('included').replace(' ', '').replace(',', '|').replace(';', '|').split('|')) hosterlist = (premiumplugins | multihosters).union(excluded).difference(included) diff --git a/module/plugins/hooks/LogMarker.py b/module/plugins/hooks/LogMarker.py index 829db4d41..80f7b17fb 100644 --- a/module/plugins/hooks/LogMarker.py +++ b/module/plugins/hooks/LogMarker.py @@ -3,13 +3,13 @@ import datetime from module.plugins.internal.Addon import Addon, Expose -from module.plugins.internal.utils import seconds_to_nexthour +from module.plugins.internal.misc import seconds_to_nexthour class LogMarker(Addon): __name__ = "LogMarker" __type__ = "hook" - __version__ = "0.04" + __version__ = "0.05" __status__ = "testing" __config__ = [("activated", "bool", "Activated" , False), @@ -22,16 +22,16 @@ class LogMarker(Addon): def activated(self): - self.start_periodical(1 * 60 * 60 - 1, delay=seconds_to_nexthour(strict=True) - 1) + self.periodical.start(1 * 60 * 60 - 1, delay=seconds_to_nexthour(strict=True) - 1) - def periodical(self): - if self.get_config('mark_day') and datetime.datetime.today().hour is 0: + def periodical_task(self): + if self.config.get('mark_day') and datetime.datetime.today().hour is 0: self.log_info("------------------------------------------------") self.log_info(_("------------------- DAY MARK -------------------")) self.log_info("------------------------------------------------") - elif self.get_config('mark_hour'): + elif self.config.get('mark_hour'): self.log_info("------------------------------------------------") self.log_info(_("------------------- HOUR MARK ------------------")) self.log_info("------------------------------------------------") diff --git a/module/plugins/hooks/MergeFiles.py b/module/plugins/hooks/MergeFiles.py index dbe7b1f5f..963f8c15b 100644 --- a/module/plugins/hooks/MergeFiles.py +++ b/module/plugins/hooks/MergeFiles.py @@ -6,13 +6,13 @@ import os import re from module.plugins.internal.Addon import Addon, threaded -from module.plugins.internal.utils import fs_join +from module.plugins.internal.misc import fsjoin class MergeFiles(Addon): __name__ = "MergeFiles" __type__ = "hook" - __version__ = "0.18" + __version__ = "0.19" __status__ = "testing" __config__ = [("activated", "bool", "Activated", True)] @@ -40,12 +40,12 @@ class MergeFiles(Addon): dl_folder = self.pyload.config.get("general", "download_folder") if self.pyload.config.get("general", "folder_per_package"): - dl_folder = fs_join(dl_folder, pack.folder) + dl_folder = fsjoin(dl_folder, pack.folder) for name, file_list in files.items(): self.log_info(_("Starting merging of"), name) - with open(fs_join(dl_folder, name), "wb") as final_file: + with open(fsjoin(dl_folder, name), "wb") as final_file: for splitted_file in file_list: self.log_debug("Merging part", splitted_file) @@ -54,7 +54,7 @@ class MergeFiles(Addon): pyfile.setStatus("processing") try: - with open(fs_join(dl_folder, splitted_file), "rb") as s_file: + with open(fsjoin(dl_folder, splitted_file), "rb") as s_file: size_written = 0 s_file_size = int(os.path.getsize(os.path.join(dl_folder, splitted_file))) while True: diff --git a/module/plugins/hooks/MultiHome.py b/module/plugins/hooks/MultiHome.py index 353753c1a..c8c5f4fa7 100644 --- a/module/plugins/hooks/MultiHome.py +++ b/module/plugins/hooks/MultiHome.py @@ -44,7 +44,7 @@ class Interface(object): class MultiHome(Addon): __name__ = "MultiHome" __type__ = "hook" - __version__ = "0.15" + __version__ = "0.16" __status__ = "testing" __config__ = [("activated" , "bool", "Activated" , False ), @@ -59,11 +59,11 @@ class MultiHome(Addon): self.register = {} self.interfaces = [] - self.parse_interfaces(self.get_config('interfaces').split(";")) + self.parse_interfaces(self.config.get('interfaces').split(";")) if not self.interfaces: self.parse_interfaces([self.pyload.config.get("download", "interface")]) - self.set_config("interfaces", self.to_config()) + self.config.set("interfaces", self.to_config()) def to_config(self): diff --git a/module/plugins/hooks/PushBullet.py b/module/plugins/hooks/PushBullet.py index 6cf7dc173..47a0f594e 100644 --- a/module/plugins/hooks/PushBullet.py +++ b/module/plugins/hooks/PushBullet.py @@ -9,19 +9,22 @@ from module.plugins.internal.Notifier import Notifier class PushBullet(Notifier): __name__ = "PushBullet" __type__ = "hook" - __version__ = "0.02" + __version__ = "0.04" __status__ = "testing" - __config__ = [("activated" , "bool", "Activated" , False), - ("tokenkey" , "str" , "Access Token" , "" ), - ("notifycaptcha" , "bool", "Notify captcha request" , True ), - ("notifypackage" , "bool", "Notify package finished" , True ), - ("notifyprocessed", "bool", "Notify packages processed" , True ), - ("notifyupdate" , "bool", "Notify plugin updates" , True ), - ("notifyexit" , "bool", "Notify pyLoad shutdown" , True ), - ("sendtimewait" , "int" , "Timewait in seconds between notifications", 5 ), - ("sendpermin" , "int" , "Max notifications per minute" , 12 ), - ("ignoreclient" , "bool", "Send notifications if client is connected", False)] + __config__ = [("activated" , "bool", "Activated" , False), + ("tokenkey" , "str" , "Access Token" , "" ), + ("captcha" , "bool", "Notify captcha request" , True ), + ("reconnection" , "bool", "Notify reconnection request" , False), + ("downloadfinished", "bool", "Notify download finished" , True ), + ("downloadfailed" , "bool", "Notify download failed" , True ), + ("packagefinished" , "bool", "Notify package finished" , True ), + ("packagefailed" , "bool", "Notify package failed" , True ), + ("update" , "bool", "Notify pyLoad update" , False), + ("exit" , "bool", "Notify pyLoad shutdown/restart" , False), + ("sendinterval" , "int" , "Interval in seconds between notifications", 1 ), + ("sendpermin" , "int" , "Max notifications per minute" , 60 ), + ("ignoreclient" , "bool", "Send notifications if client is connected", True )] __description__ = """Send push notifications to your phone using pushbullet.com""" __license__ = "GPLv3" @@ -29,7 +32,7 @@ class PushBullet(Notifier): def get_key(self): - return self.get_config('tokenkey') + return self.config.get('tokenkey') def send(self, event, msg, key): diff --git a/module/plugins/hooks/PushOver.py b/module/plugins/hooks/PushOver.py index 5d5e927ac..418f7a133 100644 --- a/module/plugins/hooks/PushOver.py +++ b/module/plugins/hooks/PushOver.py @@ -8,20 +8,23 @@ from module.plugins.internal.Notifier import Notifier class PushOver(Notifier): __name__ = "PushOver" __type__ = "hook" - __version__ = "0.04" + __version__ = "0.06" __status__ = "testing" - __config__ = [("activated" , "bool", "Activated" , False), - ("tokenkey" , "str" , "Token key" , "" ), - ("userkey" , "str" , "User key" , "" ), - ("notifycaptcha" , "bool", "Notify captcha request" , True ), - ("notifypackage" , "bool", "Notify package finished" , True ), - ("notifyprocessed", "bool", "Notify packages processed" , True ), - ("notifyupdate" , "bool", "Notify plugin updates" , True ), - ("notifyexit" , "bool", "Notify pyLoad shutdown" , True ), - ("sendtimewait" , "int" , "Timewait in seconds between notifications", 5 ), - ("sendpermin" , "int" , "Max notifications per minute" , 12 ), - ("ignoreclient" , "bool", "Send notifications if client is connected", False)] + __config__ = [("activated" , "bool", "Activated" , False), + ("tokenkey" , "str" , "Token key" , "" ), + ("userkey" , "str" , "User key" , "" ), + ("captcha" , "bool", "Notify captcha request" , True ), + ("reconnection" , "bool", "Notify reconnection request" , False), + ("downloadfinished", "bool", "Notify download finished" , True ), + ("downloadfailed" , "bool", "Notify download failed" , True ), + ("packagefinished" , "bool", "Notify package finished" , True ), + ("packagefailed" , "bool", "Notify package failed" , True ), + ("update" , "bool", "Notify pyLoad update" , False), + ("exit" , "bool", "Notify pyLoad shutdown/restart" , False), + ("sendinterval" , "int" , "Interval in seconds between notifications", 1 ), + ("sendpermin" , "int" , "Max notifications per minute" , 60 ), + ("ignoreclient" , "bool", "Send notifications if client is connected", True )] __description__ = """Send push notifications to your phone using pushover.net""" __license__ = "GPLv3" @@ -29,7 +32,7 @@ class PushOver(Notifier): def get_key(self): - return self.get_config('tokenkey'), self.get_config('userkey') + return self.config.get('tokenkey'), self.config.get('userkey') def send(self, event, msg, key): diff --git a/module/plugins/hooks/RestartFailed.py b/module/plugins/hooks/RestartFailed.py index 0e35c4629..62298ea14 100644 --- a/module/plugins/hooks/RestartFailed.py +++ b/module/plugins/hooks/RestartFailed.py @@ -6,7 +6,7 @@ from module.plugins.internal.Addon import Addon class RestartFailed(Addon): __name__ = "RestartFailed" __type__ = "hook" - __version__ = "1.63" + __version__ = "1.64" __status__ = "testing" __config__ = [("activated", "bool", "Activated" , False), @@ -17,13 +17,10 @@ class RestartFailed(Addon): __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - PERIODICAL_INTERVAL = 15 * 60 #: 15 minutes - - - def periodical(self): + def periodical_task(self): self.log_info(_("Restarting all failed downloads...")) self.pyload.api.restartFailed() def activate(self): - self.set_interval(self.get_config('interval') * 60) + self.periodical.start(self.config.get('interval') * 60) diff --git a/module/plugins/hooks/SkipRev.py b/module/plugins/hooks/SkipRev.py index 6ce1750d3..429737e94 100644 --- a/module/plugins/hooks/SkipRev.py +++ b/module/plugins/hooks/SkipRev.py @@ -1,9 +1,6 @@ # -*- coding: utf-8 -*- import re -import urllib - -from types import MethodType from module.PyFile import PyFile from module.plugins.internal.Addon import Addon @@ -12,7 +9,7 @@ from module.plugins.internal.Addon import Addon class SkipRev(Addon): __name__ = "SkipRev" __type__ = "hook" - __version__ = "0.35" + __version__ = "0.36" __status__ = "testing" __config__ = [("activated", "bool" , "Activated" , False ), @@ -28,17 +25,18 @@ class SkipRev(Addon): return pyfile.pluginclass.get_info(pyfile.url)['name'] - def _pyfile(self, link): + def _create_pyFile(self, data): + pylink = self.pyload.api._convertPyFile(data) return PyFile(self.pyload.files, - link.fid, - link.url, - link.name, - link.size, - link.status, - link.error, - link.plugin, - link.packageID, - link.order) + pylink.fid, + pylink.url, + pylink.name, + pylink.size, + pylink.status, + pylink.error, + pylink.plugin, + pylink.packageID, + pylink.order) def download_preparing(self, pyfile): @@ -47,14 +45,14 @@ class SkipRev(Addon): if pyfile.statusname is _("unskipped") or not name.endswith(".rev") or not ".part" in name: return - revtokeep = -1 if self.get_config('mode') == "Auto" else self.get_config('revtokeep') + revtokeep = -1 if self.config.get('mode') == "Auto" else self.config.get('revtokeep') if revtokeep: status_list = (1, 4, 8, 9, 14) if revtokeep < 0 else (1, 3, 4, 8, 9, 14) pyname = re.compile(r'%s\.part\d+\.rev$' % name.rsplit('.', 2)[0].replace('.', '\.')) - queued = [True for link in self.pyload.api.getPackageData(pyfile.package().id).links \ - if link.status not in status_list and pyname.match(link.name)].count(True) + queued = [True for fid, fdata in pyfile.package().getChildren().items() \ + if fdata['status'] not in status_list and pyname.match(fdata['name'])].count(True) if not queued or queued < revtokeep: #: Keep one rev at least in auto mode return @@ -63,26 +61,25 @@ class SkipRev(Addon): def download_failed(self, pyfile): - #: Check if pyfile is still "failed", maybe might has been restarted in meantime - if pyfile.status != 8 or pyfile.name.rsplit('.', 1)[-1].strip() not in ("rar", "rev"): + if pyfile.name.rsplit('.', 1)[-1].strip() not in ("rar", "rev"): return - revtokeep = -1 if self.get_config('mode') == "Auto" else self.get_config('revtokeep') + revtokeep = -1 if self.config.get('mode') == "Auto" else self.config.get('revtokeep') if not revtokeep: return pyname = re.compile(r'%s\.part\d+\.rev$' % pyfile.name.rsplit('.', 2)[0].replace('.', '\.')) - for link in self.pyload.api.getPackageData(pyfile.package().id).links: - if link.status is 4 and pyname.match(link.name): - pylink = self._pyfile(link) + for fid, fdata in pyfile.package().getChildren().items(): + if fdata['status'] is 4 and pyname.match(fdata['name']): + pyfile_new = self._create_pyFile(fdata) if revtokeep > -1 or pyfile.name.endswith(".rev"): - pylink.setStatus("queued") + pyfile_new.setStatus("queued") else: - pylink.setCustomStatus(_("unskipped"), "queued") + pyfile_new.setCustomStatus(_("unskipped"), "queued") self.pyload.files.save() - pylink.release() + pyfile_new.release() return diff --git a/module/plugins/hooks/TransmissionRPC.py b/module/plugins/hooks/TransmissionRPC.py index 7914d5c44..f0ef2e9b1 100644 --- a/module/plugins/hooks/TransmissionRPC.py +++ b/module/plugins/hooks/TransmissionRPC.py @@ -5,19 +5,19 @@ import re import pycurl -from module.plugins.internal.utils import json from module.network.HTTPRequest import BadHeader from module.network.RequestFactory import getRequest as get_request from module.plugins.internal.Addon import Addon +from module.plugins.internal.misc import json class TransmissionRPC(Addon): __name__ = "TransmissionRPC" __type__ = "hook" - __version__ = "0.16" + __version__ = "0.17" __status__ = "testing" - __pattern__ = r"https?://.+\.torrent|magnet:\?.+" + __pattern__ = r'https?://.+\.torrent|magnet:\?.+' __config__ = [("activated", "bool", "Activated" , False ), ("rpc_url" , "str" , "Transmission RPC URL", "http://127.0.0.1:9091/transmission/rpc")] @@ -41,7 +41,7 @@ class TransmissionRPC(Addon): def send_to_transmission(self, url): - transmission_rpc_url = self.get_config('rpc_url') + transmission_rpc_url = self.config.get('rpc_url') client_request_id = self.classname + "".join(random.choice('0123456789ABCDEF') for _i in xrange(4)) req = get_request() @@ -53,7 +53,7 @@ class TransmissionRPC(Addon): req=req) except Exception, e: - if isinstance(e, BadHeader) and e.code == 409: + if isinstance(e, BadHeader) and e.code is 409: headers = dict(re.findall(r"(?P<name>.+?): (?P<value>.+?)\r?\n", req.header)) session_id = headers['X-Transmission-Session-Id'] req.c.setopt(pycurl.HTTPHEADER, ["X-Transmission-Session-Id: %s" % session_id]) diff --git a/module/plugins/hooks/UnSkipOnFail.py b/module/plugins/hooks/UnSkipOnFail.py index 6842cbc51..db43bca2b 100644 --- a/module/plugins/hooks/UnSkipOnFail.py +++ b/module/plugins/hooks/UnSkipOnFail.py @@ -7,7 +7,7 @@ from module.plugins.internal.Addon import Addon class UnSkipOnFail(Addon): __name__ = "UnSkipOnFail" __type__ = "hook" - __version__ = "0.10" + __version__ = "0.11" __status__ = "testing" __config__ = [("activated", "bool", "Activated", True)] @@ -18,10 +18,6 @@ class UnSkipOnFail(Addon): def download_failed(self, pyfile): - #: Check if pyfile is still "failed", maybe might has been restarted in meantime - if pyfile.status != 8: - return - msg = _("Looking for skipped duplicates of: %s (pid:%s)") self.log_info(msg % (pyfile.name, pyfile.package().id)) @@ -36,12 +32,12 @@ class UnSkipOnFail(Addon): #: It creates a temporary PyFile object using #: "link" data, changes its status, and tells #: The pyload.files-manager to save its data. - pylink = self._pyfile(link) + pyfile_new = self._create_pyFile(link) - pylink.setCustomStatus(_("unskipped"), "queued") + pyfile_new.setCustomStatus(_("unskipped"), "queued") self.pyload.files.save() - pylink.release() + pyfile_new.release() else: self.log_info(_("No duplicates found")) @@ -57,18 +53,16 @@ class UnSkipOnFail(Addon): the data for "pyfile" iotselöf. It does MOT check the link's status. """ - queue = self.pyload.api.getQueue() #: Get packages (w/o files, as most file data is useless here) - - for package in queue: + for pinfo in self.pyload.api.getQueue(): #: Check if package-folder equals pyfile's package folder - if package.folder is not pyfile.package().folder: + if pinfo.folder is not pyfile.package().folder: continue #: Now get packaged data w/ files/links - pdata = self.pyload.api.getPackageData(package.pid) + pdata = self.pyload.api.getPackageData(pinfo.pid) for link in pdata.links: #: Check if link == "skipped" - if link.status != 4: + if link.status is not 4: continue #: Check if link name collides with pdata's name @@ -77,14 +71,14 @@ class UnSkipOnFail(Addon): return link - def _pyfile(self, link): + def _create_pyFile(self, pylink): return PyFile(self.pyload.files, - link.fid, - link.url, - link.name, - link.size, - link.status, - link.error, - link.plugin, - link.packageID, - link.order) + pylink.fid, + pylink.url, + pylink.name, + pylink.size, + pylink.status, + pylink.error, + pylink.plugin, + pylink.packageID, + pylink.order) diff --git a/module/plugins/hooks/UpdateManager.py b/module/plugins/hooks/UpdateManager.py index e235b0e47..cf36a6d40 100644 --- a/module/plugins/hooks/UpdateManager.py +++ b/module/plugins/hooks/UpdateManager.py @@ -9,13 +9,13 @@ import sys import time from module.plugins.internal.Addon import Expose, Addon, threaded -from module.plugins.internal.utils import encode, exists, fs_join +from module.plugins.internal.misc import encode, exists, fsjoin class UpdateManager(Addon): __name__ = "UpdateManager" __type__ = "hook" - __version__ = "1.04" + __version__ = "1.05" __status__ = "testing" __config__ = [("activated" , "bool", "Activated" , True ), @@ -45,7 +45,7 @@ class UpdateManager(Addon): if self.do_restart is False: self.pyload.api.unpauseServer() - self.start_periodical(10) + self.periodical.start(10) def init(self): @@ -53,7 +53,7 @@ class UpdateManager(Addon): self.mtimes = {} #: Store modification time for each plugin self.event_map = {'allDownloadsProcessed': "all_downloads_processed"} - if self.get_config('checkonstart'): + if self.config.get('checkonstart'): self.pyload.api.pauseServer() self.checkonstart = True else: @@ -67,16 +67,16 @@ class UpdateManager(Addon): self.pyload.api.restart() - def periodical(self): + def periodical_task(self): if self.pyload.debug: - if self.get_config('reloadplugins'): + if self.config.get('reloadplugins'): self.autoreload_plugins() - if self.get_config('nodebugupdate'): + if self.config.get('nodebugupdate'): return - if self.get_config('checkperiod') and \ - time.time() - max(self.CHECK_INTERVAL, self.get_config('checkinterval') * 60 * 60) > self.info['last_check']: + if self.config.get('checkperiod') and \ + time.time() - max(self.CHECK_INTERVAL, self.config.get('checkinterval') * 60 * 60) > self.info['last_check']: self.update() @@ -146,7 +146,7 @@ class UpdateManager(Addon): """ Check for updates """ - if self._update() is not 2 or not self.get_config('autorestart'): + if self._update() is not 2 or not self.config.get('autorestart'): return if not self.pyload.api.statusDownloads(): @@ -304,7 +304,7 @@ class UpdateManager(Addon): m = self._VERSION.search(content) if m and m.group(2) == plugin_version: - with open(fs_join("userplugins", plugin_type, plugin_name + ".py"), "wb") as f: + with open(fsjoin("userplugins", plugin_type, plugin_name + ".py"), "wb") as f: f.write(encode(content)) updated.append((plugin_type, plugin_name)) @@ -342,7 +342,7 @@ class UpdateManager(Addon): rootplugins = os.path.join(pypath, "module", "plugins") for basedir in ("userplugins", rootplugins): - py_filename = fs_join(basedir, plugin_type, plugin_name + ".py") + py_filename = fsjoin(basedir, plugin_type, plugin_name + ".py") pyc_filename = py_filename + "c" if plugin_type is "hook": diff --git a/module/plugins/hooks/UserAgentSwitcher.py b/module/plugins/hooks/UserAgentSwitcher.py index 402dd001d..4b0b13c93 100644 --- a/module/plugins/hooks/UserAgentSwitcher.py +++ b/module/plugins/hooks/UserAgentSwitcher.py @@ -3,13 +3,13 @@ import pycurl from module.plugins.internal.Addon import Addon -from module.plugins.internal.utils import encode +from module.plugins.internal.misc import encode class UserAgentSwitcher(Addon): __name__ = "UserAgentSwitcher" __type__ = "hook" - __version__ = "0.12" + __version__ = "0.13" __status__ = "testing" __config__ = [("activated" , "bool", "Activated" , True ), @@ -23,9 +23,9 @@ class UserAgentSwitcher(Addon): def download_preparing(self, pyfile): - connecttimeout = self.get_config('connecttimeout') - maxredirs = self.get_config('maxredirs') - useragent = self.get_config('useragent') + connecttimeout = self.config.get('connecttimeout') + maxredirs = self.config.get('maxredirs') + useragent = self.config.get('useragent') if connecttimeout: pyfile.plugin.req.http.c.setopt(pycurl.CONNECTTIMEOUT, connecttimeout) diff --git a/module/plugins/hooks/WarezWorld.py b/module/plugins/hooks/WarezWorld.py deleted file mode 100644 index b097af8b2..000000000 --- a/module/plugins/hooks/WarezWorld.py +++ /dev/null @@ -1,277 +0,0 @@ -import httplib -import re -import StringIO -import sys -import traceback -import urllib -import urllib2 -from bs4 import BeautifulSoup as Soup -from datetime import datetime -from module.plugins.internal.Addon import Addon -from pytz import timezone - - -UNIX_EPOCH = timezone('UTC').localize(datetime(1970, 1, 1)) - - -def notifyPushover(**kwargs): - Data = kwargs - Connection = httplib.HTTPSConnection('api.pushover.net:443') - Connection.request('POST', '/1/messages.json', urllib.urlencode(Data), - {'Content-type': 'application/x-www-form-urlencoded'}) - Response = Connection.getresponse() - -def replaceUmlauts(title): - title = title.replace(unichr(228), 'ae').replace(unichr(196), 'Ae') - title = title.replace(unichr(252), 'ue').replace(unichr(220), 'Ue') - title = title.replace(unichr(246), 'oe').replace(unichr(214), 'Oe') - title = title.replace(unichr(223), 'ss') - title = title.replace('&', '&') - return title - -def getUnixTimestamp(String): - String = re.search(r'^.*(\d{2}.\d{2}.\d{4})(\d{1,2}):(\d{2}).*$', String) - if String: - String = String.group(1) + \ - ('0' + String.group(2) if String.group(2) < '10' else String.group(2)) + \ - String.group(3) - String = String.replace('.', '') - - UnixTimestamp = ( - timezone('Europe/Berlin').localize(datetime.strptime(String, '%d%m%Y%H%M')).astimezone(timezone('UTC')) - - UNIX_EPOCH - ).total_seconds() - return UnixTimestamp - - -class WarezWorld(Addon): - __name__ = 'WarezWorld' - __type__ = 'hook' - __status__ = 'testing' - __author_name__ = ('Arno-Nymous') - __author_mail__ = ('Arno-Nymous@users.noreply.github.com') - __version__ = '1.2' - __description__ = 'Get new movies from Warez-World.org' - __config__ = [ - ('activated', 'bool', 'Active', 'False'), - ('interval', 'int', 'Waiting time until next run in minutes', '60'), - ('minYear', 'long', 'No movies older than year', '1970'), - ('pushoverAppToken', 'str', 'Pushover app token', ''), - ('pushoverUserToken', 'str', 'Pushover user token', ''), - ('preferredHosters', 'str', 'Preferred hosters (seperated by;)','Share-online.biz'), - ('quality', '720p;1080p', 'Video quality', '720p'), - ('ratingCollector', 'float', 'Send releases to link collector with an IMDb rating of (or higher)', '6.5'), - ('ratingQueue', 'float', 'Send releases to queue with an IMDb rating of (or higher)', '8.0'), - ('rejectGenres', 'str', 'Reject movies of an of the following genres (seperated by ;)', 'Anime;Documentary;Family'), - ('rejectReleaseTokens', 'str', 'Reject releases containing any of the following tokens (seperated by ;)', '.ts.;.hdts.'), - ('soundError', ';none;alien;bike;bugle;cashregister;classical;climb;cosmic;echo;falling;gamelan;incoming;intermission;magic;mechanical;persistent;pianobar;pushover;siren;spacealarm;tugboat;updown', 'Use this sound for errors pushed via Pushover (empty for default)', ''), - ('soundNotification', ';none;alien;bike;bugle;cashregister;classical;climb;cosmic;echo;falling;gamelan;incoming;intermission;magic;mechanical;persistent;pianobar;pushover;siren;spacealarm;tugboat;updown', 'Use this sound for notifications pushed via Pushover (empty for default)', '') - ] - - UrlOpener = urllib2.build_opener() - RejectGenres = [] - RejectReleaseTokens = [] - LastReleaseTimestamp = None - # Initialize dictionary keys here to enable quick access on keys via augmented operators - # in later code without further code magic - Statistics = {'Total': 0, 'Added': 0, 'Skipped': 0, 'AlreadyProcessed': 0} - - def __init__(self, *args, **kwargs): - super(WarezWorld, self).__init__(*args, **kwargs) - self.start_periodical(self.get_config('interval')) - - def periodical(self): - self.log_info(u'Start periodical run...') - - self.interval = self.get_config('interval') * 60 - self.RejectGenres = self.get_config('rejectGenres').split(';') - self.PreferredHosters = self.get_config('preferredHosters').lower().split(';') - self.RejectReleaseTokens = self.get_config('rejectReleaseTokens').lower().split(';') - self.LastReleaseTimestamp = float(self.retrieve('LastReleaseTimestamp', 0)) - # Setting statistics to 0 by iterating over dictionary items - # instead of recreating dictionary over and over - for Key in self.Statistics: - self.Statistics[Key] = 0 - - try: - Request = urllib2.Request('http://warez-world.org/kategorie/filme', 'html5lib') - Request.add_header('User-Agent', 'Mozilla/5.0') - Page = Soup(self.UrlOpener.open(Request).read()) - Items = Page.findAll('li', class_='main-single') - Releases = [] - - for Item in Items: - Releases.append({ - 'MovieName': Item.find('span', class_='main-rls').text, - 'ReleaseName': re.search(r'<br/>(.*)</span>', unicode(Item.find('span', class_='main-rls'))).group(1), - 'ReleaseLink': unicode(Item.find('span', class_='main-rls').a['href']), - 'ReleaseDate': getUnixTimestamp(unicode(Item.find(class_='main-date').text)) - }) - self.log_info(u'{0} releases found'.format(len(Releases))) - - for Release in Releases[::-1]: - if (Release['ReleaseDate'] < self.LastReleaseTimestamp): - self.log_debug(u'Release already processed \"{0}\"'.format (Release['ReleaseName'])) - self.Statistics['AlreadyProcessed'] += 1 - continue - self.log_debug(u'Processing release \"{0}\"'.format(Release['ReleaseName'])) - Release['MovieYear'] = 1900 - Release['MovieRating'] = 0 - Release['MovieGenres'] = [] - if self.parseRelease(Release): - self.downloadRelease(Release) - - self.store('LastReleaseTimestamp', Releases[0]['ReleaseDate']) - self.log_debug(u'Last parsed release timestamp is {0}'.format(Releases[0]['ReleaseDate'])) - - self.Statistics['Total'] = sum(self.Statistics.itervalues()) - self.log_info(u'Periodical run finished. Statistics: {0} total, {1} added, {2} skipped, {3} already processed'.format( - self.Statistics['Total'], - self.Statistics['Added'], - self.Statistics['Skipped'], - self.Statistics['AlreadyProcessed'] - )) - except: - exc_type, exc_value, exc_traceback = sys.exc_info() - output = StringIO.StringIO() - traceback.print_exception(exc_type, exc_value, exc_traceback, file=output) - if 'Release' in locals(): - msg = '<b>Stacktrace</b>\n{0}\n<b>Release</b>\n{1}\n\n<b>Date</b>\n{2}'.format( - output.getvalue(), Release['ReleaseName'].encode('utf-8'), Release['ReleaseDate'] - ) - else: - msg = '<b>Stacktrace</b>\n{0}'.format(output.getvalue()) - notifyPushover( - token=self.get_config('pushoverAppToken'), - user=self.get_config('pushoverUserToken'), - title='Error in script \"WarezWorld.py\"', - message=msg, - sound=self.get_config('soundError'), - html=1 - ) - raise - - def parseRelease(self, Release): - if any([ - set(re.split(r'[\. ]', Release['ReleaseName'].lower())) & set(self.RejectReleaseTokens), - not(self.get_config('quality').lower() in Release['ReleaseName'].lower()) - ]): - self.log_debug(u'...Skip release ({0})'.format("Release name contains unwanted tokens or quality mismatch")) - self.Statistics['Skipped'] += 1 - return False - - Request = urllib2.Request(Release['ReleaseLink'], 'html5lib') - Request.add_header('User-Agent', 'Mozilla/5.0') - ReleasePage = Soup(self.UrlOpener.open(Request).read()) - - DownloadLinks = ReleasePage.findAll('div', id='download-links') - if DownloadLinks: - for DownloadLink in DownloadLinks: - if DownloadLink.a.string and DownloadLink.a.string.lower() in self.PreferredHosters: - Release['DownloadLink'] = DownloadLink.a['href'] - break - if 'DownloadLink' not in Release: - self.log_debug('...No download link of preferred hoster found') - return False - - ReleaseNfo = ReleasePage.find('div', class_='spoiler') - ImdbUrl = re.search(r'(http://)?.*(imdb\.com/title/tt\d+)\D', unicode(ReleaseNfo)) - if ImdbUrl: - Release['ImdbUrl'] = 'http://www.' + ImdbUrl.group(2) - self.addImdbData(Release) - else: - for Div in ReleasePage.findAll('div', class_='ui2'): - if Div.a and Div.a.string == 'IMDb-Seite': - Request = urllib2.Request(urllib.quote_plus(Div.a['href'].encode('utf-8'), '/:?=')) - ImdbPage = Soup(self.UrlOpener.open(Request).read()) - if ImdbPage.find('table', class_='findList'): - Release['ImdbUrl'] = 'http://www.imdb.com' + \ - ImdbPage.find('td', class_='result_text').a['href'] - self.addImdbData(Release) - else: - self.log_debug(u'...Could not obtain IMDb data for release...Send to link collector') - self.Statistics['Added'] += 1 - break - - if all([Release['MovieYear'] >= self.get_config('minYear'), - Release['MovieRating'] >= self.get_config('ratingCollector'), - not(set(Release['MovieGenres']) & set(self.RejectGenres))]): - return True - else: - self.log_debug(u'...Skip release ({0})'.format('Movie too old, poor IMDb rating or unwanted genres')) - self.Statistics['Skipped'] += 1 - return False - - def addImdbData(self, Release): - self.log_debug(u'...Fetching IMDb data for release ({0})'.format(Release['ImdbUrl'])) - - Request = urllib2.Request(Release['ImdbUrl']) - Request.add_header('User-Agent', 'Mozilla/5.0') - ImdbPage = Soup(self.UrlOpener.open(Request).read()) - - MovieName = ImdbPage.find('span', {'itemprop': 'name'}).string - # For the year it has to be done a tiny bit of BeautifulSoup magic as it sometimes can - # be formatted as a link on IMDb and sometimes not - try: - MovieYear = ImdbPage.find('h1', class_='header').find('span', class_='nobr').find( - text=re.compile(r'\d{4}') - ).strip(u' ()\u2013') - except: - MovieYear = 0 - self.log_debug('...Could not parse movie year ({0})'.format(Release['ImdbUrl'])) - try: - MovieRating = ImdbPage.find('span', {'itemprop': 'ratingValue'}).string.replace(',', '.') - except: - MovieRating = 0 - self.log_debug(u'...Could not parse movie rating ({0})'.format(MovieName, Release['ImdbUrl'])) - MovieGenres = [] - try: - for Genre in ImdbPage.find('div', {'itemprop': 'genre'}).findAll('a'): - MovieGenres.append(Genre.string.strip()) - except: - self.log_debug(u'...Could not parse movie genres ({0})'.format(Release['ImdbUrl'])) - - Release['MovieName'] = MovieName - Release['MovieYear'] = MovieYear - Release['MovieRating'] = MovieRating - Release['MovieGenres'] = MovieGenres - - def downloadRelease(self, Release): - Storage = self.retrieve(u'{0} ({1})'.format(Release['MovieName'], Release['MovieYear'])) - - if Storage == '1': - self.log_debug(u'Skip release ({0})'.format('already downloaded')) - self.Statistics['Skipped'] += 1 - else: - Storage = u'{0} ({1})'.format(Release['MovieName'], Release['MovieYear']) - if Release['MovieRating'] >= self.get_config('ratingQueue'): - self.pyload.api.addPackage(Storage + ' IMDb: ' + Release['MovieRating'], - [Release['DownloadLink']], 1) - PushoverTitle = 'New movie added to queue' - self.log_info(u'New movie added to queue ({0})'.format(Storage)) - else: - self.pyload.api.addPackage(Storage + ' IMDb: ' + Release['MovieRating'], - [Release['DownloadLink']], 0) - PushoverTitle = 'New movie added to link collector' - self.log_info(u'New movie added to link collector ({0})'.format(Storage)) - - self.Statistics['Added'] += 1 - - notifyPushover( - token=self.get_config('pushoverAppToken'), - user=self.get_config('pushoverUserToken'), - title=PushoverTitle, - message='<b>{0} ({1})</b>\n<i>Rating:</i> {2}\n<i>Genres:</i> {3}\n\n<i>{4}</i>'.format( - Release['MovieName'].encode('utf-8'), - Release['MovieYear'].encode('utf-8'), - Release['MovieRating'].encode('utf-8'), - ', '.join(Release['MovieGenres']).encode('utf-8'), - Release['ReleaseName'].encode('utf-8') - ), - sound=self.get_config('soundNotification'), - url=(Release['ImdbUrl'].encode('utf-8') if 'ImdbUrl' in Release else ''), - url_title='View on IMDb', - html=1 - ) - - self.store(Storage, '1') diff --git a/module/plugins/hooks/WindowsPhoneNotify.py b/module/plugins/hooks/WindowsPhoneNotify.py index cd5f5dea4..84d122811 100644 --- a/module/plugins/hooks/WindowsPhoneNotify.py +++ b/module/plugins/hooks/WindowsPhoneNotify.py @@ -9,20 +9,23 @@ from module.plugins.internal.Notifier import Notifier class WindowsPhoneNotify(Notifier): __name__ = "WindowsPhoneNotify" __type__ = "hook" - __version__ = "0.15" + __version__ = "0.17" __status__ = "testing" - __config__ = [("activated" , "bool", "Activated" , False), - ("push-id" , "str" , "Push ID" , "" ), - ("push-url" , "str" , "Push url" , "" ), - ("notifycaptcha" , "bool", "Notify captcha request" , True ), - ("notifypackage" , "bool", "Notify package finished" , True ), - ("notifyprocessed", "bool", "Notify packages processed" , True ), - ("notifyupdate" , "bool", "Notify plugin updates" , True ), - ("notifyexit" , "bool", "Notify pyLoad shutdown" , True ), - ("sendtimewait" , "int" , "Timewait in seconds between notifications", 5 ), - ("sendpermin" , "int" , "Max notifications per minute" , 12 ), - ("ignoreclient" , "bool", "Send notifications if client is connected", False)] + __config__ = [("activated" , "bool", "Activated" , False), + ("pushid" , "str" , "Push ID" , "" ), + ("pushurl" , "str" , "Push url" , "" ), + ("captcha" , "bool", "Notify captcha request" , True ), + ("reconnection" , "bool", "Notify reconnection request" , False), + ("downloadfinished", "bool", "Notify download finished" , True ), + ("downloadfailed" , "bool", "Notify download failed" , True ), + ("packagefinished" , "bool", "Notify package finished" , True ), + ("packagefailed" , "bool", "Notify package failed" , True ), + ("update" , "bool", "Notify pyLoad update" , False), + ("exit" , "bool", "Notify pyLoad shutdown/restart" , False), + ("sendinterval" , "int" , "Interval in seconds between notifications", 1 ), + ("sendpermin" , "int" , "Max notifications per minute" , 60 ), + ("ignoreclient" , "bool", "Send notifications if client is connected", True )] __description__ = """Send push notifications to Windows Phone""" __license__ = "GPLv3" @@ -31,7 +34,7 @@ class WindowsPhoneNotify(Notifier): def get_key(self): - return self.get_config('push-id'), self.get_config('push-url') + return self.config.get('pushid'), self.config.get('pushurl') def format_request(self, msg): diff --git a/module/plugins/hooks/XFileSharing.py b/module/plugins/hooks/XFileSharing.py index 26dea3ec6..4af246da8 100644 --- a/module/plugins/hooks/XFileSharing.py +++ b/module/plugins/hooks/XFileSharing.py @@ -9,10 +9,10 @@ from module.plugins.internal.Addon import Addon class XFileSharing(Addon): __name__ = "XFileSharing" __type__ = "hook" - __version__ = "0.52" + __version__ = "0.55" __status__ = "testing" - __config__ = [("activated" , "bool", "Activated" , True ), + __config__ = [("activated" , "bool", "Activated" , False), ("use_hoster_list" , "bool", "Load listed hosters only" , False), ("use_crypter_list", "bool", "Load listed crypters only" , False), ("use_builtin_list", "bool", "Load built-in plugin list" , True ), @@ -24,9 +24,9 @@ class XFileSharing(Addon): __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - regexp = {'hoster' : (r'(?:https?://(?:www\.)?)(?!%s)(?:\w+\.)*?(?P<DOMAIN>(?:[\d.]+|[\w\-^_]{3,63}(?:\.[a-zA-Z]{2,}){1,2})(?:\:\d+)?)/(?:embed-)?\w{12}(?:\W|$)', + regexp = {'hoster' : (r'(?:https?://(?:www\.)?)(?!(?:www\.)?(?:%s))(?P<DOMAIN>(?:[\d.]+|[\w\-^_]{3,63}(?:\.[a-zA-Z]{2,})+)(?:\:\d+)?)/(?:embed-)?\w{12}(?:\W|$)', r'https?://(?:[^/]+\.)?(?P<DOMAIN>%s)/(?:embed-)?\w+'), - 'crypter': (r'(?:https?://(?:www\.)?)(?!%s)(?:\w+\.)*?(?P<DOMAIN>(?:[\d.]+|[\w\-^_]{3,63}(?:\.[a-zA-Z]{2,}){1,2})(?:\:\d+)?)/(?:user|folder)s?/\w+', + 'crypter': (r'(?:https?://(?:www\.)?)(?!(?:www\.)?(?:%s))(?P<DOMAIN>(?:[\d.]+|[\w\-^_]{3,63}(?:\.[a-zA-Z]{2,})+)(?:\:\d+)?)/(?:user|folder)s?/\w+', r'https?://(?:[^/]+\.)?(?P<DOMAIN>%s)/(?:user|folder)s?/\w+')} BUILTIN_HOSTERS = [# WORKING HOSTERS: @@ -60,15 +60,15 @@ class XFileSharing(Addon): def get_pattern(self, type, plugin): - if self.get_config("use_%s_list" % type): - plugin_list = self.get_config('%s_list' % type) + if self.config.get("use_%s_list" % type): + plugin_list = self.config.get('%s_list' % type) plugin_list = plugin_list.replace(' ', '').replace('\\', '') plugin_list = plugin_list.replace('|', ',').replace(';', ',') plugin_list = plugin_list.lower().split(',') plugin_set = set(plugin_list) - if self.get_config('use_builtin_list'): + if self.config.get('use_builtin_list'): builtin_list = getattr(self, "BUILTIN_%sS" % type.upper()) plugin_set.update(builtin_list) @@ -91,7 +91,13 @@ class XFileSharing(Addon): isXFS = lambda klass: any(k.__name__.startswith("XFS") for k in inspect.getmro(klass)) for p in self.pyload.pluginManager.plugins[type].values(): - klass = self.pyload.pluginManager.loadClass(type, p['name']) + try: + klass = self.pyload.pluginManager.loadClass(type, p['name']) + + except AttributeError, e: + self.log_debug(e, trace=True) + continue + if hasattr(klass, "PLUGIN_DOMAIN") and klass.PLUGIN_DOMAIN and isXFS(klass): plugin_list.append(klass.PLUGIN_DOMAIN) @@ -101,7 +107,7 @@ class XFileSharing(Addon): else: pattern = self.regexp[type][0] - self.log_info(_("Handle any %s site on the web!") % type) + self.log_info(_("Auto-discover new %ss") % type) return pattern @@ -116,13 +122,10 @@ class XFileSharing(Addon): dict['pattern'] = pattern dict['re'] = re.compile(pattern) - self.log_debug("Loaded %s pattern: %s" % (type, pattern)) + self.log_debug("Pattern for %ss: %s" % (type, pattern)) def _unload(self, type, plugin): dict = self.pyload.pluginManager.plugins[type][plugin] dict['pattern'] = r'^unmatchable$' dict['re'] = re.compile(dict['pattern']) - - - diff --git a/module/plugins/hooks/XMPPInterface.py b/module/plugins/hooks/XMPP.py index b8fe14239..1e0eda59b 100644 --- a/module/plugins/hooks/XMPPInterface.py +++ b/module/plugins/hooks/XMPP.py @@ -1,18 +1,16 @@ # -*- coding: utf-8 -*- -from pyxmpp import streamtls -from pyxmpp.all import JID, Message -from pyxmpp.interface import implements -from pyxmpp.interfaces import * +import pyxmpp + from pyxmpp.jabber.client import JabberClient -from module.plugins.hooks.IRCInterface import IRCInterface +from module.plugins.hooks.IRC import IRC -class XMPPInterface(IRCInterface, JabberClient): - __name__ = "XMPPInterface" +class XMPP(IRC, JabberClient): + __name__ = "XMPP" __type__ = "hook" - __version__ = "0.14" + __version__ = "0.15" __status__ = "testing" __config__ = [("activated", "bool", "Activated" , False ), @@ -29,21 +27,21 @@ class XMPPInterface(IRCInterface, JabberClient): __authors__ = [("RaNaN", "RaNaN@pyload.org")] - implements(IMessageHandlersProvider) + pyxmpp.interface.implements(IMessageHandlersProvider) def __init__(self, *args, **kwargs): - IRCInterface.__init__(self, *args, **kwargs) + IRC.__init__(self, *args, **kwargs) - self.jid = JID(self.get_config('jid')) - password = self.get_config('pw') + self.jid = pyxmpp.all.JID(self.config.get('jid')) + password = self.config.get('pw') #: If bare JID is provided add a resource -- it is required if not self.jid.resource: - self.jid = JID(self.jid.node, self.jid.domain, "pyLoad") + self.jid = pyxmpp.all.JID(self.jid.node, self.jid.domain, "pyLoad") - if self.get_config('tls'): - tls_settings = streamtls.TLSSettings(require=True, verify_peer=False) + if self.config.get('tls'): + tls_settings = pyxmpp.streamtls.TLSSettings(require=True, verify_peer=False) auth = ("sasl:PLAIN", "sasl:DIGEST-MD5") else: tls_settings = None @@ -69,7 +67,7 @@ class XMPPInterface(IRCInterface, JabberClient): def package_finished(self, pypack): try: - if self.get_config('info_pack'): + if self.config.get('info_pack'): self.announce(_("Package finished: %s") % pypack.name) except Exception: @@ -78,7 +76,7 @@ class XMPPInterface(IRCInterface, JabberClient): def download_finished(self, pyfile): try: - if self.get_config('info_file'): + if self.config.get('info_file'): self.announce( _("Download finished: %(name)s @ %(plugin)s") % {'name': pyfile.name, 'plugin': pyfile.pluginname}) @@ -146,11 +144,11 @@ class XMPPInterface(IRCInterface, JabberClient): to_jid = stanza.get_from() from_jid = stanza.get_to() - # j = JID() + # j = pyxmpp.all.JID() to_name = to_jid.as_utf8() from_name = from_jid.as_utf8() - names = self.get_config('owners').split(";") + names = self.config.get('owners').split(";") if to_name in names or to_jid.node + "@" + to_jid.domain in names: messages = [] @@ -171,7 +169,7 @@ class XMPPInterface(IRCInterface, JabberClient): try: res = handler(args) for line in res: - m = Message( + m = pyxmpp.all.Message( to_jid=to_jid, from_jid=from_jid, stanza_type=stanza.get_type(), @@ -197,15 +195,15 @@ class XMPPInterface(IRCInterface, JabberClient): """ Send message to all owners """ - for user in self.get_config('owners').split(";"): + for user in self.config.get('owners').split(";"): self.log_debug("Send message to", user) - to_jid = JID(user) + to_jid = pyxmpp.all.JID(user) - m = Message(from_jid=self.jid, - to_jid=to_jid, - stanza_type="chat", - body=message) + m = pyxmpp.all.Message(from_jid=self.jid, + to_jid=to_jid, + stanza_type="chat", + body=message) stream = self.get_stream() if not stream: @@ -230,7 +228,7 @@ class VersionHandler(object): This class will answer version query and announce 'jabber:iq:version' namespace in the client's disco#info results. """ - implements(IIqHandlersProvider, IFeaturesProvider) + pyxmpp.interface.implements(IIqHandlersProvider, IFeaturesProvider) def __init__(self, client): |