diff options
Diffstat (limited to 'module/plugins')
| -rw-r--r-- | module/plugins/AccountManager.py | 179 | ||||
| -rw-r--r-- | module/plugins/PluginManager.py | 329 | 
2 files changed, 508 insertions, 0 deletions
diff --git a/module/plugins/AccountManager.py b/module/plugins/AccountManager.py new file mode 100644 index 000000000..ab35334fc --- /dev/null +++ b/module/plugins/AccountManager.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python +# -*- 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 +""" + +from os.path import exists +from shutil import copy + +from module.PullEvents import AccountUpdateEvent + +ACC_VERSION = 1 + +######################################################################## +class AccountManager(): +    """manages all accounts""" + +    #---------------------------------------------------------------------- +    def __init__(self, core): +        """Constructor""" + +        self.core = core + +        self.accounts = {} # key = ( plugin ) +        self.plugins = {} + +        self.initAccountPlugins() +                 +        self.loadAccounts() + +        self.saveAccounts() # save to add categories to conf + +    #---------------------------------------------------------------------- +    def getAccountPlugin(self, plugin): +        """get account instance for plugin or None if anonymous""" +        if self.accounts.has_key(plugin): +            if not self.plugins.has_key(plugin): +                self.plugins[plugin] = self.core.pluginManager.getAccountPlugin(plugin)(self, self.accounts[plugin]) + +            return self.plugins[plugin] +        else: +            return None + +    def getAccountPlugins(self): +        """ get all account instances""" +         +        plugins = [] +        for plugin in self.accounts.keys(): +            plugins.append(self.getAccountPlugin(plugin)) +             +        return plugins +    #---------------------------------------------------------------------- +    def loadAccounts(self): +        """loads all accounts available""" +         +        if not exists("accounts.conf"): +            f = open("accounts.conf", "wb") +            f.write("version: " + str(ACC_VERSION)) +            f.close() +             +        f = open("accounts.conf", "rb") +        content = f.readlines() +        version = content[0].split(":")[1].strip() if content else "" +        f.close() + +        if not version or int(version) < ACC_VERSION: +            copy("accounts.conf", "accounts.backup") +            f = open("accounts.conf", "wb") +            f.write("version: " + str(ACC_VERSION)) +            f.close() +            self.core.log.warning(_("Account settings deleted, due to new config format.")) +            return +             +             +         +        plugin = "" +        name = "" +         +        for line in content[1:]: +            line = line.strip() +             +            if not line: continue +            if line.startswith("#"): continue +            if line.startswith("version"): continue +             +            if line.endswith(":") and line.count(":") == 1: +                plugin = line[:-1] +                self.accounts[plugin] = {} +                 +            elif line.startswith("@"): +                option = line[1:].split() +                self.accounts[plugin][name]["options"][option[0]] = [] if len(option) < 2 else ([option[1]] if len(option) < 3 else option[1:]) +                 +            elif ":" in line: +                name, sep, pw = line.partition(":") +                self.accounts[plugin][name] = {"password": pw, "options": {}, "valid": True} +    #---------------------------------------------------------------------- +    def saveAccounts(self): +        """save all account information""" +         +        f = open("accounts.conf", "wb") +        f.write("version: " + str(ACC_VERSION) + "\n") +                 +        for plugin, accounts in self.accounts.iteritems(): +            f.write("\n") +            f.write(plugin+":\n") +             +            for name,data in accounts.iteritems(): +                f.write("\n\t%s:%s\n" % (name,data["password"]) ) +                for option, values in data["options"].iteritems(): +                    f.write("\t@%s %s\n" % (option, " ".join(values))) +                     +        f.close() +             +         +    #---------------------------------------------------------------------- +    def initAccountPlugins(self): +        """init names""" +        for name in self.core.pluginManager.getAccountPlugins(): +            self.accounts[name] = {} +         +    #---------------------------------------------------------------------- +    def updateAccount(self, plugin , user, password=None, options={}): +        """add or update account""" +        if self.accounts.has_key(plugin): +            p = self.getAccountPlugin(plugin) +            p.updateAccounts(user, password, options) +            #since accounts is a ref in plugin self.accounts doesnt need to be updated here +                     +            self.saveAccounts() +            p.getAllAccounts(force=True) +            self.core.scheduler.addJob(0, self.core.accountManager.getAccountInfos) +                 +    #---------------------------------------------------------------------- +    def removeAccount(self, plugin, user): +        """remove account""" +         +        if self.accounts.has_key(plugin): +            p = self.getAccountPlugin(plugin) +            p.removeAccount(user) + +            self.saveAccounts() +            p.getAllAccounts(force=True) +            self.core.scheduler.addJob(0, self.core.accountManager.getAccountInfos) + +             +    def getAccountInfos(self, force=True, refresh=False): +        data = {} + +        if refresh: +            self.core.scheduler.addJob(0, self.core.accountManager.getAccountInfos) +            force = False +         +        for p in self.accounts.keys(): +            if self.accounts[p]: +                p = self.getAccountPlugin(p) +                data[p.__name__] = p.getAllAccounts(force) +            else: +                data[p] = [] +        e = AccountUpdateEvent() +        self.core.pullManager.addEvent(e) +        return data +     +    def sendChange(self): +        e = AccountUpdateEvent() +        self.core.pullManager.addEvent(e) diff --git a/module/plugins/PluginManager.py b/module/plugins/PluginManager.py new file mode 100644 index 000000000..3f11c067b --- /dev/null +++ b/module/plugins/PluginManager.py @@ -0,0 +1,329 @@ +# -*- 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, RaNaN +""" + +import re +import sys + +from os import listdir +from os import makedirs + +from os.path import isfile +from os.path import join +from os.path import exists +from os.path import abspath + +from sys import version_info +from itertools import chain + +try: +    from ast import literal_eval +except ImportError: # python 2.5 +    from module.SafeEval import safe_eval as literal_eval + + +IGNORE = ["FreakshareNet"] +#ignore this plugins in homefolder, add deleted plugins here + +class PluginManager(): +    def __init__(self, core): +        self.core = core +         +        #self.config = self.core.config +        self.log = core.log +         +        self.crypterPlugins = {} +        self.containerPlugins = {} +        self.hosterPlugins = {} +        self.captchaPlugins = {} +        self.accountPlugins = {} +        self.hookPlugins = {} +         +        self.createHomeDirs() +         +        self.createIndex() +         +        #@TODO plugin updater +    #---------------------------------------------------------------------- +    def createHomeDirs(self): +        """create homedirectories containing plugins""" +        #@TODO implement... +        pass +     +    def createIndex(self): +        """create information for all plugins available""" +         +        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() +         +        self.rePattern = re.compile(r'__pattern__.*=.*r("|\')([^"\']+)') +        self.reVersion = re.compile(r'__version__.*=.*("|\')([0-9.]+)') +        self.reConfig = re.compile(r'__config__.*=.*\[([^\]]+)', re.MULTILINE) +         +        self.crypterPlugins = self.parse(_("Crypter"), "crypter", pattern=True) +        self.containerPlugins = self.parse(_("Container"), "container", pattern=True) +        self.hosterPlugins = self.parse(_("Hoster") ,"hoster", pattern=True) +         +        self.captchaPlugins = self.parse(_("Captcha"), "captcha") +        self.accountPlugins = self.parse(_("Account"), "accounts", create=True) +        self.hookPlugins = self.parse(_("Hook"), "hooks") + +        self.log.debug(_("created index of plugins")) +     +    def parse(self, typ, folder, create=False, pattern=False, home={}): +        """ +        returns dict with information  +        home contains parsed plugins from module. +         +        { +        name : {path, version, config, (pattern, re), (plugin, class)} +        } +         +        """ +        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("_"): +                data = open(join(pfolder, f)) +                content = data.read() +                data.close() +                 +                if f.endswith("_25.pyc") and not version_info[0:2] == (2, 5): +                    continue +                elif f.endswith("_26.pyc") and not version_info[0:2] == (2, 6): +                    continue +                elif f.endswith("_27.pyc") and not version_info[0:2] == (2, 7): +                    continue +                                               +                name = f[:-3] +                if name[-1] == "." : name = name[:-4] +                 +                 +                version = self.reVersion.findall(content) +                if version: +                    version = float(version[0][1]) +                else: +                    version = 0 +                 +                if home and home.has_key(name): +                    if home[name]["v"] >= version: +                        continue +                 +                 +                plugins[name] = {} +                plugins[name]["v"] = version +                 +                 +                module = f.replace(".pyc","").replace(".py","") +                if home: +                    if name in IGNORE: +                        del plugins[name] +                        continue +                    path = "userplugins.%s.%s" % (folder, module) +                else: +                    path = "module.plugins.%s.%s" % (folder, module) +                     +                plugins[name]["name"] = module                 +                plugins[name]["path"] = path +                 +                 +                if pattern: +                    pattern = self.rePattern.findall(content) +                     +                    if pattern: +                        pattern = pattern[0][1] +                    else: +                        pattern = "^unmachtable$" +                         +                    plugins[name]["pattern"] = pattern +                     +                    try: +                        plugins[name]["re"] = re.compile(pattern) +                    except: +                        self.log.error(_("%s has invalid pattern.") % name) + +                 +                config = self.reConfig.findall(content) +                 +                if config: +                    config = literal_eval(config[0].strip().replace("\n", "").replace("\r", "")) +                    if type(config[0]) == tuple: +                        config = [list(x) for x in config] +                    else: +                        config = [list(config)] +                     +                    if folder == "hooks": +                        config.append( ["load", "bool", "Load on startup", True if name not in ("XMPPInterface", "MultiHome") else False] )  +                     +                    for item in config: +                        self.core.config.addPluginConfig([name]+item) +     +        if not home: +            temp = self.parse(typ, folder, create, pattern, plugins) +            plugins.update(temp) +             +        return plugins +         +    #---------------------------------------------------------------------- +    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])) +                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 +                 +            if not found: +                res.append((url, "BasePlugin"))  +         +        return res +     +    #---------------------------------------------------------------------- +    def getPlugin(self, name): +        """return plugin module from hoster|decrypter|container""" +        plugin = None +         +        if self.containerPlugins.has_key(name): +            plugin = self.containerPlugins[name] +        if self.crypterPlugins.has_key(name): +            plugin = self.crypterPlugins[name] +        if self.hosterPlugins.has_key(name): +            plugin = self.hosterPlugins[name] +         +             +        if plugin.has_key("module"): +            return plugin["module"] +         +        plugin["module"] = __import__(plugin["path"], globals(), locals(), [plugin["name"]] , -1) +         +        return plugin["module"] +         +             +    #---------------------------------------------------------------------- +    def getCaptchaPlugin(self, name): +        """return captcha modul if existent""" +        if self.captchaPlugins.has_key(name): +            plugin = self.captchaPlugins[name] +            if plugin.has_key("class"): +                return plugin["class"] +         +            module = __import__(plugin["path"], globals(), locals(), [plugin["name"]] , -1) +            plugin["class"] = getattr(module, name) +         +            return plugin["class"] +         +        return None +    #---------------------------------------------------------------------- +    def getAccountPlugin(self, name): +        """return account class if existent""" +        if self.accountPlugins.has_key(name): +            plugin = self.accountPlugins[name] +            if plugin.has_key("class"): +                return plugin["class"] +             +            module = __import__(plugin["path"], globals(), locals(), [plugin["name"]] , -1) +            plugin["class"] = getattr(module, plugin["name"]) +                  +            return plugin["class"] +         +        return None +         +    #---------------------------------------------------------------------- +    def getAccountPlugins(self): +        """return list of account plugin names""" +        res = [] +         +        for name in self.accountPlugins.keys(): +            res.append(name) +     +        return res +    #---------------------------------------------------------------------- +    def getHookPlugins(self): +        """return list of hook classes""" +         +        classes = [] +         +        for name, value in self.hookPlugins.iteritems(): +            if value.has_key("class"): +                classes.append(value["class"]) +                continue +             +            if not self.core.config.getPlugin(name, "load"): +                continue +             +            try: +                module = __import__(value["path"], globals(), locals(), [value["name"]] , -1) +            except Exception, e: +                self.log.error(_("Error importing %(name)s: %(msg)s") % {"name": name, "msg": str(e) }) +                self.log.error(_("You should fix dependicies or deactivate load on startup.")) +                continue +                 +            pluginClass = getattr(module, name) +             +            value["class"] = pluginClass + +            classes.append(pluginClass)             +         +        return classes + + +if __name__ == "__main__": +    _ = lambda x : x +    pypath = "/home/christian/Projekte/pyload-0.4/module/plugins" +     +    from time import time +     +    p = PluginManager(None) +     +    a = time()  +     +    test = [ "http://www.youtube.com/watch?v=%s" % x for x in range(0,100) ] +    print p.parseUrls(test) +     +    b = time() +     +    print b-a ,"s" +      | 
