summaryrefslogtreecommitdiffstats
path: root/module/PluginManager.py
diff options
context:
space:
mode:
Diffstat (limited to 'module/PluginManager.py')
-rw-r--r--module/PluginManager.py407
1 files changed, 0 insertions, 407 deletions
diff --git a/module/PluginManager.py b/module/PluginManager.py
deleted file mode 100644
index bb1c76bf3..000000000
--- a/module/PluginManager.py
+++ /dev/null
@@ -1,407 +0,0 @@
-# -*- coding: utf-8 -*-
-
-###############################################################################
-# Copyright(c) 2008-2013 pyLoad Team
-# http://www.pyload.org
-#
-# This file is part of pyLoad.
-# pyLoad is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# Subjected to the terms and conditions in LICENSE
-#
-# @author: RaNaN, mkaay
-###############################################################################
-
-import re
-import sys
-
-from os import listdir, makedirs
-from os.path import isfile, join, exists, abspath, basename
-from sys import version_info
-from time import time
-
-from module.lib.SafeEval import const_eval as literal_eval
-from module.plugins.Base import Base
-
-from new_collections import namedtuple
-
-#TODO: ignores not updatable
-
-# ignore these plugin configs, mainly because plugins were wiped out
-IGNORE = (
- "FreakshareNet", "SpeedManager", "ArchiveTo", "ShareCx", ('addons', 'UnRar'),
- 'EasyShareCom', 'FlyshareCz'
- )
-
-PluginTuple = namedtuple("PluginTuple", "version re deps category user path")
-
-class PluginManager:
- ROOT = "module.plugins."
- LOCALROOT = "localplugins."
- TYPES = ("crypter", "hoster", "accounts", "addons", "internal")
-
- BUILTIN = re.compile(r'__(?P<attr>[a-z0-9_]+)__\s*=\s?(True|False|None|[0-9x.]+)', re.I)
- SINGLE = re.compile(r'__(?P<attr>[a-z0-9_]+)__\s*=\s*(?:r|u|_)?((?:(?<!")"(?!")|\'|\().*(?:(?<!")"(?!")|\'|\)))',
- 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)
-
- NO_MATCH = re.compile(r'^no_match$')
-
- def __init__(self, core):
- self.core = core
-
- #self.config = self.core.config
- self.log = core.log
-
- self.plugins = {}
- self.modules = {} # cached modules
- self.history = [] # match history to speedup parsing (type, name)
- self.user_context = {} # plugins working with user context
- self.createIndex()
-
- #register for import addon
- 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"""
- # add to path, so we can import from userplugins
- sys.path.append(abspath(""))
-
- if not exists("userplugins"):
- makedirs("userplugins")
- if not exists(join("userplugins", "__init__.py")):
- f = open(join("userplugins", "__init__.py"), "wb")
- f.close()
-
- a = time()
- for type in self.TYPES:
- self.plugins[type] = self.parse(type)
-
- self.log.debug("Created index of plugins in %.2f ms", (time() - a) * 1000)
-
- def parse(self, folder, home=None):
- """ Analyze and parses all plugins in folder """
- plugins = {}
- if home:
- pfolder = join("userplugins", folder)
- if not exists(pfolder):
- makedirs(pfolder)
- if not exists(join(pfolder, "__init__.py")):
- f = open(join(pfolder, "__init__.py"), "wb")
- f.close()
-
- else:
- pfolder = join(pypath, "module", "plugins", folder)
-
- for f in listdir(pfolder):
- if (isfile(join(pfolder, f)) and f.endswith(".py") or f.endswith("_25.pyc") or f.endswith(
- "_26.pyc") or f.endswith("_27.pyc")) and not f.startswith("_"):
- if f.endswith("_25.pyc") and version_info[0:2] != (2, 5):
- continue
- elif f.endswith("_26.pyc") and version_info[0:2] != (2, 6):
- continue
- elif f.endswith("_27.pyc") and version_info[0:2] != (2, 7):
- continue
-
- # replace suffix and version tag
- name = f[:-3]
- if name[-1] == ".": name = name[:-4]
-
- plugin = self.parsePlugin(join(pfolder, f), folder, name, home)
- if plugin:
- plugins[name] = plugin
-
- if not home:
- temp = self.parse(folder, plugins)
- plugins.update(temp)
-
- return plugins
-
- def parseAttributes(self, filename, name, folder=""):
- """ Parse attribute dict from plugin"""
- data = open(filename, "rb")
- content = data.read()
- data.close()
-
- attrs = {}
- for m in self.BUILTIN.findall(content) + self.SINGLE.findall(content) + self.MULTI.findall(content):
- #replace gettext function and eval result
- try:
- attrs[m[0]] = literal_eval(m[-1].replace("_(", "("))
- except:
- self.logDebug(folder, name, "Error when parsing: %s" % m[-1])
- self.core.print_exc()
-
- 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])
-
- return attrs
-
- def parsePlugin(self, filename, folder, name, home=None):
- """ Parses a plugin from disk, folder means plugin type in this context. Also sets config.
-
- :arg home: dict with plugins, of which the found one will be matched against (according version)
- :returns PluginTuple"""
-
- attrs = self.parseAttributes(filename, name, folder)
- if not attrs: return
-
- 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:
- self.logDebug(folder, name, "No version attribute")
-
- # home contains plugins from pyload root
- if home and name in home:
- if home[name].version >= version:
- return
-
- if name in IGNORE or (folder, name) in IGNORE:
- return
-
- if "pattern" in attrs and attrs["pattern"]:
- try:
- plugin_re = re.compile(attrs["pattern"], re.I)
- except:
- self.logDebug(folder, name, "Invalid regexp pattern '%s'" % attrs["pattern"])
- plugin_re = self.NO_MATCH
- else: plugin_re = self.NO_MATCH
-
- deps = attrs.get("dependencies", None)
- category = attrs.get("category", None) if folder == "addons" else None
-
- # create plugin tuple
- plugin = PluginTuple(version, plugin_re, deps, category, bool(home), filename)
-
- # internals have no config
- if folder == "internal":
- return plugin
-
- if folder == "addons" and "config" not in attrs and not attrs.get("internal", False):
- attrs["config"] = (["activated", "bool", "Activated", False],)
-
- if "config" in attrs and attrs["config"]:
- config = attrs["config"]
- desc = attrs.get("description", "")
- long_desc = attrs.get("long_description", "")
-
- if type(config[0]) == tuple:
- config = [list(x) for x in config]
- else:
- config = [list(config)]
-
- if folder == "addons" and not attrs.get("internal", False):
- for item in config:
- if item[0] == "activated": break
- else: # activated flag missing
- config.insert(0, ("activated", "bool", "Activated", False))
-
- # Everything that is no addon and user_context=True, is added to dict
- if folder != "addons" or attrs.get("user_context", False):
- self.user_context[name] = True
-
- try:
- self.core.config.addConfigSection(name, name, desc, long_desc, config)
- except:
- self.logDebug(folder, name, "Invalid config %s" % config)
-
- return plugin
-
-
- def parseUrls(self, urls):
- """parse plugins for given list of urls, separate to crypter and hoster"""
-
- res = {"hoster": [], "crypter": []} # tupels of (url, plugin)
-
- for url in urls:
- if type(url) not in (str, unicode, buffer):
- self.log.debug("Parsing invalid type %s" % type(url))
- continue
-
- found = False
-
- for ptype, name in self.history:
- if self.plugins[ptype][name].re.match(url):
- res[ptype].append((url, name))
- found = (ptype, name)
- break # need to exit this loop first
-
- if found: # found match
- if self.history[0] != found: #update history
- self.history.remove(found)
- self.history.insert(0, found)
- continue
-
- for ptype in ("crypter", "hoster"):
- for name, plugin in self.plugins[ptype].iteritems():
- if plugin.re.match(url):
- res[ptype].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["hoster"].append((url, "BasePlugin"))
-
- return res["hoster"], res["crypter"]
-
- def getPlugins(self, type):
- return self.plugins.get(type, None)
-
- def findPlugin(self, name, pluginlist=("hoster", "crypter")):
- for ptype in pluginlist:
- if name in self.plugins[ptype]:
- return ptype, self.plugins[ptype][name]
- return None, None
-
- def getPluginModule(self, name):
- """ Decprecated: return plugin module from hoster|crypter"""
- self.log.debug("Deprecated method: .getPluginModule()")
- type, plugin = self.findPlugin(name)
- return self.loadModule(type, name)
-
- def getPluginClass(self, name):
- """ return plugin class from hoster|crypter, always the not overwritten one """
- type, plugin = self.findPlugin(name)
- return self.loadClass(type, name)
-
- # MultiHoster will overwrite this
- getPlugin = getPluginClass
-
- def loadAttributes(self, type, name):
- plugin = self.plugins[type][name]
- return self.parseAttributes(plugin.path, name, type)
-
- def loadModule(self, type, name):
- """ Returns loaded module for plugin
-
- :param type: plugin type, subfolder of module.plugins
- :param name:
- """
- plugins = self.plugins[type]
- if name in plugins:
- if (type, name) in self.modules: return self.modules[(type, name)]
- try:
- # convert path to python recognizable import
- path = basename(plugins[name].path).replace(".pyc", "").replace(".py", "")
- module = __import__(self.ROOT + "%s.%s" % (type, path), globals(), locals(), path)
- self.modules[(type, name)] = module # cache import, maybe unneeded
- return module
- except Exception, e:
- self.log.error(_("Error importing %(name)s: %(msg)s") % {"name": name, "msg": str(e)})
- self.core.print_exc()
-
- def loadClass(self, type, name):
- """Returns the class of a plugin with the same name"""
- module = self.loadModule(type, name)
- if module: return getattr(module, name)
-
- def find_module(self, fullname, path=None):
- #redirecting imports if necesarry
- if fullname.startswith(self.ROOT) or fullname.startswith(self.LOCALROOT): #separate pyload plugins
- if fullname.startswith(self.LOCALROOT): user = 1
- else: user = 0 #used as bool and int
-
- split = fullname.split(".")
- if len(split) != 4 - user: return
- type, name = split[2 - user:4 - user]
-
- 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:
- return self
- #imported from userdir, but pyloads is newer
- if user and not self.plugins[type][name].user:
- return self
-
- def load_module(self, name, replace=True):
- if name not in sys.modules: #could be already in modules
- if replace:
- if self.ROOT in name:
- newname = name.replace(self.ROOT, self.LOCALROOT)
- else:
- newname = name.replace(self.LOCALROOT, self.ROOT)
- else: newname = name
-
- base, plugin = newname.rsplit(".", 1)
-
- self.log.debug("Redirected import %s -> %s" % (name, newname))
-
- module = __import__(newname, globals(), locals(), [plugin])
- #inject under new an old name
- sys.modules[name] = module
- sys.modules[newname] = module
-
- return sys.modules[name]
-
- def reloadPlugins(self, type_plugins):
- """ reloads and reindexes plugins """
- if not type_plugins: return False
-
- self.log.debug("Request reload of plugins: %s" % type_plugins)
-
- as_dict = {}
- for t, n in type_plugins:
- if t in as_dict:
- as_dict[t].append(n)
- else:
- as_dict[t] = [n]
-
- # we do not reload addons or internals, would cause to much side effects
- if "addons" in as_dict or "internal" in as_dict:
- return False
-
- for type in as_dict.iterkeys():
- for plugin in as_dict[type]:
- if plugin in self.plugins[type]:
- if (type, plugin) in self.modules:
- self.log.debug("Reloading %s" % plugin)
- reload(self.modules[(type, plugin)])
-
- # 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()
- self.core.scheduler.addJob(0, self.core.accountManager.getAccountInfos)
-
- return True
-
- def isUserPlugin(self, plugin):
- """ A plugin suitable for multiple user """
- return plugin in self.user_context
-
- def isPluginType(self, plugin, type):
- return plugin in self.plugins[type]
-
- def getCategory(self, plugin):
- if plugin in self.plugins["addons"]:
- return self.plugins["addons"][plugin].category or "addon"
-
- def loadIcon(self, name):
- """ load icon for single plugin, base64 encoded"""
- pass
-
- def checkDependencies(self, type, name):
- """ Check deps for given plugin
-
- :return: List of unfullfilled dependencies
- """
- pass
-