diff options
Diffstat (limited to 'module/plugins/internal')
-rw-r--r-- | module/plugins/internal/Account.py | 458 | ||||
-rw-r--r-- | module/plugins/internal/Addon.py | 1 | ||||
-rw-r--r-- | module/plugins/internal/Container.py | 4 | ||||
-rw-r--r-- | module/plugins/internal/Crypter.py | 6 | ||||
-rw-r--r-- | module/plugins/internal/Extractor.py | 3 | ||||
-rw-r--r-- | module/plugins/internal/Hook.py | 2 | ||||
-rw-r--r-- | module/plugins/internal/Hoster.py | 244 | ||||
-rw-r--r-- | module/plugins/internal/MultiAccount.py (renamed from module/plugins/internal/MultiHook.py) | 59 | ||||
-rw-r--r-- | module/plugins/internal/MultiCrypter.py | 4 | ||||
-rw-r--r-- | module/plugins/internal/MultiHoster.py | 14 | ||||
-rw-r--r-- | module/plugins/internal/Plugin.py | 65 | ||||
-rw-r--r-- | module/plugins/internal/SevenZip.py | 10 | ||||
-rw-r--r-- | module/plugins/internal/SimpleCrypter.py | 6 | ||||
-rw-r--r-- | module/plugins/internal/SimpleHoster.py | 51 | ||||
-rw-r--r-- | module/plugins/internal/UnRar.py | 6 | ||||
-rw-r--r-- | module/plugins/internal/UnZip.py | 1 | ||||
-rw-r--r-- | module/plugins/internal/XFSAccount.py | 43 | ||||
-rw-r--r-- | module/plugins/internal/XFSCrypter.py | 18 | ||||
-rw-r--r-- | module/plugins/internal/XFSHoster.py | 26 |
19 files changed, 541 insertions, 480 deletions
diff --git a/module/plugins/internal/Account.py b/module/plugins/internal/Account.py index de338cd33..196589e85 100644 --- a/module/plugins/internal/Account.py +++ b/module/plugins/internal/Account.py @@ -1,11 +1,10 @@ # -*- coding: utf-8 -*- -import copy import random import time import threading -import traceback +from module.plugins.Plugin import SkipDownload as Skip from module.plugins.internal.Plugin import Plugin from module.utils import compare_time, lock, parseFileSize as parse_size @@ -13,7 +12,7 @@ from module.utils import compare_time, lock, parseFileSize as parse_size class Account(Plugin): __name__ = "Account" __type__ = "account" - __version__ = "0.18" + __version__ = "0.52" __status__ = "testing" __description__ = """Base account plugin""" @@ -21,18 +20,23 @@ class Account(Plugin): __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - LOGIN_TIMEOUT = 10 * 60 #: After that time (in minutes) pyload will relogin the account - INFO_THRESHOLD = 30 * 60 #: After that time (in minutes) account data will be reloaded + LOGIN_TIMEOUT = 10 * 60 #: Relogin accounts every 10 minutes + AUTO_TIMEOUT = True #: Automatically adjust relogin interval def __init__(self, manager, accounts): self._init(manager.core) - self.lock = threading.RLock() - self.accounts = accounts #@TODO: Remove in 0.4.10 + self.manager = manager + self.lock = threading.RLock() + + self.accounts = accounts #@TODO: Recheck in 0.4.10 + self.user = None + + self.interval = self.LOGIN_TIMEOUT + self.auto_timeout = self.interval if self.AUTO_TIMEOUT else False self.init() - self.init_accounts(accounts) def init(self): @@ -42,218 +46,172 @@ class Account(Plugin): pass - def login(self, user, password, data, req): + @property + def logged(self): """ - Login into account, the cookies will be saved so user can be recognized + Checks if user is still logged in """ - pass - - - @lock - def _login(self, user): - try: - info = self.info[user] - info['login']['timestamp'] = time.time() #: Set timestamp for login - - self.req = self.get_request(user) - self.login(user, info['login']['password'], info['data'], self.req) - - except Exception, e: - self.log_warning(_("Could not login user `%s`") % user, e) - res = info['login']['valid'] = False - self.accounts[user]['valid'] = False #@TODO: Remove in 0.4.10 + if not self.user: + return False - if self.pyload.debug: - traceback.print_exc() + self.sync() + if self.info['login']['timestamp'] + self.interval < time.time(): + self.log_debug("Reached login timeout for user `%s`" % self.user) + return False else: - res = info['login']['valid'] = True - self.accounts[user]['valid'] = True #@TODO: Remove in 0.4.10 - - finally: - self.clean() - return res + return True - def relogin(self, user): - self.log_info(_("Relogin user `%s`...") % user) + @property + def premium(self): + return bool(self.get_data('premium')) - req = self.get_request(user) - if req: - req.clearCookies() - self.clean() - return self._login(user) + def signin(self, user, password, data): + """ + Login into account, the cookies will be saved so user can be recognized + """ + pass - #@TODO: Rewrite in 0.4.10 - def init_accounts(self, accounts): - for user, data in accounts.items(): - self.add(user, data['password'], data['options']) + def login(self): + if not self.req: + self.log_info(_("Login user `%s`...") % self.user) + else: + self.log_info(_("Relogin user `%s`...") % self.user) + self.clean() + self.req = self.pyload.requestFactory.getRequest(self.__name__, self.user) - @lock - def add(self, user, password=None, options={}): - if user not in self.info: - self.info[user] = {'login': {'valid' : None, - 'password' : password or "", - 'timestamp': 0}, - 'data' : {'options' : options, - 'premium' : None, - 'validuntil' : None, - 'trafficleft': None, - 'maxtraffic' : None}} - - #@TODO: Remove in 0.4.10 - self.accounts[user] = self.info[user]['data'] - self.accounts[user].update({'login' : user, - 'type' : self.__name__, - 'valid' : self.info[user]['login']['valid'], - 'password': self.info[user]['login']['password']}) - - self.log_info(_("Login user `%s`...") % user) - self._login(user) - return True + self.sync() - else: - self.log_error(_("Error adding user `%s`") % user, _("User already exists")) + try: + self.info['login']['timestamp'] = time.time() #: Set timestamp for login + self.signin(self.user, self.info['login']['password'], self.info['data']) + except Skip: + self.info['login']['valid'] = True + if self.auto_timeout: + self.auto_timeout *= 2 + self.interval = self.auto_timeout - @lock - def update(self, user, password=None, options={}): - """ - Updates account and return true if anything changed - """ - if not (password or options): - return - - if user not in self.info: - return self.add(user, password, options) + except Exception, e: + self.log_error(_("Could not login user `%s`") % user, e) + self.info['login']['valid'] = False else: - if password: - self.info[user]['login']['password'] = password - self.accounts[user]['password'] = password #@TODO: Remove in 0.4.10 - self.relogin(user) + self.info['login']['valid'] = True + if self.interval is self.auto_timeout: + self.interval = self.auto_timeout / 2 + self.auto_timeout = False - if options: - before = self.info[user]['data']['options'] - self.info[user]['data']['options'].update(options) - return self.info[user]['data']['options'] != before + finally: + self.syncback() + return bool(self.info['login']['valid']) - return True + #@TODO: Recheck in 0.4.10 + def syncback(self): + return self.sync(reverse=True) - #: Deprecated method, use `update` instead (Remove in 0.4.10) - def updateAccounts(self, *args, **kwargs): - return self.update(*args, **kwargs) + #@TODO: Recheck in 0.4.10 + def sync(self, reverse=False): + if not self.user: + return - def remove(self, user=None): # -> def remove - if not user: - self.info.clear() - self.accounts.clear() #@TODO: Remove in 0.4.10 + u = self.accounts[self.user] - elif user in self.info: - self.info.pop(user, None) - self.accounts.pop(user, None) #@TODO: Remove in 0.4.10 + if reverse: + u.update(self.info['data']) + u.update(self.info['login']) + else: + d = {'login': {'password' : u['password'], + 'timestamp': u['timestamp'], + 'valid' : u['valid']}, + 'data' : {'maxtraffic' : u['maxtraffic'], + 'options' : u['options'], + 'premium' : u['premium'], + 'trafficleft': u['trafficleft'], + 'validuntil' : u['validuntil']}} - #: Deprecated method, use `remove` instead (Remove in 0.4.10) - def removeAccount(self, *args, **kwargs): - return self.remove(*args, **kwargs) + self.info.update(d) - #@NOTE: Remove in 0.4.10? - def get_data(self, user, reload=False): - if not user: - return + def relogin(self): + return self.login() - info = self.get_info(user, reload) - if info and 'data' in info: - return info['data'] + def reset(self): + self.sync() - #: Deprecated method, use `get_data` instead (Remove in 0.4.10) - def getAccountData(self, *args, **kwargs): - if 'force' in kwargs: - kwargs['reload'] = kwargs['force'] - kwargs.pop('force', None) + d = {'maxtraffic' : None, + 'options' : {'limitdl': ['0']}, + 'premium' : None, + 'trafficleft': None, + 'validuntil' : None} - data = self.get_data(*args, **kwargs) or {} - if 'options' not in data: - data['options'] = {'limitdl': ['0']} + self.info['data'].update(d) - return data + self.syncback() - def get_info(self, user, reload=False): + def get_info(self, refresh=True): """ - Retrieve account infos for an user, do **not** overwrite this method!\\ + Retrieve account infos for an user, do **not** overwrite this method! just use it to retrieve infos in hoster plugins. see `grab_info` :param user: username - :param reload: reloads cached account information + :param relogin: reloads cached account information :return: dictionary with information """ - if user not in self.info: - self.log_error(_("User `%s` not found while retrieving account info") % user) - return - - elif reload: - self.log_info(_("Parsing account info for user `%s`...") % user) - info = self._parse_info(user) - - safe_info = copy.deepcopy(info) - safe_info['login']['password'] = "**********" - safe_info['data']['password'] = "**********" #@TODO: Remove in 0.4.10 - self.log_debug("Account info for user `%s`: %s" % (user, safe_info)) + if not self.logged: + if self.relogin(): + refresh = True + else: + refresh = False + self.reset() - elif self.INFO_THRESHOLD > 0 and self.info[user]['login']['timestamp'] + self.INFO_THRESHOLD < time.time(): - self.log_debug("Reached data timeout for %s" % user) - info = self.get_info(user, True) + if refresh: + self.log_info(_("Grabbing account info for user `%s`...") % self.user) + self.info = self._grab_info() - else: - info = self.info[user] + self.syncback() - return info + safe_info = dict(self.info) + safe_info['login']['password'] = "**********" + self.log_debug("Account info for user `%s`: %s" % (self.user, safe_info)) + return self.info - def is_premium(self, user): - if not user: - return False - info = self.get_info(user) - return info['data']['premium'] + def get_login(self, key=None, default=None): + d = self.get_info()['login'] + return d.get(key, default) if key else d - def _parse_info(self, user): - info = self.info[user] + def get_data(self, key=None, default=None): + d = self.get_info()['data'] + return d.get(key, default) if key else d - if not info['login']['valid']: - return info + def _grab_info(self): try: - self.req = self.get_request(user) - extra_info = self.grab_info(user, info['login']['password'], info, self.req) + data = self.grab_info(self.user, self.info['login']['password'], self.info['data']) - if extra_info and isinstance(extra_info, dict): - info['data'].update(extra_info) + if data and isinstance(data, dict): + self.info['data'].update(data) - except (Fail, Exception), e: - self.log_warning(_("Error loading info for user `%s`") % user, e) - - if self.pyload.debug: - traceback.print_exc() + except Exception, e: + self.log_warning(_("Error loading info for user `%s`") % self.user, e) finally: - self.clean() - - self.info[user].update(info) - return info + return self.info - def grab_info(self, user, password, info, req): + def grab_info(self, user, password, data): """ This should be overwritten in account plugin and retrieving account information for user @@ -265,43 +223,104 @@ class Account(Plugin): pass - #: Remove in 0.4.10 - def getAllAccounts(self, *args, **kwargs): - return [self.getAccountData(user, *args, **kwargs) for user, info in self.info.items()] + ########################################################################### + #@TODO: Recheck and move to `AccountManager` in 0.4.10 #################### + ########################################################################### + @lock + def init_accounts(self): + accounts = dict(self.accounts) + self.accounts.clear() - def fail_login(self, msg=_("Login handshake has failed")): - return self.fail(msg) + for user, info in accounts.items(): + self.add(user, info['password'], info['options']) - def get_request(self, user=None): - if not user: - user, info = self.select() + @lock + def getAccountData(self, user, force=False): + self.accounts[user]['plugin'].get_info() + return self.accounts[user] - return self.pyload.requestFactory.getRequest(self.__name__, user) + @lock + def getAllAccounts(self, force=False): + if force: + self.init_accounts() #@TODO: Recheck in 0.4.10 - def get_cookies(self, user=None): - if not user: - user, info = self.select() + return [self.getAccountData(user, force) for user in self.accounts] - return self.pyload.requestFactory.getCookieJar(self.__name__, user) + #@TODO: Remove in 0.4.10 + @lock + def scheduleRefresh(self, user, force=False): + pass - def select(self): + + @lock + def add(self, user, password=None, options={}): + self.log_info(_("Adding user `%s`...") % user) + + if user in self.accounts: + self.log_error(_("Error adding user `%s`") % user, _("User already exists")) + return False + + d = {'login' : user, + 'maxtraffic' : None, + 'options' : options or {'limitdl': ['0']}, + 'password' : password or "", + 'plugin' : self.__class__(self.manager, self.accounts), + 'premium' : None, + 'timestamp' : 0, + 'trafficleft': None, + 'type' : self.__name__, + 'valid' : None, + 'validuntil' : None} + + u = self.accounts[user] = d + return u['plugin'].choose(user) + + + @lock + def updateAccounts(self, user, password=None, options={}): """ - Returns a valid account name and info + Updates account and return true if anything changed """ + if user in self.accounts: + self.log_info(_("Updating account info for user `%s`...") % user) + + u = self.accounts[user] + if password: + u['password'] = password + + if options: + u['options'].update(options) + + u['plugin'].relogin() + + else: + self.add(user, password, options) + + + @lock + def removeAccount(self, user): + self.accounts.pop(user, None) + if user is self.user: + self.choose() + + + @lock + def select(self): free_accounts = {} premium_accounts = {} - for user, info in self.info.items(): + for user in self.accounts: + info = self.accounts[user]['plugin'].get_info() + data = info['data'] + if not info['login']['valid']: continue - data = info['data'] - - if "time" in data['options'] and data['options']['time']: + if data['options'].get('time'): time_data = "" try: time_data = data['options']['time'][0] @@ -311,7 +330,8 @@ class Account(Plugin): continue except Exception: - self.log_warning(_("Wrong time format `%s` for account `%s`, use 1:22-3:44") % (user, time_data)) + self.log_warning(_("Wrong time format `%s` for account `%s`, use 1:22-3:44") + % (user, time_data)) if data['trafficleft'] == 0: continue @@ -330,68 +350,56 @@ class Account(Plugin): if not account_list: return None, None - validuntil_list = [(user, info) for user, info in account_list if info['data']['validuntil']] + validuntil_list = [(user, info) for user, info in account_list \ + if info['data']['validuntil']] if not validuntil_list: - return random.choice(account_list) #@TODO: Random account?! Recheck in 0.4.10 + return random.choice(account_list) #@TODO: Random account?! Rewrite in 0.4.10 return sorted(validuntil_list, key=lambda a: a[1]['data']['validuntil'], reverse=True)[0] - def parse_traffic(self, value, unit=None): #: Return kilobytes - if not unit and not isinstance(value, basestring): - unit = "KB" - - return parse_size(value, unit) - + @lock + def choose(self, user=None): + """ + Choose a valid account + """ + if not user: + user = self.select()[0] - def empty(self, user): - if user not in self.info: - return + elif user not in self.accounts: + self.log_error(_("Error choosing user `%s`") % user, _("User not exists")) + return False - self.log_warning(_("Account `%s` has not enough traffic") % user, _("Checking again in 30 minutes")) + if user is self.user: + return True - self.info[user]['data']['trafficleft'] = 0 - self.schedule_refresh(user, 30 * 60) + self.user = user + self.info.clear() + self.clean() + if self.user is not None: + self.login() + return True - def expired(self, user): - if user not in self.info: - return + else: + return False - self.log_warning(_("Account `%s` is expired") % user, _("Checking again in 60 minutes")) - self.info[user]['data']['validuntil'] = time.time() - 1 - self.schedule_refresh(user, 60 * 60) + ########################################################################### + def parse_traffic(self, value, unit=None): #@NOTE: Returns kilobytes in 0.4.9 + if not isinstance(unit, basestring): + unit = "KB" - def schedule_refresh(self, user, time=0): - """ - Add task to refresh account info to sheduler - """ - self.log_debug("Scheduled refresh for user `%s` in %s seconds" % (user, time)) - self.pyload.scheduler.addJob(time, self.get_info, [user, True]) + return parse_size(value, unit) / 1024 #@TODO: Remove `/ 1024` in 0.4.10 - #: Deprecated method, use `schedule_refresh` instead (Remove in 0.4.10) - def scheduleRefresh(self, *args, **kwargs): - if 'force' in kwargs: - kwargs.pop('force', None) #@TODO: Recheck in 0.4.10 - return self.schedule_refresh(*args, **kwargs) + def fail_login(self, msg=_("Login handshake has failed")): + return self.fail(msg) - @lock - def is_logged(self, user, relogin=False): - """ - Checks if user is still logged in - """ - if user in self.info: - if self.LOGIN_TIMEOUT > 0 and self.info[user]['login']['timestamp'] + self.LOGIN_TIMEOUT < time.time(): - self.log_debug("Reached login timeout for %s" % user) - return self.relogin(user) if relogin else False - else: - return True - else: - return False + def skip_login(self, msg=_("Already signed in")): + return self.skip(msg) diff --git a/module/plugins/internal/Addon.py b/module/plugins/internal/Addon.py index 5150e88f6..3a252fdfb 100644 --- a/module/plugins/internal/Addon.py +++ b/module/plugins/internal/Addon.py @@ -26,7 +26,6 @@ class Addon(Plugin): __version__ = "0.06" __status__ = "testing" - __config__ = [] #: [("name", "type", "desc", "default")] __threaded__ = [] #@TODO: Remove in 0.4.10 __description__ = """Base addon plugin""" diff --git a/module/plugins/internal/Container.py b/module/plugins/internal/Container.py index 430590421..2300c4cab 100644 --- a/module/plugins/internal/Container.py +++ b/module/plugins/internal/Container.py @@ -17,11 +17,11 @@ class Container(Crypter): __status__ = "testing" __pattern__ = r'^unmatchable$' - __config__ = [] #: [("name", "type", "desc", "default")] __description__ = """Base container decrypter plugin""" __license__ = "GPLv3" - __authors__ = [("mkaay", "mkaay@mkaay.de")] + __authors__ = [("mkaay" , "mkaay@mkaay.de" ), + ("Walter Purcaro", "vuolter@gmail.com")] def process(self, pyfile): diff --git a/module/plugins/internal/Crypter.py b/module/plugins/internal/Crypter.py index 2033b67df..ad5bcc74e 100644 --- a/module/plugins/internal/Crypter.py +++ b/module/plugins/internal/Crypter.py @@ -7,7 +7,7 @@ from module.utils import save_path as safe_filename class Crypter(Hoster): __name__ = "Crypter" __type__ = "crypter" - __version__ = "0.08" + __version__ = "0.09" __status__ = "testing" __pattern__ = r'^unmatchable$' @@ -83,7 +83,7 @@ class Crypter(Hoster): self.pyload.api.setPackageData(pid, {'password': package_password}) #: Workaround to do not break API addPackage method - set_folder = lambda x: self.pyload.api.setPackageData(pid, {'folder': safe_filename(x) or ""}) + set_folder = lambda x="": self.pyload.api.setPackageData(pid, {'folder': safe_filename(x)}) if use_subfolder: if not subfolder_per_package: @@ -98,4 +98,4 @@ class Crypter(Hoster): self.log_debug("Set package %(name)s folder to: %(folder)s" % {'name': name, 'folder': folder}) elif folder_per_package: - set_folder(None) + set_folder() diff --git a/module/plugins/internal/Extractor.py b/module/plugins/internal/Extractor.py index f21fe473c..3ab5d6a0d 100644 --- a/module/plugins/internal/Extractor.py +++ b/module/plugins/internal/Extractor.py @@ -5,6 +5,7 @@ import re from module.PyFile import PyFile from module.plugins.internal.Plugin import Plugin +from module.utils import fs_encode class ArchiveError(Exception): @@ -22,7 +23,7 @@ class PasswordError(Exception): class Extractor(Plugin): __name__ = "Extractor" __type__ = "extractor" - __version__ = "0.34" + __version__ = "0.35" __status__ = "testing" __description__ = """Base extractor plugin""" diff --git a/module/plugins/internal/Hook.py b/module/plugins/internal/Hook.py index 1f566f824..8ae731a7f 100644 --- a/module/plugins/internal/Hook.py +++ b/module/plugins/internal/Hook.py @@ -9,8 +9,6 @@ class Hook(Addon): __version__ = "0.13" __status__ = "testing" - __config__ = [] #: [("name", "type", "desc", "default")] - __description__ = """Base hook plugin""" __license__ = "GPLv3" __authors__ = [("mkaay" , "mkaay@mkaay.de" ), diff --git a/module/plugins/internal/Hoster.py b/module/plugins/internal/Hoster.py index 5d0a64f1a..bc340e78f 100644 --- a/module/plugins/internal/Hoster.py +++ b/module/plugins/internal/Hoster.py @@ -11,8 +11,8 @@ import urlparse from module.plugins.internal.Captcha import Captcha from module.plugins.internal.Plugin import (Plugin, Abort, Fail, Reconnect, Retry, Skip, - chunks, decode, encode, exists, parse_html_form, - parse_html_tag_attr_value, parse_name, + chunks, decode, encode, exists, fixurl, + parse_html_form, parse_html_tag_attr_value, parse_name, replace_patterns, seconds_to_midnight, set_cookie, set_cookies, timestamp) from module.utils import fs_decode, fs_encode, save_join as fs_join, save_path as safe_filename @@ -41,21 +41,27 @@ def create_getInfo(klass): return get_info +#@NOTE: `check_abort` decorator +def check_abort(fn): + + def wrapper(self, *args, **kwargs): + self.check_abort() + return fn(self, *args, **kwargs) + + return wrapper + + class Hoster(Plugin): __name__ = "Hoster" __type__ = "hoster" - __version__ = "0.28" + __version__ = "0.31" __status__ = "testing" __pattern__ = r'^unmatchable$' - __config__ = [] #: [("name", "type", "desc", "default")] __description__ = """Base hoster plugin""" __license__ = "GPLv3" - __authors__ = [("RaNaN" , "RaNaN@pyload.org" ), - ("spoob" , "spoob@pyload.org" ), - ("mkaay" , "mkaay@mkaay.de" ), - ("Walter Purcaro", "vuolter@gmail.com")] + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] def __init__(self, pyfile): @@ -74,7 +80,7 @@ class Hoster(Plugin): #: Account handler instance, see :py:class:`Account` self.account = None - self.req = None #: Browser instance, see `network.Browser` + self.user = None #@TODO: Remove in 0.4.10 #: Associated pyfile instance, see `PyFile` self.pyfile = pyfile @@ -98,7 +104,7 @@ class Hoster(Plugin): #: Dict of the amount of retries already made self.retries = {} - self.retry_free = False #@TODO: Recheck in 0.4.10 + self.force_free = False #@TODO: Recheck in 0.4.10 self._setup() self.init() @@ -116,9 +122,10 @@ class Hoster(Plugin): @classmethod def get_info(cls, url="", html=""): + url = fixurl(url, unquote=True) return {'name' : parse_name(url), 'size' : 0, - 'status': 3 if url.strip() else 8, + 'status': 3 if url else 8, 'url' : url} @@ -142,6 +149,11 @@ class Hoster(Plugin): self.last_download = "" self.pyfile.error = "" + try: + self.req.close() + except Exception: + pass + if self.account: self.req = self.pyload.requestFactory.getRequest(self.__name__, self.account.user) self.chunk_limit = -1 #: -1 for unlimited @@ -162,16 +174,16 @@ class Hoster(Plugin): """ self.thread = thread - if self.retry_free: + if self.force_free: self.account = False else: self.load_account() #@TODO: Move to PluginThread in 0.4.10 - self.retry_free = False + self.force_free = False self._setup() + # self.pyload.hookManager.downloadPreparing(self.pyfile) #@TODO: Recheck in 0.4.10 self.pyfile.setStatus("starting") - self.pyload.hookManager.downloadPreparing(self.pyfile) #@TODO: Recheck in 0.4.10 self.check_abort() @@ -185,17 +197,17 @@ class Hoster(Plugin): def load_account(self): - if self.req: - self.req.close() - if not self.account: self.account = self.pyload.accountManager.getAccountPlugin(self.__name__) - if self.account: - if not hasattr(self.account, 'user'): #@TODO: Move to `Account` in 0.4.10 - self.account.user = self.account.select()[0] + if not self.account: + self.account = False + self.user = None #@TODO: Remove in 0.4.10 - if not hasattr(self.account, 'logged'): + else: + self.account.choose() + self.user = self.account.user #@TODO: Remove in 0.4.10 + if self.account.user is None: self.account = False @@ -207,12 +219,8 @@ class Hoster(Plugin): def set_reconnect(self, reconnect): - if reconnect: - self.log_info(_("Requesting line reconnection...")) - else: - self.log_debug("Reconnect: %s" % reconnect) - - self.log_debug("Previous wantReconnect: %s" % self.wantReconnect) + self.log_debug("RECONNECT %s required" % ("" if reconnect else "not"), + "Previous wantReconnect: %s" % self.wantReconnect) self.wantReconnect = bool(reconnect) @@ -226,8 +234,8 @@ class Hoster(Plugin): wait_time = max(int(seconds), 1) wait_until = time.time() + wait_time + 1 - self.log_info(_("Waiting %d seconds...") % wait_time) - self.log_debug("Previous waitUntil: %f" % self.pyfile.waitUntil) + self.log_debug("WAIT set to %d seconds" % wait_time, + "Previous waitUntil: %f" % self.pyfile.waitUntil) self.pyfile.waitUntil = wait_until @@ -249,13 +257,17 @@ class Hoster(Plugin): self.waiting = True - status = pyfile.status #@NOTE: Remove in 0.4.10 + status = pyfile.status #@NOTE: Recheck in 0.4.10 pyfile.setStatus("waiting") - if not self.wantReconnect or self.account: + self.log_info(_("Waiting %d seconds...") % pyfile.waitUntil - time.time()) + + if self.wantReconnect: + self.log_info(_("Requiring reconnection...")) if self.account: self.log_warning("Ignore reconnection due logged account") + if not self.wantReconnect or self.account: while pyfile.waitUntil > time.time(): self.check_abort() time.sleep(2) @@ -263,24 +275,24 @@ class Hoster(Plugin): else: while pyfile.waitUntil > time.time(): self.check_abort() + self.thread.m.reconnecting.wait(1) if self.thread.m.reconnecting.isSet(): self.waiting = False self.wantReconnect = False raise Reconnect - self.thread.m.reconnecting.wait(2) time.sleep(2) self.waiting = False - pyfile.status = status #@NOTE: Remove in 0.4.10 + pyfile.status = status #@NOTE: Recheck in 0.4.10 def skip(self, msg=""): """ Skip and give msg """ - raise Skip(encode(msg or self.pyfile.error)) #@TODO: Remove `encode` in 0.4.10 + raise Skip(encode(msg or self.pyfile.error or self.pyfile.pluginname)) #@TODO: Remove `encode` in 0.4.10 #@TODO: Remove in 0.4.10 @@ -293,7 +305,7 @@ class Hoster(Plugin): if msg: self.pyfile.error = msg else: - msg = self.pyfile.error + msg = self.pyfile.error or (self.info['error'] if 'error' in self.info else self.pyfile.getStatusName()) raise Fail(encode(msg)) #@TODO: Remove `encode` in 0.4.10 @@ -359,30 +371,33 @@ class Hoster(Plugin): if nopremium: if self.premium: - self.retry_free = True + self.force_free = True else: self.fail("%s | %s" % (msg, _("Download was already free"))) raise Retry(encode(msg)) #@TODO: Remove `encode` in 0.4.10 - def fixurl(self, url, baseurl=None): + def fixurl(self, url, baseurl=None, unquote=None): + url = fixurl(url) + if not baseurl: - baseurl = self.pyfile.url + baseurl = fixurl(self.pyfile.url) if not urlparse.urlparse(url).scheme: url_p = urlparse.urlparse(baseurl) baseurl = "%s://%s" % (url_p.scheme, url_p.netloc) url = urlparse.urljoin(baseurl, url) - return url + return fixurl(url, unquote) + @check_abort def load(self, *args, **kwargs): - self.check_abort() return super(Hoster, self).load(*args, **kwargs) + @check_abort def download(self, url, get={}, post={}, ref=True, cookies=True, disposition=True): """ Downloads the content at url to download folder @@ -396,16 +411,18 @@ class Hoster(Plugin): the filename will be changed if needed :return: The location where the file was saved """ - self.check_abort() - if self.pyload.debug: self.log_debug("DOWNLOAD URL " + url, - *["%s=%s" % (key, val) for key, val in locals().items() if key not in ("self", "url")]) + *["%s=%s" % (key, val) for key, val in locals().items() if key not in ("self", "url", "_[1]")]) + + url = self.fixurl(url, unquote=True) self.pyfile.name = parse_name(self.pyfile.name) #: Safe check self.captcha.correct() - self.check_for_same_files() + + if self.pyload.config.get("download", "skip_existing"): + self.check_filedupe() self.pyfile.setStatus("downloading") @@ -441,7 +458,9 @@ class Hoster(Plugin): if finalname != newname: try: - os.rename(fs_join(location, newname), fs_join(location, finalname)) + oldname_enc = fs_join(download_location, newname) + newname_enc = fs_join(download_location, finalname) + os.rename(oldname_enc, newname_enc) except OSError, e: self.log_warning(_("Error renaming `%s` to `%s`") % (newname, finalname), e) @@ -463,16 +482,16 @@ class Hoster(Plugin): if not self.pyfile.abort: return - if self.pyfile.hasStatus("failed"): + if self.pyfile.status is 8: self.fail() - elif self.pyfile.hasStatus("skipped"): + elif self.pyfile.status is 4: self.skip(self.pyfile.statusname) - elif self.pyfile.hasStatus("offline"): + elif self.pyfile.status is 1: self.offline() - elif self.pyfile.hasStatus("temp. offline"): + elif self.pyfile.status is 6: self.temp_offline() else: @@ -489,7 +508,8 @@ class Hoster(Plugin): if not self.last_download: return - download_size = os.stat(fs_encode(self.last_download)).st_size + download_location = fs_encode(self.last_download) + download_size = os.stat(download_location).st_size if download_size < 1: self.fail(_("Empty file")) @@ -505,7 +525,7 @@ class Hoster(Plugin): self.log_warning(_("File size is not equal to expected size")) - def check_download(self, rules, delete=False, read_size=1048576, file_size=0, size_tolerance=1024): + def check_file(self, rules, delete=False, read_size=1048576, file_size=0, size_tolerance=1024): """ Checks the content of the last downloaded file, re match is saved to `last_check` @@ -552,7 +572,66 @@ class Hoster(Plugin): else: self.log_info(_("File deleted: ") + self.last_download) - self.last_download = "" + self.last_download = "" #: Recheck in 0.4.10 + + + def check_traffic(self): + if not self.account: + return True + + traffic = self.account.get_data(refresh=True)['trafficleft'] + + if traffic is None: + return False + + elif traffic is -1: + return True + + else: + size = self.pyfile.size / 1024 #@TODO: Remove in 0.4.10 + self.log_info(_("Filesize: %s KiB, Traffic left for user %s: %s KiB") % (size, self.account.user, traffic)) #@TODO: Rewrite in 0.4.10 + return size <= traffic + + + def check_filedupe(self): + """ + Checks if same file was/is downloaded within same package + + :param starting: indicates that the current download is going to start + :raises Skip: + """ + pack = self.pyfile.package() + + for pyfile in self.pyload.files.cache.values(): + if pyfile is self.pyfile: + continue + + if pyfile.name != self.pyfile.name or pyfile.package().folder != pack.folder: + continue + + if pyfile.status in (0, 5, 7, 12): #: (finished, waiting, starting, downloading) + self.skip(pyfile.pluginname) + + download_folder = self.pyload.config.get("general", "download_folder") + package_folder = pack.folder if self.pyload.config.get("general", "folder_per_package") else "" + download_location = fs_join(download_folder, package_folder, self.pyfile.name) + + if not exists(download_location): + return + + pyfile = self.pyload.db.findDuplicates(self.pyfile.id, package_folder, self.pyfile.name) + if pyfile: + self.skip(pyfile[0]) + + size = os.stat(download_location).st_size + if size >= self.pyfile.size: + self.skip(_("File exists")) + + + #: Deprecated method, use `check_filedupe` instead (Remove in 0.4.10) + def checkForSameFiles(self, *args, **kwargs): + if self.pyload.config.get("download", "skip_existing"): + return self.check_filedupe() def direct_link(self, url, follow_location=None): @@ -598,10 +677,10 @@ class Hoster(Plugin): if 'content-disposition' in header: link = url - elif 'location' in header and header['location']: + elif header.get('location'): location = self.fixurl(header['location'], url) - if 'code' in header and header['code'] == 302: + if header.get('code') == 302: link = location if follow_location: @@ -611,7 +690,7 @@ class Hoster(Plugin): else: extension = os.path.splitext(parse_name(url))[-1] - if 'content-type' in header and header['content-type']: + if header.get('content-type'): mimetype = header['content-type'].split(';')[0].strip() elif extension: @@ -641,63 +720,8 @@ class Hoster(Plugin): return parse_html_form(attr_str, self.html, input_names) - def check_traffic_left(self): - if not self.account: - return True - - traffic = self.account.get_data(self.account.user, True)['trafficleft'] - - if traffic is None: - return False - - elif traffic == -1: - return True - - else: - size = self.pyfile.size / 1024 - self.log_info(_("Filesize: %s KiB, Traffic left for user %s: %s KiB") % (size, self.account.user, traffic)) - return size <= traffic - - def get_password(self): """ Get the password the user provided in the package """ return self.pyfile.package().password or "" - - - #: Deprecated method, use `check_for_same_files` instead (Remove in 0.4.10) - def checkForSameFiles(self, *args, **kwargs): - return self.check_for_same_files(*args, **kwargs) - - - def check_for_same_files(self, starting=False): - """ - Checks if same file was/is downloaded within same package - - :param starting: indicates that the current download is going to start - :raises Skip: - """ - pack = self.pyfile.package() - - for pyfile in self.pyload.files.cache.values(): - if pyfile != self.pyfile and pyfile.name is self.pyfile.name and pyfile.package().folder is pack.folder: - if pyfile.status in (0, 12): #: Finished or downloading - self.skip(pyfile.pluginname) - elif pyfile.status in (5, 7) and starting: #: A download is waiting/starting and was appenrently started before - self.skip(pyfile.pluginname) - - download_folder = self.pyload.config.get("general", "download_folder") - location = fs_join(download_folder, pack.folder, self.pyfile.name) - - if starting and self.pyload.config.get("download", "skip_existing") and exists(location): - size = os.stat(location).st_size - if size >= self.pyfile.size: - self.skip("File exists") - - pyfile = self.pyload.db.findDuplicates(self.pyfile.id, self.pyfile.package().folder, self.pyfile.name) - if pyfile: - if exists(location): - self.skip(pyfile[0]) - - self.log_debug("File %s not skipped, because it does not exists." % self.pyfile.name) diff --git a/module/plugins/internal/MultiHook.py b/module/plugins/internal/MultiAccount.py index 42a1985b5..b38670ce7 100644 --- a/module/plugins/internal/MultiHook.py +++ b/module/plugins/internal/MultiAccount.py @@ -2,30 +2,29 @@ import re import time -import traceback -from module.plugins.internal.Hook import Hook +from module.plugins.internal.Account import Account from module.utils import decode, remove_chars -class MultiHook(Hook): - __name__ = "MultiHook" - __type__ = "hook" - __version__ = "0.54" +class MultiAccount(Account): + __name__ = "MultiAccount" + __type__ = "account" + __version__ = "0.02" __status__ = "testing" - __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), - ("pluginlist" , "str" , "Plugin list (comma separated)", "" ), - ("reload" , "bool" , "Reload plugin list" , True ), - ("reloadinterval", "int" , "Reload interval in hours" , 12 )] + __config__ = [("pluginmode" , "all;listed;unlisted", "Use for plugins" , "all"), + ("pluginlist" , "str" , "Plugin list (comma separated)", "" ), + ("reload" , "bool" , "Reload plugin list" , True ), + ("reloadinterval", "int" , "Reload interval in hours" , 12 )] - __description__ = """Hook plugin for multi hoster/crypter""" + __description__ = """Multi hoster account plugin""" __license__ = "GPLv3" __authors__ = [("pyLoad Team" , "admin@pyload.org" ), ("Walter Purcaro", "vuolter@gmail.com")] - MIN_RELOAD_INTERVAL = 1 * 60 * 60 #: 1 hour + REFRESH_INTERVAL = 1 * 60 * 60 #: 1 hour DOMAIN_REPLACEMENTS = [(r'180upload\.com' , "hundredeightyupload.com"), (r'bayfiles\.net' , "bayfiles.com" ), @@ -55,6 +54,34 @@ class MultiHook(Hook): (r'^0' , "zero" )] + + + + + + + + + + + + + + + + + + + + + + + + + + + + def init(self): self.plugins = [] self.supported = [] @@ -102,7 +129,7 @@ class MultiHook(Hook): for _i in xrange(5): try: - pluginset = self._plugin_set(self.get_hosters()) + pluginset = self._plugin_set(self.grab_hosters()) break except Exception, e: @@ -110,7 +137,7 @@ class MultiHook(Hook): time.sleep(60) else: self.log_error(_("No hoster list retrieved")) - self.interval = self.MIN_RELOAD_INTERVAL + self.interval = self.REFRESH_INTERVAL return list() try: @@ -144,7 +171,7 @@ class MultiHook(Hook): return set(plugins) - def get_hosters(self): + def grab_hosters(self, user, password, data): """ Load list of supported hoster @@ -160,7 +187,7 @@ class MultiHook(Hook): self.load_account() if self.get_config('reload', True): - self.interval = max(self.get_config('reloadinterval', 12) * 60 * 60, self.MIN_RELOAD_INTERVAL) + self.interval = max(self.get_config('reloadinterval', 12) * 60 * 60, self.REFRESH_INTERVAL) else: self.pyload.scheduler.removeJob(self.cb) self.cb = None diff --git a/module/plugins/internal/MultiCrypter.py b/module/plugins/internal/MultiCrypter.py index ca7b03941..ae8785116 100644 --- a/module/plugins/internal/MultiCrypter.py +++ b/module/plugins/internal/MultiCrypter.py @@ -6,7 +6,7 @@ from module.plugins.internal.SimpleCrypter import SimpleCrypter class MultiCrypter(SimpleCrypter): __name__ = "MultiCrypter" __type__ = "hoster" - __version__ = "0.02" + __version__ = "0.03" __status__ = "testing" __pattern__ = r'^unmatchable$' @@ -19,7 +19,7 @@ class MultiCrypter(SimpleCrypter): def init(self): - self.CRYPTER_NAME = self.pyload.pluginManager.crypterPlugins[self.__name__]['name'] + self.PLUGIN_NAME = self.pyload.pluginManager.crypterPlugins[self.__name__]['name'] def _log(self, level, plugintype, pluginname, messages): diff --git a/module/plugins/internal/MultiHoster.py b/module/plugins/internal/MultiHoster.py index c0c928a45..fbfab1ade 100644 --- a/module/plugins/internal/MultiHoster.py +++ b/module/plugins/internal/MultiHoster.py @@ -9,7 +9,7 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, r class MultiHoster(SimpleHoster): __name__ = "MultiHoster" __type__ = "hoster" - __version__ = "0.50" + __version__ = "0.51" __status__ = "testing" __pattern__ = r'^unmatchable$' @@ -21,21 +21,21 @@ class MultiHoster(SimpleHoster): __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - HOSTER_NAME = None + PLUGIN_NAME = None LEECH_HOSTER = False LOGIN_ACCOUNT = True def init(self): - self.HOSTER_NAME = self.pyload.pluginManager.hosterPlugins[self.__name__]['name'] + self.PLUGIN_NAME = self.pyload.pluginManager.hosterPlugins[self.__name__]['name'] def _log(self, level, plugintype, pluginname, messages): return super(MultiHoster, self)._log(level, plugintype, pluginname, - (self.HOSTER_NAME,) + messages) + (self.PLUGIN_NAME,) + messages) def setup(self): @@ -83,11 +83,11 @@ class MultiHoster(SimpleHoster): self.check_errors() self.check_status(getinfo=False) - if self.premium and (not self.CHECK_TRAFFIC or self.check_traffic_left()): + if self.premium and (not self.CHECK_TRAFFIC or self.check_traffic()): self.log_info(_("Processing as premium download...")) self.handle_premium(pyfile) - elif not self.LOGIN_ACCOUNT or (not self.CHECK_TRAFFIC or self.check_traffic_left()): + elif not self.LOGIN_ACCOUNT or (not self.CHECK_TRAFFIC or self.check_traffic()): self.log_info(_("Processing as free download...")) self.handle_free(pyfile) @@ -95,7 +95,7 @@ class MultiHoster(SimpleHoster): self.log_info(_("Downloading file...")) self.download(self.link, disposition=self.DISPOSITION) - self.check_file() + self.check_download() except Fail, e: #@TODO: Move to PluginThread in 0.4.10 if self.premium: diff --git a/module/plugins/internal/Plugin.py b/module/plugins/internal/Plugin.py index 51192d8c9..6f3e52962 100644 --- a/module/plugins/internal/Plugin.py +++ b/module/plugins/internal/Plugin.py @@ -6,7 +6,6 @@ import datetime import inspect import os import re -import sys import traceback import urllib import urlparse @@ -28,6 +27,11 @@ def decode(string, encoding='utf8'): return unicode(string) +#@TODO: Remove in 0.4.10 +def _decode(*args, **kwargs): + return decode(*args, **kwargs) + + #@TODO: Move to utils in 0.4.10 def encode(string, encoding='utf8'): """ Decode string to utf8 """ @@ -49,18 +53,25 @@ def exists(path): return False -#@TODO: Move to utils in 0.4.10 -def parse_name(url): - url = urllib.unquote(url) - url = url.decode('unicode-escape') - url = html_unescape(url) - url = urllib.quote(url) +#@TODO: Recheck in 0.4.10 +def fixurl(url, unquote=None): + newurl = urllib.unquote(url) + + if unquote is None: + unquote = newurl == url + + newurl = html_unescape(newurl.decode('unicode-escape')).strip() - url_p = urlparse.urlparse(url.strip().rstrip('/')) + return newurl if unquote else urllib.quote(newurl) - name = (url_p.path.split('/')[-1] or - url_p.query.split('=', 1)[::-1][0].split('&', 1)[0] or - url_p.netloc.split('.', 1)[0]) + +#@TODO: Recheck in 0.4.10 +def parse_name(string): + path = fixurl(decode(string), unquote=False) + url_p = urlparse.urlparse(path.rstrip('/')) + name = (url_p.path.split('/')[-1] or + url_p.query.split('=', 1)[::-1][0].split('&', 1)[0] or + url_p.netloc.split('.', 1)[0]) return urllib.unquote(name) @@ -96,7 +107,7 @@ def seconds_to_midnight(utc=None): else: now = datetime.datetime.utcnow() + datetime.timedelta(hours=utc) - midnight = now.replace(hour=0, minute=10, second=0, microsecond=0) + datetime.timedelta(days=1) + midnight = now.replace(hour=0, minute=1, second=0, microsecond=0) + datetime.timedelta(days=1) return (midnight - now).seconds @@ -173,7 +184,7 @@ def chunks(iterable, size): class Plugin(object): __name__ = "Plugin" __type__ = "plugin" - __version__ = "0.37" + __version__ = "0.38" __status__ = "testing" __pattern__ = r'^unmatchable$' @@ -181,10 +192,7 @@ class Plugin(object): __description__ = """Base plugin""" __license__ = "GPLv3" - __authors__ = [("RaNaN" , "RaNaN@pyload.org" ), - ("spoob" , "spoob@pyload.org" ), - ("mkaay" , "mkaay@mkaay.de" ), - ("Walter Purcaro", "vuolter@gmail.com")] + __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] def __init__(self, core): @@ -199,8 +207,8 @@ class Plugin(object): def _init(self, core): self.pyload = core - self.info = {} #: Provide information in dict here - self.req = None + self.info = {} #: Provide information in dict here + self.req = None #: Browser instance, see `network.Browser` def init(self): @@ -231,8 +239,6 @@ class Plugin(object): def log_warning(self, *args): self._log("warning", self.__type__, self.__name__, args) - if self.pyload.debug: - traceback.print_exc() def log_error(self, *args): @@ -278,7 +284,7 @@ class Plugin(object): return min(self.pyload.config.get("download", "chunks"), self.chunk_limit) - def set_config(self, option, value): + def set_config(self, option, value, plugin=None): """ Set config value for current plugin @@ -286,7 +292,7 @@ class Plugin(object): :param value: :return: """ - self.pyload.config.setPlugin(self.__name__, option, value) + self.pyload.config.setPlugin(plugin or self.__name__, option, value) def get_config(self, option, default="", plugin=None): @@ -347,7 +353,9 @@ class Plugin(object): """ if self.pyload.debug: self.log_debug("LOAD URL " + url, - *["%s=%s" % (key, val) for key, val in locals().items() if key not in ("self", "url")]) + *["%s=%s" % (key, val) for key, val in locals().items() if key not in ("self", "url", "_[1]")]) + + url = fixurl(url, unquote=True) #: Recheck in 0.4.10 if req is None: req = self.req or self.pyload.requestFactory.getRequest(self.__name__) @@ -364,7 +372,7 @@ class Plugin(object): #@TODO: Move to network in 0.4.10 if isinstance(decode, basestring): - res = sys.modules[self.__name__].decode(res, decode) #@TODO: See #1787, use utils.decode() in 0.4.10 + res = _decode(res, decode) #@NOTE: Use `utils.decode()` in 0.4.10 if self.pyload.debug: frame = inspect.currentframe() @@ -409,11 +417,12 @@ class Plugin(object): Clean everything and remove references """ try: + self.req.clearCookies() self.req.close() except Exception: pass - for a in ("pyfile", "thread", "html", "req"): - if hasattr(self, a): - setattr(self, a, None) + for attr in ("account", "html", "pyfile", "req", "thread"): + if hasattr(self, attr): + setattr(self, attr, None) diff --git a/module/plugins/internal/SevenZip.py b/module/plugins/internal/SevenZip.py index b79256536..7ed64ecdf 100644 --- a/module/plugins/internal/SevenZip.py +++ b/module/plugins/internal/SevenZip.py @@ -5,18 +5,18 @@ import re import subprocess from module.plugins.internal.UnRar import ArchiveError, CRCError, PasswordError, UnRar, renice -from module.utils import fs_encode, save_join as fs_join +from module.utils import save_join as fs_join class SevenZip(UnRar): __name__ = "SevenZip" - __version__ = "0.15" + __version__ = "0.16" __status__ = "testing" __description__ = """7-Zip extractor plugin""" __license__ = "GPLv3" - __authors__ = [("Michael Nowak" , "" ), - ("Walter Purcaro", "vuolter@gmail.com")] + __authors__ = [("Walter Purcaro", "vuolter@gmail.com"), + ("Michael Nowak" , None )] CMD = "7z" @@ -128,7 +128,7 @@ class SevenZip(UnRar): args.append("-y") #: Set a password - if "password" in kwargs and kwargs['password']: + if kwargs.get('password'): args.append("-p%s" % kwargs['password']) else: args.append("-p-") diff --git a/module/plugins/internal/SimpleCrypter.py b/module/plugins/internal/SimpleCrypter.py index 8c5d3599d..53d69b2a5 100644 --- a/module/plugins/internal/SimpleCrypter.py +++ b/module/plugins/internal/SimpleCrypter.py @@ -9,7 +9,7 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo, r class SimpleCrypter(Crypter, SimpleHoster): __name__ = "SimpleCrypter" __type__ = "crypter" - __version__ = "0.62" + __version__ = "0.63" __status__ = "testing" __pattern__ = r'^unmatchable$' @@ -81,7 +81,7 @@ class SimpleCrypter(Crypter, SimpleHoster): self.log_debug("Redirect #%d to: %s" % (i, redirect)) header = self.load(redirect, just_header=True) - if 'location' in header and header['location']: + if header.get('location'): self.link = header['location'] else: break @@ -137,7 +137,7 @@ class SimpleCrypter(Crypter, SimpleHoster): try: pages = int(re.search(self.PAGES_PATTERN, self.html).group(1)) - except AttributeError: + except (AttributeError, IndexError, ValueError): pages = 1 for p in xrange(2, pages + 1): diff --git a/module/plugins/internal/SimpleHoster.py b/module/plugins/internal/SimpleHoster.py index 0f030e000..00b63ac12 100644 --- a/module/plugins/internal/SimpleHoster.py +++ b/module/plugins/internal/SimpleHoster.py @@ -6,7 +6,6 @@ import os import re import time -from module.PyFile import statusMap as _statusMap from module.network.HTTPRequest import BadHeader from module.network.RequestFactory import getURL as get_url from module.plugins.internal.Hoster import Hoster, create_getInfo, parse_fileInfo @@ -14,14 +13,10 @@ from module.plugins.internal.Plugin import Fail, encode, parse_name, replace_pat from module.utils import fixup, fs_encode, parseFileSize as parse_size -#@TODO: Adapt and move to PyFile in 0.4.10 -statusMap = dict((v, k) for k, v in _statusMap.items()) - - class SimpleHoster(Hoster): __name__ = "SimpleHoster" __type__ = "hoster" - __version__ = "1.86" + __version__ = "1.87" __status__ = "testing" __pattern__ = r'^unmatchable$' @@ -124,7 +119,7 @@ class SimpleHoster(Hoster): try: info['pattern'] = re.match(cls.__pattern__, url).groupdict() #: Pattern groups will be saved here - except AttributeError: + except (AttributeError, IndexError): info['pattern'] = {} if not html and not online: @@ -164,7 +159,7 @@ class SimpleHoster(Hoster): if all(True for k in pdict if k not in info['pattern']): info['pattern'].update(pdict) - except AttributeError: + except (AttributeError, IndexError): continue else: @@ -275,11 +270,11 @@ class SimpleHoster(Hoster): if 'status' not in self.info or self.info['status'] is 3: #@TODO: Recheck in 0.4.10 self.check_info() - if self.premium and (not self.CHECK_TRAFFIC or self.check_traffic_left()): + if self.premium and (not self.CHECK_TRAFFIC or self.check_traffic()): self.log_info(_("Processing as premium download...")) self.handle_premium(pyfile) - elif not self.LOGIN_ACCOUNT or (not self.CHECK_TRAFFIC or self.check_traffic_left()): + elif not self.LOGIN_ACCOUNT or (not self.CHECK_TRAFFIC or self.check_traffic()): self.log_info(_("Processing as free download...")) self.handle_free(pyfile) @@ -287,7 +282,7 @@ class SimpleHoster(Hoster): self.log_info(_("Downloading file...")) self.download(self.link, disposition=self.DISPOSITION) - self.check_file() + self.check_download() except Fail, e: #@TODO: Move to PluginThread in 0.4.10 if self.get_config('premium_fallback', True) and self.premium: @@ -298,26 +293,26 @@ class SimpleHoster(Hoster): raise Fail(encode(e)) #@TODO: Remove `encode` in 0.4.10 - def check_file(self): - self.log_info(_("Checking file...")) + def check_download(self): + self.log_info(_("Checking downloaded file...")) if self.captcha.task and not self.last_download: self.captcha.invalid() self.retry(10, msg=_("Wrong captcha")) - elif self.check_download({'Empty file': re.compile(r'\A((.|)(\2|\s)*)\Z')}, + elif self.check_file({'Empty file': re.compile(r'\A((.|)(\2|\s)*)\Z')}, delete=True): self.error(_("Empty file")) else: - if self.get_config('chk_filesize', False) and 'size' in self.info: + if self.get_config('chk_filesize', False) and self.info.get('size'): # 10485760 is 10MB, tolerance is used when comparing displayed size on the hoster website to real size # For example displayed size can be 1.46GB for example, but real size can be 1.4649853GB self.check_filesize(self.info['size'], size_tolerance=10485760) self.log_debug("Using default check rules...") for r, p in self.FILE_ERRORS: - errmsg = self.check_download({r: re.compile(p)}) + errmsg = self.check_file({r: re.compile(p)}) if errmsg is not None: errmsg = errmsg.strip().capitalize() @@ -338,7 +333,6 @@ class SimpleHoster(Hoster): self.check_errors() self.log_info(_("No errors found")) - self.pyfile.error = "" #@TODO: Recheck in 0.4.10 def check_errors(self): @@ -361,7 +355,7 @@ class SimpleHoster(Hoster): try: errmsg = m.group(1).strip() - except AttributeError: + except (AttributeError, IndexError): errmsg = m.group(0).strip() self.info['error'] = re.sub(r'<.*?>', " ", errmsg) @@ -385,7 +379,7 @@ class SimpleHoster(Hoster): try: errmsg = m.group(1).strip() - except AttributeError: + except (AttributeError, IndexError): errmsg = m.group(0).strip() self.info['error'] = re.sub(r'<.*?>', " ", errmsg) @@ -436,7 +430,7 @@ class SimpleHoster(Hoster): try: waitmsg = m.group(1).strip() - except AttributeError: + except (AttributeError, IndexError): waitmsg = m.group(0).strip() wait_time = sum(int(v) * {'hr': 3600, 'hour': 3600, 'min': 60, 'sec': 1, "": 1}[u.lower()] for v, u in @@ -455,22 +449,19 @@ class SimpleHoster(Hoster): self.log_debug("Previous file info: %s" % old_info) try: - status = self.info['status'] or None + status = self.info['status'] or 14 - if status == 1: + if status is 1: self.offline() - elif status == 6: + elif status is 6: self.temp_offline() - elif status == 8: - if 'error' in self.info: - self.fail(self.info['error']) - else: - self.fail(_("File status: " + statusMap[status])) + elif status is 8: + self.fail() finally: - self.log_info(_("File status: ") + (statusMap[status] if status else _("Unknown"))) + self.log_info(_("File status: ") + self.pyfile.getStatusName(status)) def check_name_size(self, getinfo=True): @@ -492,7 +483,7 @@ class SimpleHoster(Hoster): if name and name is not url: self.pyfile.name = name - if 'size' in self.info and self.info['size'] > 0: + if self.info.get('size') > 0: self.pyfile.size = int(self.info['size']) #@TODO: Fix int conversion in 0.4.10 # self.pyfile.sync() diff --git a/module/plugins/internal/UnRar.py b/module/plugins/internal/UnRar.py index 88c490750..7efecc5ef 100644 --- a/module/plugins/internal/UnRar.py +++ b/module/plugins/internal/UnRar.py @@ -8,7 +8,7 @@ from glob import glob from string import digits from module.plugins.internal.Extractor import Extractor, ArchiveError, CRCError, PasswordError -from module.utils import fs_decode, fs_encode, save_join as fs_join +from module.utils import fs_decode, save_join as fs_join def renice(pid, value): @@ -22,7 +22,7 @@ def renice(pid, value): class UnRar(Extractor): __name__ = "UnRar" - __version__ = "1.26" + __version__ = "1.27" __status__ = "testing" __description__ = """Rar extractor plugin""" @@ -229,7 +229,7 @@ class UnRar(Extractor): args.append("-y") #: Set a password - if "password" in kwargs and kwargs['password']: + if kwargs.get('password'): args.append("-p%s" % kwargs['password']) else: args.append("-p-") diff --git a/module/plugins/internal/UnZip.py b/module/plugins/internal/UnZip.py index ac197a80d..87cbd568a 100644 --- a/module/plugins/internal/UnZip.py +++ b/module/plugins/internal/UnZip.py @@ -7,7 +7,6 @@ import sys import zipfile from module.plugins.internal.Extractor import Extractor, ArchiveError, CRCError, PasswordError -from module.utils import fs_encode class UnZip(Extractor): diff --git a/module/plugins/internal/XFSAccount.py b/module/plugins/internal/XFSAccount.py index bb5cbcf50..91136a2a0 100644 --- a/module/plugins/internal/XFSAccount.py +++ b/module/plugins/internal/XFSAccount.py @@ -6,13 +6,14 @@ import urlparse from module.common.json_layer import json_loads from module.plugins.internal.Account import Account +# from module.plugins.internal.MultiAccount import MultiAccount from module.plugins.internal.Plugin import parse_html_form, set_cookie class XFSAccount(Account): __name__ = "XFSAccount" __type__ = "account" - __version__ = "0.46" + __version__ = "0.48" __status__ = "testing" __description__ = """XFileSharing account plugin""" @@ -21,8 +22,8 @@ class XFSAccount(Account): ("Walter Purcaro", "vuolter@gmail.com" )] - HOSTER_DOMAIN = None - HOSTER_URL = None + PLUGIN_DOMAIN = None + PLUGIN_URL = None LOGIN_URL = None COOKIES = True @@ -38,21 +39,22 @@ class XFSAccount(Account): LEECH_TRAFFIC_UNIT = "MB" #: Used only if no group <U> was found LOGIN_FAIL_PATTERN = r'Incorrect Login or Password|account was banned|Error<' + LOGIN_SKIP_PATTERN = r'op=logout' - def grab_info(self, user, password, data, req): + def grab_info(self, user, password, data): validuntil = None trafficleft = None leechtraffic = None premium = None - if not self.HOSTER_URL: #@TODO: Remove in 0.4.10 + if not self.PLUGIN_URL: #@TODO: Remove in 0.4.10 return {'validuntil' : validuntil, 'trafficleft' : trafficleft, 'leechtraffic': leechtraffic, 'premium' : premium} - html = self.load(self.HOSTER_URL, + html = self.load(self.PLUGIN_URL, get={'op': "my_account"}, cookies=self.COOKIES) @@ -139,31 +141,34 @@ class XFSAccount(Account): 'premium' : premium} - def login(self, user, password, data, req): - if self.HOSTER_DOMAIN: - if not self.HOSTER_URL: - self.HOSTER_URL = "http://www.%s/" % self.HOSTER_DOMAIN + def signin(self, user, password, data): + if self.PLUGIN_DOMAIN: + if not self.PLUGIN_URL: + self.PLUGIN_URL = "http://www.%s/" % self.PLUGIN_DOMAIN if self.COOKIES: - if isinstance(self.COOKIES, list) and (self.HOSTER_DOMAIN, "lang", "english") not in self.COOKIES: - self.COOKIES.insert((self.HOSTER_DOMAIN, "lang", "english")) + if isinstance(self.COOKIES, list) and (self.PLUGIN_DOMAIN, "lang", "english") not in self.COOKIES: + self.COOKIES.insert((self.PLUGIN_DOMAIN, "lang", "english")) else: - set_cookie(self.req.cj, self.HOSTER_DOMAIN, "lang", "english") + set_cookie(self.req.cj, self.PLUGIN_DOMAIN, "lang", "english") - if not self.HOSTER_URL: - self.fail_login(_("Missing HOSTER_URL")) + if not self.PLUGIN_URL: + self.fail_login(_("Missing PLUGIN_URL")) else: - self.HOSTER_URL = self.HOSTER_URL.rstrip('/') + "/" + self.PLUGIN_URL = self.PLUGIN_URL.rstrip('/') + "/" if not self.LOGIN_URL: - self.LOGIN_URL = urlparse.urljoin(self.HOSTER_URL, "login.html") + self.LOGIN_URL = urlparse.urljoin(self.PLUGIN_URL, "login.html") html = self.load(self.LOGIN_URL, cookies=self.COOKIES) + if re.search(self.LOGIN_SKIP_PATTERN, html): + self.skip_login() + action, inputs = parse_html_form('name="FL"', html) if not inputs: inputs = {'op' : "login", - 'redirect': self.HOSTER_URL} + 'redirect': self.PLUGIN_URL} inputs.update({'login' : user, 'password': password}) @@ -171,7 +176,7 @@ class XFSAccount(Account): if action: url = urlparse.urljoin("http://", action) else: - url = self.HOSTER_URL + url = self.PLUGIN_URL html = self.load(url, post=inputs, cookies=self.COOKIES) diff --git a/module/plugins/internal/XFSCrypter.py b/module/plugins/internal/XFSCrypter.py index 12a48d4a3..8047fd03e 100644 --- a/module/plugins/internal/XFSCrypter.py +++ b/module/plugins/internal/XFSCrypter.py @@ -7,7 +7,7 @@ from module.plugins.internal.SimpleCrypter import SimpleCrypter, create_getInfo class XFSCrypter(SimpleCrypter): __name__ = "XFSCrypter" __type__ = "crypter" - __version__ = "0.14" + __version__ = "0.15" __status__ = "testing" __pattern__ = r'^unmatchable$' @@ -17,7 +17,7 @@ class XFSCrypter(SimpleCrypter): __authors__ = [("Walter Purcaro", "vuolter@gmail.com")] - HOSTER_DOMAIN = None + PLUGIN_DOMAIN = None URL_REPLACEMENTS = [(r'&?per_page=\d+', ""), (r'[?/&]+$', ""), (r'(.+/[^?]+)$', r'\1?'), (r'$', r'&per_page=10000')] @@ -29,22 +29,22 @@ class XFSCrypter(SimpleCrypter): def prepare(self): - if not self.HOSTER_DOMAIN: + if not self.PLUGIN_DOMAIN: if self.account: account = self.account else: account_name = (self.__name__ + ".py").replace("Folder.py", "").replace(".py", "") account = self.pyload.accountManager.getAccountPlugin(account_name) - if account and hasattr(account, "HOSTER_DOMAIN") and account.HOSTER_DOMAIN: - self.HOSTER_DOMAIN = account.HOSTER_DOMAIN + if account and hasattr(account, "PLUGIN_DOMAIN") and account.PLUGIN_DOMAIN: + self.PLUGIN_DOMAIN = account.PLUGIN_DOMAIN else: - self.fail(_("Missing HOSTER_DOMAIN")) + self.fail(_("Missing PLUGIN_DOMAIN")) if self.COOKIES: - if isinstance(self.COOKIES, list) and (self.HOSTER_DOMAIN, "lang", "english") not in self.COOKIES: - self.COOKIES.insert((self.HOSTER_DOMAIN, "lang", "english")) + if isinstance(self.COOKIES, list) and (self.PLUGIN_DOMAIN, "lang", "english") not in self.COOKIES: + self.COOKIES.insert((self.PLUGIN_DOMAIN, "lang", "english")) else: - set_cookie(self.req.cj, self.HOSTER_DOMAIN, "lang", "english") + set_cookie(self.req.cj, self.PLUGIN_DOMAIN, "lang", "english") return super(XFSCrypter, self).prepare() diff --git a/module/plugins/internal/XFSHoster.py b/module/plugins/internal/XFSHoster.py index 729c9a0ee..8af6b83ed 100644 --- a/module/plugins/internal/XFSHoster.py +++ b/module/plugins/internal/XFSHoster.py @@ -14,7 +14,7 @@ from module.utils import html_unescape class XFSHoster(SimpleHoster): __name__ = "XFSHoster" __type__ = "hoster" - __version__ = "0.60" + __version__ = "0.61" __status__ = "testing" __pattern__ = r'^unmatchable$' @@ -26,7 +26,7 @@ class XFSHoster(SimpleHoster): ("Walter Purcaro", "vuolter@gmail.com" )] - HOSTER_DOMAIN = None + PLUGIN_DOMAIN = None LEECH_HOSTER = True #@NOTE: Should be default to False for safe, but I'm lazy... @@ -61,26 +61,26 @@ class XFSHoster(SimpleHoster): """ Initialize important variables """ - if not self.HOSTER_DOMAIN: + if not self.PLUGIN_DOMAIN: if self.account: account = self.account else: account = self.pyload.accountManager.getAccountPlugin(self.__name__) - if account and hasattr(account, "HOSTER_DOMAIN") and account.HOSTER_DOMAIN: - self.HOSTER_DOMAIN = account.HOSTER_DOMAIN + if account and hasattr(account, "PLUGIN_DOMAIN") and account.PLUGIN_DOMAIN: + self.PLUGIN_DOMAIN = account.PLUGIN_DOMAIN else: - self.fail(_("Missing HOSTER_DOMAIN")) + self.fail(_("Missing PLUGIN_DOMAIN")) if self.COOKIES: - if isinstance(self.COOKIES, list) and (self.HOSTER_DOMAIN, "lang", "english") not in self.COOKIES: - self.COOKIES.insert((self.HOSTER_DOMAIN, "lang", "english")) + if isinstance(self.COOKIES, list) and (self.PLUGIN_DOMAIN, "lang", "english") not in self.COOKIES: + self.COOKIES.insert((self.PLUGIN_DOMAIN, "lang", "english")) else: - set_cookie(self.req.cj, self.HOSTER_DOMAIN, "lang", "english") + set_cookie(self.req.cj, self.PLUGIN_DOMAIN, "lang", "english") if not self.LINK_PATTERN: pattern = r'(?:file: "(.+?)"|(https?://(?:www\.)?([^/]*?%s|\d+\.\d+\.\d+\.\d+)(\:\d+)?(/d/|(/files)?/\d+/\w+/).+?)["\'<])' - self.LINK_PATTERN = pattern % self.HOSTER_DOMAIN.replace('.', '\.') + self.LINK_PATTERN = pattern % self.PLUGIN_DOMAIN.replace('.', '\.') super(XFSHoster, self).prepare() @@ -129,7 +129,7 @@ class XFSHoster(SimpleHoster): self.fail(_("Only registered or premium users can use url leech feature")) #: Only tested with easybytez.com - self.html = self.load("http://www.%s/" % self.HOSTER_DOMAIN) + self.html = self.load("http://www.%s/" % self.PLUGIN_DOMAIN) action, inputs = self.parse_html_form() @@ -244,7 +244,7 @@ class XFSHoster(SimpleHoster): try: captcha_key = re.search(self.RECAPTCHA_PATTERN, self.html).group(1) - except AttributeError: + except (AttributeError, IndexError): captcha_key = recaptcha.detect_key() else: @@ -258,7 +258,7 @@ class XFSHoster(SimpleHoster): try: captcha_key = re.search(self.SOLVEMEDIA_PATTERN, self.html).group(1) - except AttributeError: + except (AttributeError, IndexError): captcha_key = solvemedia.detect_key() else: |