summaryrefslogtreecommitdiffstats
path: root/pyload/manager
diff options
context:
space:
mode:
Diffstat (limited to 'pyload/manager')
-rw-r--r--pyload/manager/Account.py10
-rw-r--r--pyload/manager/Addon.py17
-rw-r--r--pyload/manager/Captcha.py20
-rw-r--r--pyload/manager/Event.py19
-rw-r--r--pyload/manager/Plugin.py15
-rw-r--r--pyload/manager/Remote.py8
-rw-r--r--pyload/manager/Thread.py21
-rw-r--r--pyload/manager/event/Scheduler.py14
-rw-r--r--pyload/manager/thread/Addon.py5
-rw-r--r--pyload/manager/thread/Decrypter.py2
-rw-r--r--pyload/manager/thread/Download.py6
-rw-r--r--pyload/manager/thread/Info.py6
-rw-r--r--pyload/manager/thread/Plugin.py3
13 files changed, 141 insertions, 5 deletions
diff --git a/pyload/manager/Account.py b/pyload/manager/Account.py
index 12fc970c2..9b7cb590a 100644
--- a/pyload/manager/Account.py
+++ b/pyload/manager/Account.py
@@ -16,7 +16,6 @@ ACC_VERSION = 1
class AccountManager(object):
"""manages all accounts"""
- #----------------------------------------------------------------------
def __init__(self, core):
"""Constructor"""
@@ -64,6 +63,7 @@ class AccountManager(object):
#----------------------------------------------------------------------
+
def loadAccounts(self):
"""loads all accounts available"""
@@ -111,6 +111,7 @@ class AccountManager(object):
#----------------------------------------------------------------------
+
def saveAccounts(self):
"""save all account information"""
@@ -135,6 +136,7 @@ class AccountManager(object):
#----------------------------------------------------------------------
+
def initAccountPlugins(self):
"""init names"""
for name in self.core.pluginManager.getAccountPlugins():
@@ -142,6 +144,8 @@ class AccountManager(object):
@lock
+
+
def updateAccount(self, plugin , user, password=None, options={}):
"""add or update account"""
if plugin in self.accounts:
@@ -154,6 +158,8 @@ class AccountManager(object):
@lock
+
+
def removeAccount(self, plugin, user):
"""remove account"""
@@ -165,6 +171,8 @@ class AccountManager(object):
@lock
+
+
def getAccountInfos(self, force=True, refresh=False):
data = {}
diff --git a/pyload/manager/Addon.py b/pyload/manager/Addon.py
index 9ce3a4f8f..61585e1cb 100644
--- a/pyload/manager/Addon.py
+++ b/pyload/manager/Addon.py
@@ -67,6 +67,7 @@ class AddonManager(object):
def try_catch(func):
+
def new(*args):
try:
return func(*args)
@@ -178,6 +179,8 @@ class AddonManager(object):
@try_catch
+
+
def coreReady(self):
for plugin in self.plugins:
if plugin.isActivated():
@@ -187,6 +190,8 @@ class AddonManager(object):
@try_catch
+
+
def coreExiting(self):
for plugin in self.plugins:
if plugin.isActivated():
@@ -196,6 +201,8 @@ class AddonManager(object):
@lock
+
+
def downloadPreparing(self, pyfile):
for plugin in self.plugins:
if plugin.isActivated():
@@ -205,6 +212,8 @@ class AddonManager(object):
@lock
+
+
def downloadFinished(self, pyfile):
for plugin in self.plugins:
if plugin.isActivated():
@@ -215,6 +224,8 @@ class AddonManager(object):
@lock
@try_catch
+
+
def downloadFailed(self, pyfile):
for plugin in self.plugins:
if plugin.isActivated():
@@ -224,6 +235,8 @@ class AddonManager(object):
@lock
+
+
def packageFinished(self, package):
for plugin in self.plugins:
if plugin.isActivated():
@@ -233,6 +246,8 @@ class AddonManager(object):
@lock
+
+
def beforeReconnecting(self, ip):
for plugin in self.plugins:
plugin.beforeReconnecting(ip)
@@ -241,6 +256,8 @@ class AddonManager(object):
@lock
+
+
def afterReconnecting(self, ip):
for plugin in self.plugins:
if plugin.isActivated():
diff --git a/pyload/manager/Captcha.py b/pyload/manager/Captcha.py
index e54eacf30..0814cf78a 100644
--- a/pyload/manager/Captcha.py
+++ b/pyload/manager/Captcha.py
@@ -9,23 +9,27 @@ from pyload.utils import encode
class CaptchaManager(object):
+
def __init__(self, core):
self.lock = Lock()
self.core = core
self.tasks = [] # task store, for outgoing tasks only
self.ids = 0 # only for internal purpose
+
def newTask(self, img, format, file, result_type):
task = CaptchaTask(self.ids, img, format, file, result_type)
self.ids += 1
return task
+
def removeTask(self, task):
self.lock.acquire()
if task in self.tasks:
self.tasks.remove(task)
self.lock.release()
+
def getTask(self):
self.lock.acquire()
for task in self.tasks:
@@ -35,6 +39,7 @@ class CaptchaManager(object):
self.lock.release()
return None
+
def getTaskByID(self, tid):
self.lock.acquire()
for task in self.tasks:
@@ -44,6 +49,7 @@ class CaptchaManager(object):
self.lock.release()
return None
+
def handleCaptcha(self, task, timeout=50):
cli = self.core.isClientConnected()
@@ -65,6 +71,7 @@ class CaptchaManager(object):
class CaptchaTask(object):
+
def __init__(self, id, img, format, file, result_type='textual'):
self.id = str(id)
self.captchaImg = img
@@ -78,9 +85,11 @@ class CaptchaTask(object):
self.status = "init"
self.data = {} # handler can store data here
+
def getCaptcha(self):
return self.captchaImg, self.captchaFormat, self.captchaResultType
+
def setResult(self, text):
if self.isTextual():
self.result = text
@@ -91,48 +100,59 @@ class CaptchaTask(object):
except Exception:
self.result = None
+
def getResult(self):
return encode(self.result)
+
def getStatus(self):
return self.status
+
def setWaiting(self, sec):
""" let the captcha wait secs for the solution """
self.waitUntil = max(time() + sec, self.waitUntil)
self.status = "waiting"
+
def isWaiting(self):
if self.result or self.error or self.timedOut():
return False
else:
return True
+
def isTextual(self):
""" returns if text is written on the captcha """
return self.captchaResultType == 'textual'
+
def isPositional(self):
""" returns if user have to click a specific region on the captcha """
return self.captchaResultType == 'positional'
+
def setWatingForUser(self, exclusive):
if exclusive:
self.status = "user"
else:
self.status = "shared-user"
+
def timedOut(self):
return time() > self.waitUntil
+
def invalid(self):
""" indicates the captcha was not correct """
for x in self.handler:
x.captchaInvalid(self)
+
def correct(self):
for x in self.handler:
x.captchaCorrect(self)
+
def __str__(self):
return "<CaptchaTask '%s'>" % self.id
diff --git a/pyload/manager/Event.py b/pyload/manager/Event.py
index 20897290e..90aaaca30 100644
--- a/pyload/manager/Event.py
+++ b/pyload/manager/Event.py
@@ -5,18 +5,22 @@ from time import time
from pyload.utils import uniqify
class PullManager(object):
+
def __init__(self, core):
self.core = core
self.clients = []
+
def newClient(self, uuid):
self.clients.append(Client(uuid))
+
def clean(self):
for n, client in enumerate(self.clients):
if client.lastActive + 30 < time():
del self.clients[n]
+
def getEvents(self, uuid):
events = []
validUuid = False
@@ -32,28 +36,34 @@ class PullManager(object):
events = [ReloadAllEvent("queue").toList(), ReloadAllEvent("collector").toList()]
return uniqify(events)
+
def addEvent(self, event):
for client in self.clients:
client.addEvent(event)
class Client(object):
+
def __init__(self, uuid):
self.uuid = uuid
self.lastActive = time()
self.events = []
+
def newEvents(self):
return len(self.events) > 0
+
def popEvent(self):
if not len(self.events):
return None
return self.events.pop(0)
+
def addEvent(self, event):
self.events.append(event)
class UpdateEvent(object):
+
def __init__(self, itype, iid, destination):
assert itype == "pack" or itype == "file"
assert destination == "queue" or destination == "collector"
@@ -61,10 +71,12 @@ class UpdateEvent(object):
self.id = iid
self.destination = destination
+
def toList(self):
return ["update", self.destination, self.type, self.id]
class RemoveEvent(object):
+
def __init__(self, itype, iid, destination):
assert itype == "pack" or itype == "file"
assert destination == "queue" or destination == "collector"
@@ -72,10 +84,12 @@ class RemoveEvent(object):
self.id = iid
self.destination = destination
+
def toList(self):
return ["remove", self.destination, self.type, self.id]
class InsertEvent(object):
+
def __init__(self, itype, iid, after, destination):
assert itype == "pack" or itype == "file"
assert destination == "queue" or destination == "collector"
@@ -84,21 +98,26 @@ class InsertEvent(object):
self.after = after
self.destination = destination
+
def toList(self):
return ["insert", self.destination, self.type, self.id, self.after]
class ReloadAllEvent(object):
+
def __init__(self, destination):
assert destination == "queue" or destination == "collector"
self.destination = destination
+
def toList(self):
return ["reload", self.destination]
class AccountUpdateEvent(object):
+
def toList(self):
return ["account"]
class ConfigUpdateEvent(object):
+
def toList(self):
return ["config"]
diff --git a/pyload/manager/Plugin.py b/pyload/manager/Plugin.py
index 918f6de8a..10abbc2ea 100644
--- a/pyload/manager/Plugin.py
+++ b/pyload/manager/Plugin.py
@@ -25,6 +25,7 @@ class PluginManager(object):
CONFIG = re.compile(r'__config\s*=\s*\[([^\]]+)', re.M)
DESC = re.compile(r'__description\s*=\s*("|"""|\')([^"\']+)')
+
def __init__(self, core):
self.core = core
@@ -34,6 +35,7 @@ class PluginManager(object):
# register for import addon
sys.meta_path.append(self)
+
def loadTypes(self):
rootdir = join(pypath, "pyload", "plugin")
userdir = "userplugins"
@@ -46,6 +48,7 @@ class PluginManager(object):
self.TYPES = list(set(self.TYPES) | types)
+
def createIndex(self):
"""create information for all plugins available"""
@@ -64,6 +67,7 @@ class PluginManager(object):
self.core.log.debug("Created index of plugins")
+
def parse(self, folder, rootplugins={}):
"""
returns dict with information
@@ -179,6 +183,7 @@ class PluginManager(object):
return plugins
+
def parseUrls(self, urls):
"""parse plugins for given list of urls"""
@@ -217,6 +222,7 @@ class PluginManager(object):
print res
return res
+
def findPlugin(self, type, name):
if type not in self.plugins:
return None
@@ -229,6 +235,7 @@ class PluginManager(object):
else:
return self.plugins[type][name]
+
def getPlugin(self, type, name, original=False):
"""return plugin module from hoster|decrypter|container"""
plugin = self.findPlugin(type, name)
@@ -241,6 +248,7 @@ class PluginManager(object):
else:
return self.loadModule(type, name)
+
def getPluginName(self, type, name):
""" used to obtain new name if other plugin was injected"""
plugin = self.findPlugin(type, name)
@@ -253,6 +261,7 @@ class PluginManager(object):
return name
+
def loadModule(self, type, name):
""" Returns loaded module for plugin
@@ -282,6 +291,7 @@ class PluginManager(object):
% {'name': name, 'type': type, 'version': plugins[name]['version']})
return module
+
def loadClass(self, type, name):
"""Returns the class of a plugin with the same name"""
module = self.loadModule(type, name)
@@ -290,10 +300,12 @@ class PluginManager(object):
else:
return None
+
def getAccountPlugins(self):
"""return list of account plugin names"""
return self.accountPlugins.keys()
+
def find_module(self, fullname, path=None):
# redirecting imports if necesarry
if fullname.startswith(self.ROOT) or fullname.startswith(self.USERROOT): # seperate pyload plugins
@@ -312,6 +324,7 @@ class PluginManager(object):
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:
@@ -333,6 +346,7 @@ class PluginManager(object):
return sys.modules[name]
+
def reloadPlugins(self, type_plugins):
""" reload and reindex plugins """
if not type_plugins:
@@ -378,6 +392,7 @@ class PluginManager(object):
return reloaded #: return a list of the plugins successfully reloaded
+
def reloadPlugin(self, type_plugin):
""" reload and reindex ONE plugin """
return True if self.reloadPlugins(type_plugin) else False
diff --git a/pyload/manager/Remote.py b/pyload/manager/Remote.py
index 910881164..4fdb36fc2 100644
--- a/pyload/manager/Remote.py
+++ b/pyload/manager/Remote.py
@@ -5,6 +5,7 @@ from threading import Thread
from traceback import print_exc
class BackendBase(Thread):
+
def __init__(self, manager):
Thread.__init__(self)
self.m = manager
@@ -12,6 +13,7 @@ class BackendBase(Thread):
self.enabled = True
self.running = False
+
def run(self):
self.running = True
try:
@@ -23,18 +25,23 @@ class BackendBase(Thread):
finally:
self.running = False
+
def setup(self, host, port):
pass
+
def checkDeps(self):
return True
+
def serve(self):
pass
+
def shutdown(self):
pass
+
def stop(self):
self.enabled = False# set flag and call shutdowm message, so thread can react
self.shutdown()
@@ -43,6 +50,7 @@ class BackendBase(Thread):
class RemoteManager(object):
available = []
+
def __init__(self, core):
self.core = core
self.backends = []
diff --git a/pyload/manager/Thread.py b/pyload/manager/Thread.py
index 753a8c251..dd8e6bcce 100644
--- a/pyload/manager/Thread.py
+++ b/pyload/manager/Thread.py
@@ -54,12 +54,14 @@ class ThreadManager(object):
for i in range(0, self.core.config.get("download", "max_downloads")):
self.createThread()
+
def createThread(self):
"""create a download thread"""
thread = DownloadThread(self)
self.threads.append(thread)
+
def createInfoThread(self, data, pid):
"""
start a thread whichs fetches online status and other infos
@@ -70,6 +72,8 @@ class ThreadManager(object):
InfoThread(self, data, pid)
@lock
+
+
def createResultThread(self, data, add=False):
""" creates a thread to fetch online status, returns result id """
self.timestamp = time() + 5 * 60
@@ -82,6 +86,8 @@ class ThreadManager(object):
return rid
@lock
+
+
def getInfoResult(self, rid):
"""returns result and clears it"""
self.timestamp = time() + 5 * 60
@@ -94,9 +100,12 @@ class ThreadManager(object):
return {}
@lock
+
+
def setInfoResults(self, rid, result):
self.infoResults[rid].update(result)
+
def getActiveFiles(self):
active = [x.active for x in self.threads if x.active and isinstance(x.active, PyFile)]
@@ -105,10 +114,12 @@ class ThreadManager(object):
return active
+
def processingIds(self):
"""get a id list of all pyfiles processed"""
return [x.id for x in self.getActiveFiles()]
+
def work(self):
"""run all task which have to be done (this is for repetivive call by core)"""
try:
@@ -136,7 +147,9 @@ class ThreadManager(object):
self.infoResults.clear()
self.core.log.debug("Cleared Result cache")
+
#--------------------------------------------------------------------------
+
def tryReconnect(self):
"""checks if reconnect needed"""
@@ -189,6 +202,7 @@ class ThreadManager(object):
self.reconnecting.clear()
+
def getIP(self):
"""retrieve current ip"""
services = [("http://automation.whatismyip.com/n09230945.asp", "(\S+)"),
@@ -207,7 +221,9 @@ class ThreadManager(object):
return ip
+
#--------------------------------------------------------------------------
+
def checkThreadCount(self):
"""checks if there are need for increasing or reducing thread count"""
@@ -220,6 +236,7 @@ class ThreadManager(object):
if free:
free[0].put("quit")
+
def cleanPycurl(self):
""" make a global curl cleanup (currently ununused) """
if self.processingIds():
@@ -230,7 +247,9 @@ class ThreadManager(object):
self.core.log.debug("Cleaned up pycurl")
return True
+
#--------------------------------------------------------------------------
+
def assignJob(self):
"""assing a job to a thread if possible"""
@@ -287,10 +306,12 @@ class ThreadManager(object):
else:
thread = DecrypterThread(self, job)
+
def getLimit(self, thread):
limit = thread.active.plugin.account.getAccountData(thread.active.plugin.user)["options"].get("limitDL", ["0"])[0]
return int(limit)
+
def cleanup(self):
"""do global cleanup, should be called when finished with pycurl"""
pycurl.global_cleanup()
diff --git a/pyload/manager/event/Scheduler.py b/pyload/manager/event/Scheduler.py
index 2cb537383..d67d9063a 100644
--- a/pyload/manager/event/Scheduler.py
+++ b/pyload/manager/event/Scheduler.py
@@ -11,13 +11,16 @@ class AlreadyCalled(Exception):
class Deferred(object):
+
def __init__(self):
self.call = []
self.result = ()
+
def addCallback(self, f, *cargs, **ckwargs):
self.call.append((f, cargs, ckwargs))
+
def callback(self, *args, **kwargs):
if self.result:
raise AlreadyCalled
@@ -29,11 +32,13 @@ class Deferred(object):
class Scheduler(object):
+
def __init__(self, core):
self.core = core
self.queue = PriorityQueue()
+
def addJob(self, t, call, args=[], kwargs={}, threaded=True):
d = Deferred()
t += time()
@@ -41,6 +46,7 @@ class Scheduler(object):
self.queue.put((t, j))
return d
+
def removeJob(self, d):
"""
:param d: defered object
@@ -58,6 +64,7 @@ class Scheduler(object):
return False
+
def work(self):
while True:
t, j = self.queue.get()
@@ -72,6 +79,7 @@ class Scheduler(object):
class Job(object):
+
def __init__(self, time, call, args=[], kwargs={}, deferred=None, threaded=True):
self.time = float(time)
self.call = call
@@ -80,6 +88,7 @@ class Job(object):
self.deferred = deferred
self.threaded = threaded
+
def run(self):
ret = self.call(*self.args, **self.kwargs)
if self.deferred is None:
@@ -87,6 +96,7 @@ class Job(object):
else:
self.deferred.callback(ret)
+
def start(self):
if self.threaded:
t = Thread(target=self.run)
@@ -103,17 +113,21 @@ class PriorityQueue(object):
self.queue = []
self.lock = Lock()
+
def __iter__(self):
return iter(self.queue)
+
def __delitem__(self, key):
del self.queue[key]
+
def put(self, element):
self.lock.acquire()
heappush(self.queue, element)
self.lock.release()
+
def get(self):
""" return element or None """
self.lock.acquire()
diff --git a/pyload/manager/thread/Addon.py b/pyload/manager/thread/Addon.py
index 7feec227e..f3d219989 100644
--- a/pyload/manager/thread/Addon.py
+++ b/pyload/manager/thread/Addon.py
@@ -20,7 +20,6 @@ from pyload.manager.thread.Plugin import PluginThread
class AddonThread(PluginThread):
"""thread for addons"""
- #--------------------------------------------------------------------------
def __init__(self, m, function, args, kwargs):
"""Constructor"""
PluginThread.__init__(self, m)
@@ -35,20 +34,24 @@ class AddonThread(PluginThread):
self.start()
+
def getActiveFiles(self):
return self.active
+
def addActive(self, pyfile):
""" Adds a pyfile to active list and thus will be displayed on overview"""
if pyfile not in self.active:
self.active.append(pyfile)
+
def finishFile(self, pyfile):
if pyfile in self.active:
self.active.remove(pyfile)
pyfile.finishIfDone()
+
def run(self):
try:
try:
diff --git a/pyload/manager/thread/Decrypter.py b/pyload/manager/thread/Decrypter.py
index 12806163c..308e94f10 100644
--- a/pyload/manager/thread/Decrypter.py
+++ b/pyload/manager/thread/Decrypter.py
@@ -33,9 +33,11 @@ class DecrypterThread(PluginThread):
self.start()
+
def getActiveFiles(self):
return [self.active]
+
def run(self):
"""run method"""
diff --git a/pyload/manager/thread/Download.py b/pyload/manager/thread/Download.py
index 37fe844ec..fc76b655e 100644
--- a/pyload/manager/thread/Download.py
+++ b/pyload/manager/thread/Download.py
@@ -21,8 +21,6 @@ from pyload.plugin.Plugin import Abort, Fail, Reconnect, Retry, SkipDownload
class DownloadThread(PluginThread):
"""thread for downloading files from 'real' hoster plugins"""
- #--------------------------------------------------------------------------
-
def __init__(self, manager):
"""Constructor"""
PluginThread.__init__(self, manager)
@@ -32,7 +30,9 @@ class DownloadThread(PluginThread):
self.start()
+
#--------------------------------------------------------------------------
+
def run(self):
"""run method"""
pyfile = None
@@ -201,10 +201,12 @@ class DownloadThread(PluginThread):
pyfile.finishIfDone()
self.m.core.files.save()
+
def put(self, job):
"""assing job to thread"""
self.queue.put(job)
+
def stop(self):
"""stops the thread"""
self.put("quit")
diff --git a/pyload/manager/thread/Info.py b/pyload/manager/thread/Info.py
index edc9489e9..487c3b924 100644
--- a/pyload/manager/thread/Info.py
+++ b/pyload/manager/thread/Info.py
@@ -36,6 +36,7 @@ class InfoThread(PluginThread):
self.start()
+
def run(self):
"""run method"""
@@ -120,9 +121,11 @@ class InfoThread(PluginThread):
self.m.timestamp = time() + 5 * 60
+
def updateDB(self, plugin, result):
self.m.core.files.updateFileInfo(result, self.pid)
+
def updateResult(self, plugin, result, force=False):
# parse package name and generate result
# accumulate results
@@ -144,9 +147,11 @@ class InfoThread(PluginThread):
self.cache = []
+
def updateCache(self, plugin, result):
self.cache.extend(result)
+
def fetchForPlugin(self, pluginname, plugin, urls, cb, err=None):
try:
result = [] # result loaded from cache
@@ -184,6 +189,7 @@ class InfoThread(PluginThread):
result = [(url, 0, 3, url) for url in urls]
cb(pluginname, result)
+
def decryptContainer(self, plugin, url):
data = []
# only works on container plugins
diff --git a/pyload/manager/thread/Plugin.py b/pyload/manager/thread/Plugin.py
index 1e7d7b4e4..155e687d4 100644
--- a/pyload/manager/thread/Plugin.py
+++ b/pyload/manager/thread/Plugin.py
@@ -23,7 +23,6 @@ from pyload.api import OnlineStatus
class PluginThread(Thread):
"""abstract base class for thread types"""
- #--------------------------------------------------------------------------
def __init__(self, manager):
"""Constructor"""
Thread.__init__(self)
@@ -70,6 +69,7 @@ class PluginThread(Thread):
self.m.core.log.info("Debug Report written to %s" % dump_name)
+
def getDebugDump(self, pyfile):
dump = "pyLoad %s Debug Report of %s %s \n\nTRACEBACK:\n %s \n\nFRAMESTACK:\n" % (
self.m.core.api.getServerVersion(), pyfile.pluginname, pyfile.plugin.__version, format_exc())
@@ -124,6 +124,7 @@ class PluginThread(Thread):
return dump
+
def clean(self, pyfile):
""" set thread unactive and release pyfile """
self.active = False