summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2011-12-17 21:53:57 +0100
committerGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2011-12-17 21:53:57 +0100
commit4e918edba6c3808b095eab1bad137a2a8cab970d (patch)
tree718dac3c4f048edff7711088f3ad23c7678a2378
parentimprove share online (diff)
downloadpyload-4e918edba6c3808b095eab1bad137a2a8cab970d.tar.xz
updated plugin api and plugin manager
-rw-r--r--module/HookManager.py2
-rw-r--r--module/PluginThread.py2
-rw-r--r--module/plugins/Base.py7
-rw-r--r--module/plugins/PluginManager.py185
-rw-r--r--module/plugins/hooks/UpdateManager.py4
-rw-r--r--module/plugins/hoster/RapidshareCom.py2
-rwxr-xr-xpyLoadCore.py2
7 files changed, 106 insertions, 98 deletions
diff --git a/module/HookManager.py b/module/HookManager.py
index 16f692d76..8bfcadca6 100644
--- a/module/HookManager.py
+++ b/module/HookManager.py
@@ -119,7 +119,7 @@ class HookManager:
active = []
deactive = []
- for pluginname in self.core.pluginManager.hookPlugins:
+ for pluginname in self.core.pluginManager.getPlugins("hooks"):
try:
#hookClass = getattr(plugin, plugin.__name__)
diff --git a/module/PluginThread.py b/module/PluginThread.py
index 56c36c778..e91d6d819 100644
--- a/module/PluginThread.py
+++ b/module/PluginThread.py
@@ -502,7 +502,7 @@ class InfoThread(PluginThread):
# filter out container plugins
- for name in self.m.core.pluginManager.containerPlugins:
+ for name in self.m.core.pluginManager.getPlugins("container"):
if name in plugins:
container.extend([(name, url) for url in plugins[name]])
diff --git a/module/plugins/Base.py b/module/plugins/Base.py
index 98573ea63..b166ebae8 100644
--- a/module/plugins/Base.py
+++ b/module/plugins/Base.py
@@ -17,11 +17,16 @@
@author: RaNaN
"""
+# TODO: config format definition
+# more attributes if needed
+# get rid of catpcha & container plugins ?! (move to crypter & internals)
+# adapt old plugins as needed
+
class Base(object):
"""
The Base plugin class with all shared methods and every possible attribute for plugin definition.
"""
- __version__ = "0.4"
+ __version__ = "0.1"
#: Regexp pattern which will be matched for download plugins
__pattern__ = r""
#: Flat config definition
diff --git a/module/plugins/PluginManager.py b/module/plugins/PluginManager.py
index 4bf41484a..744e09ef0 100644
--- a/module/plugins/PluginManager.py
+++ b/module/plugins/PluginManager.py
@@ -23,28 +23,27 @@ import sys
from os import listdir, makedirs
from os.path import isfile, join, exists, abspath
from sys import version_info
-from itertools import chain
+from time import time
from traceback import print_exc
from module.lib.SafeEval import const_eval as literal_eval
from module.ConfigParser import IGNORE
+from module.plugins.Base import Base
from namedtuple import namedtuple
-PluginTuple = namedtuple("PluginTuple", "version pattern desc long_desc deps user name module")
+PluginTuple = namedtuple("PluginTuple", "version re desc long_desc deps user path")
class PluginManager:
ROOT = "module.plugins."
USERROOT = "userplugins."
TYPES = ("crypter", "container", "hoster", "captcha", "accounts", "hooks", "internal")
- PATTERN = re.compile(r'__pattern__.*=.*r("|\')([^"\']+)')
- VERSION = re.compile(r'__version__.*=.*("|\')([0-9.]+)')
- CONFIG = re.compile(r'__config__.*=.*\[([^\]]+)', re.MULTILINE)
- DESC = re.compile(r'__description__.?=.?("|"""|\')([^"\']+)')
+ SINGLE = re.compile(r'__(?P<attr>[a-z0-9_]+)__\s*=\s*(?:r|u|_)?((?:(?<!")"(?!")|\'|\().*(?:(?<!")"(?!")|\'|\)))',
+ re.I)
-
- ATTR = re.compile(r'__([a-z0-9_])__\s*=\s*({|\[|\(|"|\')([^__]+)', re.M | re.I)
+ # note the nongreedy character, that means we can not embed list and dicts
+ MULTI = re.compile(r'__(?P<attr>[a-z0-9_]+)__\s*=\s*((?:\{|\[|"{3}).*?(?:"""|\}|\]))', re.DOTALL | re.M | re.I)
def __init__(self, core):
self.core = core
@@ -53,12 +52,18 @@ class PluginManager:
self.log = core.log
self.plugins = {}
+ self.modules = {} # cached modules
+ self.names = {} # overwritten names
+ self.history = [] # match history to speedup parsing (type, name)
self.createIndex()
#register for import hook
sys.meta_path.append(self)
+ def logDebug(self, type, plugin, msg):
+ self.log.debug("Plugin %s | %s: %s" % (type, plugin, msg))
+
def createIndex(self):
"""create information for all plugins available"""
@@ -70,27 +75,14 @@ class PluginManager:
f = open(join("userplugins", "__init__.py"), "wb")
f.close()
- self.plugins["crypter"] = self.crypterPlugins = self.parse("crypter", pattern=True)
- self.plugins["container"] = self.containerPlugins = self.parse("container", pattern=True)
- self.plugins["hoster"] = self.hosterPlugins = self.parse("hoster", pattern=True)
-
- self.plugins["captcha"] = self.captchaPlugins = self.parse("captcha")
- self.plugins["accounts"] = self.accountPlugins = self.parse("accounts")
- self.plugins["hooks"] = self.hookPlugins = self.parse("hooks")
- self.plugins["internal"] = self.internalPlugins = self.parse("internal")
+ a = time()
+ for type in self.TYPES:
+ self.plugins[type] = self.parse(type)
- self.log.debug("created index of plugins")
+ self.log.debug("Created index of plugins in %.2f ms", (time() - a) * 1000 )
- def parse(self, folder, pattern=False, home={}):
- """
- returns dict with information
- home contains parsed plugins from module.
-
- {
- name : {path, version, config, (pattern, re), (plugin, class)}
- }
-
- """
+ def parse(self, folder, home={}):
+ """ Creates a dict with PluginTuples according to parsed information """
plugins = {}
if home:
pfolder = join("userplugins", folder)
@@ -120,55 +112,56 @@ class PluginManager:
name = f[:-3]
if name[-1] == ".": name = name[:-4]
- version = self.VERSION.findall(content)
- if version:
- version = float(version[0][1])
+ attrs = {}
+ for m in self.SINGLE.findall(content) + self.MULTI.findall(content):
+ #replace gettext function and eval result
+ attrs[m[0]] = literal_eval(m[-1].replace("_(", "("))
+ if not hasattr(Base, "__%s__" % m[0]):
+ if m[0] != "type": #TODO remove type from all plugins, its not needed
+ self.logDebug(folder, name, "Unknown attribute '%s'" % m[0])
+
+ version = 0
+
+ if "version" in attrs:
+ try:
+ version = float(attrs["version"])
+ except ValueError:
+ self.logDebug(folder, name, "Invalid version %s" % attrs["version"])
+ version = 9 #TODO remove when plugins are fixed, causing update loops
else:
- version = 0
+ self.logDebug(folder, name, "No version attribute")
# home contains plugins from pyload root
if home and name in home:
- if home[name]["v"] >= version:
+ if home[name].version >= version:
continue
if name in IGNORE or (folder, name) in IGNORE:
- continue
-
- plugins[name] = {}
- plugins[name]["v"] = version
-
- module = f.replace(".pyc", "").replace(".py", "")
-
- # the plugin is loaded from user directory
- plugins[name]["user"] = True if home else False
- plugins[name]["name"] = module
-
- if pattern:
- pattern = self.PATTERN.findall(content)
-
- if pattern:
- pattern = pattern[0][1]
- else:
- pattern = "^unmachtable$"
-
- plugins[name]["pattern"] = pattern
+ continue
+ if "pattern" in attrs and attrs["pattern"]:
try:
- plugins[name]["re"] = re.compile(pattern)
+ plugin_re = re.compile(attrs["pattern"])
except:
- self.log.error(_("%s has a invalid pattern.") % name)
+ self.logDebug(folder, name, "Invalid regexp pattern '%s'" % attrs["pattern"])
+ plugin_re = None
+ else: plugin_re = None
+
+
+ # create plugin tuple
+ plugin = PluginTuple(version, plugin_re, None, None, None, True if home else False,
+ f.replace(".pyc", "").replace(".py", ""))
+ plugins[name] = plugin
# internals have no config
if folder == "internal":
self.core.config.deleteConfig(name)
continue
- config = self.CONFIG.findall(content)
- if config:
- config = literal_eval(config[0].strip().replace("\n", "").replace("\r", ""))
- desc = self.DESC.findall(content)
- desc = desc[0][1] if desc else ""
+ if "config" in attrs and attrs["config"]:
+ config = attrs["config"]
+ desc = attrs["description"] if "description" in attrs else ""
if type(config[0]) == tuple:
config = [list(x) for x in config]
@@ -189,8 +182,7 @@ class PluginManager:
self.log.error("Invalid config in %s: %s" % (name, config))
elif folder == "hooks": #force config creation
- desc = self.DESC.findall(content)
- desc = desc[0][1] if desc else ""
+ desc = attrs["description"] if "description" in attrs else ""
config = (["activated", "bool", "Activated", False],)
try:
@@ -199,39 +191,54 @@ class PluginManager:
self.log.error("Invalid config in %s: %s" % (name, config))
if not home:
- temp = self.parse(folder, pattern, plugins)
+ temp = self.parse(folder, plugins)
plugins.update(temp)
return plugins
+ def parsePlugin(self):
+ pass
+
def parseUrls(self, urls):
"""parse plugins for given list of urls"""
- last = None
res = [] # tupels of (url, plugin)
for url in urls:
if type(url) not in (str, unicode, buffer): continue
found = False
- if last and last[1]["re"].match(url):
- res.append((url, last[0]))
+ for ptype, name in self.history:
+ if self.plugins[ptype][name].re.match(url):
+ res.append((url, name))
+ found = (ptype, name)
+
+ if found:
+ # found match, update history
+ self.history.remove(found)
+ self.history.insert(0, found)
continue
- for name, value in chain(self.crypterPlugins.iteritems(), self.hosterPlugins.iteritems(),
- self.containerPlugins.iteritems()):
- if value["re"].match(url):
- res.append((url, name))
- last = (name, value)
- found = True
- break
+ for ptype in ("crypter", "hoster", "container"):
+ for name, plugin in self.plugins[ptype].iteritems():
+ if plugin.re.match(url):
+ res.append((url, name))
+ self.history.insert(0, (ptype, name))
+ del self.history[10:] # cut down to size of 10
+ found = True
+ break
if not found:
res.append((url, "BasePlugin"))
return res
+ def getPlugins(self, type):
+ # TODO clean this workaround
+ if type not in self.plugins: type+="s" # append s, so updater can find the plugins
+ return self.plugins[type]
+
def findPlugin(self, name, pluginlist=("hoster", "crypter", "container")):
for ptype in pluginlist:
if name in self.plugins[ptype]:
@@ -244,7 +251,7 @@ class PluginManager:
if not plugin:
self.log.warning("Plugin %s not found." % name)
- plugin = self.hosterPlugins["BasePlugin"]
+ plugin = self.plugins["hoster"]["BasePlugin"]
if "new_module" in plugin and not original:
return plugin["new_module"]
@@ -268,11 +275,11 @@ class PluginManager:
"""
plugins = self.plugins[type]
if name in plugins:
- if "module" in plugins[name]: return plugins[name]["module"]
+ if (type, name) in self.modules: return self.modules[(type, name)]
try:
- module = __import__(self.ROOT + "%s.%s" % (type, plugins[name]["name"]), globals(), locals(),
- plugins[name]["name"])
- plugins[name]["module"] = module #cache import, maybe unneeded
+ module = __import__(self.ROOT + "%s.%s" % (type, plugins[name].path), globals(), locals(),
+ plugins[name].path)
+ self.modules[(type, name)] = module # cache import, maybne unneeded
return module
except Exception, e:
self.log.error(_("Error importing %(name)s: %(msg)s") % {"name": name, "msg": str(e)})
@@ -286,7 +293,7 @@ class PluginManager:
def getAccountPlugins(self):
"""return list of account plugin names"""
- return self.accountPlugins.keys()
+ return self.plugins["accounts"].keys()
def find_module(self, fullname, path=None):
#redirecting imports if necesarry
@@ -300,10 +307,10 @@ class PluginManager:
if type in self.plugins and name in self.plugins[type]:
#userplugin is a newer version
- if not user and self.plugins[type][name]["user"]:
+ if not user and self.plugins[type][name].user:
return self
- #imported from userdir, but pyloads is newer
- if user and not self.plugins[type][name]["user"]:
+ #imported from userdir, but pyloads is newer
+ if user and not self.plugins[type][name].user:
return self
@@ -335,7 +342,7 @@ class PluginManager:
self.log.debug("Request reload of plugins: %s" % type_plugins)
as_dict = {}
- for t,n in type_plugins:
+ for t, n in type_plugins:
if t in as_dict:
as_dict[t].append(n)
else:
@@ -348,16 +355,13 @@ class PluginManager:
for type in as_dict.iterkeys():
for plugin in as_dict[type]:
if plugin in self.plugins[type]:
- if "module" in self.plugins[type][plugin]:
+ if (type, plugin) in self.modules:
self.log.debug("Reloading %s" % plugin)
- reload(self.plugins[type][plugin]["module"])
+ reload(self.modules[(type, plugin)])
- #index creation
- self.plugins["crypter"] = self.crypterPlugins = self.parse("crypter", pattern=True)
- self.plugins["container"] = self.containerPlugins = self.parse("container", pattern=True)
- self.plugins["hoster"] = self.hosterPlugins = self.parse("hoster", pattern=True)
- self.plugins["captcha"] = self.captchaPlugins = self.parse("captcha")
- self.plugins["accounts"] = self.accountPlugins = self.parse("accounts")
+ # index re-creation
+ for type in ("crypter", "container", "hoster", "captcha", "accounts"):
+ self.plugins[type] = self.parse(type)
if "accounts" in as_dict: #accounts needs to be reloaded
self.core.accountManager.initPlugins()
@@ -366,7 +370,6 @@ class PluginManager:
return True
-
if __name__ == "__main__":
_ = lambda x: x
pypath = "/home/christian/Projekte/pyload-0.4/module/plugins"
diff --git a/module/plugins/hooks/UpdateManager.py b/module/plugins/hooks/UpdateManager.py
index 920a88060..8cbc56c42 100644
--- a/module/plugins/hooks/UpdateManager.py
+++ b/module/plugins/hooks/UpdateManager.py
@@ -129,10 +129,10 @@ class UpdateManager(Hook):
else:
type = prefix
- plugins = getattr(self.core.pluginManager, "%sPlugins" % type)
+ plugins = self.core.pluginManager.getPlugins(type)
if name in plugins:
- if float(plugins[name]["v"]) >= float(version):
+ if float(plugins[name].version) >= float(version):
continue
if name in IGNORE or (type, name) in IGNORE:
diff --git a/module/plugins/hoster/RapidshareCom.py b/module/plugins/hoster/RapidshareCom.py
index 0d927c525..f3011a488 100644
--- a/module/plugins/hoster/RapidshareCom.py
+++ b/module/plugins/hoster/RapidshareCom.py
@@ -52,7 +52,7 @@ class RapidshareCom(Hoster):
__pattern__ = r"https?://[\w\.]*?rapidshare.com/(?:files/(?P<id>\d*?)/(?P<name>[^?]+)|#!download\|(?:\w+)\|(?P<id_new>\d+)\|(?P<name_new>[^|]+))"
__version__ = "1.37"
__description__ = """Rapidshare.com Download Hoster"""
- __config__ = [["server", "Cogent;Deutsche Telekom;Level(3);Level(3) #2;GlobalCrossing;Level(3) #3;Teleglobe;GlobalCrossing #2;TeliaSonera #2;Teleglobe #2;TeliaSonera #3;TeliaSonera", "Preferred Server", "None"]]
+ __config__ = [("server", "Cogent;Deutsche Telekom;Level(3);Level(3) #2;GlobalCrossing;Level(3) #3;Teleglobe;GlobalCrossing #2;TeliaSonera #2;Teleglobe #2;TeliaSonera #3;TeliaSonera", "Preferred Server", "None")]
__author_name__ = ("spoob", "RaNaN", "mkaay")
__author_mail__ = ("spoob@pyload.org", "ranan@pyload.org", "mkaay@mkaay.de")
diff --git a/pyLoadCore.py b/pyLoadCore.py
index a9faad908..35e667d01 100755
--- a/pyLoadCore.py
+++ b/pyLoadCore.py
@@ -20,7 +20,7 @@
@author: mkaay
@version: v0.4.9
"""
-CURRENT_VERSION = '0.4.9'
+CURRENT_VERSION = '0.4.9.9-dev'
import __builtin__