summaryrefslogtreecommitdiffstats
path: root/module/plugins
diff options
context:
space:
mode:
authorGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2011-12-23 21:40:22 +0100
committerGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2011-12-23 21:40:22 +0100
commit8da44b430b957b25e74dff63829d4198a52e7a0b (patch)
treef20fc60db6e7d9a93fe3ca60cd68a6e32b536fc6 /module/plugins
parentoron version increase (diff)
parentlittle fixes (diff)
downloadpyload-8da44b430b957b25e74dff63829d4198a52e7a0b.tar.xz
merge hotfixes in
Diffstat (limited to 'module/plugins')
-rw-r--r--module/plugins/Account.py335
-rw-r--r--module/plugins/AccountManager.py210
-rw-r--r--module/plugins/Base.py131
-rw-r--r--module/plugins/Hook.py2
-rw-r--r--module/plugins/Hoster.py22
-rw-r--r--module/plugins/Plugin.py112
-rw-r--r--module/plugins/PluginManager.py317
-rw-r--r--module/plugins/hooks/UpdateManager.py6
-rw-r--r--module/plugins/hoster/RapidshareCom.py2
-rw-r--r--module/plugins/internal/MultiHoster.py21
10 files changed, 571 insertions, 587 deletions
diff --git a/module/plugins/Account.py b/module/plugins/Account.py
index c147404e0..9da8d0357 100644
--- a/module/plugins/Account.py
+++ b/module/plugins/Account.py
@@ -1,63 +1,72 @@
# -*- 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 random import choice
from time import time
from traceback import print_exc
from threading import RLock
from Plugin import Base
from module.utils import compare_time, parseFileSize, lock
+from module.config.converter import from_string
+from module.Api import AccountInfo
+from module.network.CookieJar import CookieJar
class WrongPassword(Exception):
pass
-
-class Account(Base):
+#noinspection PyUnresolvedReferences
+class Account(Base, AccountInfo):
"""
Base class for every Account plugin.
Just overwrite `login` and cookies will be stored and account becomes accessible in\
associated hoster plugin. Plugin should also provide `loadAccountInfo`
"""
- __name__ = "Account"
- __version__ = "0.2"
- __type__ = "account"
- __description__ = """Account Plugin"""
- __author_name__ = ("mkaay")
- __author_mail__ = ("mkaay@mkaay.de")
+
+ # Default values
+ valid = True
+ validuntil = None
+ trafficleft = None
+ maxtraffic = None
+ premium = True
+ activated = True
#: after that time [in minutes] pyload will relogin the account
login_timeout = 600
#: account data will be reloaded after this time
info_threshold = 600
+ # known options
+ known_opt = ["time", "limitDL"]
- def __init__(self, manager, accounts):
+
+ def __init__(self, manager, loginname, password, options):
Base.__init__(self, manager.core)
+ if "activated" in options:
+ activated = from_string(options["activated"], "bool")
+ else:
+ activated = Account.activated
+
+ for opt in self.known_opt:
+ if opt not in options:
+ options[opt] = ""
+
+ for opt in options.keys():
+ if opt not in self.known_opt:
+ del options[opt]
+
+ # default account attributes
+ AccountInfo.__init__(self, self.__name__, loginname, Account.valid, Account.validuntil, Account.trafficleft,
+ Account.maxtraffic, Account.premium, activated, options)
+
self.manager = manager
- self.accounts = {}
- self.infos = {} # cache for account information
+
self.lock = RLock()
+ self.timestamp = 0
+ self.login_ts = 0 # timestamp for login
+ self.cj = CookieJar(self.__name__)
+ self.password = password
+ self.error = None
- self.timestamps = {}
- self.setAccounts(accounts)
self.init()
def init(self):
@@ -70,76 +79,68 @@ class Account(Base):
:param data: data dictionary
:param req: `Request` instance
"""
- pass
+ raise NotImplemented
@lock
- def _login(self, user, data):
+ def _login(self):
# set timestamp for login
- self.timestamps[user] = time()
-
- req = self.getAccountRequest(user)
+ self.login_ts = time()
+
+ req = self.getAccountRequest()
try:
- self.login(user, data, req)
+ self.login(self.loginname, {"password": self.password}, req)
+ self.valid = True
except WrongPassword:
self.logWarning(
- _("Could not login with account %(user)s | %(msg)s") % {"user": user
- , "msg": _("Wrong Password")})
- data["valid"] = False
+ _("Could not login with account %(user)s | %(msg)s") % {"user": self.loginname
+ , "msg": _("Wrong Password")})
+ self.valid = False
except Exception, e:
self.logWarning(
- _("Could not login with account %(user)s | %(msg)s") % {"user": user
- , "msg": e})
- data["valid"] = False
+ _("Could not login with account %(user)s | %(msg)s") % {"user": self.loginname
+ , "msg": e})
+ self.valid = False
if self.core.debug:
print_exc()
finally:
- if req: req.close()
-
- def relogin(self, user):
- req = self.getAccountRequest(user)
- if req:
- req.cj.clear()
req.close()
- if user in self.infos:
- del self.infos[user] #delete old information
-
- self._login(user, self.accounts[user])
- def setAccounts(self, accounts):
- self.accounts = accounts
- for user, data in self.accounts.iteritems():
- self._login(user, data)
- self.infos[user] = {}
+ def restoreDefaults(self):
+ self.valid = Account.valid
+ self.validuntil = Account.validuntil
+ self.trafficleft = Account.trafficleft
+ self.maxtraffic = Account.maxtraffic
+ self.premium = Account.premium
+ self.activated = Account.activated
- def updateAccounts(self, user, password=None, options={}):
+ def update(self, password=None, options={}):
""" updates account and return true if anything changed """
- if user in self.accounts:
- self.accounts[user]["valid"] = True #do not remove or accounts will not login
- if password:
- self.accounts[user]["password"] = password
- self.relogin(user)
- return True
- if options:
- before = self.accounts[user]["options"]
- self.accounts[user]["options"].update(options)
- return self.accounts[user]["options"] != before
- else:
- self.accounts[user] = {"password": password, "options": options, "valid": True}
- self._login(user, self.accounts[user])
+ self.login_ts = 0
+
+ if "activated" in options:
+ self.activated = from_string(options["avtivated"], "bool")
+
+ if password:
+ self.password = password
+ self._login()
return True
+ if options:
+ # remove unknown options
+ for opt in options.keys():
+ if opt not in self.known_opt:
+ del options[opt]
- def removeAccount(self, user):
- if user in self.accounts:
- del self.accounts[user]
- if user in self.infos:
- del self.infos[user]
- if user in self.timestamps:
- del self.timestamps[user]
+ before = self.options
+ self.options.update(options)
+ return self.options != before
+
+ def getAccountRequest(self):
+ return self.core.requestFactory.getRequest(self.__name__, self.cj)
@lock
- def getAccountInfo(self, name, force=False):
+ def getAccountInfo(self, force=False):
"""retrieve account infos for an user, do **not** overwrite this method!\\
just use it to retrieve infos in hoster plugins. see `loadAccountInfo`
@@ -147,113 +148,55 @@ class Account(Base):
:param force: reloads cached account information
:return: dictionary with information
"""
- data = Account.loadAccountInfo(self, name)
+ if force or self.timestamp + self.info_threshold * 60 < time():
- if force or name not in self.infos:
- self.logDebug("Get Account Info for %s" % name)
- req = self.getAccountRequest(name)
+ # make sure to login
+ self.checkLogin()
+ self.logDebug("Get Account Info for %s" % self.loginname)
+ req = self.getAccountRequest()
try:
- infos = self.loadAccountInfo(name, req)
- if not type(infos) == dict:
- raise Exception("Wrong return format")
+ infos = self.loadAccountInfo(self.loginname, req)
except Exception, e:
infos = {"error": str(e)}
- if req: req.close()
+ req.close()
self.logDebug("Account Info: %s" % str(infos))
+ self.timestamp = time()
+
+ self.restoreDefaults() # reset to initial state
+ if type(infos) == dict: # copy result from dict to class
+ for k, v in infos.iteritems():
+ if hasattr(self, k):
+ setattr(self, k, v)
+ else:
+ self.logDebug("Unknown attribute %s=%s" % (k, v))
+
+ def isPremium(self, user=None):
+ if user: self.logDebug("Deprecated Argument user for .isPremium()", user)
+ return self.premium
+
+ def isUsable(self):
+ """Check several contraints to determine if account should be used"""
+ if not self.valid or not self.activated: return False
+
+ if self.options["time"]:
+ time_data = ""
+ try:
+ time_data = self.options["time"]
+ start, end = time_data.split("-")
+ if not compare_time(start.split(":"), end.split(":")):
+ return False
+ except:
+ self.logWarning(_("Your Time %s has wrong format, use: 1:22-3:44") % time_data)
+
+ if 0 < self.validuntil < time():
+ return False
+ if self.trafficleft is 0: # test explicity for 0
+ return False
- infos["timestamp"] = time()
- self.infos[name] = infos
- elif "timestamp" in self.infos[name] and self.infos[name][
- "timestamp"] + self.info_threshold * 60 < time():
- self.logDebug("Reached timeout for account data")
- self.scheduleRefresh(name)
-
- data.update(self.infos[name])
- return data
-
- def isPremium(self, user):
- info = self.getAccountInfo(user)
- return info["premium"]
-
- def loadAccountInfo(self, name, req=None):
- """this should be overwritten in account plugin,\
- and retrieving account information for user
-
- :param name:
- :param req: `Request` instance
- :return:
- """
- return {
- "validuntil": None, # -1 for unlimited
- "login": name,
- #"password": self.accounts[name]["password"], #@XXX: security
- "options": self.accounts[name]["options"],
- "valid": self.accounts[name]["valid"],
- "trafficleft": None, # in kb, -1 for unlimited
- "maxtraffic": None,
- "premium": True, #useful for free accounts
- "timestamp": 0, #time this info was retrieved
- "type": self.__name__,
- }
-
- def getAllAccounts(self, force=False):
- return [self.getAccountInfo(user, force) for user, data in self.accounts.iteritems()]
-
- def getAccountRequest(self, user=None):
- if not user:
- user, data = self.selectAccount()
- if not user:
- return None
-
- req = self.core.requestFactory.getRequest(self.__name__, user)
- return req
-
- def getAccountCookies(self, user=None):
- if not user:
- user, data = self.selectAccount()
- if not user:
- return None
-
- cj = self.core.requestFactory.getCookieJar(self.__name__, user)
- return cj
-
- def getAccountData(self, user):
- return self.accounts[user]
-
- def selectAccount(self):
- """ returns an valid account name and data"""
- usable = []
- for user, data in self.accounts.iteritems():
- if not data["valid"]: continue
-
- if "time" in data["options"] and data["options"]["time"]:
- time_data = ""
- try:
- time_data = data["options"]["time"][0]
- start, end = time_data.split("-")
- if not compare_time(start.split(":"), end.split(":")):
- continue
- except:
- self.logWarning(_("Your Time %s has wrong format, use: 1:22-3:44") % time_data)
-
- if user in self.infos:
- if "validuntil" in self.infos[user]:
- if self.infos[user]["validuntil"] > 0 and time() > self.infos[user]["validuntil"]:
- continue
- if "trafficleft" in self.infos[user]:
- if self.infos[user]["trafficleft"] == 0:
- continue
-
- usable.append((user, data))
-
- if not usable: return None, None
- return choice(usable)
-
- def canUse(self):
- return False if self.selectAccount() == (None, None) else True
+ return True
def parseTraffic(self, string): #returns kbyte
return parseFileSize(string) / 1024
@@ -261,32 +204,36 @@ class Account(Base):
def wrongPassword(self):
raise WrongPassword
- def empty(self, user):
- if user in self.infos:
- self.logWarning(_("Account %s has not enough traffic, checking again in 30min") % user)
+ def empty(self, user=None):
+ if user: self.logDebug("Deprecated argument user for .empty()", user)
+
+ self.logWarning(_("Account %s has not enough traffic, checking again in 30min") % self.login)
- self.infos[user].update({"trafficleft": 0})
- self.scheduleRefresh(user, 30 * 60)
+ self.trafficleft = 0
+ self.scheduleRefresh(30 * 60)
def expired(self, user):
if user in self.infos:
self.logWarning(_("Account %s is expired, checking again in 1h") % user)
- self.infos[user].update({"validuntil": time() - 1})
- self.scheduleRefresh(user, 60 * 60)
+ self.validuntil = time() - 1
+ self.scheduleRefresh(60 * 60)
- def scheduleRefresh(self, user, time=0, force=True):
+ def scheduleRefresh(self, time=0, force=True):
""" add task to refresh account info to sheduler """
- self.logDebug("Scheduled Account refresh for %s in %s seconds." % (user, time))
- self.core.scheduler.addJob(time, self.getAccountInfo, [user, force])
+ self.logDebug("Scheduled Account refresh for %s in %s seconds." % (self.loginname, time))
+ self.core.scheduler.addJob(time, self.getAccountInfo, [force])
@lock
- def checkLogin(self, user):
+ def checkLogin(self):
""" checks if user is still logged in """
- if user in self.timestamps:
- if self.timestamps[user] + self.login_timeout * 60 < time():
- self.logDebug("Reached login timeout for %s" % user)
- self.relogin(user)
- return False
+ if self.login_ts + self.login_timeout * 60 < time():
+ if self.login_ts: # seperate from fresh login to have better debug logs
+ self.logDebug("Reached login timeout for %s" % self.loginname)
+ else:
+ self.logDebug("Login with %s" % self.loginname)
+
+ self._login()
+ return False
return True
diff --git a/module/plugins/AccountManager.py b/module/plugins/AccountManager.py
index fc521d36c..c718510ed 100644
--- a/module/plugins/AccountManager.py
+++ b/module/plugins/AccountManager.py
@@ -17,169 +17,119 @@
@author: RaNaN
"""
-from os.path import exists
-from shutil import copy
-
from threading import Lock
+from random import choice
-from module.PullEvents import AccountUpdateEvent
-from module.utils import chmod, lock
-
-ACC_VERSION = 1
+from module.common.json_layer import json
+from module.interaction.PullEvents import AccountUpdateEvent
+from module.utils import lock
class AccountManager():
"""manages all accounts"""
- #----------------------------------------------------------------------
def __init__(self, core):
"""Constructor"""
self.core = core
self.lock = Lock()
- self.initPlugins()
- self.saveAccounts() # save to add categories to conf
+ self.loadAccounts()
- def initPlugins(self):
- self.accounts = {} # key = ( plugin )
- self.plugins = {}
+ def loadAccounts(self):
+ """loads all accounts available"""
- self.initAccountPlugins()
- self.loadAccounts()
+ self.accounts = {}
+ for plugin, loginname, activated, password, options in self.core.db.loadAccounts():
+ # put into options as used in other context
+ options = json.loads(options) if options else {}
+ options["activated"] = activated
- def getAccountPlugin(self, plugin):
- """get account instance for plugin or None if anonymous"""
- if plugin in self.accounts:
- if plugin not in self.plugins:
- self.plugins[plugin] = self.core.pluginManager.loadClass("accounts", plugin)(self, self.accounts[plugin])
+ self.createAccount(plugin, loginname, password, options)
+
+ return
- 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("@"):
- try:
- 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:])
- except:
- pass
-
- 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"]) )
- if data["options"]:
- for option, values in data["options"].iteritems():
- f.write("\t@%s %s\n" % (option, " ".join(values)))
-
- f.close()
- chmod(f.name, 0600)
-
-
- #----------------------------------------------------------------------
- def initAccountPlugins(self):
- """init names"""
- for name in self.core.pluginManager.getAccountPlugins():
- self.accounts[name] = {}
-
+
+ data = []
+ for name, plugin in self.accounts.iteritems():
+ data.extend([(name, acc.loginname, acc.activated, acc.password, json.dumps(acc.options)) for acc in
+ plugin.itervalues()])
+ self.core.db.saveAccounts(data)
+
+ def createAccount(self, plugin, loginname, password, options):
+ klass = self.core.pluginManager.loadClass("accounts", plugin)
+ if not klass:
+ self.core.log.warning(_("Unknown account plugin %s") % plugin)
+ return
+
+ if plugin not in self.accounts:
+ self.accounts[plugin] = {}
+
+ self.core.log.debug("Create account %s:%s" % (plugin, loginname))
+
+ self.accounts[plugin][loginname] = klass(self, loginname, password, options)
+
+
@lock
- def updateAccount(self, plugin , user, password=None, options={}):
+ def updateAccount(self, plugin, user, password=None, options={}):
"""add or update account"""
- if plugin in self.accounts:
- p = self.getAccountPlugin(plugin)
- updated = p.updateAccounts(user, password, options)
- #since accounts is a ref in plugin self.accounts doesnt need to be updated here
-
+ if plugin in self.accounts and user in self.accounts[plugin]:
+ acc = self.accounts[plugin][user]
+ updated = acc.update(password, options)
+
self.saveAccounts()
- if updated: p.scheduleRefresh(user, force=False)
-
+ if updated: acc.scheduleRefresh(force=True)
+ else:
+ self.createAccount(plugin, user, password, options)
+ self.saveAccounts()
+
@lock
def removeAccount(self, plugin, user):
"""remove account"""
-
+ if plugin in self.accounts and user in self.accounts[plugin]:
+ del self.accounts[plugin][user]
+ self.core.db.removeAccount(plugin, user)
+ else:
+ self.core.log.debug("Remove non existing account %s %s" % (plugin, user))
+
+
+ @lock
+ def getAccountForPlugin(self, plugin):
if plugin in self.accounts:
- p = self.getAccountPlugin(plugin)
- p.removeAccount(user)
+ accs = [x for x in self.accounts[plugin].values() if x.isUsable()]
+ if accs: return choice(accs)
- self.saveAccounts()
+ return None
@lock
- def getAccountInfos(self, force=True, refresh=False):
- data = {}
+ def getAllAccounts(self, refresh=False):
+ """ Return account info, refresh afterwards if needed
+ :param refresh:
+ :return:
+ """
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] = []
+ self.core.scheduler.addJob(0, self.core.accountManager.getAllAccounts)
+
+ # load unavailable account info
+ for p_dict in self.accounts.itervalues():
+ for acc in p_dict.itervalues():
+ acc.getAccountInfo()
+
e = AccountUpdateEvent()
self.core.pullManager.addEvent(e)
- return data
-
+
+ return self.accounts
+
+ def refreshAllAccounts(self):
+ """ Force a refresh of every account """
+ for p in self.accounts.itervalues():
+ for acc in p.itervalues():
+ acc.getAccountInfo(True)
+
+
def sendChange(self):
e = AccountUpdateEvent()
self.core.pullManager.addEvent(e)
diff --git a/module/plugins/Base.py b/module/plugins/Base.py
new file mode 100644
index 000000000..36df7e423
--- /dev/null
+++ b/module/plugins/Base.py
@@ -0,0 +1,131 @@
+# -*- 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
+"""
+
+import sys
+
+# 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.1"
+ #: Regexp pattern which will be matched for download plugins
+ __pattern__ = r""
+ #: Flat config definition
+ __config__ = tuple()
+ #: Short description, one liner
+ __description__ = ""
+ #: More detailed text
+ __long_description__ = """"""
+ #: List of needed modules
+ __dependencies__ = tuple()
+ #: Tags to categorize the plugin
+ __tags__ = tuple()
+ #: Base64 encoded .png icon
+ __icon__ = ""
+ #: Alternative, link to png icon
+ __icon_url__ = ""
+ #: Url with general information/support/discussion
+ __url__ = ""
+ __author_name__ = tuple()
+ __author_mail__ = tuple()
+
+
+ def __init__(self, core):
+ self.__name__ = self.__class__.__name__
+
+ #: Core instance
+ self.core = core
+ #: logging instance
+ self.log = core.log
+ #: core config
+ self.config = core.config
+
+ #log functions
+ def logInfo(self, *args):
+ self.log.info("%s: %s" % (self.__name__, " | ".join([a if isinstance(a, basestring) else str(a) for a in args])))
+
+ def logWarning(self, *args):
+ self.log.warning("%s: %s" % (self.__name__, " | ".join([a if isinstance(a, basestring) else str(a) for a in args])))
+
+ def logError(self, *args):
+ self.log.error("%s: %s" % (self.__name__, " | ".join([a if isinstance(a, basestring) else str(a) for a in args])))
+
+ def logDebug(self, *args):
+ self.log.debug("%s: %s" % (self.__name__, " | ".join([a if isinstance(a, basestring) else str(a) for a in args])))
+
+
+ def setConf(self, option, value):
+ """ see `setConfig` """
+ self.core.config.set(self.__name__, option, value)
+
+ def setConfig(self, option, value):
+ """ Set config value for current plugin
+
+ :param option:
+ :param value:
+ :return:
+ """
+ self.setConf(option, value)
+
+ def getConf(self, option):
+ """ see `getConfig` """
+ return self.core.config.get(self.__name__, option)
+
+ def getConfig(self, option):
+ """ Returns config value for current plugin
+
+ :param option:
+ :return:
+ """
+ return self.getConf(option)
+
+ def setStorage(self, key, value):
+ """ Saves a value persistently to the database """
+ self.core.db.setStorage(self.__name__, key, value)
+
+ def store(self, key, value):
+ """ same as `setStorage` """
+ self.core.db.setStorage(self.__name__, key, value)
+
+ def getStorage(self, key=None, default=None):
+ """ Retrieves saved value or dict of all saved entries if key is None """
+ if key is not None:
+ return self.core.db.getStorage(self.__name__, key) or default
+ return self.core.db.getStorage(self.__name__, key)
+
+ def retrieve(self, *args, **kwargs):
+ """ same as `getStorage` """
+ return self.getStorage(*args, **kwargs)
+
+ def delStorage(self, key):
+ """ Delete entry in db """
+ self.core.db.delStorage(self.__name__, key)
+
+ def shell(self):
+ """ open ipython shell """
+ if self.core.debug:
+ from IPython import embed
+ #noinspection PyUnresolvedReferences
+ sys.stdout = sys._stdout
+ embed()
diff --git a/module/plugins/Hook.py b/module/plugins/Hook.py
index 5efd08bae..860dc76bb 100644
--- a/module/plugins/Hook.py
+++ b/module/plugins/Hook.py
@@ -119,7 +119,7 @@ class Hook(Base):
def isActivated(self):
""" checks if hook is activated"""
- return self.config.getPlugin(self.__name__, "activated")
+ return self.config.get(self.__name__, "activated")
#event methods - overwrite these if needed
diff --git a/module/plugins/Hoster.py b/module/plugins/Hoster.py
index 814a70949..aa50099fb 100644
--- a/module/plugins/Hoster.py
+++ b/module/plugins/Hoster.py
@@ -19,15 +19,15 @@
from module.plugins.Plugin import Plugin
-def getInfo(self):
- #result = [ .. (name, size, status, url) .. ]
- return
-
class Hoster(Plugin):
- __name__ = "Hoster"
- __version__ = "0.1"
- __pattern__ = None
- __type__ = "hoster"
- __description__ = """Base hoster plugin"""
- __author_name__ = ("mkaay")
- __author_mail__ = ("mkaay@mkaay.de")
+
+ @staticmethod
+ def getInfo(urls):
+ """This method is used to retrieve the online status of files for hoster plugins.
+ It has to *yield* list of tuples with the result in this format (name, size, status, url),
+ where status is one of API pyfile statusses.
+
+ :param urls: List of urls
+ :return:
+ """
+ pass \ No newline at end of file
diff --git a/module/plugins/Plugin.py b/module/plugins/Plugin.py
index 15bf3971f..d78eb162b 100644
--- a/module/plugins/Plugin.py
+++ b/module/plugins/Plugin.py
@@ -29,17 +29,9 @@ if os.name != "nt":
from pwd import getpwnam
from grp import getgrnam
-from itertools import islice
-
-from module.utils import save_join, save_path, fs_encode, fs_decode
-
-def chunks(iterable, size):
- it = iter(iterable)
- item = list(islice(it, size))
- while item:
- yield item
- item = list(islice(it, size))
+from Base import Base
+from module.utils import save_join, save_path, fs_encode, fs_decode, chunks
class Abort(Exception):
""" raised when aborted """
@@ -61,95 +53,11 @@ class SkipDownload(Exception):
""" raised when download should be skipped """
-class Base(object):
- """
- A Base class with log/config/db methods *all* plugin types can use
- """
-
- def __init__(self, core):
- #: Core instance
- self.core = core
- #: logging instance
- self.log = core.log
- #: core config
- self.config = core.config
-
- #log functions
- def logInfo(self, *args):
- self.log.info("%s: %s" % (self.__name__, " | ".join([a if isinstance(a, basestring) else str(a) for a in args])))
-
- def logWarning(self, *args):
- self.log.warning("%s: %s" % (self.__name__, " | ".join([a if isinstance(a, basestring) else str(a) for a in args])))
-
- def logError(self, *args):
- self.log.error("%s: %s" % (self.__name__, " | ".join([a if isinstance(a, basestring) else str(a) for a in args])))
-
- def logDebug(self, *args):
- self.log.debug("%s: %s" % (self.__name__, " | ".join([a if isinstance(a, basestring) else str(a) for a in args])))
-
-
- def setConf(self, option, value):
- """ see `setConfig` """
- self.core.config.setPlugin(self.__name__, option, value)
-
- def setConfig(self, option, value):
- """ Set config value for current plugin
-
- :param option:
- :param value:
- :return:
- """
- self.setConf(option, value)
-
- def getConf(self, option):
- """ see `getConfig` """
- return self.core.config.getPlugin(self.__name__, option)
-
- def getConfig(self, option):
- """ Returns config value for current plugin
-
- :param option:
- :return:
- """
- return self.getConf(option)
-
- def setStorage(self, key, value):
- """ Saves a value persistently to the database """
- self.core.db.setStorage(self.__name__, key, value)
-
- def store(self, key, value):
- """ same as `setStorage` """
- self.core.db.setStorage(self.__name__, key, value)
-
- def getStorage(self, key=None, default=None):
- """ Retrieves saved value or dict of all saved entries if key is None """
- if key is not None:
- return self.core.db.getStorage(self.__name__, key) or default
- return self.core.db.getStorage(self.__name__, key)
-
- def retrieve(self, *args, **kwargs):
- """ same as `getStorage` """
- return self.getStorage(*args, **kwargs)
-
- def delStorage(self, key):
- """ Delete entry in db """
- self.core.db.delStorage(self.__name__, key)
-
-
class Plugin(Base):
"""
Base plugin for hoster/crypter.
Overwrite `process` / `decrypt` in your subclassed plugin.
"""
- __name__ = "Plugin"
- __version__ = "0.4"
- __pattern__ = None
- __type__ = "hoster"
- __config__ = [("name", "type", "desc", "default")]
- __description__ = """Base Plugin"""
- __author_name__ = ("RaNaN", "spoob", "mkaay")
- __author_mail__ = ("RaNaN@pyload.org", "spoob@pyload.org", "mkaay@mkaay.de")
-
def __init__(self, pyfile):
Base.__init__(self, pyfile.m.core)
@@ -167,26 +75,26 @@ class Plugin(Base):
self.ocr = None #captcha reader instance
#: account handler instance, see :py:class:`Account`
- self.account = pyfile.m.core.accountManager.getAccountPlugin(self.__name__)
+ self.account = self.core.accountManager.getAccountForPlugin(self.__name__)
#: premium status
self.premium = False
#: username/login
self.user = None
- if self.account and not self.account.canUse(): self.account = None
+ if self.account and not self.account.isUsable(): self.account = None
if self.account:
- self.user, data = self.account.selectAccount()
+ self.user, data = self.account.loginname, {} #TODO change plugins to not use data anymore
#: Browser instance, see `network.Browser`
- self.req = self.account.getAccountRequest(self.user)
+ self.req = self.account.getAccountRequest()
self.chunkLimit = -1 # chunk limit, -1 for unlimited
#: enables resume (will be ignored if server dont accept chunks)
self.resumeDownload = True
self.multiDL = True #every hoster with account should provide multiple downloads
#: premium status
- self.premium = self.account.isPremium(self.user)
+ self.premium = self.account.isPremium()
else:
- self.req = pyfile.m.core.requestFactory.getRequest(self.__name__)
+ self.req = self.core.requestFactory.getRequest(self.__name__)
#: associated pyfile instance, see `PyFile`
self.pyfile = pyfile
@@ -226,7 +134,7 @@ class Plugin(Base):
self.thread = thread
if self.account:
- self.account.checkLogin(self.user)
+ self.account.checkLogin()
else:
self.req.clearCookies()
@@ -350,7 +258,7 @@ class Plugin(Base):
temp_file.write(img)
temp_file.close()
- has_plugin = self.__name__ in self.core.pluginManager.captchaPlugins
+ has_plugin = self.__name__ in self.core.pluginManager.getPlugins("captcha")
if self.core.captcha:
Ocr = self.core.pluginManager.loadClass("captcha", self.__name__)
diff --git a/module/plugins/PluginManager.py b/module/plugins/PluginManager.py
index f3f5f47bc..18dea7699 100644
--- a/module/plugins/PluginManager.py
+++ b/module/plugins/PluginManager.py
@@ -21,24 +21,34 @@ import re
import sys
from os import listdir, makedirs
-from os.path import isfile, join, exists, abspath
+from os.path import isfile, join, exists, abspath, basename
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 new_collections import namedtuple
+
+# ignore these plugin configs, mainly because plugins were wiped out
+IGNORE = (
+ "FreakshareNet", "SpeedManager", "ArchiveTo", "ShareCx", ('hooks', 'UnRar'),
+ 'EasyShareCom', 'FlyshareCz'
+ )
+
+PluginTuple = namedtuple("PluginTuple", "version re 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)
+ # 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
@@ -47,15 +57,24 @@ 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()
+
+ self.core.config.parseValues(self.core.config.PLUGIN)
+
#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"""
-
+ # add to path, so we can import from userplugins
sys.path.append(abspath(""))
if not exists("userplugins"):
@@ -64,27 +83,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=None):
+ """ Analyze and parses all plugins in folder """
plugins = {}
if home:
pfolder = join("userplugins", folder)
@@ -100,10 +106,6 @@ class PluginManager:
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 version_info[0:2] != (2, 5):
continue
elif f.endswith("_26.pyc") and version_info[0:2] != (2, 6):
@@ -111,146 +113,174 @@ class PluginManager:
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]
- version = self.VERSION.findall(content)
- if version:
- version = float(version[0][1])
- else:
- version = 0
+ plugin = self.parsePlugin(join(pfolder, f), folder, name, home)
+ if plugin:
+ plugins[name] = plugin
- # home contains plugins from pyload root
- if home and name in home:
- if home[name]["v"] >= version:
- continue
+ if not home:
+ temp = self.parse(folder, plugins)
+ plugins.update(temp)
- if name in IGNORE or (folder, name) in IGNORE:
- continue
+ return plugins
- plugins[name] = {}
- plugins[name]["v"] = version
+ def parsePlugin(self, filename, folder, name, home=None):
+ """ Parses a plugin from disk, folder means plugin type in this context. Also sets config.
- module = f.replace(".pyc", "").replace(".py", "")
+ :arg home: dict with plugins, of which the found one will be matched against (according version)
+ :returns PluginTuple"""
- # the plugin is loaded from user directory
- plugins[name]["user"] = True if home else False
- plugins[name]["name"] = module
+ data = open(filename, "rb")
+ content = data.read()
+ data.close()
- if pattern:
- pattern = self.PATTERN.findall(content)
+ attrs = {}
+ for m in 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])
+ return
+ 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])
- if pattern:
- pattern = pattern[0][1]
- else:
- pattern = "^unmachtable$"
+ version = 0
- plugins[name]["pattern"] = pattern
+ 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")
- try:
- plugins[name]["re"] = re.compile(pattern)
- except:
- self.log.error(_("%s has a invalid pattern.") % name)
+ # 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
- # internals have no config
- if folder == "internal":
- self.core.config.deleteConfig(name)
- continue
+ if "pattern" in attrs and attrs["pattern"]:
+ try:
+ plugin_re = re.compile(attrs["pattern"])
+ except:
+ self.logDebug(folder, name, "Invalid regexp pattern '%s'" % attrs["pattern"])
+ plugin_re = None
+ else: plugin_re = None
- 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 ""
+ deps = attrs.get("dependencies", None)
- if type(config[0]) == tuple:
- config = [list(x) for x in config]
- else:
- config = [list(config)]
+ # create plugin tuple
+ plugin = PluginTuple(version, plugin_re, deps, bool(home), filename)
- if folder == "hooks":
- append = True
- for item in config:
- if item[0] == "activated": append = False
- # activated flag missing
- if append: config.append(["activated", "bool", "Activated", False])
+ # internals have no config
+ if folder == "internal":
+ return plugin
- try:
- self.core.config.addPluginConfig(name, config, desc)
- except:
- self.log.error("Invalid config in %s: %s" % (name, config))
+ if folder == "hooks" and "config" not in attrs:
+ attrs["config"] = (["activated", "bool", "Activated", False],)
- elif folder == "hooks": #force config creation
- desc = self.DESC.findall(content)
- desc = desc[0][1] if desc else ""
- 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", "")
- try:
- self.core.config.addPluginConfig(name, config, desc)
- except:
- self.log.error("Invalid config in %s: %s" % (name, config))
+ if type(config[0]) == tuple:
+ config = [list(x) for x in config]
+ else:
+ config = [list(config)]
- if not home:
- temp = self.parse(folder, pattern, plugins)
- plugins.update(temp)
+ if folder == "hooks":
+ append = True
+ for item in config:
+ if item[0] == "activated": append = False
- return plugins
+ # activated flag missing
+ if append: config.insert(0, ("activated", "bool", "Activated", False))
+
+ 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"""
- last = None
res = [] # tupels of (url, plugin)
for url in urls:
- if type(url) not in (str, unicode, buffer): continue
+ if type(url) not in (str, unicode, buffer):
+ self.log.debug("Parsing invalid type %s" % type(url))
+ 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 and self.history[0] != 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]:
- return self.plugins[ptype][name], ptype
+ return ptype, self.plugins[ptype][name]
return None, None
def getPlugin(self, name, original=False):
"""return plugin module from hoster|decrypter|container"""
- plugin, type = self.findPlugin(name)
+ type, plugin = self.findPlugin(name)
if not plugin:
self.log.warning("Plugin %s not found." % name)
- plugin = self.hosterPlugins["BasePlugin"]
+ name = "BasePlugin"
- if "new_module" in plugin and not original:
- return plugin["new_module"]
+ if (type, name) in self.modules and not original:
+ return self.modules[(type, name)]
return self.loadModule(type, name)
def getPluginName(self, name):
""" used to obtain new name if other plugin was injected"""
- plugin, type = self.findPlugin(name)
+ type, plugin = self.findPlugin(name)
- if "new_name" in plugin:
- return plugin["new_name"]
+ if (type, name) in self.names:
+ return self.names[(type, name)]
return name
@@ -262,11 +292,12 @@ 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
+ # 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)})
@@ -278,9 +309,17 @@ class PluginManager:
module = self.loadModule(type, name)
if module: return getattr(module, name)
- def getAccountPlugins(self):
- """return list of account plugin names"""
- return self.accountPlugins.keys()
+ def injectPlugin(self, type, name, module, new_name):
+ """ Overwrite a plugin with a other module. used by Multihoster """
+ self.modules[(type, name)] = module
+ self.names[(type, name)] = new_name
+
+ def restoreState(self, type, name):
+ """ Restore the state of a plugin after injecting """
+ if (type, name) in self.modules:
+ del self.modules[(type, name)]
+ if (type, name) in self.names:
+ del self.names[(type, name)]
def find_module(self, fullname, path=None):
#redirecting imports if necesarry
@@ -294,10 +333,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
@@ -329,7 +368,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:
@@ -342,16 +381,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()
@@ -359,6 +395,23 @@ class PluginManager:
return True
+ def loadIcons(self):
+ """Loads all icons from plugins, plugin type is not in result, because its not important here.
+
+ :return: Dict of names mapped to icons
+ """
+ pass
+
+ def loadIcon(self, type, 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
if __name__ == "__main__":
diff --git a/module/plugins/hooks/UpdateManager.py b/module/plugins/hooks/UpdateManager.py
index 920a88060..4324a96ba 100644
--- a/module/plugins/hooks/UpdateManager.py
+++ b/module/plugins/hooks/UpdateManager.py
@@ -24,7 +24,7 @@ from os import stat
from os.path import join, exists
from time import time
-from module.ConfigParser import IGNORE
+from module.plugins.PluginManager import IGNORE
from module.network.RequestFactory import getURL
from module.plugins.Hook import threaded, Expose, Hook
@@ -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/module/plugins/internal/MultiHoster.py b/module/plugins/internal/MultiHoster.py
index d50df3943..872e0b770 100644
--- a/module/plugins/internal/MultiHoster.py
+++ b/module/plugins/internal/MultiHoster.py
@@ -5,6 +5,7 @@ import re
from module.utils import remove_chars
from module.plugins.Hook import Hook
+from module.plugins.PluginManager import PluginTuple
class MultiHoster(Hook):
"""
@@ -43,7 +44,7 @@ class MultiHoster(Hook):
def coreReady(self):
pluginMap = {}
- for name in self.core.pluginManager.hosterPlugins.keys():
+ for name in self.core.pluginManager.getPlugins("hoster").keys():
pluginMap[name.lower()] = name
new_supported = []
@@ -66,25 +67,19 @@ class MultiHoster(Hook):
# inject plugin plugin
self.logDebug("Overwritten Hosters: %s" % ", ".join(sorted(self.supported)))
for hoster in self.supported:
- dict = self.core.pluginManager.hosterPlugins[hoster]
- dict["new_module"] = module
- dict["new_name"] = self.__name__
+ self.core.pluginManager.injectPlugin("hoster", hoster, module, self.__name__)
self.logDebug("New Hosters: %s" % ", ".join(sorted(new_supported)))
# create new regexp
regexp = r".*(%s).*" % "|".join([klass.__pattern__] + [x.replace(".", "\\.") for x in new_supported])
- dict = self.core.pluginManager.hosterPlugins[self.__name__]
- dict["pattern"] = regexp
- dict["re"] = re.compile(regexp)
+ hoster = self.core.pluginManager.getPlugins("hoster")
+ p = hoster[self.__name__]
+ new = PluginTuple(p.version, re.compile(regexp), p.deps, p.user, p.path)
+ hoster[self.__name__] = new
def unload(self):
for hoster in self.supported:
- dict = self.core.pluginManager.hosterPlugins[hoster]
- if "module" in dict:
- del dict["module"]
-
- del dict["new_module"]
- del dict["new_name"] \ No newline at end of file
+ self.core.pluginManager.restoreState("hoster", hoster) \ No newline at end of file