summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--module/plugins/crypter/EmbeduploadCom.py2
-rw-r--r--module/plugins/crypter/SafelinkingNet.py2
-rw-r--r--module/plugins/crypter/ShSt.py2
-rw-r--r--module/plugins/crypter/XupPl.py2
-rw-r--r--module/plugins/hooks/ExtractArchive.py16
-rw-r--r--module/plugins/hooks/UpdateManager.py251
-rw-r--r--module/plugins/hoster/BitshareCom.py2
-rw-r--r--module/plugins/hoster/DlFreeFr.py8
-rw-r--r--module/plugins/hoster/FreeWayMe.py4
-rw-r--r--module/plugins/hoster/OneFichierCom.py2
-rw-r--r--module/plugins/hoster/SmoozedCom.py2
-rw-r--r--module/plugins/internal/Account.py2
-rw-r--r--module/plugins/internal/Addon.py14
-rw-r--r--module/plugins/internal/Base.py44
-rw-r--r--module/plugins/internal/Crypter.py23
-rw-r--r--module/plugins/internal/Hoster.py50
-rw-r--r--module/plugins/internal/MultiHoster.py4
-rw-r--r--module/plugins/internal/Plugin.py89
-rw-r--r--module/plugins/internal/SimpleCrypter.py12
-rw-r--r--module/plugins/internal/SimpleHoster.py2
-rw-r--r--module/plugins/internal/UnRar.py2
-rw-r--r--module/plugins/internal/XFSCrypter.py6
-rw-r--r--module/plugins/internal/XFSHoster.py6
23 files changed, 320 insertions, 227 deletions
diff --git a/module/plugins/crypter/EmbeduploadCom.py b/module/plugins/crypter/EmbeduploadCom.py
index e4a9387ae..957e1efb2 100644
--- a/module/plugins/crypter/EmbeduploadCom.py
+++ b/module/plugins/crypter/EmbeduploadCom.py
@@ -55,7 +55,7 @@ class EmbeduploadCom(Crypter):
try:
header = self.load(link, just_header=True)
if 'location' in header:
- new_links.append(header['location'])
+ new_links.append(header.get('location'))
except BadHeader:
pass
return new_links
diff --git a/module/plugins/crypter/SafelinkingNet.py b/module/plugins/crypter/SafelinkingNet.py
index c5fac837a..a11ae2cd8 100644
--- a/module/plugins/crypter/SafelinkingNet.py
+++ b/module/plugins/crypter/SafelinkingNet.py
@@ -34,7 +34,7 @@ class SafelinkingNet(Crypter):
header = self.load(url, just_header=True)
if 'location' in header:
- self.urls = [header['location']]
+ self.urls = [header.get('location')]
else:
self.error(_("Couldn't find forwarded Link"))
diff --git a/module/plugins/crypter/ShSt.py b/module/plugins/crypter/ShSt.py
index 43cc4e779..429d3f3e2 100644
--- a/module/plugins/crypter/ShSt.py
+++ b/module/plugins/crypter/ShSt.py
@@ -27,5 +27,5 @@ class ShSt(Crypter):
self.req.http.c.setopt(pycurl.USERAGENT, "curl/7.42.1")
#: Fetch the target URL
header = self.load(self.pyfile.url, just_header = True, decode = False)
- target_url = header['location']
+ target_url = header.get('location')
self.urls.append(target_url)
diff --git a/module/plugins/crypter/XupPl.py b/module/plugins/crypter/XupPl.py
index ac918a6de..458372d13 100644
--- a/module/plugins/crypter/XupPl.py
+++ b/module/plugins/crypter/XupPl.py
@@ -21,6 +21,6 @@ class XupPl(Crypter):
def decrypt(self, pyfile):
header = self.load(pyfile.url, just_header=True)
if 'location' in header:
- self.urls = [header['location']]
+ self.urls = [header.get('location')]
else:
self.fail(_("Unable to find link"))
diff --git a/module/plugins/hooks/ExtractArchive.py b/module/plugins/hooks/ExtractArchive.py
index 47ed708be..034a4b81a 100644
--- a/module/plugins/hooks/ExtractArchive.py
+++ b/module/plugins/hooks/ExtractArchive.py
@@ -63,23 +63,15 @@ class ArchiveQueue(object):
def get(self):
- try:
- return [int(pid) for pid in self.plugin.retrieve("ExtractArchive:%s" % self.storage, "").decode('base64').split()]
-
- except Exception:
- return []
+ return self.plugin.retrieve(self.storage, default=[])
def set(self, value):
- if isinstance(value, list):
- item = str(value)[1:-1].replace(' ', '').replace(',', ' ')
- else:
- item = str(value).strip()
- return self.plugin.store("ExtractArchive:%s" % self.storage, item.encode('base64')[:-1])
+ return self.plugin.store(self.storage, value)
def delete(self):
- return self.plugin.delete("ExtractArchive:%s" % self.storage)
+ return self.plugin.delete(self.storage)
def add(self, item):
@@ -107,7 +99,7 @@ class ArchiveQueue(object):
class ExtractArchive(Addon):
__name__ = "ExtractArchive"
__type__ = "hook"
- __version__ = "1.51"
+ __version__ = "1.52"
__status__ = "testing"
__config__ = [("activated" , "bool" , "Activated" , True ),
diff --git a/module/plugins/hooks/UpdateManager.py b/module/plugins/hooks/UpdateManager.py
index fdaa928eb..34b992d5b 100644
--- a/module/plugins/hooks/UpdateManager.py
+++ b/module/plugins/hooks/UpdateManager.py
@@ -16,7 +16,7 @@ from module.utils import fs_encode, save_join as fs_join
class UpdateManager(Addon):
__name__ = "UpdateManager"
__type__ = "hook"
- __version__ = "0.58"
+ __version__ = "1.00"
__status__ = "testing"
__config__ = [("activated" , "bool", "Activated" , True ),
@@ -32,7 +32,10 @@ class UpdateManager(Addon):
__authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
- SERVER_URL = "http://updatemanager.pyload.org"
+ _VERSION = re.compile(r'__version__.*=.*("|\')([\d.]+)')
+
+ SERVER_URL = "http://updatemanager.pyload.org"
+
PERIODICAL_INTERVAL = 3 * 60 * 60 #: 3 hours
@@ -40,6 +43,7 @@ class UpdateManager(Addon):
if self.checkonstart:
self.pyload.api.pauseServer()
self.update()
+
if self.do_restart is False:
self.pyload.api.unpauseServer()
@@ -47,7 +51,7 @@ class UpdateManager(Addon):
def init(self):
- self.info = {'pyload': False, 'version': None, 'plugins': False, 'last_check': time.time()}
+ self.info = {'pyload': False, 'plugins': False, 'last_check': time.time()}
self.mtimes = {} #: Store modification time for each plugin
self.event_map = {'allDownloadsProcessed': "all_downloads_processed"}
@@ -93,14 +97,12 @@ class UpdateManager(Addon):
"""
Reload and reindex all modified plugins
"""
+ reloads = []
modules = filter(
lambda m: m and (m.__name__.startswith("module.plugins.") or
m.__name__.startswith("userplugins.")) and
m.__name__.count(".") >= 2, sys.modules.values()
)
-
- reloads = []
-
for m in modules:
root, type, name = m.__name__.rsplit(".", 2)
id = (type, name)
@@ -113,6 +115,7 @@ class UpdateManager(Addon):
if id not in self.mtimes:
self.mtimes[id] = mtime
+
elif self.mtimes[id] < mtime:
reloads.append(id)
self.mtimes[id] = mtime
@@ -120,14 +123,25 @@ class UpdateManager(Addon):
return True if self.pyload.pluginManager.reloadPlugins(reloads) else False
- def server_response(self):
+ def server_response(self, line=None):
try:
- return self.load(self.SERVER_URL,
- get={'v': self.pyload.api.getServerVersion()}).splitlines()
+ html = self.load(self.SERVER_URL,
+ get={'v': self.pyload.api.getServerVersion()})
except Exception:
self.log_warning(_("Unable to retrieve server to get updates"))
+ else:
+ res = html.splitlines()
+
+ if line is not None:
+ try:
+ res = res[line]
+ except IndexError:
+ res = None
+
+ return res
+
@Expose
@threaded
@@ -135,35 +149,34 @@ class UpdateManager(Addon):
"""
Check for updates
"""
- if self._update() == 2 and self.get_config('autorestart'):
- if not self.pyload.api.statusDownloads():
- self.pyload.api.restart()
- else:
- self.do_restart = True
- self.log_warning(_("Downloads are active, will restart once the download is done"))
- self.pyload.api.pauseServer()
+ if self._update() is not 2 or not self.get_config('autorestart'):
+ return
+
+ if not self.pyload.api.statusDownloads():
+ self.pyload.api.restart()
+ else:
+ self.do_restart = True
+ self.log_warning(_("Downloads are active, will restart once the download is done"))
+ self.pyload.api.pauseServer()
def _update(self):
- data = self.server_response()
+ newversion = self.server_response(0)
+ self.info['pyload'] = False
self.info['last_check'] = time.time()
- if not data:
+ if not newversion:
exitcode = 0
- elif data[0] == "None":
+ elif newversion == "None":
self.log_info(_("No new pyLoad version available"))
- exitcode = self._update_plugins(data[1:])
-
- elif onlyplugin:
- exitcode = 0
+ exitcode = self.update_plugins()
else:
- self.log_info(_("*** New pyLoad Version %s available ***") % data[0])
+ self.log_info(_("*** New pyLoad Version %s available ***") % newversion)
self.log_info(_("*** Get it here: https://github.com/pyload/pyload/releases ***"))
- self.info['pyload'] = True
- self.info['version'] = data[0]
+ self.info['pyload'] = True
exitcode = 3
#: Exit codes:
@@ -174,64 +187,101 @@ class UpdateManager(Addon):
return exitcode
- def _update_plugins(self, data):
- """
- Check for plugin updates
- """
- exitcode = 0
- updated = []
+ @Expose
+ def update_plugins(self):
+ updates = self.server_response()
+
+ if not updates or updates[0] != "None":
+ return 0
- url = data[0]
- schema = data[1].split('|')
+ updated = self._update_plugins(updates)
+
+ if updated:
+ self.log_info(_("*** Plugins updated ***"))
- VERSION = re.compile(r'__version__.*=.*("|\')([\d.]+)')
+ if self.pyload.pluginManager.reloadPlugins(updated):
+ exitcode = 1
+ else:
+ self.log_warning(_("You have to restart pyLoad to reload the updated plugins"))
+ self.info['plugins'] = True
+ exitcode = 2
- if "BLACKLIST" in data:
- blacklist = data[data.index('BLACKLIST') + 1:]
- updatelist = data[2:data.index('BLACKLIST')]
+ self.manager.dispatchEvent("plugin_updated", updated)
+ else:
+ self.log_info(_("*** No plugin updates available ***"))
+ exitcode = 0
+
+ #: Exit codes:
+ #: 0 = No plugin updated
+ #: 1 = Plugins updated
+ #: 2 = Plugins updated, but restart required
+ return exitcode
+
+
+ def parse_list(self, list):
+ schema = list[2].split('|')
+
+ if "BLACKLIST" in list:
+ blacklist = list[list.index('BLACKLIST') + 1:]
+ updatelist = list[3:list.index('BLACKLIST')]
else:
blacklist = []
- updatelist = data[2:]
+ updatelist = list[3:]
- updatelist = [dict(zip(schema, x.split('|'))) for x in updatelist]
- blacklist = [dict(zip(schema, x.split('|'))) for x in blacklist]
+ for l in updatelist, blacklist:
+ nl = []
+ for line in l:
+ d = dict(zip(schema, line.split('|')))
+ d['name'] = d['name'].rsplit('.py', 1)[0]
+ d['type'] = d['type'].rstrip('s')
+ nl.append(d)
+ l[:] = nl
- if blacklist:
- type_plugins = [(plugin['type'], plugin['name'].rsplit('.', 1)[0]) for plugin in blacklist]
+ updatelist = sorted(updatelist, key=operator.itemgetter("type", "name"))
+ blacklist = sorted(blacklist, key=operator.itemgetter("type", "name"))
- #: Protect UpdateManager from self-removing
- try:
- type_plugins.remove(("hook", "UpdateManager"))
- except ValueError:
- pass
+ return updatelist, blacklist
+
+
+ def _update_plugins(self, updates):
+ """
+ Check for plugin updates
+ """
+ updated = []
+
+ updatelist, blacklist = self.parse_list(updates)
+
+ url = updates[1]
- for t, n in type_plugins:
- for idx, plugin in enumerate(updatelist):
- if n is plugin['name'] and t is plugin['type']:
- updatelist.pop(idx)
- break
+ if blacklist:
+ #@NOTE: Protect UpdateManager from self-removing
+ type_plugins = [(plugin['type'], plugin['name']) for plugin in blacklist \
+ if plugin['name'] is not self.__name__ and plugin['type'] is not self.__type__]
+
+ c = 1
+ l = len(type_plugins)
+ for idx, plugin in enumerate(updatelist):
+ if c > l:
+ break
+ name = plugin['name']
+ type = plugin['type']
+ for t, n in type_plugins:
+ if n != name or t != type:
+ continue
+ updatelist.pop(idx)
+ c += 1
+ break
- for t, n in self.remove_plugins(sorted(type_plugins)):
+ for t, n in self.remove_plugins(type_plugins):
self.log_info(_("Removed blacklisted plugin: %(type)s %(name)s") % {
'type': t.upper(),
'name': n,
})
- for plugin in sorted(updatelist, key=operator.itemgetter("type", "name")):
- filename = plugin['name']
- prefix = plugin['type']
- version = plugin['version']
-
- if filename.endswith(".pyc"):
- name = filename[:filename.find("_")]
- else:
- name = filename.replace(".py", "")
-
- #@TODO: Remove in 0.4.10
- if prefix.endswith("s"):
- type = prefix[:-1]
- else:
- type = prefix
+ for plugin in updatelist:
+ name = plugin['name']
+ type = plugin['type']
+ version = plugin['version']
plugins = getattr(self.pyload.pluginManager, "%sPlugins" % type)
@@ -239,50 +289,38 @@ class UpdateManager(Addon):
newver = float(version)
if not oldver:
- msg = "New plugin: [%(type)s] %(name)s (v%(newver).2f)"
+ msg = "New plugin: %(type)s %(name)s (v%(newver).2f)"
elif newver > oldver:
- msg = "New version of plugin: [%(type)s] %(name)s (v%(oldver).2f -> v%(newver).2f)"
+ msg = "New version of plugin: %(type)s %(name)s (v%(oldver).2f -> v%(newver).2f)"
else:
continue
- self.log_info(_(msg) % {'type' : type,
- 'name' : name,
- 'oldver': oldver,
- 'newver': newver})
+ self.log_info(_(msg) % {'type' : type.upper(),
+ 'name' : name,
+ 'oldver': oldver,
+ 'newver': newver})
try:
- content = self.load(url % plugin, decode=False)
- m = VERSION.search(content)
+ content = self.load(url % plugin + ".py", decode=False)
+ m = self._VERSION.search(content)
if m and m.group(2) == version:
- with open(fs_join("userplugins", prefix, filename), "wb") as f:
+ #@TODO: Remove in 0.4.10
+ if type in ("account", "hook"):
+ folder = type + "s"
+ else:
+ folder = type
+
+ with open(fs_join("userplugins", folder, name + ".py"), "wb") as f:
f.write(fs_encode(content))
- updated.append((prefix, name))
+ updated.append((type, name))
else:
raise Exception(_("Version mismatch"))
except Exception, e:
- self.log_error(_("Error updating plugin: [%s] %s") % (type, name), e)
+ self.log_error(_("Error updating plugin: %s %s") % (type.upper(), name), e)
- if updated:
- self.log_info(_("*** Plugins updated ***"))
-
- if self.pyload.pluginManager.reloadPlugins(updated):
- exitcode = 1
- else:
- self.log_warning(_("You have to restart pyLoad to reload the updated plugins"))
- self.info['plugins'] = True
- exitcode = 2
-
- self.manager.dispatchEvent("plugin_updated", updated)
- else:
- self.log_info(_("No plugin updates available"))
-
- #: Exit codes:
- #: 0 = No plugin updated
- #: 1 = Plugins updated
- #: 2 = Plugins updated, but restart required
- return exitcode
+ return updated
#: Deprecated method, use `remove_plugins` instead
@@ -309,16 +347,17 @@ class UpdateManager(Addon):
for type, name in type_plugins:
rootplugins = os.path.join(pypath, "module", "plugins")
- for dir in ("userplugins", rootplugins):
- py_filename = fs_join(dir, type, name + ".py")
-
- #@TODO: Remove in 0.4.10
- if type == "hook":
- py_filename = fs_join(dir, "hooks" , name + ".py")
+ #@TODO: Remove in 0.4.10
+ if type in ("account", "hook"):
+ folder = type + "s"
+ else:
+ folder = type
+ for dir in ("userplugins", rootplugins):
+ py_filename = fs_join(dir, folder, name + ".py")
pyc_filename = py_filename + "c"
- if type == "hook":
+ if type is "hook":
try:
self.manager.deactivateHook(name)
diff --git a/module/plugins/hoster/BitshareCom.py b/module/plugins/hoster/BitshareCom.py
index e426de092..5b9abe7cc 100644
--- a/module/plugins/hoster/BitshareCom.py
+++ b/module/plugins/hoster/BitshareCom.py
@@ -84,7 +84,7 @@ class BitshareCom(SimpleHoster):
if self.premium:
header = self.load(self.pyfile.url, just_header=True)
if 'location' in header:
- return header['location']
+ return header.get('location')
#: Get download info
self.log_debug("Getting download info")
diff --git a/module/plugins/hoster/DlFreeFr.py b/module/plugins/hoster/DlFreeFr.py
index f77b9596a..6c094636e 100644
--- a/module/plugins/hoster/DlFreeFr.py
+++ b/module/plugins/hoster/DlFreeFr.py
@@ -125,12 +125,14 @@ class DlFreeFr(SimpleHoster):
value = value.strip()
if key in header:
- if type(header[key]) is list:
- header[key].append(value)
+ header_key = header.get(key)
+ if type(header_key) is list:
+ header_key.append(value)
else:
- header[key] = [header[key], value]
+ header[key] = [header_key, value]
else:
header[key] = value
+
return header
diff --git a/module/plugins/hoster/FreeWayMe.py b/module/plugins/hoster/FreeWayMe.py
index c0053fc76..501b544c6 100644
--- a/module/plugins/hoster/FreeWayMe.py
+++ b/module/plugins/hoster/FreeWayMe.py
@@ -38,13 +38,13 @@ class FreeWayMe(MultiHoster):
just_header=True)
if 'location' in header:
- headers = self.load(header['location'], just_header=True)
+ headers = self.load(header.get('location'), just_header=True)
if headers['code'] == 500:
#: Error on 2nd stage
self.log_error(_("Error [stage2]"))
else:
#: Seems to work..
- self.download(header['location'])
+ self.download(header.get('location'))
break
else:
#: Error page first stage
diff --git a/module/plugins/hoster/OneFichierCom.py b/module/plugins/hoster/OneFichierCom.py
index a8e7f6dc8..6c1d4ab82 100644
--- a/module/plugins/hoster/OneFichierCom.py
+++ b/module/plugins/hoster/OneFichierCom.py
@@ -99,7 +99,7 @@ class OneFichierCom(SimpleHoster):
def handle_free(self, pyfile):
self.check_errors()
- url, inputs = self.parse_html_form('action="https://1fichier.com/\?[a-zA-Z0-9]+')
+ url, inputs = self.parse_html_form('action="https://1fichier.com/\?[\w^_]+')
if not url:
return
diff --git a/module/plugins/hoster/SmoozedCom.py b/module/plugins/hoster/SmoozedCom.py
index e864bb2c0..29768d50b 100644
--- a/module/plugins/hoster/SmoozedCom.py
+++ b/module/plugins/hoster/SmoozedCom.py
@@ -59,4 +59,4 @@ class SmoozedCom(MultiHoster):
if not "location" in header:
self.fail(_("Unable to initialize download"))
else:
- self.link = header['location'][-1] if isinstance(header['location'], list) else header['location']
+ self.link = header.get('location')[-1] if isinstance(header.get('location'), list) else header.get('location')
diff --git a/module/plugins/internal/Account.py b/module/plugins/internal/Account.py
index a0c46a6a1..a1ecdd76f 100644
--- a/module/plugins/internal/Account.py
+++ b/module/plugins/internal/Account.py
@@ -40,7 +40,7 @@ class Account(Plugin):
#: Callback of periodical job task
self.cb = None
- self.interval = None
+ self.interval = self.PERIODICAL_INTERVAL
self.init()
diff --git a/module/plugins/internal/Addon.py b/module/plugins/internal/Addon.py
index 47c5584f5..bdde514c0 100644
--- a/module/plugins/internal/Addon.py
+++ b/module/plugins/internal/Addon.py
@@ -23,7 +23,7 @@ def threaded(fn):
class Addon(Plugin):
__name__ = "Addon"
__type__ = "hook" #@TODO: Change to `addon` in 0.4.10
- __version__ = "0.11"
+ __version__ = "0.12"
__status__ = "testing"
__threaded__ = [] #@TODO: Remove in 0.4.10
@@ -53,7 +53,7 @@ class Addon(Plugin):
#: Callback of periodical job task, used by HookManager
self.cb = None
- self.interval = None
+ self.interval = self.PERIODICAL_INTERVAL
self.init()
self.init_events()
@@ -132,6 +132,14 @@ class Addon(Plugin):
raise NotImplementedError
+ def save_info(self):
+ self.store("info", self.info)
+
+
+ def restore_info(self):
+ self.retrieve("info", self.info)
+
+
@property
def activated(self):
"""
@@ -154,6 +162,7 @@ class Addon(Plugin):
#: Deprecated method, use `deactivate` instead (Remove in 0.4.10)
def unload(self, *args, **kwargs):
+ self.save_info()
return self.deactivate(*args, **kwargs)
@@ -166,6 +175,7 @@ class Addon(Plugin):
#: Deprecated method, use `activate` instead (Remove in 0.4.10)
def coreReady(self, *args, **kwargs):
+ self.restore_info()
return self.activate(*args, **kwargs)
diff --git a/module/plugins/internal/Base.py b/module/plugins/internal/Base.py
index 423e53695..e3aaf202b 100644
--- a/module/plugins/internal/Base.py
+++ b/module/plugins/internal/Base.py
@@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
-import re
import inspect
import mimetypes
import os
+import re
import time
import urlparse
@@ -47,7 +47,7 @@ def check_abort(fn):
class Base(Plugin):
__name__ = "Base"
__type__ = "base"
- __version__ = "0.09"
+ __version__ = "0.11"
__status__ = "testing"
__pattern__ = r'^unmatchable$'
@@ -64,6 +64,9 @@ class Base(Plugin):
def __init__(self, pyfile):
self._init(pyfile.m.core)
+ #:
+ self.premium = None
+
#: Engage wan reconnection
self.wantReconnect = False #@TODO: Change to `want_reconnect` in 0.4.10
@@ -95,6 +98,9 @@ class Base(Plugin):
#: Dict of the amount of retries already made
self.retries = {}
+ self.init_base()
+ self.init()
+
def _log(self, level, plugintype, pluginname, messages):
log = getattr(self.pyload.log, level)
@@ -124,6 +130,10 @@ class Base(Plugin):
return info
+ def init_base(self):
+ pass
+
+
def init(self):
"""
Initialize the plugin (in addition to `__init__`)
@@ -131,6 +141,10 @@ class Base(Plugin):
pass
+ def setup_base(self):
+ pass
+
+
def setup(self):
"""
Setup for enviroment and other things, called before downloading (possibly more than one time)
@@ -156,16 +170,13 @@ class Base(Plugin):
pass
if self.account:
- self.req = self.pyload.requestFactory.getRequest(self.__name__, self.account.user)
- self.chunk_limit = -1 #: -1 for unlimited
- self.resume_download = True
- self.premium = self.account.info['data']['premium'] #: Don't use `self.account.premium` to avoid one unnecessary get_info call
+ self.req = self.pyload.requestFactory.getRequest(self.__name__, self.account.user)
+ self.premium = self.account.info['data']['premium'] #@NOTE: Avoid one unnecessary get_info call by `self.account.premium` here
else:
- self.req = self.pyload.requestFactory.getRequest(self.__name__)
- self.chunk_limit = 1
- self.resume_download = False
- self.premium = False
+ self.req = self.pyload.requestFactory.getRequest(self.__name__)
+ self.premium = False
+ self.setup_base()
self.setup()
@@ -306,7 +317,7 @@ class Base(Plugin):
if msg:
self.pyfile.error = msg
else:
- msg = self.pyfile.error or (self.info['error'] if 'error' in self.info else self.pyfile.getStatusName())
+ msg = self.pyfile.error or self.info.get('error') or self.pyfile.getStatusName()
raise Fail(encode(msg)) #@TODO: Remove `encode` in 0.4.10
@@ -464,10 +475,11 @@ class Base(Plugin):
value = value.strip()
if key in header:
- if type(header[key]) is list:
- header[key].append(value)
+ header_key = header.get(key)
+ if type(header_key) is list:
+ header_key.append(value)
else:
- header[key] = [header[key], value]
+ header[key] = [header_key, value]
else:
header[key] = value
@@ -475,7 +487,7 @@ class Base(Plugin):
link = url
elif header.get('location'):
- location = self.fixurl(header['location'], url)
+ location = self.fixurl(header.get('location'), url)
if header.get('code') == 302:
link = location
@@ -488,7 +500,7 @@ class Base(Plugin):
extension = os.path.splitext(parse_name(url))[-1]
if header.get('content-type'):
- mimetype = header['content-type'].split(';')[0].strip()
+ mimetype = header.get('content-type').split(';')[0].strip()
elif extension:
mimetype = mimetypes.guess_type(extension, False)[0] or "application/octet-stream"
diff --git a/module/plugins/internal/Crypter.py b/module/plugins/internal/Crypter.py
index db13e445c..20322bb33 100644
--- a/module/plugins/internal/Crypter.py
+++ b/module/plugins/internal/Crypter.py
@@ -1,13 +1,14 @@
# -*- coding: utf-8 -*-
-from module.plugins.internal.Base import Base, parse_name
+from module.plugins.internal.Base import Base, check_abort, create_getInfo, parse_fileInfo
+from module.plugins.internal.Plugin import parse_name
from module.utils import save_path as safe_filename
class Crypter(Base):
__name__ = "Crypter"
__type__ = "crypter"
- __version__ = "0.12"
+ __version__ = "0.13"
__status__ = "testing"
__pattern__ = r'^unmatchable$'
@@ -20,22 +21,12 @@ class Crypter(Base):
__authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
- def __init__(self, *args, **kwargs):
- super(Crypter, self).__init__(*args, **kwargs)
+ def init_base(self):
+ self.packages = [] #: Put all packages here. It's a list of tuples like: ( name, [list of links], folder )
+ self.urls = [] #: List of urls, pyLoad will generate packagenames
- #: Put all packages here. It's a list of tuples like: ( name, [list of links], folder )
- self.packages = []
-
- #: List of urls, pyLoad will generate packagenames
- self.urls = []
-
- self._setup()
- self.init()
-
-
- def _setup(self):
- super(Crypter, self)._setup()
+ def setup_base(self):
self.packages = []
self.urls = []
diff --git a/module/plugins/internal/Hoster.py b/module/plugins/internal/Hoster.py
index c65946413..d81154554 100644
--- a/module/plugins/internal/Hoster.py
+++ b/module/plugins/internal/Hoster.py
@@ -5,7 +5,7 @@ from __future__ import with_statement
import os
import re
-from module.plugins.internal.Base import Base, check_abort, create_getInfo, getInfo, parse_fileInfo
+from module.plugins.internal.Base import Base, check_abort, create_getInfo, parse_fileInfo
from module.plugins.internal.Plugin import Fail, Retry, encode, exists, fixurl, parse_name
from module.utils import fs_decode, fs_encode, save_join as fs_join, save_path as safe_filename
@@ -13,7 +13,7 @@ from module.utils import fs_decode, fs_encode, save_join as fs_join, save_path a
class Hoster(Base):
__name__ = "Hoster"
__type__ = "hoster"
- __version__ = "0.36"
+ __version__ = "0.37"
__status__ = "testing"
__pattern__ = r'^unmatchable$'
@@ -26,11 +26,15 @@ class Hoster(Base):
__authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
- def __init__(self, *args, **kwargs):
- super(Hoster, self).__init__(*args, **kwargs)
-
+ def init_base(self):
#: Enable simultaneous processing of multiple downloads
- self.limitDL = 0 #@TODO: Change to `limit_dl` in 0.4.10
+ self.limitDL = 0 #@TODO: Change to `limit_dl` in 0.4.10
+
+ #:
+ self.chunk_limit = None
+
+ #:
+ self.resume_download = False
#: Location where the last call to download was saved
self.last_download = None
@@ -41,17 +45,19 @@ class Hoster(Base):
#: Restart flag
self.rst_free = False #@TODO: Recheck in 0.4.10
- self._setup()
- self.init()
-
-
- def _setup(self):
- super(Hoster, self)._setup()
+ def setup_base(self):
self.last_download = None
self.last_check = None
self.rst_free = False
+ if self.account:
+ self.chunk_limit = -1 #: -1 for unlimited
+ self.resume_download = True
+ else:
+ self.chunk_limit = 1
+ self.resume_download = False
+
def load_account(self):
if self.rst_free:
@@ -76,7 +82,8 @@ class Hoster(Base):
self.pyfile.setStatus("starting")
try:
- self.log_debug("PROCESS URL " + self.pyfile.url, "PLUGIN VERSION %s" % self.__version__) #@TODO: Remove in 0.4.10
+ self.log_debug("PROCESS URL " + self.pyfile.url,
+ "PLUGIN VERSION %s" % self.__version__) #@TODO: Remove in 0.4.10
self.process(self.pyfile)
self.check_abort()
@@ -94,7 +101,7 @@ class Hoster(Base):
@check_abort
- def download(self, url, get={}, post={}, ref=True, cookies=True, disposition=True):
+ def download(self, url, get={}, post={}, ref=True, cookies=True, disposition=True, resume=None, chunks=None):
"""
Downloads the content at url to download folder
@@ -141,10 +148,16 @@ class Hoster(Base):
self.check_abort()
+ chunks = min(self.pyload.config.get("download", "chunks"), chunks or self.chunk_limit or -1)
+
+ if resume is None:
+ resume = self.resume_download
+
try:
- newname = self.req.httpDownload(url, filename, get=get, post=post, ref=ref, cookies=cookies,
- chunks=self.get_chunk_count(), resume=self.resume_download,
- progressNotify=self.pyfile.setProgress, disposition=disposition)
+ newname = self.req.httpDownload(url, filename, get=get, post=post, ref=ref,
+ cookies=cookies, chunks=chunks, resume=resume,
+ progressNotify=self.pyfile.setProgress,
+ disposition=disposition)
finally:
self.pyfile.size = self.req.size
@@ -159,7 +172,8 @@ class Hoster(Base):
os.rename(oldname_enc, newname_enc)
except OSError, e:
- self.log_warning(_("Error renaming `%s` to `%s`") % (newname, finalname), e)
+ self.log_warning(_("Error renaming `%s` to `%s`")
+ % (newname, finalname), e)
finalname = newname
self.log_info(_("`%s` saved as `%s`") % (self.pyfile.name, finalname))
diff --git a/module/plugins/internal/MultiHoster.py b/module/plugins/internal/MultiHoster.py
index f5c3d091d..231615ae5 100644
--- a/module/plugins/internal/MultiHoster.py
+++ b/module/plugins/internal/MultiHoster.py
@@ -104,8 +104,8 @@ class MultiHoster(SimpleHoster):
self.log_warning(_("Premium download failed"))
self.restart(premium=False)
- elif self.get_config("revertfailed", True) \
- and "new_module" in self.pyload.pluginManager.hosterPlugins[self.__name__]:
+ elif self.get_config("revertfailed", True) and \
+ self.pyload.pluginManager.hosterPlugins[self.__name__].get('new_module'):
hdict = self.pyload.pluginManager.hosterPlugins[self.__name__]
tmp_module = hdict['new_module']
diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py
index d6eac7e58..a2392fdcc 100644
--- a/module/plugins/internal/Plugin.py
+++ b/module/plugins/internal/Plugin.py
@@ -6,6 +6,7 @@ import datetime
import inspect
import os
import re
+import sys
import time
import traceback
import urllib
@@ -17,17 +18,38 @@ if os.name is not "nt":
import grp
import pwd
+from module.common.json_layer import json_dumps, json_loads
from module.plugins.Plugin import Abort, Fail, Reconnect, Retry, SkipDownload as Skip #@TODO: Remove in 0.4.10
-from module.utils import fs_encode, fs_decode, html_unescape, parseFileSize as parse_size, save_join as fs_join
+from module.utils import (fs_encode, fs_decode, get_console_encoding, html_unescape,
+ parseFileSize as parse_size, save_join as fs_join)
#@TODO: Move to utils in 0.4.10
-def decode(string, encoding='utf8'):
- """ Decode string to unicode with utf8 """
+def isiterable(obj):
+ return hasattr(obj, "__iter__")
+
+
+#@TODO: Move to utils in 0.4.10
+def decode(string, encoding=None):
+ """Encoded string (default to UTF-8) -> unicode string"""
if type(string) is str:
- return string.decode(encoding, "replace")
+ try:
+ res = unicode(string, encoding or "utf-8")
+
+ except UnicodeDecodeError, e:
+ if encoding:
+ raise UnicodeDecodeError(e)
+
+ encoding = get_console_encoding(sys.stdout.encoding)
+ res = unicode(string, encoding)
+
+ elif type(string) is unicode:
+ res = string
+
else:
- return unicode(string)
+ res = unicode(string)
+
+ return res
#@TODO: Remove in 0.4.10
@@ -36,12 +58,18 @@ def _decode(*args, **kwargs):
#@TODO: Move to utils in 0.4.10
-def encode(string, encoding='utf8'):
- """ Decode string to utf8 """
+def encode(string, encoding=None, decoding=None):
+ """Unicode or decoded string -> encoded string (default to UTF-8)"""
if type(string) is unicode:
- return string.encode(encoding, "replace")
+ res = string.encode(encoding or "utf-8")
+
+ elif type(string) is str:
+ res = encode(decode(string, decoding), encoding)
+
else:
- return str(string)
+ res = str(string)
+
+ return res
#@TODO: Move to utils in 0.4.10
@@ -186,11 +214,11 @@ def parse_html_tag_attr_value(attr_name, tag):
def parse_html_form(attr_str, html, input_names={}):
for form in re.finditer(r"(?P<TAG><form[^>]*%s[^>]*>)(?P<CONTENT>.*?)</?(form|body|html)[^>]*>" % attr_str,
- html, re.S | re.I):
+ html, re.I | re.S):
inputs = {}
action = parse_html_tag_attr_value("action", form.group('TAG'))
- for inputtag in re.finditer(r'(<(input|textarea)[^>]*>)([^<]*(?=</\2)|)', form.group('CONTENT'), re.S | re.I):
+ for inputtag in re.finditer(r'(<(input|textarea)[^>]*>)([^<]*(?=</\2)|)', form.group('CONTENT'), re.I | re.S):
name = parse_html_tag_attr_value("name", inputtag.group(1))
if name:
value = parse_html_tag_attr_value("value", inputtag.group(1))
@@ -234,7 +262,7 @@ def chunks(iterable, size):
class Plugin(object):
__name__ = "Plugin"
__type__ = "plugin"
- __version__ = "0.52"
+ __version__ = "0.53"
__status__ = "testing"
__pattern__ = r'^unmatchable$'
@@ -301,7 +329,7 @@ class Plugin(object):
def log_error(self, *args, **kwargs):
self._log("error", self.__type__, self.__name__, args)
- if kwargs.get('trace'):
+ if self.pyload.debug and kwargs.get('trace', True):
print "Traceback (most recent call last):"
traceback.print_stack()
@@ -338,12 +366,6 @@ class Plugin(object):
self.log_warning(_("Setting owner and group failed"), e)
- def get_chunk_count(self):
- if self.chunk_limit <= 0:
- return self.pyload.config.get("download", "chunks")
- return min(self.pyload.config.get("download", "chunks"), self.chunk_limit)
-
-
def set_config(self, option, value, plugin=None):
"""
Set config value for current plugin
@@ -374,14 +396,26 @@ class Plugin(object):
"""
Saves a value persistently to the database
"""
- self.pyload.db.setStorage(self.__name__, key, value)
+ value = map(decode, value) if isiterable(value) else decode(value)
+ entry = json_dumps(value).encode('base64')
+ self.pyload.db.setStorage(self.__name__, key, entry)
- def retrieve(self, key, default=None):
+ def retrieve(self, key=None, default=None):
"""
Retrieves saved value or dict of all saved entries if key is None
"""
- return self.pyload.db.getStorage(self.__name__, key) or default
+ entry = self.pyload.db.getStorage(self.__name__, key)
+
+ if entry:
+ if type(entry) is dict:
+ value = dict((k, json_loads(v.decode('base64'))) for k, v in value.items()) or default
+ else:
+ value = json_loads(entry.decode('base64')) or default
+ else:
+ value = entry
+
+ return value
def delete(self, key):
@@ -456,13 +490,13 @@ class Plugin(object):
frame = inspect.currentframe()
try:
- framefile = fs_join("tmp", self.__name__, "%s_line%s.dump.html" % (frame.f_back.f_code.co_name, frame.f_back.f_lineno))
+ framefile = fs_join("tmp", self.__name__, "%s_line%s.dump.html" %
+ (frame.f_back.f_code.co_name, frame.f_back.f_lineno))
if not exists(os.path.join("tmp", self.__name__)):
os.makedirs(os.path.join("tmp", self.__name__))
with open(framefile, "wb") as f:
-
f.write(encode(html))
except IOError, e:
@@ -487,10 +521,11 @@ class Plugin(object):
value = value.strip()
if key in header:
- if type(header[key]) is list:
- header[key].append(value)
+ header_key = header.get(key)
+ if type(header_key) is list:
+ header_key.append(value)
else:
- header[key] = [header[key], value]
+ header[key] = [header_key, value]
else:
header[key] = value
diff --git a/module/plugins/internal/SimpleCrypter.py b/module/plugins/internal/SimpleCrypter.py
index d4ecd3117..ba4235072 100644
--- a/module/plugins/internal/SimpleCrypter.py
+++ b/module/plugins/internal/SimpleCrypter.py
@@ -10,7 +10,7 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
class SimpleCrypter(Crypter, SimpleHoster):
__name__ = "SimpleCrypter"
__type__ = "crypter"
- __version__ = "0.66"
+ __version__ = "0.67"
__status__ = "testing"
__pattern__ = r'^unmatchable$'
@@ -82,20 +82,16 @@ class SimpleCrypter(Crypter, SimpleHoster):
#@TODO: Remove in 0.4.10
def _setup(self):
orig_name = self.__name__
- self.__name__ = (orig_name + ".py").replace("Folder.py", "").replace(".py", "")
-
+ self.__name__ = re.sub(r'Folder$', "", self.__name__)
super(SimpleCrypter, self)._setup()
-
self.__name__ = orig_name
#@TODO: Remove in 0.4.10
def load_account(self):
orig_name = self.__name__
- self.__name__ = (orig_name + ".py").replace("Folder.py", "").replace(".py", "")
-
+ self.__name__ = re.sub(r'Folder$', "", self.__name__)
super(SimpleCrypter, self).load_account()
-
self.__name__ = orig_name
@@ -106,7 +102,7 @@ class SimpleCrypter(Crypter, SimpleHoster):
header = self.load(redirect, just_header=True)
if header.get('location'):
- self.link = header['location']
+ self.link = header.get('location')
else:
break
else:
diff --git a/module/plugins/internal/SimpleHoster.py b/module/plugins/internal/SimpleHoster.py
index 0f27ecc91..cf74c6646 100644
--- a/module/plugins/internal/SimpleHoster.py
+++ b/module/plugins/internal/SimpleHoster.py
@@ -270,7 +270,7 @@ class SimpleHoster(Hoster):
if not self.link and not self.last_download:
self.preload()
- if 'status' not in self.info or self.info['status'] is 3: #@TODO: Recheck in 0.4.10
+ if self.info.get('status', 3) is 3: #@TODO: Recheck in 0.4.10
self.check_info()
if self.premium and (not self.CHECK_TRAFFIC or self.check_traffic()):
diff --git a/module/plugins/internal/UnRar.py b/module/plugins/internal/UnRar.py
index f31a386a7..6f85c286a 100644
--- a/module/plugins/internal/UnRar.py
+++ b/module/plugins/internal/UnRar.py
@@ -38,7 +38,7 @@ class UnRar(Extractor):
re_multipart = re.compile(r'\.(part|r)(\d+)(?:\.rar)?(\.rev|\.bad)?', re.I)
re_filefixed = re.compile(r'Building (.+)')
- re_filelist = re.compile(r'^(.)(\s*[\w\-.]+)\s+(\d+\s+)+(?:\d+\%\s+)?[\d\-]{8}\s+[\d\:]{5}', re.M|re.I)
+ re_filelist = re.compile(r'^(.)(\s*[\w\-.]+)\s+(\d+\s+)+(?:\d+\%\s+)?[\d\-]{8}\s+[\d\:]{5}', re.I | re.M)
re_wrongpwd = re.compile(r'password', re.I)
re_wrongcrc = re.compile(r'encrypted|damaged|CRC failed|checksum error|corrupt', re.I)
diff --git a/module/plugins/internal/XFSCrypter.py b/module/plugins/internal/XFSCrypter.py
index dd2fba568..7ec9f3895 100644
--- a/module/plugins/internal/XFSCrypter.py
+++ b/module/plugins/internal/XFSCrypter.py
@@ -1,5 +1,7 @@
# -*- coding: utf-8 -*-
+import re
+
from module.plugins.internal.Plugin import set_cookie
from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
@@ -7,7 +9,7 @@ from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo
class XFSCrypter(SimpleCrypter):
__name__ = "XFSCrypter"
__type__ = "crypter"
- __version__ = "0.17"
+ __version__ = "0.18"
__status__ = "testing"
__pattern__ = r'^unmatchable$'
@@ -49,7 +51,7 @@ class XFSCrypter(SimpleCrypter):
if self.account:
account = self.account
else:
- account_name = (self.__name__ + ".py").replace("Folder.py", "").replace(".py", "")
+ account_name = re.sub(r'Folder$', "", self.__name__)
account = self.pyload.accountManager.getAccountPlugin(account_name)
if account and hasattr(account, "PLUGIN_DOMAIN") and account.PLUGIN_DOMAIN:
diff --git a/module/plugins/internal/XFSHoster.py b/module/plugins/internal/XFSHoster.py
index 80ef9a977..06715d2f1 100644
--- a/module/plugins/internal/XFSHoster.py
+++ b/module/plugins/internal/XFSHoster.py
@@ -158,7 +158,7 @@ class XFSHoster(SimpleHoster):
action, inputs = self.parse_html_form('F1')
if not inputs:
- self.retry(msg=self.info['error'] if 'error' in self.info else _("TEXTAREA F1 not found"))
+ self.retry(msg=self.info.get('error') or _("TEXTAREA F1 not found"))
self.log_debug(inputs)
@@ -184,7 +184,7 @@ class XFSHoster(SimpleHoster):
header = self.load(m.group(1), just_header=True)
if 'location' in header: #: Direct download link
- self.link = header['location']
+ self.link = header.get('location')
def get_post_parameters(self):
@@ -196,7 +196,7 @@ class XFSHoster(SimpleHoster):
if not inputs:
action, inputs = self.parse_html_form('F1')
if not inputs:
- self.retry(msg=self.info['error'] if 'error' in self.info else _("TEXTAREA F1 not found"))
+ self.retry(msg=self.info.get('error') or _("TEXTAREA F1 not found"))
self.log_debug(inputs)