summaryrefslogtreecommitdiffstats
path: root/module/plugins/hooks
diff options
context:
space:
mode:
authorGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2010-08-25 18:22:27 +0200
committerGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2010-08-25 18:22:27 +0200
commit29f9dc8fb3396b03d732ebcbeb1cc8f00fe13897 (patch)
treef2a910cbea747a7b0c0a50d6c66691e54f5ef47f /module/plugins/hooks
parentmerged gui (diff)
downloadpyload-29f9dc8fb3396b03d732ebcbeb1cc8f00fe13897.tar.xz
new dirs
Diffstat (limited to 'module/plugins/hooks')
-rw-r--r--module/plugins/hooks/ClickAndLoad.py79
-rw-r--r--module/plugins/hooks/ExternalScripts.py108
-rw-r--r--module/plugins/hooks/HotFolder.py81
-rw-r--r--module/plugins/hooks/IRCInterface.py364
-rw-r--r--module/plugins/hooks/MultiHome.py82
-rw-r--r--module/plugins/hooks/UnRar.py137
-rw-r--r--module/plugins/hooks/UpdateManager.py59
-rw-r--r--module/plugins/hooks/XMPPInterface.py229
-rw-r--r--module/plugins/hooks/__init__.py0
9 files changed, 1139 insertions, 0 deletions
diff --git a/module/plugins/hooks/ClickAndLoad.py b/module/plugins/hooks/ClickAndLoad.py
new file mode 100644
index 000000000..b9824b863
--- /dev/null
+++ b/module/plugins/hooks/ClickAndLoad.py
@@ -0,0 +1,79 @@
+# -*- coding: utf-8 -*-
+
+"""
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+ @author: RaNaN
+ @interface-version: 0.2
+"""
+
+import socket
+import thread
+
+from module.plugins.Hook import Hook
+
+class ClickAndLoad(Hook):
+ __name__ = "ClickAndLoad"
+ __version__ = "0.2"
+ __description__ = """Gives abillity to use jd's click and load. depends on webinterface"""
+ __config__ = [ ("activated", "bool", "Activated" , "True"),
+ ("extern", "bool", "Allow external link adding", "False") ]
+ __author_name__ = ("RaNaN", "mkaay")
+ __author_mail__ = ("RaNaN@pyload.de", "mkaay@mkaay.de")
+
+ def coreReady(self):
+ self.port = int(self.core.config['webinterface']['port'])
+ if self.core.config['webinterface']['activated']:
+ try:
+ if self.getConfig("extern"):
+ ip = "0.0.0.0"
+ else:
+ ip = "127.0.0.1"
+
+ thread.start_new_thread(proxy, (ip, self.port, 9666))
+ except:
+ self.logger.error("ClickAndLoad port already in use.")
+
+
+def proxy(*settings):
+ thread.start_new_thread(server, settings)
+ lock = thread.allocate_lock()
+ lock.acquire()
+ lock.acquire()
+
+def server(*settings):
+ try:
+ dock_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ dock_socket.bind((settings[0], settings[2]))
+ dock_socket.listen(5)
+ while True:
+ client_socket = dock_socket.accept()[0]
+ server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ server_socket.connect(("127.0.0.1", settings[1]))
+ thread.start_new_thread(forward, (client_socket, server_socket))
+ thread.start_new_thread(forward, (server_socket, client_socket))
+ except:
+ pass
+ finally:
+ thread.start_new_thread(server, settings)
+
+def forward(source, destination):
+ string = ' '
+ while string:
+ string = source.recv(1024)
+ if string:
+ destination.sendall(string)
+ else:
+ #source.shutdown(socket.SHUT_RD)
+ destination.shutdown(socket.SHUT_WR)
diff --git a/module/plugins/hooks/ExternalScripts.py b/module/plugins/hooks/ExternalScripts.py
new file mode 100644
index 000000000..a3ed2f168
--- /dev/null
+++ b/module/plugins/hooks/ExternalScripts.py
@@ -0,0 +1,108 @@
+# -*- coding: utf-8 -*-
+
+"""
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+ @author: mkaay
+ @interface-version: 0.1
+"""
+
+from module.plugins.Hook import Hook
+import subprocess
+from os import listdir, sep
+from os.path import join
+import sys
+
+class ExternalScripts(Hook):
+ __name__ = "ExternalScripts"
+ __version__ = "0.1"
+ __description__ = """run external scripts"""
+ __config__ = [ ("activated", "bool", "Activated" , "True") ]
+ __author_name__ = ("mkaay", "RaNaN", "spoob")
+ __author_mail__ = ("mkaay@mkaay.de", "ranan@pyload.org", "spoob@pyload.org")
+
+ def __init__(self, core):
+ Hook.__init__(self, core)
+ self.scripts = {}
+
+ script_folders = [join(pypath, 'scripts','download_preparing'),
+ join(pypath,'scripts','download_finished'),
+ join(pypath,'scripts','package_finished'),
+ join(pypath,'scripts','before_reconnect'),
+ join(pypath,'scripts','after_reconnect')]
+
+ folder = core.path("scripts")
+
+ self.core.check_file(folder, _("folders for scripts"), True)
+ self.core.check_file(script_folders, _("folders for scripts"), True)
+
+ f = lambda x: False if x.startswith("#") or x.endswith("~") else True
+ self.scripts = {}
+
+
+ self.scripts['download_preparing'] = filter(f, listdir(join(folder, 'download_preparing')))
+ self.scripts['download_finished'] = filter(f, listdir(join(folder, 'download_finished')))
+ self.scripts['package_finished'] = filter(f, listdir(join(folder, 'package_finished')))
+ self.scripts['before_reconnect'] = filter(f, listdir(join(folder, 'before_reconnect')))
+ self.scripts['after_reconnect'] = filter(f, listdir(join(folder, 'after_reconnect')))
+
+ for script_type, script_name in self.scripts.iteritems():
+ if script_name != []:
+ self.log.info("Installed %s Scripts: %s" % (script_type, ", ".join(script_name)))
+
+ #~ self.core.logger.info("Installed Scripts: %s" % str(self.scripts))
+
+ self.folder = folder
+
+ def downloadStarts(self, pyfile):
+ for script in self.scripts['download_preparing']:
+ try:
+ cmd = [join(self.folder, 'download_preparing', script), pyfile.pluginname, pyfile.url]
+ out = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+ out.wait()
+ except:
+ pass
+
+ def downloadFinished(self, pyfile):
+ for script in self.scripts['download_finished']:
+ try:
+ out = subprocess.Popen([join(self.folder, 'download_finished', script), pyfile.pluginname, pyfile.url, pyfile.name, join(self.core.config['general']['download_folder'], pyfile.package().folder, pyfile.name)], stdout=subprocess.PIPE)
+ except:
+ pass
+
+ def packageFinished(self, pypack):
+ for script in self.scripts['package_finished']:
+ folder = self.core.config['general']['download_folder']
+ if self.core.config.get("general", "folder_per_package"):
+ folder = join(folder.decode(sys.getfilesystemencoding()), pypack.folder.decode(sys.getfilesystemencoding()))
+
+ try:
+ out = subprocess.Popen([join(self.folder, 'package_finished', script), pypack.name, folder], stdout=subprocess.PIPE)
+ except:
+ pass
+
+ def beforeReconnecting(self, ip):
+ for script in self.scripts['before_reconnect']:
+ try:
+ out = subprocess.Popen([join(self.folder, 'before_reconnect', script), ip], stdout=subprocess.PIPE)
+ out.wait()
+ except:
+ pass
+
+ def afterReconnecting(self, ip):
+ for script in self.scripts['after_reconnect']:
+ try:
+ out = subprocess.Popen([join(self.folder, 'download_preparing', script), ip], stdout=subprocess.PIPE)
+ except:
+ pass
diff --git a/module/plugins/hooks/HotFolder.py b/module/plugins/hooks/HotFolder.py
new file mode 100644
index 000000000..6c6825954
--- /dev/null
+++ b/module/plugins/hooks/HotFolder.py
@@ -0,0 +1,81 @@
+# -*- coding: utf-8 -*-
+
+"""
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+ @author: RaNaN
+ @interface-version: 0.2
+"""
+
+from os import makedirs
+from os import listdir
+from os.path import exists
+from os.path import join
+from os.path import isfile
+from shutil import move
+import time
+
+from module.plugins.Hook import Hook
+
+class HotFolder(Hook):
+ __name__ = "HotFolder"
+ __version__ = "0.1"
+ __description__ = """observe folder and file for changes and add container and links"""
+ __config__ = [ ("activated", "bool", "Activated" , "False"),
+ ("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")]
+ __threaded__ = []
+ __author_name__ = ("RaNaN")
+ __author_mail__ = ("RaNaN@pyload.de")
+
+ def setup(self):
+ self.interval = 10
+
+ def periodical(self):
+
+ if not exists(join(self.getConfig("folder"), "finished")):
+ makedirs(join(self.getConfig("folder"), "finished"))
+
+ if self.getConfig("watch_file"):
+
+ if not exists(self.getConfig("file")):
+ f = open(self.getConfig("file"), "wb")
+ f.close()
+
+
+ f = open(self.getConfig("file"), "rb")
+ urls = [x.strip() for x in f.readlines() if x.strip()]
+ f.close()
+ if urls:
+ name = "%s @ %s" % (self.getConfig("file"), time.strftime("%H:%M:%S %d%b%Y") )
+ f = open(self.getConfig("file"), "wb")
+ f.close()
+
+ self.core.server_methods.add_package(f.name, urls, 1)
+
+ for f in listdir(self.getConfig("folder")):
+ path = join(self.getConfig("folder"), f)
+
+ if not isfile(path) or f.endswith("~") or f.startswith("#"):
+ continue
+
+ newpath = join(self.getConfig("folder"), "finished", f if self.getConfig("keep") else "tmp_"+f)
+ move(path, newpath)
+
+ self.log.info(_("Added %s from HotFolder") % f)
+ self.core.server_methods.add_package(f, [newpath], 1)
+
+ \ No newline at end of file
diff --git a/module/plugins/hooks/IRCInterface.py b/module/plugins/hooks/IRCInterface.py
new file mode 100644
index 000000000..e7e1e6797
--- /dev/null
+++ b/module/plugins/hooks/IRCInterface.py
@@ -0,0 +1,364 @@
+# -*- coding: utf-8 -*-
+
+"""
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+ @author: RaNaN
+ @author: jeix
+ @interface-version: 0.2
+"""
+
+from select import select
+import socket
+import sys
+from threading import Thread
+import time
+from time import sleep
+from traceback import print_exc
+
+from module.plugins.Hook import Hook
+
+class IRCInterface(Thread, Hook):
+ __name__ = "IRCInterface"
+ __version__ = "0.1"
+ __description__ = """connect to irc and let owner perform different tasks"""
+ __config__ = [("activated", "bool", "Activated", "False"),
+ ("host", "str", "IRC-Server Address", "Enter your server here!"),
+ ("port", "int", "IRC-Server Port", "6667"),
+ ("ident", "str", "Clients ident", "pyload-irc"),
+ ("realname", "str", "Realname", "pyload-irc"),
+ ("nick", "str", "Nickname the Client will take", "pyLoad-IRC"),
+ ("owner", "str", "Nickname the Client will accept commands from", "Enter your nick here!"),
+ ("info_file", "bool", "Inform about every file finished", "False"),
+ ("info_pack", "bool", "Inform about every package finished", "True")]
+ __author_name__ = ("Jeix")
+ __author_mail__ = ("Jeix@hasnomail.com")
+
+ def __init__(self, core):
+ Thread.__init__(self)
+ Hook.__init__(self, core)
+ self.setDaemon(True)
+ self.sm = core.server_methods
+
+ def coreReady(self):
+ self.new_package = {}
+
+ self.abort = False
+
+ self.links_added = 0
+ self.more = []
+
+ self.start()
+
+
+ def packageFinished(self, pypack):
+ try:
+ if self.getConfig("info_pack"):
+ self.response(_("Package finished: %s") % pypack.name)
+ except:
+ pass
+
+ def downloadFinished(self, pyfile):
+ try:
+ if self.getConfig("info_file"):
+ self.response(_("Download finished: %s @ %s") % (pyfile.name, pyfile.pluginname) )
+ except:
+ pass
+
+ def run(self):
+ # connect to IRC etc.
+ self.sock = socket.socket()
+ host = self.getConfig("host")
+ self.sock.connect((host, self.getConfig("port")))
+ 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():
+ if t.strip().startswith("#"):
+ self.sock.send("JOIN %s\r\n" % t.strip())
+ self.log.info("pyLoad IRC: Connected to %s!" % host)
+ self.log.info("pyLoad IRC: Switching to listening mode!")
+ try:
+ self.main_loop()
+
+ except IRCError, ex:
+ self.sock.send("QUIT :byebye\r\n")
+ print_exc()
+ self.sock.close()
+
+
+ def main_loop(self):
+ readbuffer = ""
+ while True:
+ sleep(1)
+ fdset = select([self.sock], [], [], 0)
+ if self.sock not in fdset[0]:
+ continue
+
+ if self.abort:
+ raise IRCError("quit")
+
+ readbuffer += self.sock.recv(1024)
+ temp = readbuffer.split("\n")
+ readbuffer = temp.pop()
+
+ for line in temp:
+ line = line.rstrip()
+ first = line.split()
+
+ if(first[0] == "PING"):
+ self.sock.send("PING %s\r\n" % first[1])
+
+ if first[0] == "ERROR":
+ raise IRCError(line)
+
+ msg = line.split(None, 3)
+ if len(msg) < 4:
+ continue
+
+ msg = {
+ "origin":msg[0][1:],
+ "action":msg[1],
+ "target":msg[2],
+ "text":msg[3][1:]
+ }
+
+ self.handle_events(msg)
+
+
+ def handle_events(self, msg):
+ if not msg["origin"].split("!", 1)[0] in self.getConfig("owner").split():
+ return
+
+ if msg["target"].split("!", 1)[0] != self.getConfig("nick"):
+ return
+
+ if msg["action"] != "PRIVMSG":
+ return
+
+ # HANDLE CTCP ANTI FLOOD/BOT PROTECTION
+ if msg["text"] == "\x01VERSION\x01":
+ self.log.debug("Sending CTCP VERSION.")
+ self.sock.send("NOTICE %s :%s\r\n" % (msg['origin'], "pyLoad! IRC Interface"))
+ return
+ elif msg["text"] == "\x01TIME\x01":
+ self.log.debug("Sending CTCP TIME.")
+ self.sock.send("NOTICE %s :%d\r\n" % (msg['origin'], time.time()))
+ return
+ elif msg["text"] == "\x01LAG\x01":
+ self.log.debug("Received CTCP LAG.") # don't know how to answer
+ return
+
+ trigger = "pass"
+ args = None
+
+ temp = msg["text"].split()
+ trigger = temp[0]
+ if len(temp) > 1:
+ args = temp[1:]
+
+ handler = getattr(self, "event_%s" % trigger, self.event_pass)
+ try:
+ res = handler(args)
+ for line in res:
+ self.response(line, msg["origin"])
+ except Exception, e:
+ self.log.error("pyLoad IRC: "+ repr(e))
+
+
+ def response(self, msg, origin=""):
+ if origin == "":
+ 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))
+
+
+#### Events
+ def event_pass(self, args):
+ return []
+
+ def event_status(self, args):
+ downloads = self.sm.status_downloads()
+ if not downloads:
+ return ["INFO: There are no active downloads currently."]
+
+ lines = []
+ lines.append("ID - Name - Status - Speed - ETA - Progress")
+ for data in downloads:
+ lines.append("#%d - %s - %s - %s - %s - %s" %
+ (
+ data['id'],
+ data['name'],
+ data['statusmsg'],
+ "%.2f kb/s" % data['speed'],
+ "%s" % data['format_eta'],
+ "%d%% (%s)" % (data['percent'], data['format_size'])
+ )
+ )
+ return lines
+
+ def event_queue(self, args):
+ ps = self.sm.get_queue()
+
+ if not ps:
+ return ["INFO: There are no packages in queue."]
+
+ lines = []
+ for id, pack in ps.iteritems():
+ lines.append('PACKAGE #%s: "%s" with %d links.' % (id, pack['name'], len(pack['links']) ))
+
+ return lines
+
+ def event_collector(self, args):
+ ps = self.sm.get_collector()
+ if not ps:
+ return ["INFO: No packages in collector!"]
+
+ lines = []
+ for id, pack in ps.iteritems():
+ lines.append('PACKAGE #%s: "%s" with %d links.' % (id, pack['name'], len(pack['links']) ))
+
+ return lines
+
+ def event_info(self, args):
+ if not args:
+ return ['ERROR: Use info like this: info <id>']
+
+ info = self.sm.get_file_data(int(args[0]))
+
+ if not info:
+ return ["ERROR: Link doesn't exists."]
+
+ id = info.keys()[0]
+ data = info[id]
+
+ return ['LINK #%s: %s (%s) [%s][%s]' % (id, data['name'], data['format_size'], data['statusmsg'], data['plugin'])]
+
+ def event_packinfo(self, args):
+ if not args:
+ return ['ERROR: Use packinfo like this: packinfo <id>']
+
+ lines = []
+ pack = self.sm.get_package_data(int(args[0]))
+
+ if not pack:
+ return ["ERROR: Package doesn't exists."]
+
+ id = args[0]
+
+ self.more = []
+
+ lines.append('PACKAGE #%s: "%s" with %d links' % (id, pack['name'], len(pack["links"])) )
+ for id, pyfile in pack["links"].iteritems():
+ self.more.append('LINK #%s: %s (%s) [%s][%s]' % (id, pyfile["name"], pyfile["format_size"], pyfile["statusmsg"], pyfile["plugin"]))
+
+ if len(self.more) < 6:
+ lines.extend(self.more)
+ self.more = []
+ else:
+ lines.extend(self.more[:6])
+ self.more = self.more[6:]
+ lines.append("%d more links do display." % len(self.more))
+
+
+ return lines
+
+ def event_more(self, args):
+ if not self.more:
+ return ["No more information to display."]
+
+ lines = self.more[:6]
+ self.more = self.more[6:]
+ lines.append("%d more links do display." % len(self.more))
+
+ return lines
+
+ def event_start(self, args):
+
+ self.sm.unpause_server()
+ return ["INFO: Starting downloads."]
+
+ def event_stop(self, args):
+
+ self.sm.pause_server()
+ return ["INFO: No new downloads will be started."]
+
+
+ def event_add(self, args):
+ if len(args) < 2:
+ return ['ERROR: Add links like this: "add <packagename|id> links". '\
+ 'This will add the link <link> to to the package <package> / the package with id <id>!']
+
+
+
+ pack = args[0].strip()
+ links = [x.strip() for x in args[1:]]
+
+ count_added = 0
+ count_failed = 0
+ try:
+ id = int(pack)
+ pack = self.sm.get_package_data(id)
+ if not pack:
+ return ["ERROR: Package doesn't exists."]
+
+ #add links
+
+
+ return ["INFO: Added %d links to Package %s [#%d]" % (len(links), pack["name"], id)]
+
+ except:
+ # create new package
+ id = self.sm.add_package(pack, links, 1)
+ return ["INFO: Created new Package %s [#%d] with %d links." % (pack, id, len(links))]
+
+
+ def event_del(self, args):
+ if len(args) < 2:
+ return ["ERROR: Use del command like this: del -p|-l <id> [...] (-p indicates that the ids are from packages, -l indicates that the ids are from links)"]
+
+ if args[0] == "-p":
+ ret = self.sm.del_packages(map(int, args[1:]))
+ return ["INFO: Deleted %d packages!" % len(args[1:])]
+
+ elif args[0] == "-l":
+ ret = self.sm.del_links(map(int, args[1:]))
+ return ["INFO: Deleted %d links!" % len(args[1:])]
+
+ else:
+ return ["ERROR: Use del command like this: del <-p|-l> <id> [...] (-p indicates that the ids are from packages, -l indicates that the ids are from links)"]
+
+ def event_help(self, args):
+ lines = []
+ lines.append("The following commands are available:")
+ lines.append("add <package|packid> <links> [...] Adds link to package. (creates new package if it does not exist)")
+ lines.append("queue Shows all packages in the queue")
+ lines.append("collector Shows all packages in collector")
+ lines.append("del -p|-l <id> [...] Deletes all packages|links with the ids specified")
+ lines.append("info <id> Shows info of the link with id <id>")
+ lines.append("packinfo <id> Shows info of the package with id <id>")
+ lines.append("more Shows more info when the result was truncated")
+ lines.append("start Starts all downloads")
+ lines.append("stop Stops the download (but not abort active downloads)")
+ lines.append("status Show general download status")
+ lines.append("help Shows this help message")
+ return lines
+
+
+class IRCError(Exception):
+ def __init__(self, value):
+ self.value = value
+ def __str__(self):
+ return repr(self.value) \ No newline at end of file
diff --git a/module/plugins/hooks/MultiHome.py b/module/plugins/hooks/MultiHome.py
new file mode 100644
index 000000000..3f41938dc
--- /dev/null
+++ b/module/plugins/hooks/MultiHome.py
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+
+"""
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+ @author: mkaay
+"""
+
+from module.plugins.Hook import Hook
+from time import time
+
+class MultiHome(Hook):
+ __name__ = "MultiHome"
+ __version__ = "0.1"
+ __description__ = """ip address changer"""
+ __config__ = [ ("activated", "bool", "Activated" , "False"),
+ ("interfaces", "str", "Interfaces" , "None") ]
+ __author_name__ = ("mkaay")
+ __author_mail__ = ("mkaay@mkaay.de")
+
+ def setup(self):
+ self.register = {}
+ self.interfaces = []
+ self.parseInterfaces(self.getConfig("interfaces").split(";"))
+ if not self.interfaces:
+ self.parseInterfaces([self.config["general"]["download_interface"]])
+ self.setConfig("interfaces", self.toConfig())
+
+ def toConfig(self):
+ return ";".join([i.adress for i in self.interfaces])
+
+ def parseInterfaces(self, interfaces):
+ for interface in interfaces:
+ if not interface or str(interface).lower() == "none":
+ continue
+ self.interfaces.append(Interface(interface))
+
+ def coreReady(self):
+ requestFactory = self.core.requestFactory
+ oldGetRequest = requestFactory.getRequest
+ def getRequest(pluginName, account=None, type="HTTP"):
+ iface = self.bestInterface(pluginName, account)
+ if iface:
+ iface.useFor(pluginName, account)
+ requestFactory.iface = iface.adress
+ self.log.debug("Multihome: using address: "+iface.adress)
+ return oldGetRequest(pluginName, account, type)
+ requestFactory.getRequest = getRequest
+
+ def bestInterface(self, pluginName, account):
+ best = None
+ for interface in self.interfaces:
+ if not best or interface.lastPluginAccess(pluginName, account) < best.lastPluginAccess(pluginName, account):
+ best = interface
+ return best
+
+class Interface(object):
+ def __init__(self, adress):
+ self.adress = adress
+ self.history = {}
+
+ def lastPluginAccess(self, pluginName, account):
+ if self.history.has_key((pluginName, account)):
+ return self.history[(pluginName, account)]
+ return 0
+
+ def useFor(self, pluginName, account):
+ self.history[(pluginName, account)] = time()
+
+ def __repr__(self):
+ return "<Interface - %s>" % self.adress
diff --git a/module/plugins/hooks/UnRar.py b/module/plugins/hooks/UnRar.py
new file mode 100644
index 000000000..faa06d179
--- /dev/null
+++ b/module/plugins/hooks/UnRar.py
@@ -0,0 +1,137 @@
+# -*- coding: utf-8 -*-
+
+"""
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+ @author: mkaay
+"""
+from __future__ import with_statement
+
+import sys
+
+from module.plugins.Hook import Hook
+from module.pyunrar import Unrar, WrongPasswordError, CommandError, UnknownError
+
+from os.path import exists, join
+from os import remove
+import re
+
+class UnRar(Hook):
+ __name__ = "UnRar"
+ __version__ = "0.1"
+ __description__ = """unrar"""
+ __config__ = [ ("activated", "bool", "Activated", False),
+ ("fullpath", "bool", "extract full path", True),
+ ("overwrite", "bool", "overwrite files", True),
+ ("passwordfile", "str", "unrar passoword file", "unrar_passwords.txt"),
+ ("deletearchive", "bool", "delete archives when done", False) ]
+ __threaded__ = ["packageFinished"]
+ __author_name__ = ("mkaay")
+ __author_mail__ = ("mkaay@mkaay.de")
+
+ def setup(self):
+ self.comments = ["# one password each line"]
+ self.passwords = []
+ if exists(self.getConfig("passwordfile")):
+ with open(self.getConfig("passwordfile"), "r") as f:
+ for l in f.readlines():
+ l = l.strip("\n\r")
+ if l and not l.startswith("#"):
+ self.passwords.append(l)
+ else:
+ with open(self.getConfig("passwordfile"), "w") as f:
+ f.writelines(self.comments)
+ self.re_splitfile = re.compile("(.*)\.part(\d+)\.rar$")
+
+ def addPassword(self, pw):
+ if not pw in self.passwords:
+ self.passwords.insert(0, pw)
+ with open(self.getConfig("passwordfile"), "w") as f:
+ f.writelines(self.comments)
+ f.writelines(self.passwords)
+
+ def removeFiles(self, pack, fname):
+ if not self.getConfig("deletearchive"):
+ return
+ m = self.re_splitfile.search(fname)
+
+ download_folder = self.core.config['general']['download_folder']
+ if self.core.config['general']['folder_per_package']:
+ folder = join(download_folder, pack.folder.decode(sys.getfilesystemencoding()))
+ else:
+ folder = download_folder
+ if m:
+ nre = re.compile("%s\.part\d+\.rar" % m.group(1))
+ for fid, data in pack.getChildren().iteritems():
+ if nre.match(data["name"]):
+ remove(join(folder, data["name"]))
+ elif not m and fname.endswith(".rar"):
+ nre = re.compile("^%s\.r..$" % fname.replace(".rar",""))
+ for fid, data in pack.getChildren().iteritems():
+ if nre.match(data["name"]):
+ remove(join(folder, data["name"]))
+
+ def packageFinished(self, pack):
+ if pack.password:
+ self.addPassword(pack.password)
+ files = []
+ for fid, data in pack.getChildren().iteritems():
+ m = self.re_splitfile.search(data["name"])
+ if m and int(m.group(2)) == 1:
+ files.append((fid,m.group(0)))
+ elif not m and data["name"].endswith(".rar"):
+ files.append((fid,data["name"]))
+
+ for fid, fname in files:
+ pyfile = self.core.files.getFile(fid)
+ pyfile.setStatus("custom")
+ def s(p):
+ pyfile.alternativePercent = p
+
+ download_folder = self.core.config['general']['download_folder']
+ if self.core.config['general']['folder_per_package']:
+ folder = join(download_folder, pack.folder.decode(sys.getfilesystemencoding()))
+ else:
+ folder = download_folder
+
+ u = Unrar(join(folder, fname))
+ try:
+ success = u.crackPassword(passwords=self.passwords, statusFunction=s, overwrite=True, destination=folder, fullPath=self.getConfig("fullpath"))
+ except WrongPasswordError:
+ self.core.log.info("Unrar of %s failed (wrong password)" % fname)
+ continue
+ except CommandError, e:
+ if re.search("Cannot find volume", e.stderr):
+ self.core.log.info("Unrar of %s failed (missing volume)" % fname)
+ continue
+ try:
+ if e.getExitCode() == 1 and len(u.listContent(u.getPassword())) == 1:
+ self.core.log.debug("Unrar of %s ok" % fname)
+ self.removeFiles(pack, fname)
+ except:
+ self.core.log.info("Unrar of %s failed" % fname)
+ continue
+ except UnknownError:
+ self.core.log.info("Unrar of %s failed" % fname)
+ continue
+ else:
+ if success:
+ self.core.log.debug("Unrar of %s ok" % fname)
+ self.removeFiles(pack, fname)
+ else:
+ self.core.log.info("Unrar of %s failed (wrong password)" % fname)
+ finally:
+ pyfile.alternativePercent = None
+ pyfile.setStatus("finished")
+
diff --git a/module/plugins/hooks/UpdateManager.py b/module/plugins/hooks/UpdateManager.py
new file mode 100644
index 000000000..2981df9a0
--- /dev/null
+++ b/module/plugins/hooks/UpdateManager.py
@@ -0,0 +1,59 @@
+# -*- coding: utf-8 -*-
+
+"""
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+ @author: mkaay
+ @interface-version: 0.1
+"""
+
+from module.network.Request import getURL
+from module.plugins.Hook import Hook
+
+class UpdateManager(Hook):
+ __name__ = "UpdateManager"
+ __version__ = "0.1"
+ __description__ = """checks for updates"""
+ __config__ = [ ("activated", "bool", "Activated" , "True"),
+ ("interval", "int", "Check interval in minutes" , "180")]
+ __author_name__ = ("RaNaN")
+ __author_mail__ = ("ranan@pyload.org")
+
+ def setup(self):
+ self.interval = self.getConfig("interval") * 60
+
+ def coreReady(self):
+ #@TODO check plugins, restart, and other stuff
+ pass
+
+ def periodical(self):
+ self.checkForUpdate()
+
+
+ def checkForUpdate(self):
+ """ checks if an update is available"""
+
+ try:
+ version_check = getURL("http://get.pyload.org/check/%s/" % self.core.server_methods.get_server_version() )
+ if version_check == "":
+ self.log.info(_("No Updates for pyLoad"))
+ return False
+ else:
+ self.log.info(_("*** New pyLoad Version %s available ***") % version_check)
+ self.log.info(_("*** Get it here: http://get.pyload.org/get/ ***"))
+ return True
+ except:
+ self.log.error(_("Not able to connect server"))
+
+ \ No newline at end of file
diff --git a/module/plugins/hooks/XMPPInterface.py b/module/plugins/hooks/XMPPInterface.py
new file mode 100644
index 000000000..67a7f1b77
--- /dev/null
+++ b/module/plugins/hooks/XMPPInterface.py
@@ -0,0 +1,229 @@
+# -*- coding: utf-8 -*-
+
+"""
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+ @author: RaNaN
+ @interface-version: 0.2
+"""
+
+import socket
+import sys
+from threading import Thread
+import time
+from time import sleep
+from traceback import print_exc
+
+from pyxmpp.all import JID,Iq,Presence,Message,StreamError
+from pyxmpp.jabber.client import JabberClient
+from pyxmpp.interface import implements
+from pyxmpp.interfaces import *
+from pyxmpp.streamtls import TLSSettings
+
+from module.plugins.Hook import Hook
+from module.plugins.hooks.IRCInterface import IRCInterface
+
+class XMPPInterface(IRCInterface, JabberClient):
+ __name__ = "XMPPInterface"
+ __version__ = "0.1"
+ __description__ = """connect to jabber and let owner perform different tasks"""
+ __config__ = [("activated", "bool", "Activated", "False"),
+ ("jid", "str", "Jabber ID", "user@exmaple-jabber-server.org"),
+ ("pw", "str", "Password", ""),
+ ("owners", "str", "List of JIDs accepting commands from", "me@icq-gateway.org;some@msn-gateway.org"),
+ ("info_file", "bool", "Inform about every file finished", "False"),
+ ("info_pack", "bool", "Inform about every package finished", "True")]
+ __author_name__ = ("RaNaN")
+ __author_mail__ = ("RaNaN@pyload.org")
+
+ implements(IMessageHandlersProvider)
+
+ def __init__(self, core):
+ IRCInterface.__init__(self, core)
+
+ 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")
+
+ tls_settings = None
+
+ # setup client with provided connection information
+ # and identity data
+ JabberClient.__init__(self, self.jid, password,
+ disco_name="pyLoad XMPP Client", disco_type="bot",
+ tls_settings = tls_settings)
+
+ self.interface_providers = [
+ VersionHandler(self),
+ self,
+ ]
+
+ def coreReady(self):
+ self.new_package = {}
+
+ self.start()
+
+ def packageFinished(self, pypack):
+
+ try:
+ if self.getConfig("info_pack"):
+ self.announce(_("Package finished: %s") % pypack.name)
+ except:
+ pass
+
+ def downloadFinished(self, pyfile):
+ try:
+ if self.getConfig("info_file"):
+ self.announce(_("Download finished: %s @ %s") % (pyfile.name, pyfile.pluginname) )
+ except:
+ pass
+
+ def run(self):
+ # connect to IRC etc.
+ self.connect()
+ try:
+ self.loop(1)
+ except Exception, ex:
+ self.core.log.error("pyLoad XMPP: %s" % str(ex))
+
+ def stream_state_changed(self,state,arg):
+ """This one is called when the state of stream connecting the component
+ to a server changes. This will usually be used to let the user
+ know what is going on."""
+ self.log.debug("pyLoad XMPP: *** State changed: %s %r ***" % (state,arg) )
+
+ def get_message_handlers(self):
+ """Return list of (message_type, message_handler) tuples.
+
+ The handlers returned will be called when matching message is received
+ in a client session."""
+ return [
+ ("normal", self.message),
+ ]
+
+ def message(self,stanza):
+ """Message handler for the component."""
+ subject=stanza.get_subject()
+ body=stanza.get_body()
+ t=stanza.get_type()
+ self.log.debug(_(u'pyLoad XMPP: Message from %s received.') % (unicode(stanza.get_from(),)))
+ self.log.debug(_(u'pyLoad XMPP: Body: %s') % body)
+
+ if stanza.get_type()=="headline":
+ # 'headline' messages should never be replied to
+ return True
+ if subject:
+ subject=u"Re: "+subject
+
+ to_jid = stanza.get_from()
+ from_jid = stanza.get_to()
+
+ #j = JID()
+ to_name = to_jid.as_utf8()
+ from_name = from_jid.as_utf8()
+
+ names = self.getConfig("owners").split(";")
+
+ if to_name in names or to_jid.node+"@"+to_jid.domain in names:
+
+ messages = []
+
+ trigger = "pass"
+ args = None
+
+ temp = body.split()
+ trigger = temp[0]
+ if len(temp) > 1:
+ args = temp[1:]
+
+ handler = getattr(self, "event_%s" % trigger, self.event_pass)
+ try:
+ res = handler(args)
+ for line in res:
+ m=Message(
+ to_jid=to_jid,
+ from_jid=from_jid,
+ stanza_type=stanza.get_type(),
+ subject=subject,
+ body=line)
+
+ messages.append(m)
+ except Exception, e:
+ self.log.error("pyLoad XMPP: "+ repr(e))
+
+ return messages
+
+ else:
+ return True
+
+
+ def announce(self, message):
+ """ send message to all owners"""
+ for user in self.getConfig("owners").split(";"):
+
+ self.log.debug(_("pyLoad XMPP: Send message to %s") % user)
+
+ to_jid = JID(user)
+
+ m = Message(from_jid=self.jid,
+ to_jid=to_jid,
+ stanza_type="chat",
+ body=message)
+
+ self.stream.send(m)
+
+
+class VersionHandler(object):
+ """Provides handler for a version query.
+
+ This class will answer version query and announce 'jabber:iq:version' namespace
+ in the client's disco#info results."""
+
+ implements(IIqHandlersProvider, IFeaturesProvider)
+
+ def __init__(self, client):
+ """Just remember who created this."""
+ self.client = client
+
+ def get_features(self):
+ """Return namespace which should the client include in its reply to a
+ disco#info query."""
+ return ["jabber:iq:version"]
+
+ def get_iq_get_handlers(self):
+ """Return list of tuples (element_name, namespace, handler) describing
+ handlers of <iq type='get'/> stanzas"""
+ return [
+ ("query", "jabber:iq:version", self.get_version),
+ ]
+
+ def get_iq_set_handlers(self):
+ """Return empty list, as this class provides no <iq type='set'/> stanza handler."""
+ return []
+
+ def get_version(self,iq):
+ """Handler for jabber:iq:version queries.
+
+ jabber:iq:version queries are not supported directly by PyXMPP, so the
+ XML node is accessed directly through the libxml2 API. This should be
+ used very carefully!"""
+ iq=iq.make_result_response()
+ q=iq.new_query("jabber:iq:version")
+ q.newTextChild(q.ns(),"name","Echo component")
+ q.newTextChild(q.ns(),"version","1.0")
+ return iq
+ \ No newline at end of file
diff --git a/module/plugins/hooks/__init__.py b/module/plugins/hooks/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/module/plugins/hooks/__init__.py