summaryrefslogtreecommitdiffstats
path: root/pyload/AddonManager.py
diff options
context:
space:
mode:
Diffstat (limited to 'pyload/AddonManager.py')
-rw-r--r--pyload/AddonManager.py98
1 files changed, 60 insertions, 38 deletions
diff --git a/pyload/AddonManager.py b/pyload/AddonManager.py
index 7935ff112..5c5524061 100644
--- a/pyload/AddonManager.py
+++ b/pyload/AddonManager.py
@@ -17,14 +17,23 @@
import __builtin__
+from gettext import gettext
+from copy import copy
from thread import start_new_thread
from threading import RLock
+from collections import defaultdict
+from new_collections import namedtuple
+
from types import MethodType
+from pyload.Api import AddonService, AddonInfo
from pyload.threads.AddonThread import AddonThread
from utils import lock, to_string
+AddonTuple = namedtuple('AddonTuple', 'instances events handler')
+
+
class AddonManager:
""" Manages addons, loading, unloading. """
@@ -35,10 +44,13 @@ class AddonManager:
__builtin__.addonManager = self #needed to let addons register themselves
self.log = self.core.log
- # TODO: multiuser, addons can store the user itself, probably not needed here
- self.plugins = {}
- self.methods = {} # dict of names and list of methods usable by rpc
- self.events = {} # Contains event that will be registered
+
+ # TODO: multiuser addons
+
+ # maps plugin names to info tuple
+ self.plugins = defaultdict(lambda: AddonTuple([], [], {}))
+ # Property hash mapped to meta data
+ self.info_props = {}
self.lock = RLock()
self.createIndex()
@@ -46,11 +58,16 @@ class AddonManager:
# manage addons on config change
self.listenTo("config:changed", self.manageAddon)
+ def iterAddons(self):
+ """ Yields (name, meta_data) of all addons """
+ return self.plugins.iteritems()
+
@lock
def callInHooks(self, event, eventName, *args):
""" Calls a method in all addons and catch / log errors"""
for plugin in self.plugins.itervalues():
- self.call(plugin, event, *args)
+ for inst in plugin.instances:
+ self.call(inst, event, *args)
self.dispatchEvent(eventName, *args)
def call(self, addon, f, *args):
@@ -78,7 +95,7 @@ class AddonManager:
if not pluginClass: continue
plugin = pluginClass(self.core, self)
- self.plugins[pluginClass.__name__] = plugin
+ self.plugins[pluginClass.__name__].instances.append(plugin)
# hide internals from printing
if not internal and plugin.isActivated():
@@ -96,7 +113,7 @@ class AddonManager:
self.log.info(_("Deactivated addons: %s") % ", ".join(sorted(deactive)))
def manageAddon(self, plugin, name, value):
- # TODO: user
+ # TODO: multi user
# check if section was a plugin
if plugin not in self.core.pluginManager.getPlugins("addons"):
@@ -120,18 +137,18 @@ class AddonManager:
self.log.debug("Plugin loaded: %s" % plugin)
plugin = pluginClass(self.core, self)
- self.plugins[pluginClass.__name__] = plugin
+ self.plugins[pluginClass.__name__].instances.append(plugin)
# active the addon in new thread
start_new_thread(plugin.activate, tuple())
- self.registerEvents() # TODO: BUG: events will be destroyed and not re-registered
+ self.registerEvents()
@lock
def deactivateAddon(self, plugin):
if plugin not in self.plugins:
return
- else:
- addon = self.plugins[plugin]
+ else: # todo: multiple instances
+ addon = self.plugins[plugin].instances[0]
if addon.__internal__: return
@@ -140,8 +157,11 @@ class AddonManager:
#remove periodic call
self.log.debug("Removed callback %s" % self.core.scheduler.removeJob(addon.cb))
+
+ # todo: only delete instances, meta data is lost otherwise
del self.plugins[addon.__name__]
+ # TODO: could be improved
#remove event listener
for f in dir(addon):
if f.startswith("__") or type(getattr(addon, f)) != MethodType:
@@ -151,8 +171,9 @@ class AddonManager:
def activateAddons(self):
self.log.info(_("Activating addons..."))
for plugin in self.plugins.itervalues():
- if plugin.isActivated():
- self.call(plugin, "activate")
+ for inst in plugin.instances:
+ if inst.isActivated():
+ self.call(inst, "activate")
self.registerEvents()
@@ -160,7 +181,8 @@ class AddonManager:
""" Called when core is shutting down """
self.log.info(_("Deactivating addons..."))
for plugin in self.plugins.itervalues():
- self.call(plugin, "deactivate")
+ for inst in plugin.instances:
+ self.call(inst, "deactivate")
def downloadPreparing(self, pyfile):
self.callInHooks("downloadPreparing", "download:preparing", pyfile)
@@ -180,40 +202,40 @@ class AddonManager:
def activePlugins(self):
""" returns all active plugins """
- return [x for x in self.plugins.itervalues() if x.isActivated()]
-
- def getAllInfo(self):
- """returns info stored by addon plugins"""
- info = {}
- for name, plugin in self.plugins.iteritems():
- if plugin.info:
- #copy and convert so str
- info[name] = dict(
- [(x, to_string(y)) for x, y in plugin.info.iteritems()])
- return info
+ return [p for x in self.plugins.values() for p in x.instances if p.isActivated()]
def getInfo(self, plugin):
- info = {}
- if plugin in self.plugins and self.plugins[plugin].info:
- info = dict([(x, to_string(y))
- for x, y in self.plugins[plugin].info.iteritems()])
+ """ Retrieves all info data for a plugin """
- return info
+ data = []
+ # TODO
+ if plugin in self.plugins:
+ if plugin.instances:
+ for attr in dir(plugin.instances[0]):
+ if attr.startswith("__Property"):
+ info = self.info_props[attr]
+ info.value = getattr(plugin.instances[0], attr)
+ data.append(info)
+ return data
def addEventListener(self, plugin, func, event):
""" add the event to the list """
- if plugin not in self.events:
- self.events[plugin] = []
- self.events[plugin].append((func, event))
+ self.plugins[plugin].events.append((func, event))
def registerEvents(self):
""" actually register all saved events """
for name, plugin in self.plugins.iteritems():
- if name in self.events:
- for func, event in self.events[name]:
- self.listenTo(event, getattr(plugin, func))
- # clean up
- del self.events[name]
+ for func, event in plugin.events:
+ for inst in plugin.instances:
+ self.listenTo(event, getattr(inst, func))
+
+ def addAddonHandler(self, plugin, func, label, desc, args, package, media):
+ """ Registers addon service description """
+ self.plugins[plugin].handler[func] = AddonService(func, gettext(label), gettext(desc), args, package, media)
+
+ def addInfoProperty(self, h, name, desc):
+ """ Register property as :class:`AddonInfo` """
+ self.info_props[h] = AddonInfo(name, desc)
def listenTo(self, *args):
self.core.eventManager.listenTo(*args)