diff options
Diffstat (limited to 'module/plugins/hooks')
56 files changed, 1682 insertions, 1193 deletions
diff --git a/module/plugins/hooks/AlldebridCom.py b/module/plugins/hooks/AlldebridComHook.py index dddd97c0c..092921134 100644 --- a/module/plugins/hooks/AlldebridCom.py +++ b/module/plugins/hooks/AlldebridComHook.py @@ -3,16 +3,14 @@ from module.plugins.internal.MultiHook import MultiHook -class AlldebridCom(MultiHook): - __name__ = "AlldebridCom" +class AlldebridComHook(MultiHook): + __name__ = "AlldebridComHook" __type__ = "hook" __version__ = "0.16" __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), ("reload" , "bool" , "Reload plugin list" , True ), ("reloadinterval", "int" , "Reload interval in hours" , 12 ), ("ssl" , "bool" , "Use HTTPS" , True )] @@ -23,7 +21,7 @@ class AlldebridCom(MultiHook): def getHosters(self): - https = "https" if self.getConfig("ssl") else "http" - page = self.getURL(https + "://www.alldebrid.com/api.php", get={'action': "get_host"}).replace("\"", "").strip() + https = "https" if self.getConfig('ssl') else "http" + html = self.getURL(https + "://www.alldebrid.com/api.php", get={'action': "get_host"}).replace("\"", "").strip() - return [x.strip() for x in page.split(",") if x.strip()] + return [x.strip() for x in html.split(",") if x.strip()] diff --git a/module/plugins/hooks/AndroidPhoneNotify.py b/module/plugins/hooks/AndroidPhoneNotify.py index 18e1cce66..a8a1cff72 100644 --- a/module/plugins/hooks/AndroidPhoneNotify.py +++ b/module/plugins/hooks/AndroidPhoneNotify.py @@ -1,59 +1,80 @@ # -*- coding: utf-8 -*- -from time import time +import time from module.network.RequestFactory import getURL -from module.plugins.Hook import Hook +from module.plugins.Hook import Hook, Expose class AndroidPhoneNotify(Hook): __name__ = "AndroidPhoneNotify" __type__ = "hook" - __version__ = "0.02" + __version__ = "0.08" __config__ = [("apikey" , "str" , "API key" , "" ), ("notifycaptcha" , "bool", "Notify captcha request" , True ), ("notifypackage" , "bool", "Notify package finished" , True ), - ("notifyprocessed", "bool", "Notify processed packages status" , True ), - ("timeout" , "int" , "Timeout between captchas in seconds" , 5 ), - ("force" , "bool", "Send notifications if client is connected", False)] - - __description__ = """Send push notifications to your Android Phone using notifymyandroid.com""" + ("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)] + + __description__ = """Send push notifications to your Android Phone (using notifymyandroid.com)""" __license__ = "GPLv3" - __authors__ = [("Steven Kosyra", "steven.kosyra@gmail.com"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - event_list = ["allDownloadsProcessed"] + __authors__ = [("Steven Kosyra" , "steven.kosyra@gmail.com"), + ("Walter Purcaro", "vuolter@gmail.com" )] - #@TODO: Remove in 0.4.10 - def initPeriodical(self): - pass + interval = 0 #@TODO: Remove in 0.4.10 def setup(self): self.info = {} #@TODO: Remove in 0.4.10 + self.event_list = ["allDownloadsProcessed", "plugin_updated"] + + self.last_notify = 0 + self.notifications = 0 + + + def plugin_updated(self, type_plugins): + if not self.getConfig('notifyupdate'): + return + + self.notify(_("Plugins updated"), str(type_plugins)) + + + def coreReady(self): + self.key = self.getConfig('apikey') - def newCaptchaTask(self, task): - if not self.getConfig("notifycaptcha"): - return False - if time() - float(self.getStorage("AndroidPhoneNotify", 0)) < self.getConf("timeout"): - return False + def coreExiting(self): + if not self.getConfig('notifyexit'): + return + + if self.core.do_restart: + self.notify(_("Restarting pyLoad")) + else: + self.notify(_("Exiting pyLoad")) + + + def newCaptchaTask(self, task): + if not self.getConfig('notifycaptcha'): + return self.notify(_("Captcha"), _("New request waiting user input")) def packageFinished(self, pypack): - if self.getConfig("notifypackage"): + if self.getConfig('notifypackage'): self.notify(_("Package finished"), pypack.name) - def allDownloadsProcessed(self, thread): - if not self.getConfig("notifyprocessed"): - return False + def allDownloadsProcessed(self): + if not self.getConfig('notifyprocessed'): + return if any(True for pdata in self.core.api.getQueue() if pdata.linksdone < pdata.linkstotal): self.notify(_("Package failed"), _("One or more packages was not completed successfully")) @@ -61,19 +82,37 @@ class AndroidPhoneNotify(Hook): self.notify(_("All packages finished")) - def notify(self, event, msg=""): - apikey = self.getConfig("apikey") + @Expose + def notify(self, + event, + msg="", + key=None): - if not apikey: - return False + key = key or self.key + if not key: + return - if self.core.isClientConnected() and not self.getConfig("force"): - return False + if self.core.isClientConnected() and not self.getConfig('ignoreclient'): + return + + elapsed_time = time.time() - self.last_notify + + if elapsed_time < self.getConf("sendtimewait"): + return + + if elapsed_time > 60: + self.notifications = 0 + + elif self.notifications >= self.getConf("sendpermin"): + return getURL("http://www.notifymyandroid.com/publicapi/notify", - get={'apikey' : apikey, + get={'apikey' : key, 'application': "pyLoad", 'event' : event, 'description': msg}) - self.setStorage("AndroidPhoneNotify", time()) + self.last_notify = time.time() + self.notifications += 1 + + return True diff --git a/module/plugins/hooks/AntiVirus.py b/module/plugins/hooks/AntiVirus.py new file mode 100644 index 000000000..c620f556d --- /dev/null +++ b/module/plugins/hooks/AntiVirus.py @@ -0,0 +1,119 @@ +# -*- coding: utf-8 -*- + +import os +import shutil +import subprocess + +try: + import send2trash +except ImportError: + pass + +from module.plugins.Hook import Hook, Expose, threaded +from module.utils import fs_encode, save_join + + +class AntiVirus(Hook): + __name__ = "AntiVirus" + __type__ = "hook" + __version__ = "0.09" + + #@TODO: add trash option (use Send2Trash lib) + __config__ = [("action" , "Antivirus default;Delete;Quarantine", "Manage infected files" , "Antivirus default"), + ("quardir" , "folder" , "Quarantine folder" , "" ), + ("deltotrash", "bool" , "Move to trash (recycle bin) instead delete", True ), + ("scanfailed", "bool" , "Scan incompleted files (failed downloads)" , False ), + ("cmdfile" , "file" , "Antivirus executable" , "" ), + ("cmdargs" , "str" , "Scan options" , "" ), + ("ignore-err", "bool" , "Ignore scan errors" , False )] + + __description__ = """Scan downloaded files with antivirus program""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + interval = 0 #@TODO: Remove in 0.4.10 + + + def setup(self): + self.info = {} #@TODO: Remove in 0.4.10 + + + @Expose + @threaded + def scan(self, pyfile, thread): + file = fs_encode(pyfile.plugin.lastDownload) + filename = os.path.basename(pyfile.plugin.lastDownload) + cmdfile = fs_encode(self.getConfig('cmdfile')) + cmdargs = fs_encode(self.getConfig('cmdargs').strip()) + + if not os.path.isfile(file) or not os.path.isfile(cmdfile): + return + + thread.addActive(pyfile) + pyfile.setCustomStatus(_("virus scanning")) + pyfile.setProgress(0) + + try: + p = subprocess.Popen([cmdfile, cmdargs, file], bufsize=-1, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + out, err = map(str.strip, p.communicate()) + + if out: + self.logInfo(filename, out) + + if err: + self.logWarning(filename, err) + if not self.getConfig('ignore-err'): + self.logDebug("Delete/Quarantine task is aborted") + return + + if p.returncode: + pyfile.error = _("infected file") + action = self.getConfig('action') + try: + if action == "Delete": + if not self.getConfig('deltotrash'): + os.remove(file) + + else: + try: + send2trash.send2trash(file) + + except NameError: + self.logWarning(_("Send2Trash lib not found, moving to quarantine instead")) + pyfile.setCustomStatus(_("file moving")) + shutil.move(file, self.getConfig('quardir')) + + except Exception, e: + self.logWarning(_("Unable to move file to trash: %s, moving to quarantine instead") % e.message) + pyfile.setCustomStatus(_("file moving")) + shutil.move(file, self.getConfig('quardir')) + + else: + self.logDebug(_("Successfully moved file to trash")) + + elif action == "Quarantine": + pyfile.setCustomStatus(_("file moving")) + shutil.move(file, self.getConfig('quardir')) + + except (IOError, shutil.Error), e: + self.logError(filename, action + " action failed!", e) + + elif not out and not err: + self.logDebug(filename, "No infected file found") + + finally: + pyfile.setProgress(100) + thread.finishFile(pyfile) + + + def downloadFinished(self, pyfile): + return self.scan(pyfile) + + + def downloadFailed(self, pyfile): + #: Check if pyfile is still "failed", + # maybe might has been restarted in meantime + if pyfile.status == 8 and self.getConfig('scanfailed'): + return self.scan(pyfile) diff --git a/module/plugins/hooks/BypassCaptcha.py b/module/plugins/hooks/BypassCaptcha.py index 8e0d9d36e..9e01edfa2 100644 --- a/module/plugins/hooks/BypassCaptcha.py +++ b/module/plugins/hooks/BypassCaptcha.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -from pycurl import FORM_FILE, LOW_SPEED_TIME +import pycurl from module.network.HTTPRequest import BadHeader from module.network.RequestFactory import getURL, getRequest @@ -35,11 +35,13 @@ class BypassCaptcha(Hook): __description__ = """Send captchas to BypassCaptcha.com""" __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org"), + __authors__ = [("RaNaN" , "RaNaN@pyload.org" ), ("Godofdream", "soilfcition@gmail.com"), - ("zoidberg", "zoidberg@mujmail.cz")] + ("zoidberg" , "zoidberg@mujmail.cz" )] + interval = 0 #@TODO: Remove in 0.4.10 + PYLOAD_KEY = "4f771155b640970d5607f919a615bdefc67e7d32" SUBMIT_URL = "http://bypasscaptcha.com/upload.php" @@ -47,19 +49,14 @@ class BypassCaptcha(Hook): GETCREDITS_URL = "http://bypasscaptcha.com/ex_left.php" - #@TODO: Remove in 0.4.10 - def initPeriodical(self): - pass - - def setup(self): self.info = {} #@TODO: Remove in 0.4.10 def getCredits(self): - res = getURL(self.GETCREDITS_URL, post={"key": self.getConfig("passkey")}) + res = getURL(self.GETCREDITS_URL, post={"key": self.getConfig('passkey')}) - data = dict([x.split(' ', 1) for x in res.splitlines()]) + data = dict(x.split(' ', 1) for x in res.splitlines()) return int(data['Left']) @@ -67,19 +64,19 @@ class BypassCaptcha(Hook): req = getRequest() #raise timeout threshold - req.c.setopt(LOW_SPEED_TIME, 80) + req.c.setopt(pycurl.LOW_SPEED_TIME, 80) try: res = req.load(self.SUBMIT_URL, post={'vendor_key': self.PYLOAD_KEY, - 'key': self.getConfig("passkey"), + 'key': self.getConfig('passkey'), 'gen_task_id': "1", - 'file': (FORM_FILE, captcha)}, + 'file': (pycurl.FORM_FILE, captcha)}, multipart=True) finally: req.close() - data = dict([x.split(' ', 1) for x in res.splitlines()]) + data = dict(x.split(' ', 1) for x in res.splitlines()) if not data or "Value" not in data: raise BypassCaptchaException(res) @@ -92,7 +89,7 @@ class BypassCaptcha(Hook): def respond(self, ticket, success): try: - res = getURL(self.RESPOND_URL, post={"task_id": ticket, "key": self.getConfig("passkey"), + res = getURL(self.RESPOND_URL, post={"task_id": ticket, "key": self.getConfig('passkey'), "cv": 1 if success else 0}) except BadHeader, e: self.logError(_("Could not send response"), e) @@ -105,10 +102,10 @@ class BypassCaptcha(Hook): if not task.isTextual(): return False - if not self.getConfig("passkey"): + if not self.getConfig('passkey'): return False - if self.core.isClientConnected() and not self.getConfig("force"): + if self.core.isClientConnected() and not self.getConfig('force'): return False if self.getCredits() > 0: diff --git a/module/plugins/hooks/Captcha9kw.py b/module/plugins/hooks/Captcha9Kw.py index 600694e78..60482b8fc 100755..100644 --- a/module/plugins/hooks/Captcha9kw.py +++ b/module/plugins/hooks/Captcha9Kw.py @@ -3,9 +3,9 @@ from __future__ import with_statement import re +import time from base64 import b64encode -from time import sleep from module.network.HTTPRequest import BadHeader from module.network.RequestFactory import getURL @@ -16,10 +16,9 @@ from module.plugins.Hook import Hook, threaded class Captcha9Kw(Hook): __name__ = "Captcha9Kw" __type__ = "hook" - __version__ = "0.27" + __version__ = "0.28" - __config__ = [("activated" , "bool" , "Activated" , True ), - ("ssl" , "bool" , "Use HTTPS" , True ), + __config__ = [("ssl" , "bool" , "Use HTTPS" , True ), ("force" , "bool" , "Force captcha resolving even if client is connected" , True ), ("confirm" , "bool" , "Confirm Captcha (cost +6 credits)" , False ), ("captchaperhour", "int" , "Captcha per hour" , "9999" ), @@ -33,27 +32,24 @@ class Captcha9Kw(Hook): __description__ = """Send captchas to 9kw.eu""" __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org"), + __authors__ = [("RaNaN" , "RaNaN@pyload.org" ), ("Walter Purcaro", "vuolter@gmail.com")] - API_URL = "http://www.9kw.eu/index.cgi" - + interval = 0 #@TODO: Remove in 0.4.10 - #@TODO: Remove in 0.4.10 - def initPeriodical(self): - pass + API_URL = "http://www.9kw.eu/index.cgi" def setup(self): self.info = {} #@TODO: Remove in 0.4.10 - if self.getConfig("ssl"): + if self.getConfig('ssl'): self.API_URL = self.API_URL.replace("http://", "https://") def getCredits(self): res = getURL(self.API_URL, - get={'apikey': self.getConfig("passkey"), + get={'apikey': self.getConfig('passkey'), 'pyload': "1", 'source': "pyload", 'action': "usercaptchaguthaben"}) @@ -77,24 +73,21 @@ class Captcha9Kw(Hook): self.logError(e) return - data = b64encode(data) - mouse = 1 if task.isPositional() else 0 pluginname = re.search(r'_([^_]*)_\d+.\w+', task.captchaFile).group(1) - - option = {'min' : 2, - 'max' : 50, - 'phrase' : 0, - 'numeric' : 0, - 'case_sensitive': 0, - 'math' : 0, - 'prio' : min(max(self.getConfig("prio"), 0), 10), - 'confirm' : self.getConfig("confirm"), - 'timeout' : min(max(self.getConfig("timeout"), 300), 3999), - 'selfsolve' : self.getConfig("selfsolve"), - 'cph' : self.getConfig("captchaperhour"), - 'cpm' : self.getConfig("captchapermin")} - - for opt in str(self.getConfig("hoster_options").split('|')): + option = {'min' : 2, + 'max' : 50, + 'phrase' : 0, + 'numeric' : 0, + 'case_sensitive': 0, + 'math' : 0, + 'prio' : min(max(self.getConfig('prio'), 0), 10), + 'confirm' : self.getConfig('confirm'), + 'timeout' : min(max(self.getConfig('timeout'), 300), 3999), + 'selfsolve' : self.getConfig('selfsolve'), + 'cph' : self.getConfig('captchaperhour'), + 'cpm' : self.getConfig('captchapermin')} + + for opt in str(self.getConfig('hoster_options').split('|')): details = map(str.strip, opt.split(':')) @@ -113,7 +106,7 @@ class Captcha9Kw(Hook): break - post_data = {'apikey' : self.getConfig("passkey"), + post_data = {'apikey' : self.getConfig('passkey'), 'prio' : option['prio'], 'confirm' : option['confirm'], 'maxtimeout' : option['timeout'], @@ -130,15 +123,15 @@ class Captcha9Kw(Hook): 'pyload' : "1", 'source' : "pyload", 'base64' : "1", - 'mouse' : mouse, - 'file-upload-01': data, + 'mouse' : 1 if task.isPositional() else 0, + 'file-upload-01': b64encode(data), 'action' : "usercaptchaupload"} for _i in xrange(5): try: res = getURL(self.API_URL, post=post_data) except BadHeader, e: - sleep(3) + time.sleep(3) else: if res and res.isdigit(): break @@ -150,9 +143,9 @@ class Captcha9Kw(Hook): task.data["ticket"] = res - for _i in xrange(int(self.getConfig("timeout") / 5)): + for _i in xrange(int(self.getConfig('timeout') / 5)): result = getURL(self.API_URL, - get={'apikey': self.getConfig("passkey"), + get={'apikey': self.getConfig('passkey'), 'id' : res, 'pyload': "1", 'info' : "1", @@ -160,7 +153,7 @@ class Captcha9Kw(Hook): 'action': "usercaptchacorrectdata"}) if not result or result == "NO DATA": - sleep(5) + time.sleep(5) else: break else: @@ -176,10 +169,10 @@ class Captcha9Kw(Hook): if not task.isTextual() and not task.isPositional(): return - if not self.getConfig("passkey"): + if not self.getConfig('passkey'): return - if self.core.isClientConnected() and not self.getConfig("force"): + if self.core.isClientConnected() and not self.getConfig('force'): return credits = self.getCredits() @@ -188,8 +181,8 @@ class Captcha9Kw(Hook): self.logError(_("Your captcha 9kw.eu account has not enough credits")) return - queue = min(self.getConfig("queue"), 999) - timeout = min(max(self.getConfig("timeout"), 300), 3999) + queue = min(self.getConfig('queue'), 999) + timeout = min(max(self.getConfig('timeout'), 300), 3999) pluginname = re.search(r'_([^_]*)_\d+.\w+', task.captchaFile).group(1) for _i in xrange(5): @@ -197,11 +190,11 @@ class Captcha9Kw(Hook): if queue < re.search(r'queue=(\d+)', servercheck).group(1): break - sleep(10) + time.sleep(10) else: self.fail(_("Too many captchas in queue")) - for opt in str(self.getConfig("hoster_options").split('|')): + for opt in str(self.getConfig('hoster_options').split('|')): details = map(str.strip, opt.split(':')) if not details or details[0].lower() != pluginname.lower(): @@ -210,9 +203,9 @@ class Captcha9Kw(Hook): for d in details: hosteroption = d.split("=") - if (len(hosteroption) > 1 - and hosteroption[0].lower() == 'timeout' - and hosteroption[1].isdigit()): + if len(hosteroption) > 1 \ + and hosteroption[0].lower() == 'timeout' \ + and hosteroption[1].isdigit(): timeout = int(hosteroption[1]) break @@ -231,7 +224,7 @@ class Captcha9Kw(Hook): self.logDebug("No CaptchaID for %s request (task: %s)" % (type, task)) return - passkey = self.getConfig("passkey") + passkey = self.getConfig('passkey') for _i in xrange(3): res = getURL(self.API_URL, @@ -248,7 +241,7 @@ class Captcha9Kw(Hook): if res == "OK": break - sleep(5) + time.sleep(5) else: self.logDebug("Could not send %s request: %s" % (type, res)) diff --git a/module/plugins/hooks/CaptchaBrotherhood.py b/module/plugins/hooks/CaptchaBrotherhood.py index 3c08f5e36..bda080037 100644 --- a/module/plugins/hooks/CaptchaBrotherhood.py +++ b/module/plugins/hooks/CaptchaBrotherhood.py @@ -4,15 +4,14 @@ from __future__ import with_statement import StringIO import pycurl +import time +import urllib try: from PIL import Image except ImportError: import Image -from time import sleep -from urllib import urlencode - from module.network.RequestFactory import getURL, getRequest from module.plugins.Hook import Hook, threaded @@ -46,16 +45,13 @@ class CaptchaBrotherhood(Hook): __description__ = """Send captchas to CaptchaBrotherhood.com""" __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org"), + __authors__ = [("RaNaN" , "RaNaN@pyload.org" ), ("zoidberg", "zoidberg@mujmail.cz")] - API_URL = "http://www.captchabrotherhood.com/" - + interval = 0 #@TODO: Remove in 0.4.10 - #@TODO: Remove in 0.4.10 - def initPeriodical(self): - pass + API_URL = "http://www.captchabrotherhood.com/" def setup(self): @@ -64,7 +60,7 @@ class CaptchaBrotherhood(Hook): def getCredits(self): res = getURL(self.API_URL + "askCredits.aspx", - get={"username": self.getConfig("username"), "password": self.getConfig("passkey")}) + get={"username": self.getConfig('username'), "password": self.getConfig('passkey')}) if not res.startswith("OK"): raise CaptchaBrotherhoodException(res) else: @@ -93,10 +89,10 @@ class CaptchaBrotherhood(Hook): req = getRequest() url = "%ssendNewCaptcha.aspx?%s" % (self.API_URL, - urlencode({'username' : self.getConfig("username"), - 'password' : self.getConfig("passkey"), - 'captchaSource': "pyLoad", - 'timeout' : "80"})) + urllib.urlencode({'username' : self.getConfig('username'), + 'password' : self.getConfig('passkey'), + 'captchaSource': "pyLoad", + 'timeout' : "80"})) req.c.setopt(pycurl.URL, url) req.c.setopt(pycurl.POST, 1) @@ -117,7 +113,7 @@ class CaptchaBrotherhood(Hook): ticket = res[3:] for _i in xrange(15): - sleep(5) + time.sleep(5) res = self.api_response("askCaptchaResult", ticket) if res.startswith("OK-answered"): return ticket, res[12:] @@ -127,8 +123,8 @@ class CaptchaBrotherhood(Hook): def api_response(self, api, ticket): res = getURL("%s%s.aspx" % (self.API_URL, api), - get={"username": self.getConfig("username"), - "password": self.getConfig("passkey"), + get={"username": self.getConfig('username'), + "password": self.getConfig('passkey'), "captchaID": ticket}) if not res.startswith("OK"): raise CaptchaBrotherhoodException("Unknown response: %s" % res) @@ -143,10 +139,10 @@ class CaptchaBrotherhood(Hook): if not task.isTextual(): return False - if not self.getConfig("username") or not self.getConfig("passkey"): + if not self.getConfig('username') or not self.getConfig('passkey'): return False - if self.core.isClientConnected() and not self.getConfig("force"): + if self.core.isClientConnected() and not self.getConfig('force'): return False if self.getCredits() > 10: diff --git a/module/plugins/hooks/Checksum.py b/module/plugins/hooks/Checksum.py index 8d9f8f981..ab7daf701 100644 --- a/module/plugins/hooks/Checksum.py +++ b/module/plugins/hooks/Checksum.py @@ -3,12 +3,10 @@ from __future__ import with_statement import hashlib +import os import re import zlib -from os import remove -from os.path import getsize, isfile, splitext - from module.plugins.Hook import Hook from module.utils import save_join, fs_encode @@ -40,7 +38,7 @@ def computeChecksum(local_file, algorithm): class Checksum(Hook): __name__ = "Checksum" __type__ = "hook" - __version__ = "0.15" + __version__ = "0.16" __config__ = [("check_checksum", "bool", "Check checksum? (If False only size will be verified)", True), ("check_action", "fail;retry;nothing", "What to do if check fails?", "retry"), @@ -50,32 +48,33 @@ class Checksum(Hook): __description__ = """Verify downloaded file size and checksum""" __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), - ("Walter Purcaro", "vuolter@gmail.com"), - ("stickell", "l.stickell@yahoo.it")] - + __authors__ = [("zoidberg" , "zoidberg@mujmail.cz"), + ("Walter Purcaro", "vuolter@gmail.com" ), + ("stickell" , "l.stickell@yahoo.it")] - methods = {'sfv': 'crc32', 'crc': 'crc32', 'hash': 'md5'} - regexps = {'sfv': r'^(?P<NAME>[^;].+)\s+(?P<HASH>[0-9A-Fa-f]{8})$', - 'md5': r'^(?P<NAME>[0-9A-Fa-f]{32}) (?P<FILE>.+)$', - 'crc': r'filename=(?P<NAME>.+)\nsize=(?P<SIZE>\d+)\ncrc32=(?P<HASH>[0-9A-Fa-f]{8})$', - 'default': r'^(?P<HASH>[0-9A-Fa-f]+)\s+\*?(?P<NAME>.+)$'} - - #@TODO: Remove in 0.4.10 - def initPeriodical(self): - pass + interval = 0 #@TODO: Remove in 0.4.10 + methods = {'sfv' : 'crc32', + 'crc' : 'crc32', + 'hash': 'md5'} + regexps = {'sfv' : r'^(?P<NAME>[^;].+)\s+(?P<HASH>[0-9A-Fa-f]{8})$', + 'md5' : r'^(?P<NAME>[0-9A-Fa-f]{32}) (?P<FILE>.+)$', + 'crc' : r'filename=(?P<NAME>.+)\nsize=(?P<SIZE>\d+)\ncrc32=(?P<HASH>[0-9A-Fa-f]{8})$', + 'default': r'^(?P<HASH>[0-9A-Fa-f]+)\s+\*?(?P<NAME>.+)$'} def coreReady(self): - if not self.getConfig("check_checksum"): + if not self.getConfig('check_checksum'): self.logInfo(_("Checksum validation is disabled in plugin configuration")) def setup(self): + self.info = {} #@TODO: Remove in 0.4.10 self.algorithms = sorted( getattr(hashlib, "algorithms", ("md5", "sha1", "sha224", "sha256", "sha384", "sha512")), reverse=True) + self.algorithms.extend(["crc32", "adler32"]) + self.formats = self.algorithms + ["sfv", "crc", "hash"] @@ -92,8 +91,9 @@ class Checksum(Hook): elif hasattr(pyfile.plugin, "api_data") and isinstance(pyfile.plugin.api_data, dict): data = pyfile.plugin.api_data.copy() - # elif hasattr(pyfile.plugin, "info") and isinstance(pyfile.plugin.info, dict): - # data = pyfile.plugin.info.copy() + elif hasattr(pyfile.plugin, "info") and isinstance(pyfile.plugin.info, dict): + data = pyfile.plugin.info.copy() + data.pop('size', None) #@NOTE: Don't check file size until a similary matcher will be implemented else: return @@ -107,22 +107,28 @@ class Checksum(Hook): #download_folder = self.config['general']['download_folder'] #local_file = fs_encode(save_join(download_folder, pyfile.package().folder, pyfile.name)) - if not isfile(local_file): + if not os.path.isfile(local_file): self.checkFailed(pyfile, None, "File does not exist") - # validate file size + # validate file size if "size" in data: - api_size = int(data['size']) - file_size = getsize(local_file) + api_size = int(data['size']) + file_size = os.path.getsize(local_file) + if api_size != file_size: self.logWarning(_("File %s has incorrect size: %d B (%d expected)") % (pyfile.name, file_size, api_size)) self.checkFailed(pyfile, local_file, "Incorrect file size") - del data['size'] + + data.pop('size', None) # validate checksum - if data and self.getConfig("check_checksum"): - if "checksum" in data: - data['md5'] = data['checksum'] + if data and self.getConfig('check_checksum'): + + if not 'md5' in data: + for type in ("checksum", "hashsum", "hash"): + if type in data: + data['md5'] = data[type] #@NOTE: What happens if it's not an md5 hash? + break for key in self.algorithms: if key in data: @@ -143,14 +149,14 @@ class Checksum(Hook): def checkFailed(self, pyfile, local_file, msg): - check_action = self.getConfig("check_action") + check_action = self.getConfig('check_action') if check_action == "retry": - max_tries = self.getConfig("max_tries") - retry_action = self.getConfig("retry_action") + max_tries = self.getConfig('max_tries') + retry_action = self.getConfig('retry_action') if pyfile.plugin.retries < max_tries: if local_file: - remove(local_file) - pyfile.plugin.retry(max_tries, self.getConfig("wait_time"), msg) + os.remove(local_file) + pyfile.plugin.retry(max_tries, self.getConfig('wait_time'), msg) elif retry_action == "nothing": return elif check_action == "nothing": @@ -162,13 +168,13 @@ class Checksum(Hook): download_folder = save_join(self.config['general']['download_folder'], pypack.folder, "") for link in pypack.getChildren().itervalues(): - file_type = splitext(link['name'])[1][1:].lower() + file_type = os.path.splitext(link['name'])[1][1:].lower() if file_type not in self.formats: continue hash_file = fs_encode(save_join(download_folder, link['name'])) - if not isfile(hash_file): + if not os.path.isfile(hash_file): self.logWarning(_("File not found"), link['name']) continue diff --git a/module/plugins/hooks/ClickAndLoad.py b/module/plugins/hooks/ClickAndLoad.py index 8ef31ec1e..a7862045e 100644 --- a/module/plugins/hooks/ClickAndLoad.py +++ b/module/plugins/hooks/ClickAndLoad.py @@ -1,43 +1,59 @@ # -*- coding: utf-8 -*- import socket +import time -from threading import Thread, Lock +try: + import ssl +except ImportError: + pass + +from threading import Lock from module.plugins.Hook import Hook, threaded def forward(source, destination): - string = ' ' - while string: - string = source.recv(1024) - if string: - destination.sendall(string) - else: - destination.shutdown(socket.SHUT_WR) - - + try: + bufsize = 1024 + bufdata = source.recv(bufsize) + while bufdata: + destination.sendall(bufdata) + bufdata = source.recv(bufsize) + finally: + destination.shutdown(socket.SHUT_WR) + # destination.close() + + +#@TODO: IPv6 support class ClickAndLoad(Hook): __name__ = "ClickAndLoad" __type__ = "hook" - __version__ = "0.25" + __version__ = "0.43" - __config__ = [("activated", "bool", "Activated" , True ), - ("port" , "int" , "Port" , 9666 ), - ("extern" , "bool", "Listen for requests coming from WAN (internet)", False)] + __config__ = [("activated", "bool", "Activated" , True), + ("port" , "int" , "Port" , 9666), + ("extern" , "bool", "Listen on the public network interface", True)] - __description__ = """Click'N'Load hook plugin""" + __description__ = """Click'n'Load hook plugin""" __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.de"), + __authors__ = [("RaNaN" , "RaNaN@pyload.de" ), ("Walter Purcaro", "vuolter@gmail.com")] + interval = 0 #@TODO: Remove in 0.4.10 + + + def setup(self): + self.info = {} #@TODO: Remove in 0.4.10 + + def coreReady(self): if not self.config['webinterface']['activated']: return - ip = "0.0.0.0" if self.getConfig("extern") else "127.0.0.1" - webport = int(self.config['webinterface']['port']) + ip = "" if self.getConfig('extern') else "127.0.0.1" + webport = self.config['webinterface']['port'] cnlport = self.getConfig('port') self.proxy(ip, webport, cnlport) @@ -45,37 +61,54 @@ class ClickAndLoad(Hook): @threaded def proxy(self, ip, webport, cnlport): - hookManager.startThread(self.server, ip, webport, cnlport) + time.sleep(10) #@TODO: Remove in 0.4.10 (implement addon delay on startup) + + self.logInfo(_("Proxy listening on %s:%s") % (ip or "0.0.0.0", cnlport)) + + self._server(ip, webport, cnlport) + lock = Lock() lock.acquire() lock.acquire() - def server(self, ip, webport, cnlport): + @threaded + def _server(self, ip, webport, cnlport): try: dock_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) dock_socket.bind((ip, cnlport)) dock_socket.listen(5) while True: - server_socket = dock_socket.accept()[0] - client_socket = socket.create_connection(("127.0.0.1", webport)) + client_socket, client_addr = dock_socket.accept() + self.logDebug("Connection from %s:%s" % client_addr) + + server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + if self.config['webinterface']['https']: + try: + server_socket = ssl.wrap_socket(server_socket) + + except NameError: + self.logError(_("pyLoad's webinterface is configured to use HTTPS, Please install python's ssl lib or disable HTTPS")) + client_socket.close() #: reset the connection. + continue + + except Exception, e: + self.logError(_("SSL error: %s") % e.message) + client_socket.close() #: reset the connection. + continue + + server_socket.connect(("127.0.0.1", webport)) + + self.manager.startThread(forward, client_socket, server_socket) + self.manager.startThread(forward, server_socket, client_socket) - hookManager.startThread(forward, server_socket, client_socket) - hookManager.startThread(forward, client_socket, server_socket) + except socket.timeout: + self.logDebug("Connection timed out, retrying...") + return self._server(ip, webport, cnlport) except socket.error, e: - if hasattr(e, "errno"): - errno = e.errno - else: - errno = e.args[0] - - if errno == 98: - self.logWarning(_("Port %s already in use") % cnlport) - else: - self.logError(e) - self.server(ip, webport, cnlport) - - except Exception, e: self.logError(e) - self.server(ip, webport, cnlport) + time.sleep(240) + return self._server(ip, webport, cnlport) diff --git a/module/plugins/hooks/DeathByCaptcha.py b/module/plugins/hooks/DeathByCaptcha.py index 050b6fe15..f9618f011 100644 --- a/module/plugins/hooks/DeathByCaptcha.py +++ b/module/plugins/hooks/DeathByCaptcha.py @@ -2,11 +2,11 @@ from __future__ import with_statement +import pycurl import re +import time from base64 import b64encode -from pycurl import FORM_FILE, HTTPHEADER -from time import sleep from module.common.json_layer import json_loads from module.network.HTTPRequest import BadHeader @@ -59,16 +59,13 @@ class DeathByCaptcha(Hook): __description__ = """Send captchas to DeathByCaptcha.com""" __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org"), + __authors__ = [("RaNaN" , "RaNaN@pyload.org" ), ("zoidberg", "zoidberg@mujmail.cz")] - API_URL = "http://api.dbcapi.me/api/" - + interval = 0 #@TODO: Remove in 0.4.10 - #@TODO: Remove in 0.4.10 - def initPeriodical(self): - pass + API_URL = "http://api.dbcapi.me/api/" def setup(self): @@ -77,13 +74,13 @@ class DeathByCaptcha(Hook): def api_response(self, api="captcha", post=False, multipart=False): req = getRequest() - req.c.setopt(HTTPHEADER, ["Accept: application/json", "User-Agent: pyLoad %s" % self.core.version]) + req.c.setopt(pycurl.HTTPHEADER, ["Accept: application/json", "User-Agent: pyLoad %s" % self.core.version]) if post: if not isinstance(post, dict): post = {} - post.update({"username": self.getConfig("username"), - "password": self.getConfig("passkey")}) + post.update({"username": self.getConfig('username'), + "password": self.getConfig('passkey')}) res = None try: @@ -135,10 +132,10 @@ class DeathByCaptcha(Hook): def submit(self, captcha, captchaType="file", match=None): - #workaround multipart-post bug in HTTPRequest.py - if re.match("^\w*$", self.getConfig("passkey")): + #@NOTE: Workaround multipart-post bug in HTTPRequest.py + if re.match("^\w*$", self.getConfig('passkey')): multipart = True - data = (FORM_FILE, captcha) + data = (pycurl.FORM_FILE, captcha) else: multipart = False with open(captcha, 'rb') as f: @@ -152,7 +149,7 @@ class DeathByCaptcha(Hook): ticket = res['captcha'] for _i in xrange(24): - sleep(5) + time.sleep(5) res = self.api_response("captcha/%d" % ticket, False) if res['text'] and res['is_correct']: break @@ -172,10 +169,10 @@ class DeathByCaptcha(Hook): if not task.isTextual(): return False - if not self.getConfig("username") or not self.getConfig("passkey"): + if not self.getConfig('username') or not self.getConfig('passkey'): return False - if self.core.isClientConnected() and not self.getConfig("force"): + if self.core.isClientConnected() and not self.getConfig('force'): return False try: diff --git a/module/plugins/hooks/DebridItaliaCom.py b/module/plugins/hooks/DebridItaliaComHook.py index 719f3dd3a..36b307696 100644 --- a/module/plugins/hooks/DebridItaliaCom.py +++ b/module/plugins/hooks/DebridItaliaComHook.py @@ -5,23 +5,21 @@ import re from module.plugins.internal.MultiHook import MultiHook -class DebridItaliaCom(MultiHook): - __name__ = "DebridItaliaCom" +class DebridItaliaComHook(MultiHook): + __name__ = "DebridItaliaComHook" __type__ = "hook" __version__ = "0.12" __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), ("reload" , "bool" , "Reload plugin list" , True ), ("reloadinterval", "int" , "Reload interval in hours" , 12 )] __description__ = """Debriditalia.com hook plugin""" __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it"), - ("Walter Purcaro", "vuolter@gmail.com")] + __authors__ = [("stickell" , "l.stickell@yahoo.it"), + ("Walter Purcaro", "vuolter@gmail.com" )] def getHosters(self): diff --git a/module/plugins/hooks/DeleteFinished.py b/module/plugins/hooks/DeleteFinished.py index 5d2b78d50..be17c3c0f 100644 --- a/module/plugins/hooks/DeleteFinished.py +++ b/module/plugins/hooks/DeleteFinished.py @@ -7,21 +7,26 @@ from module.plugins.Hook import Hook class DeleteFinished(Hook): __name__ = "DeleteFinished" __type__ = "hook" - __version__ = "1.11" + __version__ = "1.12" - __config__ = [('activated', 'bool', 'Activated', 'False'), - ('interval', 'int', 'Delete every (hours)', '72'), - ('deloffline', 'bool', 'Delete packages with offline links', 'False')] + __config__ = [("interval" , "int" , "Check interval in hours" , 72 ), + ("deloffline", "bool", "Delete package with offline links", False)] __description__ = """Automatically delete all finished packages from queue""" __license__ = "GPLv3" __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - # event_list = ["pluginConfigChanged"] + MIN_CHECK_INTERVAL = 1 * 60 * 60 #: 1 hour ## overwritten methods ## + def setup(self): + self.info = {} #@TODO: Remove in 0.4.10 + # self.event_list = ["pluginConfigChanged"] + self.interval = self.MIN_CHECK_INTERVAL + + def periodical(self): if not self.info['sleep']: deloffline = self.getConfig('deloffline') @@ -33,20 +38,21 @@ class DeleteFinished(Hook): self.addEvent('packageFinished', self.wakeup) - def pluginConfigChanged(self, plugin, name, value): - if name == "interval" and value != self.interval: - self.interval = value * 3600 - self.initPeriodical() + # def pluginConfigChanged(self, plugin, name, value): + # if name == "interval" and value != self.interval: + # self.interval = value * 3600 + # self.initPeriodical() def unload(self): - self.removeEvent('packageFinished', self.wakeup) + self.manager.removeEvent('packageFinished', self.wakeup) def coreReady(self): - self.info = {'sleep': True} - interval = self.getConfig('interval') - self.pluginConfigChanged(self.__name__, 'interval', interval) + self.info['sleep'] = True + # interval = self.getConfig('interval') + # self.pluginConfigChanged(self.__name__, 'interval', interval) + self.interval = max(self.MIN_CHECK_INTERVAL, self.getConfig('interval') * 60 * 60) self.addEvent('packageFinished', self.wakeup) @@ -58,22 +64,17 @@ class DeleteFinished(Hook): def wakeup(self, pypack): - self.removeEvent('packageFinished', self.wakeup) + self.manager.removeEvent('packageFinished', self.wakeup) self.info['sleep'] = False ## event managing ## def addEvent(self, event, func): """Adds an event listener for event name""" - if event in self.m.events: - if func in self.m.events[event]: + if event in self.manager.events: + if func in self.manager.events[event]: self.logDebug("Function already registered", func) else: - self.m.events[event].append(func) + self.manager.events[event].append(func) else: - self.m.events[event] = [func] - - - def setup(self): - self.m = self.manager - self.removeEvent = self.m.removeEvent + self.manager.events[event] = [func] diff --git a/module/plugins/hooks/DownloadScheduler.py b/module/plugins/hooks/DownloadScheduler.py index 4996e212d..9c74ac1d4 100644 --- a/module/plugins/hooks/DownloadScheduler.py +++ b/module/plugins/hooks/DownloadScheduler.py @@ -1,8 +1,7 @@ # -*- coding: utf-8 -*- import re - -from time import localtime +import time from module.plugins.Hook import Hook @@ -22,13 +21,12 @@ class DownloadScheduler(Hook): ("stickell", "l.stickell@yahoo.it")] - #@TODO: Remove in 0.4.10 - def initPeriodical(self): - pass + interval = 0 #@TODO: Remove in 0.4.10 def setup(self): - self.cb = None # callback to scheduler job; will be by removed hookmanager when hook unloaded + self.info = {} #@TODO: Remove in 0.4.10 + self.cb = None # callback to scheduler job; will be by removed hookmanager when hook unloaded def coreReady(self): @@ -37,7 +35,7 @@ class DownloadScheduler(Hook): def updateSchedule(self, schedule=None): if schedule is None: - schedule = self.getConfig("timetable") + schedule = self.getConfig('timetable') schedule = re.findall("(\d{1,2}):(\d{2})[\s]*(-?\d+)", schedule.lower().replace("full", "-1").replace("none", "0")) @@ -45,7 +43,7 @@ class DownloadScheduler(Hook): self.logError(_("Invalid schedule")) return - t0 = localtime() + t0 = time.localtime() now = (t0.tm_hour, t0.tm_min, t0.tm_sec, "X") schedule = sorted([(int(x[0]), int(x[1]), 0, int(x[2])) for x in schedule] + [now]) @@ -65,7 +63,7 @@ class DownloadScheduler(Hook): def setDownloadSpeed(self, speed): if speed == 0: - abort = self.getConfig("abort") + abort = self.getConfig('abort') self.logInfo(_("Stopping download server. (Running downloads will %sbe aborted.)") % '' if abort else _('not ')) self.core.api.pauseServer() if abort: diff --git a/module/plugins/hooks/EasybytezCom.py b/module/plugins/hooks/EasybytezComHook.py index e08127514..43efb5048 100644 --- a/module/plugins/hooks/EasybytezCom.py +++ b/module/plugins/hooks/EasybytezComHook.py @@ -5,16 +5,14 @@ import re from module.plugins.internal.MultiHook import MultiHook -class EasybytezCom(MultiHook): - __name__ = "EasybytezCom" +class EasybytezComHook(MultiHook): + __name__ = "EasybytezComHook" __type__ = "hook" __version__ = "0.07" __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), ("reload" , "bool" , "Reload plugin list" , True ), ("reloadinterval", "int" , "Reload interval in hours" , 12 )] @@ -27,6 +25,6 @@ class EasybytezCom(MultiHook): user, data = self.account.selectAccount() req = self.account.getAccountRequest(user) - page = req.load("http://www.easybytez.com") + html = req.load("http://www.easybytez.com") - return re.search(r'</textarea>\s*Supported sites:(.*)', page).group(1).split(',') + return re.search(r'</textarea>\s*Supported sites:(.*)', html).group(1).split(',') diff --git a/module/plugins/hooks/ExpertDecoders.py b/module/plugins/hooks/ExpertDecoders.py index c80401003..ccd48f664 100644 --- a/module/plugins/hooks/ExpertDecoders.py +++ b/module/plugins/hooks/ExpertDecoders.py @@ -2,9 +2,10 @@ from __future__ import with_statement +import pycurl +import uuid + from base64 import b64encode -from pycurl import LOW_SPEED_TIME -from uuid import uuid4 from module.network.HTTPRequest import BadHeader from module.network.RequestFactory import getURL, getRequest @@ -21,16 +22,13 @@ class ExpertDecoders(Hook): __description__ = """Send captchas to expertdecoders.com""" __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org"), + __authors__ = [("RaNaN" , "RaNaN@pyload.org" ), ("zoidberg", "zoidberg@mujmail.cz")] - API_URL = "http://www.fasttypers.org/imagepost.ashx" - + interval = 0 #@TODO: Remove in 0.4.10 - #@TODO: Remove in 0.4.10 - def initPeriodical(self): - pass + API_URL = "http://www.fasttypers.org/imagepost.ashx" def setup(self): @@ -38,7 +36,7 @@ class ExpertDecoders(Hook): def getCredits(self): - res = getURL(self.API_URL, post={"key": self.getConfig("passkey"), "action": "balance"}) + res = getURL(self.API_URL, post={"key": self.getConfig('passkey'), "action": "balance"}) if res.isdigit(): self.logInfo(_("%s credits left") % res) @@ -51,20 +49,22 @@ class ExpertDecoders(Hook): @threaded def _processCaptcha(self, task): - task.data['ticket'] = ticket = uuid4() + task.data['ticket'] = ticket = uuid.uuid4() result = None with open(task.captchaFile, 'rb') as f: data = f.read() - data = b64encode(data) req = getRequest() #raise timeout threshold - req.c.setopt(LOW_SPEED_TIME, 80) + req.c.setopt(pycurl.LOW_SPEED_TIME, 80) try: - result = req.load(self.API_URL, post={"action": "upload", "key": self.getConfig("passkey"), - "file": data, "gen_task_id": ticket}) + result = req.load(self.API_URL, + post={'action' : "upload", + 'key' : self.getConfig('passkey'), + 'file' : b64encode(data), + 'gen_task_id': ticket}) finally: req.close() @@ -76,10 +76,10 @@ class ExpertDecoders(Hook): if not task.isTextual(): return False - if not self.getConfig("passkey"): + if not self.getConfig('passkey'): return False - if self.core.isClientConnected() and not self.getConfig("force"): + if self.core.isClientConnected() and not self.getConfig('force'): return False if self.getCredits() > 0: @@ -96,7 +96,7 @@ class ExpertDecoders(Hook): try: res = getURL(self.API_URL, - post={'action': "refund", 'key': self.getConfig("passkey"), 'gen_task_id': task.data['ticket']}) + post={'action': "refund", 'key': self.getConfig('passkey'), 'gen_task_id': task.data['ticket']}) self.logInfo(_("Request refund"), res) except BadHeader, e: diff --git a/module/plugins/hooks/ExternalScripts.py b/module/plugins/hooks/ExternalScripts.py index fc0cae44f..a0815499b 100644 --- a/module/plugins/hooks/ExternalScripts.py +++ b/module/plugins/hooks/ExternalScripts.py @@ -1,146 +1,218 @@ # -*- coding: utf-8 -*- +import os import subprocess -from itertools import chain -from os import listdir, access, X_OK, makedirs -from os.path import join, exists, basename, abspath - from module.plugins.Hook import Hook -from module.utils import save_join +from module.utils import fs_encode, save_join class ExternalScripts(Hook): __name__ = "ExternalScripts" __type__ = "hook" - __version__ = "0.26" + __version__ = "0.39" - __config__ = [("activated", "bool", "Activated", True)] + __config__ = [("activated", "bool", "Activated" , True ), + ("waitend" , "bool", "Wait script ending", False)] __description__ = """Run external scripts""" __license__ = "GPLv3" - __authors__ = [("mkaay", "mkaay@mkaay.de"), - ("RaNaN", "ranan@pyload.org"), - ("spoob", "spoob@pyload.org"), + __authors__ = [("mkaay" , "mkaay@mkaay.de" ), + ("RaNaN" , "ranan@pyload.org" ), + ("spoob" , "spoob@pyload.org" ), ("Walter Purcaro", "vuolter@gmail.com")] - event_list = ["archive_extracted", "package_extracted", "all_archives_extracted", "all_archives_processed", - "allDownloadsFinished", "allDownloadsProcessed"] - - - #@TODO: Remove in 0.4.10 - def initPeriodical(self): - pass + interval = 0 #@TODO: Remove in 0.4.10 def setup(self): + self.info = {'oldip': None} self.scripts = {} - folders = ["download_preparing", "download_finished", "all_downloads_finished", "all_downloads_processed", + self.event_list = ["archive_extract_failed", "archive_extracted" , + "package_extract_failed", "package_extracted" , + "all_archives_extracted", "all_archives_processed", + "allDownloadsFinished" , "allDownloadsProcessed" , + "packageDeleted"] + + folders = ["pyload_start", "pyload_restart", "pyload_stop", "before_reconnect", "after_reconnect", - "package_finished", "package_extracted", - "archive_extracted", "all_archives_extracted", "all_archives_processed", - # deprecated folders - "unrar_finished", "all_dls_finished", "all_dls_processed"] + "download_preparing", "download_failed", "download_finished", + "archive_extract_failed", "archive_extracted", + "package_finished", "package_deleted", "package_extract_failed", "package_extracted", + "all_downloads_processed", "all_downloads_finished", #@TODO: Invert `all_downloads_processed`, `all_downloads_finished` order in 0.4.10 + "all_archives_extracted", "all_archives_processed"] for folder in folders: self.scripts[folder] = [] - - self.initPluginType(folder, join(pypath, 'scripts', folder)) - self.initPluginType(folder, join('scripts', folder)) + for dir in (pypath, ''): + self.initPluginType(folder, os.path.join(dir, 'scripts', folder)) for script_type, names in self.scripts.iteritems(): if names: - self.logInfo(_("Installed scripts for"), script_type, ", ".join([basename(x) for x in names])) + self.logInfo(_("Installed scripts for: ") + script_type, ", ".join(map(os.path.basename, names))) + + self.pyload_start() - def initPluginType(self, folder, path): - if not exists(path): + def initPluginType(self, name, dir): + if not os.path.isdir(dir): try: - makedirs(path) - except: - self.logDebug("Script folder %s not created" % folder) + os.makedirs(dir) + + except OSError, e: + self.logDebug(e) return - for f in listdir(path): - if f.startswith("#") or f.startswith(".") or f.startswith("_") or f.endswith("~") or f.endswith(".swp"): + for filename in os.listdir(dir): + file = save_join(dir, filename) + + if not os.path.isfile(file): + continue + + if filename[0] in ("#", "_") or filename.endswith("~") or filename.endswith(".swp"): continue - if not access(join(path, f), X_OK): - self.logWarning(_("Script not executable:") + " %s/%s" % (folder, f)) + if not os.access(file, os.X_OK): + self.logWarning(_("Script not executable:") + " %s/%s" % (name, filename)) - self.scripts[folder].append(join(path, f)) + self.scripts[name].append(file) def callScript(self, script, *args): try: - cmd = [script] + [str(x) if not isinstance(x, basestring) else x for x in args] - self.logDebug("Executing", abspath(script), " ".join(cmd)) - #output goes to pyload - subprocess.Popen(cmd, bufsize=-1) + cmd_args = [fs_encode(str(x) if not isinstance(x, basestring) else x) for x in args] + cmd = [script] + cmd_args + + self.logDebug("Executing: %s" % os.path.abspath(script), "Args: " + ' '.join(cmd_args)) + + p = subprocess.Popen(cmd, bufsize=-1) #@NOTE: output goes to pyload + if self.getConfig('waitend'): + p.communicate() + except Exception, e: - self.logError(_("Error in %(script)s: %(error)s") % {"script": basename(script), "error": e}) + try: + self.logError(_("Runtime error: %s") % os.path.abspath(script), e) + except Exception: + self.logError(_("Runtime error: %s") % os.path.abspath(script), _("Unknown error")) + + + def pyload_start(self): + for script in self.scripts['pyload_start']: + self.callScript(script) + + + def coreExiting(self): + for script in self.scripts['pyload_restart' if self.core.do_restart else 'pyload_stop']: + self.callScript(script) + + + def beforeReconnecting(self, ip): + for script in self.scripts['before_reconnect']: + self.callScript(script, ip) + self.info['oldip'] = ip + + + def afterReconnecting(self, ip): + for script in self.scripts['after_reconnect']: + self.callScript(script, ip, self.info['oldip']) #@TODO: Use built-in oldip in 0.4.10 def downloadPreparing(self, pyfile): for script in self.scripts['download_preparing']: - self.callScript(script, pyfile.pluginname, pyfile.url, pyfile.id) + self.callScript(script, pyfile.id, pyfile.name, None, pyfile.pluginname, pyfile.url) + + + def downloadFailed(self, pyfile): + if self.config['general']['folder_per_package']: + download_folder = save_join(self.config['general']['download_folder'], pyfile.package().folder) + else: + download_folder = self.config['general']['download_folder'] + + for script in self.scripts['download_failed']: + file = save_join(download_folder, pyfile.name) + self.callScript(script, pyfile.id, pyfile.name, file, pyfile.pluginname, pyfile.url) def downloadFinished(self, pyfile): - download_folder = self.config['general']['download_folder'] + if self.config['general']['folder_per_package']: + download_folder = save_join(self.config['general']['download_folder'], pyfile.package().folder) + else: + download_folder = self.config['general']['download_folder'] + for script in self.scripts['download_finished']: - filename = save_join(download_folder, pyfile.package().folder, pyfile.name) - self.callScript(script, pyfile.pluginname, pyfile.url, pyfile.name, filename, pyfile.id) + file = save_join(download_folder, pyfile.name) + self.callScript(script, pyfile.id, pyfile.name, file, pyfile.pluginname, pyfile.url) + + + def archive_extract_failed(self, pyfile, archive): + for script in self.scripts['archive_extract_failed']: + self.callScript(script, pyfile.id, pyfile.name, archive.filename, archive.out, archive.files) + + + def archive_extracted(self, pyfile, archive): + for script in self.scripts['archive_extracted']: + self.callScript(script, pyfile.id, pyfile.name, archive.filename, archive.out, archive.files) def packageFinished(self, pypack): - download_folder = self.config['general']['download_folder'] + if self.config['general']['folder_per_package']: + download_folder = save_join(self.config['general']['download_folder'], pypack.folder) + else: + download_folder = self.config['general']['download_folder'] + for script in self.scripts['package_finished']: - folder = save_join(download_folder, pypack.folder) - self.callScript(script, pypack.name, folder, pypack.password, pypack.id) + self.callScript(script, pypack.id, pypack.name, download_folder, pypack.password) - def beforeReconnecting(self, ip): - for script in self.scripts['before_reconnect']: - self.callScript(script, ip) + def packageDeleted(self, pid): + pack = self.core.api.getPackageInfo(pid) + if self.config['general']['folder_per_package']: + download_folder = save_join(self.config['general']['download_folder'], pack.folder) + else: + download_folder = self.config['general']['download_folder'] - def afterReconnecting(self, ip): - for script in self.scripts['after_reconnect']: - self.callScript(script, ip) + for script in self.scripts['package_deleted']: + self.callScript(script, pack.id, pack.name, download_folder, pack.password) - def archive_extracted(self, pyfile, folder, filename, files): - for script in self.scripts['archive_extracted']: - self.callScript(script, folder, filename, files) - for script in self.scripts['unrar_finished']: #: deprecated - self.callScript(script, folder, filename) + def package_extract_failed(self, pypack): + if self.config['general']['folder_per_package']: + download_folder = save_join(self.config['general']['download_folder'], pypack.folder) + else: + download_folder = self.config['general']['download_folder'] + + for script in self.scripts['package_extract_failed']: + self.callScript(script, pypack.id, pypack.name, download_folder, pypack.password) def package_extracted(self, pypack): - download_folder = self.config['general']['download_folder'] + if self.config['general']['folder_per_package']: + download_folder = save_join(self.config['general']['download_folder'], pypack.folder) + else: + download_folder = self.config['general']['download_folder'] + for script in self.scripts['package_extracted']: - folder = save_join(download_folder, pypack.folder) - self.callScript(script, pypack.name, folder, pypack.password, pypack.id) + self.callScript(script, pypack.id, pypack.name, download_folder) - def all_archives_extracted(self): - for script in self.scripts['all_archives_extracted']: + def allDownloadsFinished(self): + for script in self.scripts['all_downloads_finished']: self.callScript(script) - def all_archives_processed(self): - for script in self.scripts['all_archives_processed']: + def allDownloadsProcessed(self): + for script in self.scripts['all_downloads_processed']: self.callScript(script) - def allDownloadsFinished(self, thread): - for script in chain(self.scripts['all_downloads_finished'], self.scripts['all_dls_finished']): + def all_archives_extracted(self): + for script in self.scripts['all_archives_extracted']: self.callScript(script) - def allDownloadsProcessed(self, thread): - for script in chain(self.scripts['all_downloads_processed'], self.scripts['all_dls_processed']): + def all_archives_processed(self): + for script in self.scripts['all_archives_processed']: self.callScript(script) diff --git a/module/plugins/hooks/ExtractArchive.py b/module/plugins/hooks/ExtractArchive.py index 2e9efa2b0..3e371ec2b 100644 --- a/module/plugins/hooks/ExtractArchive.py +++ b/module/plugins/hooks/ExtractArchive.py @@ -4,22 +4,19 @@ from __future__ import with_statement import os import sys - -from copy import copy -from os import remove, chmod, makedirs -from os.path import exists, basename, isfile, isdir -from traceback import print_exc +import traceback # monkey patch bug in python 2.6 and lower # http://bugs.python.org/issue6122 , http://bugs.python.org/issue1236 , http://bugs.python.org/issue1731717 if sys.version_info < (2, 7) and os.name != "nt": import errno - from subprocess import Popen + import subprocess def _eintr_retry_call(func, *args): while True: try: return func(*args) + except OSError, e: if e.errno == errno.EINTR: continue @@ -33,6 +30,7 @@ if sys.version_info < (2, 7) and os.name != "nt": if self.returncode is None: try: pid, sts = _eintr_retry_call(os.waitpid, self.pid, 0) + except OSError, e: if e.errno != errno.ECHILD: raise @@ -43,376 +41,488 @@ if sys.version_info < (2, 7) and os.name != "nt": self._handle_exitstatus(sts) return self.returncode - Popen.wait = wait + subprocess.Popen.wait = wait + +try: + import send2trash +except ImportError: + pass +from copy import copy if os.name != "nt": from grp import getgrnam - from os import chown from pwd import getpwnam -from module.plugins.Hook import Hook, threaded, Expose +from module.plugins.Hook import Hook, Expose, threaded from module.plugins.internal.Extractor import ArchiveError, CRCError, PasswordError -from module.utils import save_join, uniqify +from module.plugins.internal.SimpleHoster import replace_patterns +from module.utils import fs_encode, save_join, uniqify + + +class ArchiveQueue(object): + + def __init__(self, plugin, storage): + self.plugin = plugin + self.storage = storage + + + def get(self): + try: + return [int(pid) for pid in self.plugin.getStorage("ExtractArchive:%s" % self.storage, "").decode('base64').split()] + except Exception: + return [] + + + def set(self, value): + if isinstance(value, list): + item = str(value)[1:-1].replace(' ', '').replace(',', ' ') + else: + item = str(value).strip() + return self.plugin.setStorage("ExtractArchive:%s" % self.storage, item.encode('base64')[:-1]) + + + def delete(self): + return self.plugin.delStorage("ExtractArchive:%s" % self.storage) + + + def add(self, item): + queue = self.get() + if item not in queue: + return self.set(queue + [item]) + else: + return True + + + def remove(self, item): + queue = self.get() + try: + queue.remove(item) + + except ValueError: + pass + + if queue == []: + return self.delete() + + return self.set(queue) class ExtractArchive(Hook): __name__ = "ExtractArchive" __type__ = "hook" - __version__ = "1.03" - - __config__ = [("activated" , "bool" , "Activated" , True ), - ("fullpath" , "bool" , "Extract full path" , True ), - ("overwrite" , "bool" , "Overwrite files" , False ), - ("keepbroken" , "bool" , "Extract broken archives" , False ), - ("repair" , "bool" , "Repair broken archives" , True ), - ("passwordfile" , "file" , "Store passwords in file" , "archive_password.txt" ), - ("delete" , "bool" , "Delete archive when successfully extracted", False ), - ("subfolder" , "bool" , "Create subfolder for each package" , False ), - ("destination" , "folder", "Extract files to" , "" ), - ("extensions" , "str" , "Extract the following extensions" , "7z,bz2,bzip2,gz,gzip,lha,lzh,lzma,rar,tar,taz,tbz,tbz2,tgz,xar,xz,z,zip"), - ("excludefiles" , "str" , "Don't extract the following files" , "*.nfo,*.DS_Store,index.dat,thumb.db" ), - ("recursive" , "bool" , "Extract archives in archives" , True ), - ("queue" , "bool" , "Wait for all downloads to be finished" , False ), - ("renice" , "int" , "CPU Priority" , 0 )] + __version__ = "1.44" + + __config__ = [("activated" , "bool" , "Activated" , True ), + ("fullpath" , "bool" , "Extract with full paths" , True ), + ("overwrite" , "bool" , "Overwrite files" , False ), + ("keepbroken" , "bool" , "Try to extract broken archives" , False ), + ("repair" , "bool" , "Repair broken archives (RAR required)" , False ), + ("test" , "bool" , "Test archive before extracting" , False ), + ("usepasswordfile", "bool" , "Use password file" , True ), + ("passwordfile" , "file" , "Password file" , "archive_password.txt" ), + ("delete" , "bool" , "Delete archive after extraction" , True ), + ("deltotrash" , "bool" , "Move to trash (recycle bin) instead delete", True ), + ("subfolder" , "bool" , "Create subfolder for each package" , False ), + ("destination" , "folder" , "Extract files to folder" , "" ), + ("extensions" , "str" , "Extract archives ending with extension" , "7z,bz2,bzip2,gz,gzip,lha,lzh,lzma,rar,tar,taz,tbz,tbz2,tgz,xar,xz,z,zip"), + ("excludefiles" , "str" , "Don't extract the following files" , "*.nfo,*.DS_Store,index.dat,thumb.db" ), + ("recursive" , "bool" , "Extract archives in archives" , True ), + ("waitall" , "bool" , "Run after all downloads was processed" , False ), + ("renice" , "int" , "CPU priority" , 0 )] __description__ = """Extract different kind of archives""" __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + __authors__ = [("Walter Purcaro", "vuolter@gmail.com"), + ("Immenz" , "immenz@gmx.net" )] - event_list = ["allDownloadsProcessed"] + NAME_REPLACEMENTS = [(r'\.part\d+\.rar$', ".part.rar")] - #@TODO: Remove in 0.4.10 - def initPeriodical(self): - pass + def setup(self): + self.info = {} #@TODO: Remove in 0.4.10 + self.event_list = ["allDownloadsProcessed","packageDeleted"] + self.queue = ArchiveQueue(self, "Queue") + self.failed = ArchiveQueue(self, "Failed") - def coreReady(self): - self.extracting = False - + self.interval = 60 + self.extracting = False + self.lastPackage = False + self.extractors = [] + self.passwords = [] + self.repair = False - def setup(self): - self.plugins = [] - self.passwords = [] - names = [] + def coreReady(self): for p in ("UnRar", "SevenZip", "UnZip"): try: module = self.core.pluginManager.loadModule("internal", p) - klass = getattr(module, p) - if klass.checkDeps(): - names.append(p) - self.plugins.append(klass) + klass = getattr(module, p) + if klass.isUsable(): + self.extractors.append(klass) + if klass.REPAIR: + self.repair = self.getConfig('repair') except OSError, e: if e.errno == 2: - self.logInfo(_("No %s installed") % p) + self.logWarning(_("No %s installed") % p) else: - self.logWarning(_("Could not activate %s") % p, e) + self.logWarning(_("Could not activate: %s") % p, e) if self.core.debug: - print_exc() + traceback.print_exc() except Exception, e: - self.logWarning(_("Could not activate %s") % p, e) + self.logWarning(_("Could not activate: %s") % p, e) if self.core.debug: - print_exc() + traceback.print_exc() - if names: - self.logInfo(_("Activated") + " " + " ".join(names)) + if self.extractors: + self.logDebug(*["Found %s %s" % (Extractor.__name__, Extractor.VERSION) for Extractor in self.extractors]) + self.extractQueued() #: Resume unfinished extractions else: self.logInfo(_("No Extract plugins activated")) - # queue with package ids - self.queue = [] - - def periodical(self): - if not self.queue or self.extracting: + @threaded + def extractQueued(self, thread): + if self.extracting: #@NOTE: doing the check here for safty (called by coreReady) return - local = copy(self.queue) - self.queue[:] = [] + self.extracting = True - self.extractPackages(*local) + packages = self.queue.get() + while packages: + if self.lastPackage: #: called from allDownloadsProcessed + self.lastPackage = False + if self.extract(packages, thread): #@NOTE: check only if all gone fine, no failed reporting for now + self.manager.dispatchEvent("all_archives_extracted") + self.manager.dispatchEvent("all_archives_processed") + else: + if self.extract(packages, thread): #@NOTE: check only if all gone fine, no failed reporting for now + pass + packages = self.queue.get() #: check for packages added during extraction - @Expose - def extractPackage(self, id): - """ Extract package wrapper""" - self.extractPackages(id) + self.extracting = False @Expose - def extractPackages(self, *ids): + def extractPackage(self, *ids): """ Extract packages with given id""" - self.manager.startThread(self.extract, ids) + for id in ids: + self.queue.add(id) + if not self.getConfig('waitall') and not self.extracting: + self.extractQueued() - def packageFinished(self, pypack): - if self.getConfig("queue") or self.extracting: - self.logInfo(_("Package %s queued for later extracting") % pypack.name) - self.queue.append(pypack.id) - else: - self.extractPackage(pypack.id) + def packageDeleted(self, pid): + self.queue.remove(pid) - @threaded - def allDownloadsProcessed(self, thread): - local = copy(self.queue) - self.queue[:] = [] + def packageFinished(self, pypack): + self.queue.add(pypack.id) + if not self.getConfig('waitall') and not self.extracting: + self.extractQueued() - if self.extract(local): #: check only if all gone fine, no failed reporting for now - self.manager.dispatchEvent("all_archives_extracted") - self.manager.dispatchEvent("all_archives_processed") + def allDownloadsProcessed(self): + self.lastPackage = True + if self.getConfig('waitall') and not self.extracting: + self.extractQueued() - def extract(self, ids): - self.extracting = True + @Expose + def extract(self, ids, thread=None): #@TODO: Use pypack, not pid to improve method usability + if not ids: + return False processed = [] extracted = [] failed = [] - clearlist = lambda string: [x.lstrip('.') for x in string.replace(' ', '').replace(',', '|').replace(';', '|').split('|')] + toList = lambda string: string.replace(' ', '').replace(',', '|').replace(';', '|').split('|') + + destination = self.getConfig('destination') + subfolder = self.getConfig('subfolder') + fullpath = self.getConfig('fullpath') + overwrite = self.getConfig('overwrite') + renice = self.getConfig('renice') + recursive = self.getConfig('recursive') + delete = self.getConfig('delete') + keepbroken = self.getConfig('keepbroken') - destination = self.getConfig("destination") - subfolder = self.getConfig("subfolder") - fullpath = self.getConfig("fullpath") - overwrite = self.getConfig("overwrite") - extensions = clearlist(self.getConfig("extensions")) - excludefiles = clearlist(self.getConfig("excludefiles")) - renice = self.getConfig("renice") - recursive = self.getConfig("recursive") - delete = self.getConfig("delete") - keepbroken = self.getConfig("keepbroken") + extensions = [x.lstrip('.').lower() for x in toList(self.getConfig('extensions'))] + excludefiles = toList(self.getConfig('excludefiles')) if extensions: - self.logDebug("Extensions: %s" % "|.".join(extensions)) + self.logDebug("Use for extensions: %s" % "|.".join(extensions)) # reload from txt file self.reloadPasswords() - # dl folder - dl = self.config['general']['download_folder'] + download_folder = self.config['general']['download_folder'] - #iterate packages -> plugins -> targets + # iterate packages -> extractors -> targets for pid in ids: - p = self.core.files.getPackage(pid) - self.logInfo(_("Check package: %s") % p.name) - if not p: + pypack = self.core.files.getPackage(pid) + + if not pypack: + self.queue.remove(pid) continue + self.logInfo(_("Check package: %s") % pypack.name) + # determine output folder - out = save_join(dl, p.folder, destination, "") #: force trailing slash + out = save_join(download_folder, pypack.folder, destination, "") #: force trailing slash if subfolder: - out = save_join(out, p.folder) + out = save_join(out, pypack.folder) - if not exists(out): - makedirs(out) + if not os.path.exists(out): + os.makedirs(out) - files_ids = [(save_join(dl, p.folder, x['name']), x['id']) for x in p.getChildren().itervalues()] matched = False success = True + files_ids = dict((pylink['name'],((save_join(download_folder, pypack.folder, pylink['name'])), pylink['id'], out)) for pylink \ + in sorted(pypack.getChildren().itervalues(), key=lambda k: k['name'])).values() #: remove duplicates # check as long there are unseen files while files_ids: new_files_ids = [] if extensions: - files_ids = [(file, id) for file, id in files_ids if filter(lambda ext: file.endswith(ext), extensions)] - - for plugin in self.plugins: - targets = plugin.getTargets(files_ids) + files_ids = [(fname, fid, fout) for fname, fid, fout in files_ids \ + if filter(lambda ext: fname.lower().endswith(ext), extensions)] + for Extractor in self.extractors: + targets = Extractor.getTargets(files_ids) if targets: - self.logDebug("Targets for %s: %s" % (plugin.__name__, targets)) + self.logDebug("Targets for %s: %s" % (Extractor.__name__, targets)) matched = True - for target, fid in targets: - if target in processed: - self.logDebug(basename(target), "skipped") - continue + for fname, fid, fout in targets: + name = os.path.basename(fname) - processed.append(target) # prevent extracting same file twice + if not os.path.exists(fname): + self.logDebug(name, "File not found") + continue - self.logInfo(basename(target), _("Extract to: %s") % out) + self.logInfo(name, _("Extract to: %s") % fout) try: - klass = plugin(self, - target, - out, - p.password, - fullpath, - overwrite, - excludefiles, - renice, - delete, - keepbroken) - klass.init() - - new_files = self._extract(klass, fid) + pyfile = self.core.files.getFile(fid) + archive = Extractor(self, + fname, + fout, + fullpath, + overwrite, + excludefiles, + renice, + delete, + keepbroken, + fid) + + thread.addActive(pyfile) + archive.init() + + try: + new_files = self._extract(pyfile, archive, pypack.password) + + finally: + pyfile.setProgress(100) + thread.finishFile(pyfile) except Exception, e: - self.logError(basename(target), e) - new_files = None - - if new_files is None: - self.logWarning(basename(target), _("No files extracted")) + self.logError(name, e) success = False continue + # remove processed file and related multiparts from list + files_ids = [(fname, fid, fout) for fname, fid, fout in files_ids \ + if fname not in archive.getDeleteFiles()] self.logDebug("Extracted files: %s" % new_files) self.setPermissions(new_files) - for file in new_files: - if not exists(file): - self.logDebug("New file %s does not exists" % file) + for filename in new_files: + file = fs_encode(save_join(os.path.dirname(archive.filename), filename)) + if not os.path.exists(file): + self.logDebug("New file %s does not exists" % filename) continue - if recursive and isfile(file): - new_files_ids.append((file, fid)) # append as new target - files_ids = new_files_ids # also check extracted files + if recursive and os.path.isfile(file): + new_files_ids.append((filename, fid, os.path.dirname(filename))) #: append as new target + + self.manager.dispatchEvent("archive_extracted", pyfile, archive) + + files_ids = new_files_ids #: also check extracted files if matched: if success: extracted.append(pid) - self.manager.dispatchEvent("package_extracted", p) + self.manager.dispatchEvent("package_extracted", pypack) + else: failed.append(pid) - self.manager.dispatchEvent("package_extract_failed", p) + self.manager.dispatchEvent("package_extract_failed", pypack) + + self.failed.add(pid) else: self.logInfo(_("No files found to extract")) if not matched or not success and subfolder: try: os.rmdir(out) + except OSError: pass - self.extracting = False + self.queue.remove(pid) + return True if not failed else False - def _extract(self, plugin, fid): - pyfile = self.core.files.getFile(fid) + def _extract(self, pyfile, archive, password): + name = os.path.basename(archive.filename) - pyfile.setCustomStatus(_("extracting")) + pyfile.setStatus("processing") + encrypted = False try: - progress = lambda x: pyfile.setProgress(x) - encrypted = False - passwords = self.getPasswords() - - try: - self.logInfo(basename(plugin.file), "Verifying...") + self.logDebug("Password: %s" % (password or "None provided")) + passwords = uniqify([password] + self.getPasswords(False)) if self.getConfig('usepasswordfile') else [password] + for pw in passwords: + try: + if self.getConfig('test') or self.repair: + pyfile.setCustomStatus(_("archive testing")) + if pw: + self.logDebug("Testing with password: %s" % pw) + pyfile.setProgress(0) + archive.verify(pw) + pyfile.setProgress(100) + else: + archive.check(pw) - tmp_password = plugin.password - plugin.password = "" #: Force verifying without password + self.addPassword(pw) + break - plugin.verify() + except PasswordError: + if not encrypted: + self.logInfo(name, _("Password protected")) + encrypted = True - except PasswordError: - encrypted = True + except CRCError, e: + self.logDebug(name, e) + self.logInfo(name, _("CRC Error")) - except CRCError: - self.logWarning(basename(plugin.file), _("Archive damaged")) + if self.repair: + self.logWarning(name, _("Repairing...")) - if not self.getConfig("repair"): - raise CRCError + pyfile.setCustomStatus(_("archive repairing")) + pyfile.setProgress(0) + repaired = archive.repair() + pyfile.setProgress(100) - elif plugin.repair(): - self.logInfo(basename(plugin.file), _("Successfully repaired")) + if not repaired and not self.getConfig('keepbroken'): + raise CRCError("Archive damaged") - elif not self.getConfig("keepbroken"): - raise ArchiveError(_("Broken archive")) + self.addPassword(pw) + break - else: - self.logInfo(basename(plugin.file), _("All OK")) + raise CRCError("Archive damaged") - plugin.password = tmp_password + except ArchiveError, e: + raise ArchiveError(e) - if not encrypted: - plugin.extract(progress) + pyfile.setCustomStatus(_("extracting")) + pyfile.setProgress(0) + if not encrypted or not self.getConfig('usepasswordfile'): + self.logDebug("Extracting using password: %s" % (password or "None")) + archive.extract(password) else: - self.logInfo(basename(plugin.file), _("Password protected")) - - if plugin.password: - passwords.insert(0, plugin.password) - passwords = uniqify(self.passwords) - self.logDebug("Password: %s" % plugin.password) - else: - self.logDebug("No package password provided") - - for pw in passwords: + for pw in filter(None, uniqify([password] + self.getPasswords(False))): try: - self.logDebug("Try password: %s" % pw) + self.logDebug("Extracting using password: %s" % pw) - if plugin.setPassword(pw): - plugin.extract(progress) - self.addPassword(pw) - break - else: - raise PasswordError + archive.extract(pw) + self.addPassword(pw) + break except PasswordError: self.logDebug("Password was wrong") else: raise PasswordError - if self.core.debug: - self.logDebug("Would delete: %s" % ", ".join(plugin.getDeleteFiles())) - - if self.getConfig("delete"): - files = plugin.getDeleteFiles() - self.logInfo(_("Deleting %s files") % len(files)) - for f in files: - if exists(f): - remove(f) + pyfile.setProgress(100) + pyfile.setStatus("processing") + + delfiles = archive.getDeleteFiles() + self.logDebug("Would delete: " + ", ".join(delfiles)) + + if self.getConfig('delete'): + self.logInfo(_("Deleting %s files") % len(delfiles)) + + deltotrash = self.getConfig('deltotrash') + for f in delfiles: + file = fs_encode(f) + if not os.path.exists(file): + continue + + if not deltotrash: + os.remove(file) + else: - self.logDebug("%s does not exists" % f) + try: + send2trash.send2trash(file) - self.logInfo(basename(plugin.file), _("Extracting finished")) + except NameError: + self.logWarning(_("Unable to move %s to trash: Send2Trash lib not found") % os.path.basename(f)) - extracted_files = plugin.getExtractedFiles() - self.manager.dispatchEvent("archive_extracted", pyfile, plugin.out, plugin.file, extracted_files) + except Exception, e: + self.logWarning(_("Unable to move %s to trash: %s") % (os.path.basename(f), e.message)) + + else: + self.logDebug(_("Successfully moved %s to trash") % os.path.basename(f)) + + self.logInfo(name, _("Extracting finished")) + extracted_files = archive.files or archive.list() return extracted_files except PasswordError: - self.logError(basename(plugin.file), _("Wrong password" if passwords else "No password found")) - plugin.password = "" + self.logError(name, _("Wrong password" if password else "No password found")) - except CRCError: - self.logError(basename(plugin.file), _("CRC Mismatch")) + except CRCError, e: + self.logError(name, _("CRC mismatch"), e) except ArchiveError, e: - self.logError(basename(plugin.file), _("Archive Error"), e) + self.logError(name, _("Archive error"), e) except Exception, e: + self.logError(name, _("Unknown error"), e) if self.core.debug: - print_exc() - self.logError(basename(plugin.file), _("Unknown Error"), e) + traceback.print_exc() - self.manager.dispatchEvent("archive_extract_failed", pyfile) + self.manager.dispatchEvent("archive_extract_failed", pyfile, archive) - self.logError(basename(plugin.file), _("Extract failed")) + raise Exception(_("Extract failed")) @Expose - def getPasswords(self): + def getPasswords(self, reload=True): """ List of saved passwords """ + if reload: + self.reloadPasswords() + return self.passwords def reloadPasswords(self): - passwordfile = self.getConfig("passwordfile") - try: passwords = [] - with open(passwordfile, "a+") as f: + + file = fs_encode(self.getConfig('passwordfile')) + with open(file) as f: for pw in f.read().splitlines(): passwords.append(pw) @@ -424,15 +534,13 @@ class ExtractArchive(Hook): @Expose - def addPassword(self, pw): + def addPassword(self, password): """ Adds a password to saved list""" - passwordfile = self.getConfig("passwordfile") - - self.passwords.insert(0, pw) - self.passwords = uniqify(self.passwords) - try: - with open(passwordfile, "wb") as f: + self.passwords = uniqify([password] + self.passwords) + + file = fs_encode(self.getConfig('passwordfile')) + with open(file, "wb") as f: for pw in self.passwords: f.write(pw + '\n') @@ -442,20 +550,21 @@ class ExtractArchive(Hook): def setPermissions(self, files): for f in files: - if not exists(f): + if not os.path.exists(f): continue try: if self.config['permission']['change_file']: - if isfile(f): - chmod(f, int(self.config['permission']['file'], 8)) - elif isdir(f): - chmod(f, int(self.config['permission']['folder'], 8)) + if os.path.isfile(f): + os.chmod(f, int(self.config['permission']['file'], 8)) + + elif os.path.isdir(f): + os.chmod(f, int(self.config['permission']['folder'], 8)) if self.config['permission']['change_dl'] and os.name != "nt": uid = getpwnam(self.config['permission']['user'])[2] gid = getgrnam(self.config['permission']['group'])[2] - chown(f, uid, gid) + os.chown(f, uid, gid) except Exception, e: self.logWarning(_("Setting User and Group failed"), e) diff --git a/module/plugins/hooks/FastixRu.py b/module/plugins/hooks/FastixRuHook.py index 25126fbd3..16e30e93a 100644 --- a/module/plugins/hooks/FastixRu.py +++ b/module/plugins/hooks/FastixRuHook.py @@ -4,16 +4,14 @@ from module.common.json_layer import json_loads from module.plugins.internal.MultiHook import MultiHook -class FastixRu(MultiHook): - __name__ = "FastixRu" +class FastixRuHook(MultiHook): + __name__ = "FastixRuHook" __type__ = "hook" __version__ = "0.05" __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), ("reload" , "bool" , "Reload plugin list" , True ), ("reloadinterval", "int" , "Reload interval in hours" , 12 )] @@ -23,9 +21,9 @@ class FastixRu(MultiHook): def getHosters(self): - page = self.getURL("http://fastix.ru/api_v2", + html = self.getURL("http://fastix.ru/api_v2", get={'apikey': "5182964c3f8f9a7f0b00000a_kelmFB4n1IrnCDYuIFn2y", 'sub' : "allowed_sources"}) - host_list = json_loads(page) + host_list = json_loads(html) host_list = host_list['allow'] return host_list diff --git a/module/plugins/hooks/FreeWayMe.py b/module/plugins/hooks/FreeWayMeHook.py index 6fec037d8..baea44540 100644 --- a/module/plugins/hooks/FreeWayMe.py +++ b/module/plugins/hooks/FreeWayMeHook.py @@ -3,16 +3,14 @@ from module.plugins.internal.MultiHook import MultiHook -class FreeWayMe(MultiHook): - __name__ = "FreeWayMe" +class FreeWayMeHook(MultiHook): + __name__ = "FreeWayMeHook" __type__ = "hook" - __version__ = "0.14" + __version__ = "0.15" __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), ("reload" , "bool" , "Reload plugin list" , True ), ("reloadinterval", "int" , "Reload interval in hours" , 12 )] @@ -22,6 +20,13 @@ class FreeWayMe(MultiHook): def getHosters(self): - hostis = self.getURL("https://www.free-way.me/ajax/jd.php", get={'id': 3}).replace("\"", "").strip() - self.logDebug("Hosters", hostis) + # Get account data + if not self.account or not self.account.canUse(): + hostis = self.getURL("https://www.free-way.me/ajax/jd.php", get={"id": 3}).replace("\"", "").strip() + else: + self.logDebug("AccountInfo available - Get HosterList with User Pass") + (user, data) = self.account.selectAccount() + hostis = self.getURL("https://www.free-way.me/ajax/jd.php", get={"id": 3, "user": user, "pass": data['password']}).replace("\"", "").strip() + + self.logDebug("hosters: %s" % hostis) return [x.strip() for x in hostis.split(",") if x.strip()] diff --git a/module/plugins/hooks/HotFolder.py b/module/plugins/hooks/HotFolder.py index b0b59e2ba..f771cf232 100644 --- a/module/plugins/hooks/HotFolder.py +++ b/module/plugins/hooks/HotFolder.py @@ -2,10 +2,9 @@ from __future__ import with_statement +import os import time -from os import listdir, makedirs -from os.path import exists, isfile, join from shutil import move from module.plugins.Hook import Hook @@ -15,12 +14,12 @@ from module.utils import fs_encode, save_join class HotFolder(Hook): __name__ = "HotFolder" __type__ = "hook" - __version__ = "0.12" + __version__ = "0.14" - __config__ = [("folder", "str", "Folder to observe", "container"), - ("watch_file", "bool", "Observe link file", False), - ("keep", "bool", "Keep added containers", True), - ("file", "str", "Link file", "links.txt")] + __config__ = [("folder" , "str" , "Folder to observe" , "container"), + ("watch_file", "bool", "Observe link file" , False ), + ("keep" , "bool", "Keep added containers", True ), + ("file" , "str" , "Link file" , "links.txt")] __description__ = """Observe folder and file for changes and add container and links""" __license__ = "GPLv3" @@ -28,39 +27,45 @@ class HotFolder(Hook): def setup(self): - self.interval = 10 + self.info = {} #@TODO: Remove in 0.4.10 + self.interval = 30 def periodical(self): - folder = fs_encode(self.getConfig("folder")) + folder = fs_encode(self.getConfig('folder')) + file = fs_encode(self.getConfig('file')) try: - if not exists(join(folder, "finished")): - makedirs(join(folder, "finished")) + if not os.path.isdir(os.path.join(folder, "finished")): + os.makedirs(os.path.join(folder, "finished")) - if self.getConfig("watch_file"): - with open(fs_encode(self.getConfig("file")), "a+") as f: + if self.getConfig('watch_file'): + with open(file, "a+") as f: + f.seek(0) content = f.read().strip() if content: - name = "%s_%s.txt" % (self.getConfig("file"), time.strftime("%H-%M-%S_%d%b%Y")) + f = open(file, "wb") + f.close() + + name = "%s_%s.txt" % (file, time.strftime("%H-%M-%S_%d%b%Y")) with open(save_join(folder, "finished", name), "wb") as f: f.write(content) self.core.api.addPackage(f.name, [f.name], 1) - for f in listdir(folder): - path = join(folder, f) + for f in os.listdir(folder): + path = os.path.join(folder, f) - if not isfile(path) or f.endswith("~") or f.startswith("#") or f.startswith("."): + if not os.path.isfile(path) or f.endswith("~") or f.startswith("#") or f.startswith("."): continue - newpath = join(folder, "finished", f if self.getConfig("keep") else "tmp_" + f) + newpath = os.path.join(folder, "finished", f if self.getConfig('keep') else "tmp_" + f) move(path, newpath) self.logInfo(_("Added %s from HotFolder") % f) self.core.api.addPackage(f, [newpath], 1) - except IOError, e: + except (IOError, OSError), e: self.logError(e) diff --git a/module/plugins/hooks/IRCInterface.py b/module/plugins/hooks/IRCInterface.py index efd4e411d..33fde3d20 100644 --- a/module/plugins/hooks/IRCInterface.py +++ b/module/plugins/hooks/IRCInterface.py @@ -1,15 +1,14 @@ # -*- coding: utf-8 -*- +import pycurl import re import socket import ssl import time +import traceback -from pycurl import FORM_FILE from select import select from threading import Thread -from time import sleep -from traceback import print_exc from module.Api import PackageDoesNotExists, FileDoesNotExists from module.network.RequestFactory import getURL @@ -38,17 +37,15 @@ class IRCInterface(Thread, Hook): __authors__ = [("Jeix", "Jeix@hasnomail.com")] + interval = 0 #@TODO: Remove in 0.4.10 + + def __init__(self, core, manager): Thread.__init__(self) Hook.__init__(self, core, manager) self.setDaemon(True) - #@TODO: Remove in 0.4.10 - def initPeriodical(self): - pass - - def coreReady(self): self.abort = False self.more = [] @@ -59,30 +56,30 @@ class IRCInterface(Thread, Hook): def packageFinished(self, pypack): try: - if self.getConfig("info_pack"): + if self.getConfig('info_pack'): self.response(_("Package finished: %s") % pypack.name) - except: + except Exception: pass def downloadFinished(self, pyfile): try: - if self.getConfig("info_file"): + if self.getConfig('info_file'): self.response( _("Download finished: %(name)s @ %(plugin)s ") % {"name": pyfile.name, "plugin": pyfile.pluginname}) - except: + except Exception: pass def newCaptchaTask(self, task): - if self.getConfig("captcha") and task.isTextual(): + if self.getConfig('captcha') and task.isTextual(): task.handler.append(self) task.setWaiting(60) - page = getURL("http://www.freeimagehosting.net/upload.php", - post={"attached": (FORM_FILE, task.captchaFile)}, multipart=True) + html = getURL("http://www.freeimagehosting.net/upload.php", + post={"attached": (pycurl.FORM_FILE, task.captchaFile)}, multipart=True) - url = re.search(r"\[img\]([^\[]+)\[/img\]\[/url\]", page).group(1) + url = re.search(r"\[img\]([^\[]+)\[/img\]\[/url\]", html).group(1) self.response(_("New Captcha Request: %s") % url) self.response(_("Answer with 'c %s text on the captcha'") % task.id) @@ -90,16 +87,16 @@ class IRCInterface(Thread, Hook): def run(self): # connect to IRC etc. self.sock = socket.socket() - host = self.getConfig("host") - self.sock.connect((host, self.getConfig("port"))) + host = self.getConfig('host') + self.sock.connect((host, self.getConfig('port'))) - if self.getConfig("ssl"): + if self.getConfig('ssl'): self.sock = ssl.wrap_socket(self.sock, cert_reqs=ssl.CERT_NONE) #@TODO: support certificate - nick = self.getConfig("nick") + nick = self.getConfig('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.getConfig("owner").split(): + for t in self.getConfig('owner').split(): if t.strip().startswith("#"): self.sock.send("JOIN %s\r\n" % t.strip()) self.logInfo(_("Connected to"), host) @@ -109,14 +106,14 @@ class IRCInterface(Thread, Hook): except IRCError, ex: self.sock.send("QUIT :byebye\r\n") - print_exc() + traceback.print_exc() self.sock.close() def main_loop(self): readbuffer = "" while True: - sleep(1) + time.sleep(1) fdset = select([self.sock], [], [], 0) if self.sock not in fdset[0]: continue @@ -153,10 +150,10 @@ class IRCInterface(Thread, Hook): def handle_events(self, msg): - if not msg['origin'].split("!", 1)[0] in self.getConfig("owner").split(): + if not msg['origin'].split("!", 1)[0] in self.getConfig('owner').split(): return - if msg['target'].split("!", 1)[0] != self.getConfig("nick"): + if msg['target'].split("!", 1)[0] != self.getConfig('nick'): return if msg['action'] != "PRIVMSG": @@ -183,7 +180,7 @@ class IRCInterface(Thread, Hook): trigger = temp[0] if len(temp) > 1: args = temp[1:] - except: + except Exception: pass handler = getattr(self, "event_%s" % trigger, self.event_pass) @@ -197,7 +194,7 @@ class IRCInterface(Thread, Hook): def response(self, msg, origin=""): if origin == "": - for t in self.getConfig("owner").split(): + for t in self.getConfig('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)) @@ -347,7 +344,7 @@ class IRCInterface(Thread, Hook): return ["INFO: Added %d links to Package %s [#%d]" % (len(links), pack['name'], id)] - except: + except Exception: # create new package id = self.core.api.addPackage(pack, links, 1) return ["INFO: Created new Package %s [#%d] with %d links." % (pack, id, len(links))] diff --git a/module/plugins/hooks/ImageTyperz.py b/module/plugins/hooks/ImageTyperz.py index d448d1be9..f1fcacb71 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 re from base64 import b64encode -from pycurl import FORM_FILE, LOW_SPEED_TIME from module.network.RequestFactory import getURL, getRequest from module.plugins.Hook import Hook, threaded @@ -40,20 +40,17 @@ class ImageTyperz(Hook): __description__ = """Send captchas to ImageTyperz.com""" __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org"), + __authors__ = [("RaNaN" , "RaNaN@pyload.org" ), ("zoidberg", "zoidberg@mujmail.cz")] + interval = 0 #@TODO: Remove in 0.4.10 + SUBMIT_URL = "http://captchatypers.com/Forms/UploadFileAndGetTextNEW.ashx" RESPOND_URL = "http://captchatypers.com/Forms/SetBadImage.ashx" GETCREDITS_URL = "http://captchatypers.com/Forms/RequestBalance.ashx" - #@TODO: Remove in 0.4.10 - def initPeriodical(self): - pass - - def setup(self): self.info = {} #@TODO: Remove in 0.4.10 @@ -61,15 +58,15 @@ class ImageTyperz(Hook): def getCredits(self): res = getURL(self.GETCREDITS_URL, post={'action': "REQUESTBALANCE", - 'username': self.getConfig("username"), - 'password': self.getConfig("passkey")}) + 'username': self.getConfig('username'), + 'password': self.getConfig('passkey')}) if res.startswith('ERROR'): raise ImageTyperzException(res) try: balance = float(res) - except: + except Exception: raise ImageTyperzException("Invalid response") self.logInfo(_("Account balance: $%s left") % res) @@ -79,13 +76,13 @@ class ImageTyperz(Hook): def submit(self, captcha, captchaType="file", match=None): req = getRequest() #raise timeout threshold - req.c.setopt(LOW_SPEED_TIME, 80) + req.c.setopt(pycurl.LOW_SPEED_TIME, 80) try: - #workaround multipart-post bug in HTTPRequest.py - if re.match("^\w*$", self.getConfig("passkey")): + #@NOTE: Workaround multipart-post bug in HTTPRequest.py + if re.match("^\w*$", self.getConfig('passkey')): multipart = True - data = (FORM_FILE, captcha) + data = (pycurl.FORM_FILE, captcha) else: multipart = False with open(captcha, 'rb') as f: @@ -94,8 +91,8 @@ class ImageTyperz(Hook): res = req.load(self.SUBMIT_URL, post={'action': "UPLOADCAPTCHA", - 'username': self.getConfig("username"), - 'password': self.getConfig("passkey"), "file": data}, + 'username': self.getConfig('username'), + 'password': self.getConfig('passkey'), "file": data}, multipart=multipart) finally: req.close() @@ -119,10 +116,10 @@ class ImageTyperz(Hook): if not task.isTextual(): return False - if not self.getConfig("username") or not self.getConfig("passkey"): + if not self.getConfig('username') or not self.getConfig('passkey'): return False - if self.core.isClientConnected() and not self.getConfig("force"): + if self.core.isClientConnected() and not self.getConfig('force'): return False if self.getCredits() > 0: @@ -139,8 +136,8 @@ class ImageTyperz(Hook): if task.data['service'] == self.__name__ and "ticket" in task.data: res = getURL(self.RESPOND_URL, post={'action': "SETBADIMAGE", - 'username': self.getConfig("username"), - 'password': self.getConfig("passkey"), + 'username': self.getConfig('username'), + 'password': self.getConfig('passkey'), 'imageid': task.data['ticket']}) if res == "SUCCESS": diff --git a/module/plugins/hooks/JustPremium.py b/module/plugins/hooks/JustPremium.py new file mode 100644 index 000000000..f66747f82 --- /dev/null +++ b/module/plugins/hooks/JustPremium.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- + +import re + +from module.plugins.Hook import Hook + + +class JustPremium(Hook): + __name__ = "JustPremium" + __type__ = "hook" + __version__ = "0.22" + + __config__ = [("excluded", "str", "Exclude hosters (comma separated)", ""), + ("included", "str", "Include hosters (comma separated)", "")] + + __description__ = """Remove not-premium links from added urls""" + __license__ = "GPLv3" + __authors__ = [("mazleu" , "mazleica@gmail.com"), + ("Walter Purcaro", "vuolter@gmail.com" ), + ("immenz" , "immenz@gmx.net" )] + + + interval = 0 #@TODO: Remove in 0.4.10 + + + def setup(self): + self.info = {} #@TODO: Remove in 0.4.10 + self.event_list = ["linksAdded"] + + + def linksAdded(self, links, pid): + hosterdict = self.core.pluginManager.hosterPlugins + linkdict = self.core.api.checkURLs(links) + + premiumplugins = set(account.type for account in self.core.api.getAccounts(False) \ + if account.valid and account.premium) + multihosters = set(hoster for hoster in self.core.pluginManager.hosterPlugins \ + if 'new_name' in hosterdict[hoster] \ + 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.getConfig('excluded').replace(' ', '').replace(',', '|').replace(';', '|').split('|')) + included = map(lambda domain: "".join(part.capitalize() for part in re.split(r'(\.|\d+)', domain) if part != '.'), + self.getConfig('included').replace(' ', '').replace(',', '|').replace(';', '|').split('|')) + + hosterlist = (premiumplugins | multihosters).union(excluded).difference(included) + + #: Found at least one hoster with account or multihoster + if not any( True for pluginname in linkdict if pluginname in hosterlist ): + return + + for pluginname in set(linkdict.keys()) - hosterlist: + self.logInfo(_("Remove links of plugin: %s") % pluginname) + for link in linkdict[pluginname]: + self.logDebug("Remove link: %s" % link) + links.remove(link) diff --git a/module/plugins/hooks/LinkdecrypterCom.py b/module/plugins/hooks/LinkdecrypterCom.py deleted file mode 100644 index d4924a687..000000000 --- a/module/plugins/hooks/LinkdecrypterCom.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from module.plugins.internal.MultiHook import MultiHook - - -class LinkdecrypterCom(MultiHook): - __name__ = "LinkdecrypterCom" - __type__ = "hook" - __version__ = "1.01" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 )] - - __description__ = """Linkdecrypter.com hook plugin""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - def getCrypters(self): - try: - html = self.getURL("http://linkdecrypter.com/") - return re.search(r'>Supported\(\d+\)</b>: <i>(.+?) \+ RSDF', html).group(1).split(', ') - except Exception: - return list() diff --git a/module/plugins/hooks/LinkdecrypterComHook.py b/module/plugins/hooks/LinkdecrypterComHook.py new file mode 100644 index 000000000..b2eaece62 --- /dev/null +++ b/module/plugins/hooks/LinkdecrypterComHook.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- + +import re + +from module.plugins.internal.MultiHook import MultiHook + + +class LinkdecrypterComHook(MultiHook): + __name__ = "LinkdecrypterComHook" + __type__ = "hook" + __version__ = "1.06" + + __config__ = [("activated" , "bool" , "Activated" , True ), + ("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)", "" ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 )] + + __description__ = """Linkdecrypter.com hook plugin""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + def getHosters(self): + list = re.search(r'>Supported\(\d+\)</b>: <i>(.[\w.\-, ]+)', + self.getURL("http://linkdecrypter.com/", decode=True).replace("(g)", "")).group(1).split(', ') + try: + list.remove("download.serienjunkies.org") + except ValueError: + pass + + return list diff --git a/module/plugins/hooks/LinksnappyCom.py b/module/plugins/hooks/LinksnappyComHook.py index 5eb0c7f6d..72282575b 100644 --- a/module/plugins/hooks/LinksnappyCom.py +++ b/module/plugins/hooks/LinksnappyComHook.py @@ -4,16 +4,14 @@ from module.common.json_layer import json_loads from module.plugins.internal.MultiHook import MultiHook -class LinksnappyCom(MultiHook): - __name__ = "LinksnappyCom" +class LinksnappyComHook(MultiHook): + __name__ = "LinksnappyComHook" __type__ = "hook" __version__ = "0.04" __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), ("reload" , "bool" , "Reload plugin list" , True ), ("reloadinterval", "int" , "Reload interval in hours" , 12 )] diff --git a/module/plugins/hooks/MegaDebridEu.py b/module/plugins/hooks/MegaDebridEuHook.py index f67fa7ac0..0de7b4dcf 100644 --- a/module/plugins/hooks/MegaDebridEu.py +++ b/module/plugins/hooks/MegaDebridEuHook.py @@ -4,16 +4,14 @@ from module.common.json_layer import json_loads from module.plugins.internal.MultiHook import MultiHook -class MegaDebridEu(MultiHook): - __name__ = "MegaDebridEu" +class MegaDebridEuHook(MultiHook): + __name__ = "MegaDebridEuHook" __type__ = "hook" __version__ = "0.05" __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), ("reload" , "bool" , "Reload plugin list" , True ), ("reloadinterval", "int" , "Reload interval in hours" , 12 )] diff --git a/module/plugins/hooks/MegaRapidoNetHook.py b/module/plugins/hooks/MegaRapidoNetHook.py new file mode 100644 index 000000000..e113b305e --- /dev/null +++ b/module/plugins/hooks/MegaRapidoNetHook.py @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- + +import re + +from module.plugins.internal.MultiHook import MultiHook + + +class MegaRapidoNetHook(MultiHook): + __name__ = "MegaRapidoNetHook" + __type__ = "hook" + __version__ = "0.02" + + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)", "" ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 )] + + __description__ = """MegaRapido.net hook plugin""" + __license__ = "GPLv3" + __authors__ = [("Kagenoshin", "kagenoshin@gmx.ch")] + + + def getHosters(self): + hosters = {'1fichier' : [],#leave it there are so many possible addresses? + '1st-files' : ['1st-files.com'], + '2shared' : ['2shared.com'], + '4shared' : ['4shared.com', '4shared-china.com'], + 'asfile' : ['http://asfile.com/'], + 'bitshare' : ['bitshare.com'], + 'brupload' : ['brupload.net'], + 'crocko' : ['crocko.com','easy-share.com'], + 'dailymotion' : ['dailymotion.com'], + 'depfile' : ['depfile.com'], + 'depositfiles': ['depositfiles.com', 'dfiles.eu'], + 'dizzcloud' : ['dizzcloud.com'], + 'dl.dropbox' : [], + 'extabit' : ['extabit.com'], + 'extmatrix' : ['extmatrix.com'], + 'facebook' : [], + 'file4go' : ['file4go.com'], + 'filecloud' : ['filecloud.io','ifile.it','mihd.net'], + 'filefactory' : ['filefactory.com'], + 'fileom' : ['fileom.com'], + 'fileparadox' : ['fileparadox.in'], + 'filepost' : ['filepost.com', 'fp.io'], + 'filerio' : ['filerio.in','filerio.com','filekeen.com'], + 'filesflash' : ['filesflash.com'], + 'firedrive' : ['firedrive.com', 'putlocker.com'], + 'flashx' : [], + 'freakshare' : ['freakshare.net', 'freakshare.com'], + 'gigasize' : ['gigasize.com'], + 'hipfile' : ['hipfile.com'], + 'junocloud' : ['junocloud.me'], + 'letitbit' : ['letitbit.net','shareflare.net'], + 'mediafire' : ['mediafire.com'], + 'mega' : ['mega.co.nz'], + 'megashares' : ['megashares.com'], + 'metacafe' : ['metacafe.com'], + 'netload' : ['netload.in'], + 'oboom' : ['oboom.com'], + 'rapidgator' : ['rapidgator.net'], + 'rapidshare' : ['rapidshare.com'], + 'rarefile' : ['rarefile.net'], + 'ryushare' : ['ryushare.com'], + 'sendspace' : ['sendspace.com'], + 'turbobit' : ['turbobit.net', 'unextfiles.com'], + 'uploadable' : ['uploadable.ch'], + 'uploadbaz' : ['uploadbaz.com'], + 'uploaded' : ['uploaded.to', 'uploaded.net', 'ul.to'], + 'uploadhero' : ['uploadhero.com'], + 'uploading' : ['uploading.com'], + 'uptobox' : ['uptobox.com'], + 'xvideos' : ['xvideos.com'], + 'youtube' : ['youtube.com']} + + hoster_list = [] + + for item in hosters.itervalues(): + hoster_list.extend(item) + + return hoster_list diff --git a/module/plugins/hooks/MergeFiles.py b/module/plugins/hooks/MergeFiles.py index 4de45f958..941938920 100644 --- a/module/plugins/hooks/MergeFiles.py +++ b/module/plugins/hooks/MergeFiles.py @@ -4,17 +4,16 @@ from __future__ import with_statement import os import re - -from traceback import print_exc +import traceback from module.plugins.Hook import Hook, threaded -from module.utils import save_join, fs_encode +from module.utils import save_join class MergeFiles(Hook): __name__ = "MergeFiles" __type__ = "hook" - __version__ = "0.13" + __version__ = "0.14" __config__ = [("activated", "bool", "Activated", True)] @@ -23,17 +22,13 @@ class MergeFiles(Hook): __authors__ = [("and9000", "me@has-no-mail.com")] - BUFFER_SIZE = 4096 - + interval = 0 #@TODO: Remove in 0.4.10 - #@TODO: Remove in 0.4.10 - def initPeriodical(self): - pass + BUFFER_SIZE = 4096 def setup(self): - # nothing to do - pass + self.info = {} #@TODO: Remove in 0.4.10 @threaded @@ -65,7 +60,7 @@ class MergeFiles(Hook): pyfile.setStatus("processing") try: - with open(os.path.join(download_folder, splitted_file), "rb") as s_file: + with open(save_join(download_folder, splitted_file), "rb") as s_file: size_written = 0 s_file_size = int(os.path.getsize(os.path.join(download_folder, splitted_file))) while True: @@ -79,7 +74,7 @@ class MergeFiles(Hook): self.logDebug("Finished merging part", splitted_file) except Exception, e: - print_exc() + traceback.print_exc() finally: pyfile.setProgress(100) diff --git a/module/plugins/hooks/MultiHome.py b/module/plugins/hooks/MultiHome.py index 105a42abd..a26d139c0 100644 --- a/module/plugins/hooks/MultiHome.py +++ b/module/plugins/hooks/MultiHome.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -from time import time +import time from module.plugins.Hook import Hook @@ -17,22 +17,23 @@ class MultiHome(Hook): __authors__ = [("mkaay", "mkaay@mkaay.de")] - #@TODO: Remove in 0.4.10 - def initPeriodical(self): - pass + interval = 0 #@TODO: Remove in 0.4.10 def setup(self): - self.register = {} + self.info = {} #@TODO: Remove in 0.4.10 + self.register = {} self.interfaces = [] - self.parseInterfaces(self.getConfig("interfaces").split(";")) + + self.parseInterfaces(self.getConfig('interfaces').split(";")) + if not self.interfaces: self.parseInterfaces([self.config['download']['interface']]) self.setConfig("interfaces", self.toConfig()) def toConfig(self): - return ";".join([i.adress for i in self.interfaces]) + return ";".join(i.adress for i in self.interfaces) def parseInterfaces(self, interfaces): @@ -80,7 +81,7 @@ class Interface(object): def useFor(self, pluginName, account): - self.history[(pluginName, account)] = time() + self.history[(pluginName, account)] = time.time() def __repr__(self): diff --git a/module/plugins/hooks/MultihostersCom.py b/module/plugins/hooks/MultihostersComHook.py index bf88cfae7..7b5e49c49 100644 --- a/module/plugins/hooks/MultihostersCom.py +++ b/module/plugins/hooks/MultihostersComHook.py @@ -1,10 +1,10 @@ # -*- coding: utf-8 -*- -from module.plugins.hooks.ZeveraCom import ZeveraCom +from module.plugins.hooks.ZeveraComHook import ZeveraComHook -class MultihostersCom(ZeveraCom): - __name__ = "MultihostersCom" +class MultihostersComHook(ZeveraComHook): + __name__ = "MultihostersComHook" __type__ = "hook" __version__ = "0.02" diff --git a/module/plugins/hooks/MultishareCz.py b/module/plugins/hooks/MultishareCzHook.py index 8349e0de8..6052b7673 100644 --- a/module/plugins/hooks/MultishareCz.py +++ b/module/plugins/hooks/MultishareCzHook.py @@ -5,16 +5,14 @@ import re from module.plugins.internal.MultiHook import MultiHook -class MultishareCz(MultiHook): - __name__ = "MultishareCz" +class MultishareCzHook(MultiHook): + __name__ = "MultishareCzHook" __type__ = "hook" __version__ = "0.07" __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), ("reload" , "bool" , "Reload plugin list" , True ), ("reloadinterval", "int" , "Reload interval in hours" , 12 )] @@ -23,9 +21,9 @@ class MultishareCz(MultiHook): __authors__ = [("zoidberg", "zoidberg@mujmail.cz")] - HOSTER_PATTERN = r'<img class="logo-shareserveru"[^>]*?alt="([^"]+)"></td>\s*<td class="stav">[^>]*?alt="OK"' + HOSTER_PATTERN = r'<img class="logo-shareserveru"[^>]*?alt="(.+?)"></td>\s*<td class="stav">[^>]*?alt="OK"' def getHosters(self): - page = self.getURL("http://www.multishare.cz/monitoring/") - return re.findall(self.HOSTER_PATTERN, page) + html = self.getURL("http://www.multishare.cz/monitoring/") + return re.findall(self.HOSTER_PATTERN, html) diff --git a/module/plugins/hooks/MyfastfileCom.py b/module/plugins/hooks/MyfastfileComHook.py index 86408cb6d..20a1cfac2 100644 --- a/module/plugins/hooks/MyfastfileCom.py +++ b/module/plugins/hooks/MyfastfileComHook.py @@ -4,16 +4,14 @@ from module.common.json_layer import json_loads from module.plugins.internal.MultiHook import MultiHook -class MyfastfileCom(MultiHook): - __name__ = "MyfastfileCom" +class MyfastfileComHook(MultiHook): + __name__ = "MyfastfileComHook" __type__ = "hook" __version__ = "0.05" __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), ("reload" , "bool" , "Reload plugin list" , True ), ("reloadinterval", "int" , "Reload interval in hours" , 12 )] diff --git a/module/plugins/hooks/NoPremiumPl.py b/module/plugins/hooks/NoPremiumPlHook.py index 1727bec70..b5a007ff9 100644 --- a/module/plugins/hooks/NoPremiumPl.py +++ b/module/plugins/hooks/NoPremiumPlHook.py @@ -4,16 +4,14 @@ from module.common.json_layer import json_loads from module.plugins.internal.MultiHook import MultiHook -class NoPremiumPl(MultiHook): - __name__ = "NoPremiumPl" +class NoPremiumPlHook(MultiHook): + __name__ = "NoPremiumPlHook" __type__ = "hook" __version__ = "0.03" __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), ("reload" , "bool" , "Reload plugin list" , True ), ("reloadinterval", "int" , "Reload interval in hours" , 12 )] diff --git a/module/plugins/hooks/OverLoadMe.py b/module/plugins/hooks/OverLoadMeHook.py index 1872f8ccb..d608a2ecd 100644 --- a/module/plugins/hooks/OverLoadMe.py +++ b/module/plugins/hooks/OverLoadMeHook.py @@ -3,16 +3,14 @@ from module.plugins.internal.MultiHook import MultiHook -class OverLoadMe(MultiHook): - __name__ = "OverLoadMe" +class OverLoadMeHook(MultiHook): + __name__ = "OverLoadMeHook" __type__ = "hook" __version__ = "0.04" __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), ("reload" , "bool" , "Reload plugin list" , True ), ("reloadinterval", "int" , "Reload interval in hours" , 12 ), ("ssl" , "bool" , "Use HTTPS" , True )] @@ -23,9 +21,9 @@ class OverLoadMe(MultiHook): def getHosters(self): - https = "https" if self.getConfig("ssl") else "http" - page = self.getURL(https + "://api.over-load.me/hoster.php", + https = "https" if self.getConfig('ssl') else "http" + html = self.getURL(https + "://api.over-load.me/hoster.php", get={'auth': "0001-cb1f24dadb3aa487bda5afd3b76298935329be7700cd7-5329be77-00cf-1ca0135f"}).replace("\"", "").strip() - self.logDebug("Hosterlist", page) + self.logDebug("Hosterlist", html) - return [x.strip() for x in page.split(",") if x.strip()] + return [x.strip() for x in html.split(",") if x.strip()] diff --git a/module/plugins/hooks/PremiumTo.py b/module/plugins/hooks/PremiumToHook.py index 844ecc89d..ef2a84223 100644 --- a/module/plugins/hooks/PremiumTo.py +++ b/module/plugins/hooks/PremiumToHook.py @@ -3,27 +3,25 @@ from module.plugins.internal.MultiHook import MultiHook -class PremiumTo(MultiHook): - __name__ = "PremiumTo" +class PremiumToHook(MultiHook): + __name__ = "PremiumToHook" __type__ = "hook" __version__ = "0.08" __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), ("reload" , "bool" , "Reload plugin list" , True ), ("reloadinterval", "int" , "Reload interval in hours" , 12 )] __description__ = """Premium.to hook plugin""" __license__ = "GPLv3" - __authors__ = [("RaNaN", "RaNaN@pyload.org"), + __authors__ = [("RaNaN" , "RaNaN@pyload.org" ), ("zoidberg", "zoidberg@mujmail.cz"), ("stickell", "l.stickell@yahoo.it")] def getHosters(self): - page = self.getURL("http://premium.to/api/hosters.php", + html = self.getURL("http://premium.to/api/hosters.php", get={'username': self.account.username, 'password': self.account.password}) - return [x.strip() for x in page.replace("\"", "").split(";")] + return [x.strip() for x in html.replace("\"", "").split(";")] diff --git a/module/plugins/hooks/PremiumizeMe.py b/module/plugins/hooks/PremiumizeMeHook.py index 293fcf339..f13520323 100644 --- a/module/plugins/hooks/PremiumizeMe.py +++ b/module/plugins/hooks/PremiumizeMeHook.py @@ -4,16 +4,14 @@ from module.common.json_layer import json_loads from module.plugins.internal.MultiHook import MultiHook -class PremiumizeMe(MultiHook): - __name__ = "PremiumizeMe" +class PremiumizeMeHook(MultiHook): + __name__ = "PremiumizeMeHook" __type__ = "hook" - __version__ = "0.17" + __version__ = "0.18" __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), ("reload" , "bool" , "Reload plugin list" , True ), ("reloadinterval", "int" , "Reload interval in hours" , 12 )] @@ -28,7 +26,7 @@ class PremiumizeMe(MultiHook): # Get supported hosters list from premiumize.me using the # json API v1 (see https://secure.premiumize.me/?show=api) - answer = self.getURL("https://api.premiumize.me/pm-api/v1.php", + answer = self.getURL("http://api.premiumize.me/pm-api/v1.php", get={'method': "hosterlist", 'params[login]': user, 'params[pass]': data['password']}) data = json_loads(answer) diff --git a/module/plugins/hooks/PutdriveCom.py b/module/plugins/hooks/PutdriveComHook.py index f665dabee..c3ebf4ff3 100644 --- a/module/plugins/hooks/PutdriveCom.py +++ b/module/plugins/hooks/PutdriveComHook.py @@ -1,10 +1,10 @@ # -*- coding: utf-8 -*- -from module.plugins.hooks.ZeveraCom import ZeveraCom +from module.plugins.hooks.ZeveraComHook import ZeveraComHook -class PutdriveCom(ZeveraCom): - __name__ = "PutdriveCom" +class PutdriveComHook(ZeveraComHook): + __name__ = "PutdriveComHook" __type__ = "hook" __version__ = "0.01" diff --git a/module/plugins/hooks/RPNetBiz.py b/module/plugins/hooks/RPNetBizHook.py index 0768bd6cd..10332948d 100644 --- a/module/plugins/hooks/RPNetBiz.py +++ b/module/plugins/hooks/RPNetBizHook.py @@ -4,16 +4,14 @@ from module.common.json_layer import json_loads from module.plugins.internal.MultiHook import MultiHook -class RPNetBiz(MultiHook): - __name__ = "RPNetBiz" +class RPNetBizHook(MultiHook): + __name__ = "RPNetBizHook" __type__ = "hook" __version__ = "0.14" __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), ("reload" , "bool" , "Reload plugin list" , True ), ("reloadinterval", "int" , "Reload interval in hours" , 12 )] diff --git a/module/plugins/hooks/RapideoPl.py b/module/plugins/hooks/RapideoPlHook.py index b605eca17..0400f07ba 100644 --- a/module/plugins/hooks/RapideoPl.py +++ b/module/plugins/hooks/RapideoPlHook.py @@ -4,16 +4,14 @@ from module.common.json_layer import json_loads from module.plugins.internal.MultiHook import MultiHook -class RapideoPl(MultiHook): - __name__ = "RapideoPl" +class RapideoPlHook(MultiHook): + __name__ = "RapideoPlHook" __type__ = "hook" __version__ = "0.03" __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), ("reload" , "bool" , "Reload plugin list" , True ), ("reloadinterval", "int" , "Reload interval in hours" , 12 )] diff --git a/module/plugins/hooks/RealdebridCom.py b/module/plugins/hooks/RealdebridComHook.py index cff97c2f9..aa0c9f640 100644 --- a/module/plugins/hooks/RealdebridCom.py +++ b/module/plugins/hooks/RealdebridComHook.py @@ -3,16 +3,14 @@ from module.plugins.internal.MultiHook import MultiHook -class RealdebridCom(MultiHook): - __name__ = "RealdebridCom" +class RealdebridComHook(MultiHook): + __name__ = "RealdebridComHook" __type__ = "hook" __version__ = "0.46" __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), ("reload" , "bool" , "Reload plugin list" , True ), ("reloadinterval", "int" , "Reload interval in hours" , 12 ), ("ssl" , "bool" , "Use HTTPS" , True )] @@ -23,7 +21,7 @@ class RealdebridCom(MultiHook): def getHosters(self): - https = "https" if self.getConfig("ssl") else "http" - page = self.getURL(https + "://real-debrid.com/api/hosters.php").replace("\"", "").strip() + https = "https" if self.getConfig('ssl') else "http" + html = self.getURL(https + "://real-debrid.com/api/hosters.php").replace("\"", "").strip() - return [x.strip() for x in page.split(",") if x.strip()] + return [x.strip() for x in html.split(",") if x.strip()] diff --git a/module/plugins/hooks/RehostTo.py b/module/plugins/hooks/RehostToHook.py index ddb8b3eb0..a2415129a 100644 --- a/module/plugins/hooks/RehostTo.py +++ b/module/plugins/hooks/RehostToHook.py @@ -3,16 +3,14 @@ from module.plugins.internal.MultiHook import MultiHook -class RehostTo(MultiHook): - __name__ = "RehostTo" +class RehostToHook(MultiHook): + __name__ = "RehostToHook" __type__ = "hook" __version__ = "0.50" __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), ("reload" , "bool" , "Reload plugin list" , True ), ("reloadinterval", "int" , "Reload interval in hours" , 12 )] @@ -23,7 +21,7 @@ class RehostTo(MultiHook): def getHosters(self): user, data = self.account.selectAccount() - page = self.getURL("http://rehost.to/api.php", + html = self.getURL("http://rehost.to/api.php", get={'cmd' : "get_supported_och_dl", 'long_ses': self.account.getAccountInfo(user)['session']}) - return [x.strip() for x in page.replace("\"", "").split(",")] + return [x.strip() for x in html.replace("\"", "").split(",")] diff --git a/module/plugins/hooks/RestartFailed.py b/module/plugins/hooks/RestartFailed.py index 07fb80967..865af2a6b 100644 --- a/module/plugins/hooks/RestartFailed.py +++ b/module/plugins/hooks/RestartFailed.py @@ -6,29 +6,27 @@ from module.plugins.Hook import Hook class RestartFailed(Hook): __name__ = "RestartFailed" __type__ = "hook" - __version__ = "1.57" + __version__ = "1.58" __config__ = [("interval", "int", "Check interval in minutes", 90)] - __description__ = """Periodically restart all failed downloads in queue""" + __description__ = """Restart all the failed downloads in queue""" __license__ = "GPLv3" __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - # event_list = ["pluginConfigChanged"] + MIN_CHECK_INTERVAL = 15 * 60 #: 15 minutes - MIN_INTERVAL = 15 * 60 #: 15m minimum check interval (value is in seconds) - - def pluginConfigChanged(self, plugin, name, value): - if name == "interval": - interval = value * 60 - if self.MIN_INTERVAL <= interval != self.interval: - self.core.scheduler.removeJob(self.cb) - self.interval = interval - self.initPeriodical() - else: - self.logDebug("Invalid interval value, kept current") + # def pluginConfigChanged(self, plugin, name, value): + # if name == "interval": + # interval = value * 60 + # if self.MIN_CHECK_INTERVAL <= interval != self.interval: + # self.core.scheduler.removeJob(self.cb) + # self.interval = interval + # self.initPeriodical() + # else: + # self.logDebug("Invalid interval value, kept current") def periodical(self): @@ -37,8 +35,11 @@ class RestartFailed(Hook): def setup(self): - self.interval = self.MIN_INTERVAL + self.info = {} #@TODO: Remove in 0.4.10 + # self.event_list = ["pluginConfigChanged"] + self.interval = self.MIN_CHECK_INTERVAL def coreReady(self): - self.pluginConfigChanged(self.__name__, "interval", self.getConfig("interval")) + # self.pluginConfigChanged(self.__name__, "interval", self.getConfig('interval')) + self.interval = max(self.MIN_CHECK_INTERVAL, self.getConfig('interval') * 60) diff --git a/module/plugins/hooks/RestartSlow.py b/module/plugins/hooks/RestartSlow.py deleted file mode 100644 index c2fdf6f95..000000000 --- a/module/plugins/hooks/RestartSlow.py +++ /dev/null @@ -1,61 +0,0 @@ -# -*- coding: utf-8 -*- - -import pycurl - -from module.plugins.Hook import Hook - - -class RestartSlow(Hook): - __name__ = "RestartSlow" - __type__ = "hook" - __version__ = "0.03" - - __config__ = [("free_limit" , "int" , "Transfer speed threshold in kilobytes" , 100 ), - ("free_time" , "int" , "Sample interval in minutes" , 5 ), - ("premium_limit", "int" , "Transfer speed threshold for premium download in kilobytes", 300 ), - ("premium_time" , "int" , "Sample interval for premium download in minutes" , 2 ), - ("safe_mode" , "bool", "Don't restart if download is not resumable" , True)] - - __description__ = """Restart slow downloads""" - __license__ = "GPLv3" - __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - - - event_list = ["downloadStarts"] - - - def setup(self): - self.info = {'chunk': {}} - - - def initPeriodical(self): - pass - - - def periodical(self): - if not self.pyfile.req.dl: - return - - if self.getConfig("safe_mode") and not self.pyfile.plugin.resumeDownload: - time = 30 - limit = 5 - else: - type = "premium" if self.pyfile.plugin.premium else "free" - time = max(30, self.getConfig("%s_time" % type) * 60) - limit = max(5, self.getConfig("%s_limit" % type) * 1024) - - chunks = [chunk for chunk in self.pyfile.req.dl.chunks \ - if chunk.id not in self.info['chunk'] or self.info['chunk'][chunk.id] is not (time, limit)] - - for chunk in chunks: - chunk.c.setopt(pycurl.LOW_SPEED_TIME , time) - chunk.c.setopt(pycurl.LOW_SPEED_LIMIT, limit) - - self.info['chunk'][chunk.id] = (time, limit) - - - def downloadStarts(self, pyfile, url, filename): - if self.cb or (self.getConfig("safe_mode") and not pyfile.plugin.resumeDownload): - return - - super(RestartSlow, self).initPeriodical() diff --git a/module/plugins/hooks/SimplyPremiumCom.py b/module/plugins/hooks/SimplyPremiumComHook.py index 843a3aa82..116e3a76e 100644 --- a/module/plugins/hooks/SimplyPremiumCom.py +++ b/module/plugins/hooks/SimplyPremiumComHook.py @@ -4,16 +4,14 @@ from module.common.json_layer import json_loads from module.plugins.internal.MultiHook import MultiHook -class SimplyPremiumCom(MultiHook): - __name__ = "SimplyPremiumCom" +class SimplyPremiumComHook(MultiHook): + __name__ = "SimplyPremiumComHook" __type__ = "hook" __version__ = "0.05" __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), ("reload" , "bool" , "Reload plugin list" , True ), ("reloadinterval", "int" , "Reload interval in hours" , 12 )] diff --git a/module/plugins/hooks/SimplydebridCom.py b/module/plugins/hooks/SimplydebridComHook.py index 10c613fb5..01629df99 100644 --- a/module/plugins/hooks/SimplydebridCom.py +++ b/module/plugins/hooks/SimplydebridComHook.py @@ -3,16 +3,14 @@ from module.plugins.internal.MultiHook import MultiHook -class SimplydebridCom(MultiHook): - __name__ = "SimplydebridCom" +class SimplydebridComHook(MultiHook): + __name__ = "SimplydebridComHook" __type__ = "hook" __version__ = "0.04" __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), ("reload" , "bool" , "Reload plugin list" , True ), ("reloadinterval", "int" , "Reload interval in hours" , 12 )] @@ -22,5 +20,5 @@ class SimplydebridCom(MultiHook): def getHosters(self): - page = self.getURL("http://simply-debrid.com/api.php", get={'list': 1}) - return [x.strip() for x in page.rstrip(';').replace("\"", "").split(";")] + html = self.getURL("http://simply-debrid.com/api.php", get={'list': 1}) + return [x.strip() for x in html.rstrip(';').replace("\"", "").split(";")] diff --git a/module/plugins/hooks/SkipRev.py b/module/plugins/hooks/SkipRev.py index 6b4e715da..7901ca540 100644 --- a/module/plugins/hooks/SkipRev.py +++ b/module/plugins/hooks/SkipRev.py @@ -1,43 +1,49 @@ # -*- coding: utf-8 -*- +import re +import urllib +import urlparse + from types import MethodType -from urllib import unquote -from urlparse import urlparse from module.PyFile import PyFile from module.plugins.Hook import Hook from module.plugins.Plugin import SkipDownload -def _setup(self): - self.pyfile.plugin._setup() - if self.pyfile.hasStatus("skipped"): - raise SkipDownload(self.pyfile.statusname or self.pyfile.pluginname) - - class SkipRev(Hook): __name__ = "SkipRev" __type__ = "hook" - __version__ = "0.23" + __version__ = "0.29" - __config__ = [("tokeep", "int", "Number of rev files to keep for package (-1 to auto)", -1)] + __config__ = [("mode" , "Auto;Manual", "Choose recovery archives to skip" , "Auto"), + ("revtokeep", "int" , "Number of recovery archives to keep for package", 0 )] - __description__ = """Skip files ending with extension rev""" + __description__ = """Skip recovery archives (.rev)""" __license__ = "GPLv3" __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - #@TODO: Remove in 0.4.10 - def initPeriodical(self): - pass + interval = 0 #@TODO: Remove in 0.4.10 + + + def setup(self): + self.info = {} #@TODO: Remove in 0.4.10 + + @staticmethod + def _setup(self): + self.pyfile.plugin._setup() + if self.pyfile.hasStatus("skipped"): + raise SkipDownload(self.pyfile.statusname or self.pyfile.pluginname) - def _pyname(self, pyfile): - if hasattr(pyfile.pluginmodule, "getInfo"): - return next(getattr(pyfile.pluginmodule, "getInfo")([pyfile.url]))[0] + + def _name(self, pyfile): + if hasattr(pyfile.pluginmodule, "getInfo"): #@NOTE: getInfo is deprecated in 0.4.10 + return pyfile.pluginmodule.getInfo([pyfile.url]).next()[0] else: self.logWarning("Unable to grab file name") - return urlparse(unquote(pyfile.url)).path.split('/')[-1] + return urlparse.urlparse(urllib.unquote(pyfile.url)).path.split('/')[-1] def _pyfile(self, link): @@ -54,42 +60,52 @@ class SkipRev(Hook): def downloadPreparing(self, pyfile): - if pyfile.statusname is "unskipped" or not self._pyname(pyfile).endswith(".rev"): + name = self._name(pyfile) + + if pyfile.statusname is _("unskipped") or not name.endswith(".rev") or not ".part" in name: return - tokeep = self.getConfig("tokeep") + revtokeep = -1 if self.getConfig('mode') == "Auto" else self.getConfig('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('.', '\.')) - if tokeep: - saved = [True for link in self.core.api.getPackageData(pyfile.package().id).links \ - if link.name.endswith(".rev") and link.status in (0, 12)].count(True) + queued = [True for link in self.core.api.getPackageData(pyfile.package().id).links \ + if link.status not in status_list and pyname.match(link.name)].count(True) - if not saved or saved < tokeep: #: keep one rev at least in auto mode + if not queued or queued < revtokeep: #: keep one rev at least in auto mode return pyfile.setCustomStatus("SkipRev", "skipped") - pyfile.plugin._setup = pyfile.plugin.setup - pyfile.plugin.setup = MethodType(_setup, pyfile.plugin) #: work-around: inject status checker inside the preprocessing routine of the plugin + + if not hasattr(pyfile.plugin, "_setup"): + # Work-around: inject status checker inside the preprocessing routine of the plugin + pyfile.plugin._setup = pyfile.plugin.setup + pyfile.plugin.setup = MethodType(self._setup, pyfile.plugin) def downloadFailed(self, pyfile): #: Check if pyfile is still "failed", # maybe might has been restarted in meantime - if pyfile.status != 8: + if pyfile.status != 8 or pyfile.name.rsplit('.', 1)[-1].strip() not in ("rar", "rev"): return - tokeep = self.getConfig("tokeep") + revtokeep = -1 if self.getConfig('mode') == "Auto" else self.getConfig('revtokeep') - if not tokeep: + if not revtokeep: return + pyname = re.compile(r'%s\.part\d+\.rev$' % pyfile.name.rsplit('.', 2)[0].replace('.', '\.')) + for link in self.core.api.getPackageData(pyfile.package().id).links: - if link.status is 4 and link.name.endswith(".rev"): + if link.status is 4 and pyname.match(link.name): pylink = self._pyfile(link) - if tokeep > -1 or pyfile.name.endswith(".rev"): + if revtokeep > -1 or pyfile.name.endswith(".rev"): pylink.setStatus("queued") else: - pylink.setCustomStatus("unskipped", "queued") + pylink.setCustomStatus(_("unskipped"), "queued") self.core.files.save() pylink.release() diff --git a/module/plugins/hooks/SmoozedCom.py b/module/plugins/hooks/SmoozedComHook.py index 9ba2daac9..24b7c8df0 100644 --- a/module/plugins/hooks/SmoozedCom.py +++ b/module/plugins/hooks/SmoozedComHook.py @@ -3,16 +3,14 @@ from module.plugins.internal.MultiHook import MultiHook -class SmoozedCom(MultiHook): - __name__ = "SmoozedCom" +class SmoozedComHook(MultiHook): + __name__ = "SmoozedComHook" __type__ = "hook" __version__ = "0.03" __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), ("reload" , "bool" , "Reload plugin list" , True ), ("reloadinterval", "int" , "Reload interval in hours" , 12 )] diff --git a/module/plugins/hooks/UnSkipOnFail.py b/module/plugins/hooks/UnSkipOnFail.py index 1becb937a..9059d0350 100644 --- a/module/plugins/hooks/UnSkipOnFail.py +++ b/module/plugins/hooks/UnSkipOnFail.py @@ -7,18 +7,20 @@ from module.plugins.Hook import Hook class UnSkipOnFail(Hook): __name__ = "UnSkipOnFail" __type__ = "hook" - __version__ = "0.05" + __version__ = "0.07" __config__ = [("activated", "bool", "Activated", True)] - __description__ = """Queue skipped duplicates when download fails""" + __description__ = """Restart skipped duplicates when download fails""" __license__ = "GPLv3" __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - #@TODO: Remove in 0.4.10 - def initPeriodical(self): - pass + interval = 0 #@TODO: Remove in 0.4.10 + + + def setup(self): + self.info = {} #@TODO: Remove in 0.4.10 def downloadFailed(self, pyfile): @@ -30,9 +32,9 @@ class UnSkipOnFail(Hook): msg = _("Looking for skipped duplicates of: %s (pid:%s)") self.logInfo(msg % (pyfile.name, pyfile.package().id)) - dup = self.findDuplicate(pyfile) - if dup: - self.logInfo(_("Queue found duplicate: %s (pid:%s)") % (dup.name, dup.packageID)) + link = self.findDuplicate(pyfile) + if link: + self.logInfo(_("Queue found duplicate: %s (pid:%s)") % (link.name, link.packageID)) #: Change status of "link" to "new_status". # "link" has to be a valid FileData object, @@ -41,9 +43,9 @@ class UnSkipOnFail(Hook): # It creates a temporary PyFile object using # "link" data, changes its status, and tells # the core.files-manager to save its data. - pylink = _pyfile(link) + pylink = self._pyfile(link) - pylink.setCustomStatus("UnSkipOnFail", "queued") + pylink.setCustomStatus(_("unskipped"), "queued") self.core.files.save() pylink.release() diff --git a/module/plugins/hooks/UnrestrictLi.py b/module/plugins/hooks/UnrestrictLi.py deleted file mode 100644 index cb5abb26e..000000000 --- a/module/plugins/hooks/UnrestrictLi.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- - -from module.common.json_layer import json_loads -from module.plugins.internal.MultiHook import MultiHook - - -class UnrestrictLi(MultiHook): - __name__ = "UnrestrictLi" - __type__ = "hook" - __version__ = "0.05" - - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), - ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 ), - ("history" , "bool" , "Delete History" , False)] - - __description__ = """Unrestrict.li hook plugin""" - __license__ = "GPLv3" - __authors__ = [("stickell", "l.stickell@yahoo.it")] - - - def getHosters(self): - json_data = self.getURL("http://unrestrict.li/api/jdownloader/hosts.php", get={'format': "json"}) - json_data = json_loads(json_data) - - return [element['host'] for element in json_data['result']] diff --git a/module/plugins/hooks/UpdateManager.py b/module/plugins/hooks/UpdateManager.py index c72699228..98d602226 100644 --- a/module/plugins/hooks/UpdateManager.py +++ b/module/plugins/hooks/UpdateManager.py @@ -2,81 +2,98 @@ from __future__ import with_statement +import os import re import sys +import time from operator import itemgetter -from os import path, remove, stat from module.network.RequestFactory import getURL from module.plugins.Hook import Expose, Hook, threaded from module.utils import save_join +# Case-sensitive os.path.exists +def exists(path): + if os.path.exists(path): + if os.name == 'nt': + dir, name = os.path.split(path) + return name in os.listdir(dir) + else: + return True + else: + return False + + class UpdateManager(Hook): __name__ = "UpdateManager" __type__ = "hook" - __version__ = "0.42" + __version__ = "0.52" - __config__ = [("activated" , "bool" , "Activated" , True ), - ("mode" , "pyLoad + plugins;plugins only", "Check updates for" , "pyLoad + plugins"), - ("interval" , "int" , "Check interval in hours" , 8 ), - ("autorestart" , "bool" , "Automatically restart pyLoad when required" , True ), - ("reloadplugins", "bool" , "Monitor plugins for code changes in debug mode", True ), - ("nodebugupdate", "bool" , "Don't check for updates in debug mode" , True )] + __config__ = [("activated" , "bool", "Activated" , True ), + ("checkinterval", "int" , "Check interval in hours" , 8 ), + ("autorestart" , "bool", "Auto-restart pyLoad when required" , True ), + ("checkonstart" , "bool", "Check for updates on startup" , True ), + ("checkperiod" , "bool", "Check for updates periodically" , True ), + ("reloadplugins", "bool", "Monitor plugin code changes in debug mode", True ), + ("nodebugupdate", "bool", "Don't update plugins in debug mode" , False)] __description__ = """ Check for updates """ __license__ = "GPLv3" __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - # event_list = ["pluginConfigChanged"] + interval = 0 - SERVER_URL = "http://updatemanager.pyload.org" - VERSION = re.compile(r'__version__.*=.*("|\')([\d.]+)') - MIN_INTERVAL = 3 * 60 * 60 #: 3h minimum check interval (value is in seconds) + SERVER_URL = "http://updatemanager.pyload.org" + MIN_CHECK_INTERVAL = 3 * 60 * 60 #: 3 hours - def pluginConfigChanged(self, plugin, name, value): - if name == "interval": - interval = value * 60 * 60 - if self.MIN_INTERVAL <= interval != self.interval: - self.core.scheduler.removeJob(self.cb) - self.interval = interval - self.initPeriodical() - else: - self.logDebug("Invalid interval value, kept current") + def coreReady(self): + if self.checkonstart: + self.core.api.pauseServer() + self.update() + if self.do_restart is False: + self.core.api.unpauseServer() - elif name == "reloadplugins": - if self.cb2: - self.core.scheduler.removeJob(self.cb2) - if value is True and self.core.debug: - self.periodical2() + self.initPeriodical() - def coreReady(self): - self.pluginConfigChanged(self.__name__, "interval", self.getConfig("interval")) - x = lambda: self.pluginConfigChanged(self.__name__, "reloadplugins", self.getConfig("reloadplugins")) - self.core.scheduler.addJob(10, x, threaded=False) + def setup(self): + self.info = {'pyload': False, 'version': None, 'plugins': False, 'last_check': time.time()} + self.mtimes = {} #: store modification time for each plugin + self.event_list = ["allDownloadsProcessed"] - def unload(self): - self.pluginConfigChanged(self.__name__, "reloadplugins", False) + self.interval = 10 + if self.getConfig('checkonstart'): + self.core.api.pauseServer() + self.checkonstart = True + else: + self.checkonstart = False - def setup(self): - self.cb2 = None - self.interval = self.MIN_INTERVAL - self.updating = False - self.info = {'pyload': False, 'version': None, 'plugins': False} - self.mtimes = {} #: store modification time for each plugin + self.do_restart = False - def periodical2(self): - if not self.updating: - self.autoreloadPlugins() + def allDownloadsProcessed(self): + if self.do_restart is True: + self.logWarning(_("Downloads are done, restarting pyLoad to reload the updated plugins")) + self.core.api.restart() + + + def periodical(self): + if self.core.debug: + if self.getConfig('reloadplugins'): + self.autoreloadPlugins() + + if self.getConfig('nodebugupdate'): + return - self.cb2 = self.core.scheduler.addJob(4, self.periodical2, threaded=False) + if self.getConfig('checkperiod') \ + and time.time() - max(self.MIN_CHECK_INTERVAL, self.getConfig('checkinterval') * 60 * 60) > self.info['last_check']: + self.update() @Expose @@ -95,10 +112,10 @@ class UpdateManager(Hook): id = (type, name) if type in self.core.pluginManager.plugins: f = m.__file__.replace(".pyc", ".py") - if not path.isfile(f): + if not os.path.isfile(f): continue - mtime = stat(f).st_mtime + mtime = os.stat(f).st_mtime if id not in self.mtimes: self.mtimes[id] = mtime @@ -109,105 +126,101 @@ class UpdateManager(Hook): return True if self.core.pluginManager.reloadPlugins(reloads) else False - def periodical(self): - if not self.info['pyload'] and not (self.getConfig("nodebugupdate") and self.core.debug): - self.updateThread() - - - def server_request(self): + def server_response(self): try: return getURL(self.SERVER_URL, get={'v': self.core.api.getServerVersion()}).splitlines() - except: - self.logWarning(_("Unable to contact server to get updates")) + except Exception: + self.logWarning(_("Unable to retrieve server to get updates")) - @threaded - def updateThread(self): - self.updating = True - status = self.update(onlyplugin=self.getConfig("mode") == "plugins only") - - if status is 2 and self.getConfig("autorestart"): - self.core.api.restart() - else: - self.updating = False + @Expose + @threaded + def update(self): + """ check for updates """ + if self._update() is 2 and self.getConfig('autorestart'): + if not self.core.api.statusDownloads(): + self.core.api.restart() + else: + self.do_restart = True + self.logWarning(_("Downloads are active, will restart once the download is done")) + self.core.api.pauseServer() - @Expose - def updatePlugins(self): - """ simple wrapper for calling plugin update quickly """ - return self.update(onlyplugin=True) + def _update(self): + data = self.server_response() - @Expose - def update(self, onlyplugin=False): - """ check for updates """ - data = self.server_request() + self.info['last_check'] = time.time() if not data: exitcode = 0 elif data[0] == "None": self.logInfo(_("No new pyLoad version available")) - updates = data[1:] - exitcode = self._updatePlugins(updates) + exitcode = self._updatePlugins(data[1:]) elif onlyplugin: exitcode = 0 else: - newversion = data[0] - self.logInfo(_("*** New pyLoad Version %s available ***") % newversion) + self.logInfo(_("*** New pyLoad Version %s available ***") % data[0]) self.logInfo(_("*** Get it here: https://github.com/pyload/pyload/releases ***")) + self.info['pyload'] = True + self.info['version'] = data[0] exitcode = 3 - self.info['pyload'] = True - self.info['version'] = newversion - return exitcode #: 0 = No plugins updated; 1 = Plugins updated; 2 = Plugins updated, but restart required; 3 = No plugins updated, new pyLoad version available + # Exit codes: + # -1 = No plugin updated, new pyLoad version available + # 0 = No plugin updated + # 1 = Plugins updated + # 2 = Plugins updated, but restart required + return exitcode - def _updatePlugins(self, updates): + def _updatePlugins(self, data): """ check for plugin updates """ - if self.info['plugins']: - return False #: plugins were already updated - exitcode = 0 updated = [] - url = updates[0] - schema = updates[1].split('|') + url = data[0] + schema = data[1].split('|') - if "BLACKLIST" in updates: - blacklist = updates[updates.index('BLACKLIST') + 1:] - updates = updates[2:updates.index('BLACKLIST')] + VERSION = re.compile(r'__version__.*=.*("|\')([\d.]+)') + + if "BLACKLIST" in data: + blacklist = data[data.index('BLACKLIST') + 1:] + updatelist = data[2:data.index('BLACKLIST')] else: - blacklist = None - updates = updates[2:] + blacklist = [] + updatelist = data[2:] - upgradable = [dict(zip(schema, x.split('|'))) for x in updates] - blacklisted = [(x.split('|')[0], x.split('|')[1].rsplit('.', 1)[0]) for x in blacklist] if blacklist else [] + updatelist = [dict(zip(schema, x.split('|'))) for x in updatelist] + blacklist = [dict(zip(schema, x.split('|'))) for x in blacklist] if blacklist: + type_plugins = [(plugin['type'], plugin['name'].rsplit('.', 1)[0]) for plugin in blacklist] + # Protect UpdateManager from self-removing try: - blacklisted.remove(("hook", "UpdateManager")) - except: + type_plugins.remove(("hook", "UpdateManager")) + except ValueError: pass - for t, n in blacklisted: - for idx, plugin in enumerate(upgradable): + for t, n in type_plugins: + for idx, plugin in enumerate(updatelist): if n == plugin['name'] and t == plugin['type']: - upgradable.pop(idx) + updatelist.pop(idx) break - for t, n in self.removePlugins(sorted(blacklisted)): - self.logInfo(_("Removed blacklisted plugin [%(type)s] %(name)s") % { + for t, n in self.removePlugins(sorted(type_plugins)): + self.logInfo(_("Removed blacklisted plugin: [%(type)s] %(name)s") % { 'type': t, 'name': n, }) - for plugin in sorted(upgradable, key=itemgetter("type", "name")): + for plugin in sorted(updatelist, key=itemgetter("type", "name")): filename = plugin['name'] prefix = plugin['type'] version = plugin['version'] @@ -217,7 +230,7 @@ class UpdateManager(Hook): else: name = filename.replace(".py", "") - #@TODO: obsolete after 0.4.10 + #@TODO: Remove in 0.4.10 if prefix.endswith("s"): type = prefix[:-1] else: @@ -241,7 +254,7 @@ class UpdateManager(Hook): 'newver': newver}) try: content = getURL(url % plugin) - m = self.VERSION.search(content) + m = VERSION.search(content) if m and m.group(2) == version: with open(save_join("userplugins", prefix, filename), "wb") as f: @@ -252,21 +265,27 @@ class UpdateManager(Hook): raise Exception, _("Version mismatch") except Exception, e: - self.logError(_("Error updating plugin: %s") % filename, str(e)) + self.logError(_("Error updating plugin: %s") % filename, e) if updated: - reloaded = self.core.pluginManager.reloadPlugins(updated) - if reloaded: - self.logInfo(_("Plugins updated and reloaded")) + self.logInfo(_("*** Plugins updated ***")) + + if self.core.pluginManager.reloadPlugins(updated): exitcode = 1 else: - self.logInfo(_("*** Plugins have been updated, but need a pyLoad restart to be reloaded ***")) + self.logWarning(_("pyLoad restart required to reload the updated plugins")) self.info['plugins'] = True exitcode = 2 + + self.manager.dispatchEvent("plugin_updated", updated) else: self.logInfo(_("No plugin updates available")) - return exitcode #: 0 = No plugins updated; 1 = Plugins updated; 2 = Plugins updated, but restart required + # Exit codes: + # 0 = No plugin updated + # 1 = Plugins updated + # 2 = Plugins updated, but restart required + return exitcode @Expose @@ -276,35 +295,36 @@ class UpdateManager(Hook): if not type_plugins: return - self.logDebug("Requested deletion of plugins: %s" % type_plugins) + removed = set() - removed = [] + self.logDebug("Requested deletion of plugins: %s" % type_plugins) for type, name in type_plugins: - err = False - file = name + ".py" - - for root in ("userplugins", path.join(pypath, "module", "plugins")): + rootplugins = os.path.join(pypath, "module", "plugins") - filename = save_join(root, type, file) - try: - remove(filename) - except Exception, e: - self.logDebug("Error removing: %s" % path.basename(filename), str(e)) - err = True + for dir in ("userplugins", rootplugins): + py_filename = save_join(dir, type, name + ".py") + pyc_filename = py_filename + "c" - filename += "c" - if path.isfile(filename): + if type == "hook": try: - if type == "hook": - self.manager.deactivateHook(name) - remove(filename) + self.manager.deactivateHook(name) + except Exception, e: - self.logDebug("Error removing: %s" % path.basename(filename), str(e)) - err = True + self.logDebug(e) + + for filename in (py_filename, pyc_filename): + if not exists(filename): + continue + + try: + os.remove(filename) + + except OSError, e: + self.logError(_("Error removing: %s") % filename, e) - if not err: - id = (type, name) - removed.append(id) + else: + id = (type, name) + removed.add(id) - return removed #: return a list of the plugins successfully removed + return list(removed) #: return a list of the plugins successfully removed diff --git a/module/plugins/hooks/UserAgentSwitcher.py b/module/plugins/hooks/UserAgentSwitcher.py new file mode 100644 index 000000000..74c43f7c4 --- /dev/null +++ b/module/plugins/hooks/UserAgentSwitcher.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- + +import pycurl + +from module.plugins.Hook import Hook + + +class UserAgentSwitcher(Hook): + __name__ = "UserAgentSwitcher" + __type__ = "hook" + __version__ = "0.08" + + __config__ = [("activated" , "bool", "Activated" , True ), + ("connecttimeout", "int" , "Connection timeout in seconds" , 60 ), + ("maxredirs" , "int" , "Maximum number of redirects to follow" , 10 ), + ("useragent" , "str" , "Custom user-agent string" , "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0")] + + __description__ = """Custom user-agent""" + __license__ = "GPLv3" + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] + + + interval = 0 #@TODO: Remove in 0.4.10 + + + def setup(self): + self.info = {} #@TODO: Remove in 0.4.10 + + + def downloadPreparing(self, pyfile): + connecttimeout = self.getConfig('connecttimeout') + maxredirs = self.getConfig('maxredirs') + useragent = self.getConfig('useragent').encode("utf8", "replace") #@TODO: Remove `encode` in 0.4.10 + + if connecttimeout: + pyfile.plugin.req.http.c.setopt(pycurl.CONNECTTIMEOUT, connecttimeout) + + if maxredirs: + pyfile.plugin.req.http.c.setopt(pycurl.MAXREDIRS, maxredirs) + + if useragent: + self.logDebug("Use custom user-agent string: " + useragent) + pyfile.plugin.req.http.c.setopt(pycurl.USERAGENT, useragent) diff --git a/module/plugins/hooks/WindowsPhoneNotify.py b/module/plugins/hooks/WindowsPhoneNotify.py new file mode 100644 index 000000000..8f66761f6 --- /dev/null +++ b/module/plugins/hooks/WindowsPhoneNotify.py @@ -0,0 +1,132 @@ +# -*- coding: utf-8 -*- + +import httplib +import time + +from module.plugins.Hook import Hook, Expose + + +class WindowsPhoneNotify(Hook): + __name__ = "WindowsPhoneNotify" + __type__ = "hook" + __version__ = "0.10" + + __config__ = [("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)] + + __description__ = """Send push notifications to Windows Phone""" + __license__ = "GPLv3" + __authors__ = [("Andy Voigt" , "phone-support@hotmail.de"), + ("Walter Purcaro", "vuolter@gmail.com" )] + + + interval = 0 #@TODO: Remove in 0.4.10 + + + def setup(self): + self.info = {} #@TODO: Remove in 0.4.10 + + self.event_list = ["allDownloadsProcessed", "plugin_updated"] + + self.last_notify = 0 + self.notifications = 0 + + + def plugin_updated(self, type_plugins): + if not self.getConfig('notifyupdate'): + return + + self.notify(_("Plugins updated"), str(type_plugins)) + + + def coreReady(self): + self.key = (self.getConfig('push-id'), self.getConfig('push-url')) + + + def coreExiting(self): + if not self.getConfig('notifyexit'): + return + + if self.core.do_restart: + self.notify(_("Restarting pyLoad")) + else: + self.notify(_("Exiting pyLoad")) + + + def newCaptchaTask(self, task): + if not self.getConfig('notifycaptcha'): + return + + self.notify(_("Captcha"), _("New request waiting user input")) + + + def packageFinished(self, pypack): + if self.getConfig('notifypackage'): + self.notify(_("Package finished"), pypack.name) + + + def allDownloadsProcessed(self): + if not self.getConfig('notifyprocessed'): + return + + if any(True for pdata in self.core.api.getQueue() if pdata.linksdone < pdata.linkstotal): + self.notify(_("Package failed"), _("One or more packages was not completed successfully")) + else: + self.notify(_("All packages finished")) + + + def getXmlData(self, msg): + return ("<?xml version='1.0' encoding='utf-8'?> <wp:Notification xmlns:wp='WPNotification'> " + "<wp:Toast> <wp:Text1>pyLoad</wp:Text1> <wp:Text2>%s</wp:Text2> " + "</wp:Toast> </wp:Notification>" % msg) + + + @Expose + def notify(self, + event, + msg="", + key=(None, None)): + + id, url = key or self.key + if not id or not url: + return + + if self.core.isClientConnected() and not self.getConfig('ignoreclient'): + return + + elapsed_time = time.time() - self.last_notify + + if elapsed_time < self.getConf("sendtimewait"): + return + + if elapsed_time > 60: + self.notifications = 0 + + elif self.notifications >= self.getConf("sendpermin"): + return + + request = self.getXmlData("%s: %s" % (event, msg) if msg else event) + webservice = httplib.HTTP(url) + + webservice.putrequest("POST", id) + webservice.putheader("Host", url) + webservice.putheader("Content-type", "text/xml") + webservice.putheader("X-NotificationClass", "2") + webservice.putheader("X-WindowsPhone-Target", "toast") + webservice.putheader("Content-length", "%d" % len(request)) + webservice.endheaders() + webservice.send(request) + webservice.close() + + self.last_notify = time.time() + self.notifications += 1 + + return True diff --git a/module/plugins/hooks/WindowsPhoneToastNotify.py b/module/plugins/hooks/WindowsPhoneToastNotify.py deleted file mode 100644 index 886d4ca6a..000000000 --- a/module/plugins/hooks/WindowsPhoneToastNotify.py +++ /dev/null @@ -1,95 +0,0 @@ -# -*- coding: utf-8 -*- - -import httplib - -from time import time - -from module.plugins.Hook import Hook - - -class WindowsPhoneToastNotify(Hook): - __name__ = "WindowsPhoneToastNotify" - __type__ = "hook" - __version__ = "0.04" - - __config__ = [("id" , "str" , "Push ID" , "" ), - ("url" , "str" , "Push url" , "" ), - ("notifycaptcha" , "bool", "Notify captcha request" , True ), - ("notifypackage" , "bool", "Notify package finished" , True ), - ("notifyprocessed", "bool", "Notify processed packages status" , True ), - ("timeout" , "int" , "Timeout between captchas in seconds" , 5 ), - ("force" , "bool", "Send notifications if client is connected", False)] - - __description__ = """Send push notifications to Windows Phone""" - __license__ = "GPLv3" - __authors__ = [("Andy Voigt", "phone-support@hotmail.de"), - ("Walter Purcaro", "vuolter@gmail.com")] - - - event_list = ["allDownloadsProcessed"] - - - #@TODO: Remove in 0.4.10 - def initPeriodical(self): - pass - - - def setup(self): - self.info = {} #@TODO: Remove in 0.4.10 - - - def newCaptchaTask(self, task): - if not self.getConfig("notifycaptcha"): - return False - - if time() - float(self.getStorage("WindowsPhoneToastNotify", 0)) < self.getConf("timeout"): - return False - - self.notify(_("Captcha"), _("New request waiting user input")) - - - def packageFinished(self, pypack): - if self.getConfig("notifypackage"): - self.notify(_("Package finished"), pypack.name) - - - def allDownloadsProcessed(self, thread): - if not self.getConfig("notifyprocessed"): - return False - - if any(True for pdata in self.core.api.getQueue() if pdata.linksdone < pdata.linkstotal): - self.notify(_("Package failed"), _("One or more packages was not completed successfully")) - else: - self.notify(_("All packages finished")) - - - def getXmlData(self, msg): - return ("<?xml version='1.0' encoding='utf-8'?> <wp:Notification xmlns:wp='WPNotification'> " - "<wp:Toast> <wp:Text1>pyLoad</wp:Text1> <wp:Text2>%s</wp:Text2> " - "</wp:Toast> </wp:Notification>" % msg) - - - def notify(self, event, msg=""): - id = self.getConfig("id") - url = self.getConfig("url") - - if not id or not url: - return False - - if self.core.isClientConnected() and not self.getConfig("force"): - return False - - request = self.getXmlData("%s: %s" % (event, msg) if msg else event) - webservice = httplib.HTTP(url) - - webservice.putrequest("POST", id) - webservice.putheader("Host", url) - webservice.putheader("Content-type", "text/xml") - webservice.putheader("X-NotificationClass", "2") - webservice.putheader("X-WindowsPhone-Target", "toast") - webservice.putheader("Content-length", "%d" % len(request)) - webservice.endheaders() - webservice.send(request) - webservice.close() - - self.setStorage("WindowsPhoneToastNotify", time()) diff --git a/module/plugins/hooks/XFileSharingPro.py b/module/plugins/hooks/XFileSharingPro.py index 0745a6c7e..62872992c 100644 --- a/module/plugins/hooks/XFileSharingPro.py +++ b/module/plugins/hooks/XFileSharingPro.py @@ -8,7 +8,7 @@ from module.plugins.Hook import Hook class XFileSharingPro(Hook): __name__ = "XFileSharingPro" __type__ = "hook" - __version__ = "0.30" + __version__ = "0.38" __config__ = [("activated" , "bool", "Activated" , True ), ("use_hoster_list" , "bool", "Load listed hosters only" , False), @@ -17,37 +17,37 @@ class XFileSharingPro(Hook): ("hoster_list" , "str" , "Hoster list (comma separated)" , "" ), ("crypter_list" , "str" , "Crypter list (comma separated)", "" )] - __description__ = """Load XFileSharingPro based hosters and crypter which don't need a own plugin to run""" + __description__ = """Load XFileSharingPro based hosters and crypters which don't need a own plugin to run""" __license__ = "GPLv3" __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - # event_list = ["pluginConfigChanged"] - regexp = {'hoster' : (r'https?://(?:www\.)?(?P<DOMAIN>[\w.^_]+(?:\.[a-zA-Z]{2,})(?:\:\d+)?)/(?:embed-)?\w{12}(?:\W|$)', - r'https?://(?:[^/]+\.)?(?P<DOMAIN>%s)/(?:embed-)?\w+'), - 'crypter': (r'https?://(?:www\.)?(?P<DOMAIN>[\w.^_]+(?:\.[a-zA-Z]{2,})(?:\:\d+)?)/(?:user|folder)s?/\w+', - r'https?://(?:[^/]+\.)?(?P<DOMAIN>%s)/(?:user|folder)s?/\w+')} + interval = 0 #@TODO: Remove in 0.4.10 + regexp = {'hoster' : (r'https?://(?:www\.)?(?:\w+\.)*?(?P<DOMAIN>(?:[\d.]+|[\w\-^_]{3,}(?:\.[a-zA-Z]{2,}){1,2})(?:\:\d+)?)/(?:embed-)?\w{12}(?:\W|$)', + r'https?://(?:[^/]+\.)?(?P<DOMAIN>%s)/(?:embed-)?\w+'), + 'crypter': (r'https?://(?:www\.)?(?:\w+\.)*?(?P<DOMAIN>(?:[\d.]+|[\w\-^_]{3,}(?:\.[a-zA-Z]{2,}){1,2})(?:\:\d+)?)/(?:user|folder)s?/\w+', + r'https?://(?:[^/]+\.)?(?P<DOMAIN>%s)/(?:user|folder)s?/\w+')} HOSTER_BUILTIN = [#WORKING HOSTERS: - "180upload.com", "backin.net", "eyesfile.ca", "file4safe.com", "fileband.com", "filedwon.com", - "fileparadox.in", "filevice.com", "hostingbulk.com", "linestorage.com", "ravishare.com", "ryushare.com", - "salefiles.com", "sendmyway.com", "sharesix.com", "thefile.me", "verzend.be", "xvidstage.com", + "backin.net", "eyesfile.ca", "file4safe.com", "fileband.com", "filedwon.com", "fileparadox.in", + "filevice.com", "hostingbulk.com", "junkyvideo.com", "linestorage.com", "ravishare.com", "ryushare.com", + "salefiles.com", "sendmyway.com", "sharesix.com", "thefile.me", "verzend.be", "worldbytez.com", "xvidstage.com", #NOT TESTED: "101shared.com", "4upfiles.com", "filemaze.ws", "filenuke.com", "linkzhost.com", "mightyupload.com", "rockdizfile.com", "sharebeast.com", "sharerepo.com", "shareswift.com", "uploadbaz.com", "uploadc.com", "vidbull.com", "zalaa.com", "zomgupload.com", #NOT WORKING: "amonshare.com", "banicrazy.info", "boosterking.com", "host4desi.com", "laoupload.com", "rd-fs.com"] - CRYPTER_BUILTIN = [] + CRYPTER_BUILTIN = ["junocloud.me", "rapidfileshare.net"] - # def pluginConfigChanged(self.__name__, plugin, name, value): + # def pluginConfigChanged(self, plugin, name, value): # self.loadPattern() - #@TODO: Remove in 0.4.10 - def initPeriodical(self): - pass + def setup(self): + self.info = {} #@TODO: Remove in 0.4.10 + # self.event_list = ["pluginConfigChanged"] def coreReady(self): @@ -65,22 +65,22 @@ class XFileSharingPro(Hook): self.logInfo(_("Handling any %s I can!") % type) pattern = self.regexp[type][0] else: - s = self.getConfig('%s_list' % type).replace('\\', '').replace('|', ',').replace(';', ',').lower() - plugin_list = set([x.strip() for x in s.split(',')]) + plugins = self.getConfig('%s_list' % type) + plugin_set = set(plugins.replace(' ', '').replace('\\', '').replace('|', ',').replace(';', ',').lower().split(',')) if use_builtin_list: - plugin_list |= set([x.lower() for x in getattr(self, "%s_BUILTIN" % type.upper())]) + plugin_set |= set(x.lower() for x in getattr(self, "%s_BUILTIN" % type.upper())) - plugin_list -= set(('', u'')) + plugin_set -= set(('', u'')) - if not plugin_list: + if not plugin_set: self.logInfo(_("No %s to handle") % type) self._unload(type, plugin) return - match_list = '|'.join(sorted(plugin_list)) + match_list = '|'.join(sorted(plugin_set)) - len_match_list = len(plugin_list) + len_match_list = len(plugin_set) self.logInfo(_("Handling %d %s%s: %s") % (len_match_list, type, "" if len_match_list == 1 else "s", @@ -112,11 +112,11 @@ class XFileSharingPro(Hook): hdict = self.core.pluginManager.hosterPlugins[hoster] if "new_name" in hdict and hdict['new_name'] == "XFileSharingPro": if "module" in hdict: - del hdict['module'] + hdict.pop('module', None) if "new_module" in hdict: - del hdict['new_module'] - del hdict['new_name'] + hdict.pop('new_module', None) + hdict.pop('new_name', None) return True else: @@ -126,7 +126,7 @@ class XFileSharingPro(Hook): # def downloadFailed(self, pyfile): # if pyfile.pluginname == "BasePlugin" \ # and pyfile.hasStatus("failed") \ - # and not self.getConfig("use_hoster_list") \ + # and not self.getConfig('use_hoster_list') \ # and self.unloadHoster("BasePlugin"): # self.logDebug("Unloaded XFileSharingPro from BasePlugin") # pyfile.setStatus("queued") diff --git a/module/plugins/hooks/XMPPInterface.py b/module/plugins/hooks/XMPPInterface.py index bbeab4341..b61428392 100644 --- a/module/plugins/hooks/XMPPInterface.py +++ b/module/plugins/hooks/XMPPInterface.py @@ -33,14 +33,14 @@ class XMPPInterface(IRCInterface, JabberClient): def __init__(self, core, manager): IRCInterface.__init__(self, core, manager) - self.jid = JID(self.getConfig("jid")) - password = self.getConfig("pw") + self.jid = JID(self.getConfig('jid')) + password = self.getConfig('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") - if self.getConfig("tls"): + if self.getConfig('tls'): tls_settings = streamtls.TLSSettings(require=True, verify_peer=False) auth = ("sasl:PLAIN", "sasl:DIGEST-MD5") else: @@ -67,18 +67,18 @@ class XMPPInterface(IRCInterface, JabberClient): def packageFinished(self, pypack): try: - if self.getConfig("info_pack"): + if self.getConfig('info_pack'): self.announce(_("Package finished: %s") % pypack.name) - except: + except Exception: pass def downloadFinished(self, pyfile): try: - if self.getConfig("info_file"): + if self.getConfig('info_file'): self.announce( _("Download finished: %(name)s @ %(plugin)s") % {"name": pyfile.name, "plugin": pyfile.pluginname}) - except: + except Exception: pass @@ -139,7 +139,7 @@ class XMPPInterface(IRCInterface, JabberClient): to_name = to_jid.as_utf8() from_name = from_jid.as_utf8() - names = self.getConfig("owners").split(";") + names = self.getConfig('owners').split(";") if to_name in names or to_jid.node + "@" + to_jid.domain in names: messages = [] @@ -152,7 +152,7 @@ class XMPPInterface(IRCInterface, JabberClient): trigger = temp[0] if len(temp) > 1: args = temp[1:] - except: + except Exception: pass handler = getattr(self, "event_%s" % trigger, self.event_pass) @@ -182,7 +182,7 @@ class XMPPInterface(IRCInterface, JabberClient): def announce(self, message): """ send message to all owners""" - for user in self.getConfig("owners").split(";"): + for user in self.getConfig('owners').split(";"): self.logDebug("Send message to", user) to_jid = JID(user) diff --git a/module/plugins/hooks/ZeveraCom.py b/module/plugins/hooks/ZeveraComHook.py index 215ec3673..21c1741d2 100644 --- a/module/plugins/hooks/ZeveraCom.py +++ b/module/plugins/hooks/ZeveraComHook.py @@ -3,23 +3,21 @@ from module.plugins.internal.MultiHook import MultiHook -class ZeveraCom(MultiHook): - __name__ = "ZeveraCom" +class ZeveraComHook(MultiHook): + __name__ = "ZeveraComHook" __type__ = "hook" __version__ = "0.05" __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), ("pluginlist" , "str" , "Plugin list (comma separated)" , "" ), ("revertfailed" , "bool" , "Revert to standard download if fails", True ), - ("retry" , "int" , "Number of retries before revert" , 10 ), - ("retryinterval" , "int" , "Retry interval in minutes" , 1 ), ("reload" , "bool" , "Reload plugin list" , True ), ("reloadinterval", "int" , "Reload interval in hours" , 12 )] __description__ = """Zevera.com hook plugin""" __license__ = "GPLv3" - __authors__ = [("zoidberg", "zoidberg@mujmail.cz"), - ("Walter Purcaro", "vuolter@gmail.com")] + __authors__ = [("zoidberg" , "zoidberg@mujmail.cz"), + ("Walter Purcaro", "vuolter@gmail.com" )] def getHosters(self): |