diff options
author | Walter Purcaro <vuolter@users.noreply.github.com> | 2015-07-25 04:59:27 +0200 |
---|---|---|
committer | Walter Purcaro <vuolter@users.noreply.github.com> | 2015-07-25 04:59:27 +0200 |
commit | 8f17f875f6e28f73ddb10da59c6464bd04922222 (patch) | |
tree | 29631cd1f81a40283c71dfdd005b9d24370d5d7f /module/plugins/internal | |
parent | Fix typo (diff) | |
download | pyload-8f17f875f6e28f73ddb10da59c6464bd04922222.tar.xz |
Account rewritten
Diffstat (limited to 'module/plugins/internal')
-rw-r--r-- | module/plugins/internal/Account.py | 328 | ||||
-rw-r--r-- | module/plugins/internal/Addon.py | 30 | ||||
-rw-r--r-- | module/plugins/internal/CaptchaService.py | 4 | ||||
-rw-r--r-- | module/plugins/internal/Container.py | 4 | ||||
-rw-r--r-- | module/plugins/internal/Hoster.py | 8 | ||||
-rw-r--r-- | module/plugins/internal/SimpleCrypter.py | 4 | ||||
-rw-r--r-- | module/plugins/internal/SimpleHoster.py | 4 | ||||
-rw-r--r-- | module/plugins/internal/XFSAccount.py | 6 |
8 files changed, 190 insertions, 198 deletions
diff --git a/module/plugins/internal/Account.py b/module/plugins/internal/Account.py index 03521a0ea..3a3fd4768 100644 --- a/module/plugins/internal/Account.py +++ b/module/plugins/internal/Account.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- +from __future__ import with_statement + import random -import threading import time import traceback @@ -9,10 +10,6 @@ from module.plugins.internal.Plugin import Plugin from module.utils import compare_time, lock, parseFileSize as parse_size -class WrongPassword(Exception): - pass - - class Account(Plugin): __name__ = "Account" __type__ = "account" @@ -21,25 +18,20 @@ class Account(Plugin): __description__ = """Base account plugin""" __license__ = "GPLv3" - __authors__ = [("mkaay", "mkaay@mkaay.de")] + __authors__ = [("mkaay" , "mkaay@mkaay.de" ), + ("Walter Purcaro", "vuolter@gmail.com")] + + + LOGIN_TIMEOUT = 10 * 60 #: After that time (in minutes) pyload will relogin the account + INFO_THRESHOLD = 10 * 60 #: After that time (in minutes) account data will be reloaded def __init__(self, manager, accounts): self.pyload = manager.core self.info = {} #: Provide information in dict here - self.manager = manager - self.accounts = {} - self.infos = {} #: Cache for account information - self.lock = threading.RLock() - self.timestamps = {} - - self.login_timeout = 10 * 60 #: After that time (in minutes) pyload will relogin the account - self.info_threshold = 10 * 60 #: After that time (in minutes) account data will be reloaded - self.init() - - self.set_accounts(accounts) + self.init_accounts(accounts) def init(self): @@ -49,240 +41,239 @@ class Account(Plugin): pass - def login(self, user, data, req): + def login(self, user, password, data, req): """ Login into account, the cookies will be saved so user can be recognized - - :param user: loginname - :param data: data dictionary - :param req: `Request` instance """ pass @lock - def _login(self, user, data): - #: Set timestamp for login - self.timestamps[user] = time.time() - - self.req = self.get_account_request(user) + def _login(self, user): try: - self.login(user, data, self.req) + info = self.info[user] + info['login']['timestamp'] = time.time() #: Set timestamp for login - except WrongPassword: - self.log_warning( - _("Could not login with account %(user)s | %(msg)s") % {'user': user, - 'msg': _("Wrong Password")}) - success = data['valid'] = False + 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 with account %(user)s | %(msg)s") % {'user': user, - 'msg': e}) - success = data['valid'] = False + 'msg' : e}) + res = info['login']['valid'] = False if self.pyload.debug: traceback.print_exc() else: - success = True + res = True finally: - if hasattr(self, "req"): - if self.req: - self.req.close() - del self.req - return success + if self.req: + self.req.close() + del self.req + + return res def relogin(self, user): - req = self.get_account_request(user) - if req: + with self.get_request(user) as req: req.clearCookies() - req.close() - if user in self.infos: - del self.infos[user] #: Delete old information + if user in self.info: + self.info[user]['login'].clear() - return self._login(user, self.accounts[user]) + return self._login(user) - def set_accounts(self, accounts): - self.accounts = accounts - for user, data in self.accounts.iteritems(): - self._login(user, data) - self.infos[user] = {} + def init_accounts(self, accounts): + for user, data in accounts.iteritems(): + self.add(user, data['password'], data['options']) + self._login(user) - def update_accounts(self, user, password=None, options={}): + def add(self, user, password=None, options): + if user not in self.info: + self.info[user] = {'login': {'valid': True, 'password': password or "", 'timestamp': 0}, #@NOTE: Do not remove `'valid': True` in 0.4.9 or accounts will not login + 'data' : {'options': options, 'timestamp': 0}} + self._login(user) + return True + else: + self.log_error(_("Error adding account"), _("User already exists")) + + + def update(self, user, password=None, options): """ Updates account and return true if anything changed """ - if user in self.accounts: - self.accounts[user]['valid'] = True #: Do not remove or accounts will not login + if user not in self.info: + return self.add(user, password, options) + + elif password or options: if password: - self.accounts[user]['password'] = password + self.info[user]['login']['password'] = password self.relogin(user) return True + if options: - before = self.accounts[user]['options'] - self.accounts[user]['options'].update(options) - return self.accounts[user]['options'] is not before - else: - self.accounts[user] = {'password': password, 'options': options, 'valid': True} - self._login(user, self.accounts[user]) - return True + before = self.info[user]['data'][user]['options'] + self.info[user]['data']['options'].update(options) + return self.info[user]['data']['options'] != before - #: Deprecated method, use `update_accounts` instead + #: Deprecated method, use `update` instead (Remove in 0.4.10) def updateAccounts(self, *args, **kwargs): - return self.update_accounts(*args, **kwargs) + return self.update(*args, **kwargs) + + def remove(self, user=None): # -> def remove + if not user: + self.info.clear() - def remove_account(self, user): - if user in self.accounts: - del self.accounts[user] - if user in self.infos: - del self.infos[user] - if user in self.timestamps: - del self.timestamps[user] + elif user in self.info: + del self.info[user] - #: Deprecated method, use `remove_account` instead + #: Deprecated method, use `remove` instead (Remove in 0.4.10) def removeAccount(self, *args, **kwargs): - return self.remove_account(*args, **kwargs) + return self.remove(*args, **kwargs) + + + def get_data(self, user, reload=False): + return self.get_info(user, reload)['data'] @lock - def get_account_info(self, name, force=False): + def get_info(self, user, reload=False): """ Retrieve account infos for an user, do **not** overwrite this method!\\ - just use it to retrieve infos in hoster plugins. see `load_account_info` + just use it to retrieve infos in hoster plugins. see `load_info` - :param name: username - :param force: reloads cached account information + :param user: username + :param reload: reloads cached account information :return: dictionary with information """ - data = Account.load_account_info(self, name) + if not reload and user in self.info: + info = self.info[user] - if force or name not in self.infos: - self.log_debug("Get Account Info for %s" % name) - self.req = self.get_account_request(name) + if info['data']['timestamp'] + self.INFO_THRESHOLD * 60 < time.time(): + self.log_debug("Reached timeout for account data") + self.schedule_refresh(user) - try: - infos = self.load_account_info(name, self.req) - if not type(infos) is dict: - raise Exception("Wrong return format") + else: + self.log_debug("Get Account Info for: %s" % user) + info = self.load_info(user) - except Exception, e: - infos = super(self.__class__, self).load_account_info(name, self.req) - infos['error'] = str(e) + self.log_debug("Account Info: %s" % info) + return info - if self.pyload.debug: - traceback.print_exc() - finally: - if hasattr(self, "req"): - if self.req: - self.req.close() - del self.req + def is_premium(self, user): + return self.get_info(user)['premium'] - self.log_debug("Account Info: %s" % infos) - infos['timestamp'] = time.time() - self.infos[name] = infos + def load_info(self, user): + self.log_critical(user in self.info) ############################# - elif "timestamp" in self.infos[name] and self.infos[name]['timestamp'] + self.info_threshold * 60 < time.time(): - self.log_debug("Reached timeout for account data") - self.schedule_refresh(name) + info = self.info[user] + data = info['data'] - data.update(self.infos[name]) - return data + #@TODO: Remove in 0.4.10 + data.update({'login': user, + 'type' : self.__name__}, + 'valid': self.info[user]['login']['valid']) + try: + self.req = self.get_request(user) + extra_info = self.parse_info(user, info['login']['password'], info, req) - def is_premium(self, user): - info = self.get_account_info(user) - return info['premium'] + if extra_info and isinstance(extra_info, dict): + data.update(extra_info) + data['timestamp'] = time.time() + except Exception, e: + self.log_warning(_("Error loading info for account %(user)s | %(err)s") % + {'user': user, 'err': e}) + data['error'] = str(e) - def load_account_info(self, name, req=None): + if self.pyload.debug: + traceback.print_exc(): + + else: + for key in ('premium', 'validuntil', 'trafficleft', 'maxtraffic'): + if key not in data: + data[key] = None + + finally: + if self.req: + self.req.close() + del self.req + + self.info[user].update(info) + return info + + + def parse_info(self, user, password, info, req): """ This should be overwritten in account plugin and retrieving account information for user - :param name: + :param user: :param req: `Request` instance :return: """ - return {'validuntil' : None, #: -1 for unlimited - 'login' : name, - # 'password' : self.accounts[name]['password'], #: Commented due security reason - 'options' : self.accounts[name]['options'], - 'valid' : self.accounts[name]['valid'], - 'trafficleft': None, #: In bytes, -1 for unlimited - 'maxtraffic' : None, - 'premium' : None, - 'timestamp' : 0, #: Time this info was retrieved - 'type' : self.__name__} - - - def get_all_accounts(self, force=False): - return [self.get_account_info(user, force) for user, data in self.accounts.iteritems()] + pass - #: Deprecated method, use `get_all_accounts` instead + #: Remove in 0.4.10 def getAllAccounts(self, *args, **kwargs): - return self.get_all_accounts(*args, **kwargs) + return [self.get_data(user, reload) for user, info in self.info.iteritems()] - def get_account_request(self, user=None): + def get_request(self, user=None): if not user: - user, data = self.select_account() + user, info = self.select() return self.pyload.requestFactory.getRequest(self.__name__, user) - def get_account_cookies(self, user=None): - if not user: - user, data = self.select_account() + def get_cookies(self, user=None): if not user: + user, info = self.select() return None - cj = self.pyload.requestFactory.getCookieJar(self.__name__, user) - return cj - + return self.pyload.requestFactory.getCookieJar(self.__name__, user) - def get_account_data(self, user): - return self.accounts[user] - - def select_account(self): + #@TODO: Random account only? Simply crazy... rewrite + def select(self): """ Returns an valid account name and data """ usable = [] - for user, data in self.accounts.iteritems(): - if not data['valid']: + for user, info in self.info.iteritems(): + if not info['login']['valid']: continue - if "time" in data['options'] and data['options']['time']: + options = info['data']['options'] + if "time" in options and options['time']: time_data = "" try: - time_data = data['options']['time'][0] + time_data = options['time'][0] start, end = time_data.split("-") if not compare_time(start.split(":"), end.split(":")): continue + except Exception: - self.log_warning(_("Your Time %s has wrong format, use 1:22-3:44") % time_data) + self.log_warning(_("Your time %s has wrong format, use 1:22-3:44") % time_data) - if user in self.infos: - if "validuntil" in self.infos[user]: - if self.infos[user]['validuntil'] > 0 and time.time() > self.infos[user]['validuntil']: - continue - if "trafficleft" in self.infos[user]: - if self.infos[user]['trafficleft'] == 0: - continue + if user in self.info: + if None is not self.info[user]['validuntil'] > 0 and time.time() > self.info[user]['validuntil']: + continue + if None is not self.info[user]['trafficleft'] == 0: + continue - usable.append((user, data)) + usable.append((user, info)) if not usable: return None, None @@ -291,44 +282,45 @@ class Account(Plugin): def can_use(self): - return self.select_account() is not (None, None) + return self.select() is not (None, None) def parse_traffic(self, value, unit=None): #: Return kilobytes if not unit and not isinstance(value, basestring): unit = "KB" - return parse_size(value, unit) - - def wrong_password(self): - raise WrongPassword + return parse_size(value, unit) def empty(self, user): - if user in self.infos: - self.log_warning(_("Account %s has not enough traffic, checking again in 30min") % user) + if user not in self.info: + return + + self.log_warning(_("Account %s has not enough traffic, checking again in 30min") % user) - self.infos[user].update({'trafficleft': 0}) - self.schedule_refresh(user, 30 * 60) + self.info[user]['data'].update({'trafficleft': 0}) + self.schedule_refresh(user, 30 * 60) def expired(self, user): - if user in self.infos: - self.log_warning(_("Account %s is expired, checking again in 1h") % user) + if user not in self.info: + return + + self.log_warning(_("Account %s is expired, checking again in 1h") % user) - self.infos[user].update({'validuntil': time.time() - 1}) - self.schedule_refresh(user, 60 * 60) + self.info[user]['data'].update({'validuntil': time.time() - 1}) + self.schedule_refresh(user, 60 * 60) - def schedule_refresh(self, user, time=0, force=True): + def schedule_refresh(self, user, time=0, reload=True): """ Add task to refresh account info to sheduler """ self.log_debug("Scheduled Account refresh for %s in %s seconds." % (user, time)) - self.pyload.scheduler.addJob(time, self.get_account_info, [user, force]) + self.pyload.scheduler.addJob(time, self.get_info, [user, reload]) - #: Deprecated method, use `schedule_refresh` instead + #: Deprecated method, use `schedule_refresh` instead (Remove in 0.4.10) def scheduleRefresh(self, *args, **kwargs): return self.schedule_refresh(*args, **kwargs) @@ -338,8 +330,8 @@ class Account(Plugin): """ Checks if user is still logged in """ - if user in self.timestamps: - if self.login_timeout > 0 and self.timestamps[user] + self.login_timeout * 60 < time.time(): + if user in self.info: + if self.LOGIN_TIMEOUT > 0 and self.info[user]['login']['timestamp'] + self.LOGIN_TIMEOUT * 60 < time.time(): self.log_debug("Reached login timeout for %s" % user) return self.relogin(user) else: diff --git a/module/plugins/internal/Addon.py b/module/plugins/internal/Addon.py index 23512d7c4..16aab6188 100644 --- a/module/plugins/internal/Addon.py +++ b/module/plugins/internal/Addon.py @@ -71,7 +71,7 @@ class Addon(Plugin): self.event_map = None if self.event_list: - self.log_debug("Deprecated method `event_list`, use `event_map` instead") + self.log_debug("Deprecated method `event_list`, use `event_map` instead") (Remove in 0.4.10) for f in self.event_list: self.manager.addEvent(f, getattr(self, f)) @@ -83,7 +83,7 @@ class Addon(Plugin): self.cb = self.pyload.scheduler.addJob(max(0, delay), self._periodical, [threaded], threaded=threaded) - #: Deprecated method, use `init_periodical` instead + #: Deprecated method, use `init_periodical` instead (Remove in 0.4.10) def initPeriodical(self, *args, **kwargs): return self.init_periodical(*args, **kwargs) @@ -119,7 +119,7 @@ class Addon(Plugin): return self.get_config("activated") - #: Deprecated method, use `is_activated` instead + #: Deprecated method, use `is_activated` instead (Remove in 0.4.10) def isActivated(self, *args, **kwargs): return self.is_activated(*args, **kwargs) @@ -131,7 +131,7 @@ class Addon(Plugin): pass - #: Deprecated method, use `deactivate` instead + #: Deprecated method, use `deactivate` instead (Remove in 0.4.10) def unload(self, *args, **kwargs): return self.deactivate(*args, **kwargs) @@ -143,7 +143,7 @@ class Addon(Plugin): pass - #: Deprecated method, use `activate` instead + #: Deprecated method, use `activate` instead (Remove in 0.4.10) def coreReady(self, *args, **kwargs): return self.activate(*args, **kwargs) @@ -155,7 +155,7 @@ class Addon(Plugin): pass - #: Deprecated method, use `exit` instead + #: Deprecated method, use `exit` instead (Remove in 0.4.10) def coreExiting(self, *args, **kwargs): return self.exit(*args, **kwargs) @@ -164,7 +164,7 @@ class Addon(Plugin): pass - #: Deprecated method, use `download_preparing` instead + #: Deprecated method, use `download_preparing` instead (Remove in 0.4.10) def downloadPreparing(self, *args, **kwargs): return self.download_preparing(*args, **kwargs) @@ -173,7 +173,7 @@ class Addon(Plugin): pass - #: Deprecated method, use `download_finished` instead + #: Deprecated method, use `download_finished` instead (Remove in 0.4.10) def downloadFinished(self, *args, **kwargs): return self.download_finished(*args, **kwargs) @@ -182,7 +182,7 @@ class Addon(Plugin): pass - #: Deprecated method, use `download_failed` instead + #: Deprecated method, use `download_failed` instead (Remove in 0.4.10) def downloadFailed(self, *args, **kwargs): return self.download_failed(*args, **kwargs) @@ -191,7 +191,7 @@ class Addon(Plugin): pass - #: Deprecated method, use `package_finished` instead + #: Deprecated method, use `package_finished` instead (Remove in 0.4.10) def packageFinished(self, *args, **kwargs): return self.package_finished(*args, **kwargs) @@ -200,7 +200,7 @@ class Addon(Plugin): pass - #: Deprecated method, use `before_reconnect` instead + #: Deprecated method, use `before_reconnect` instead (Remove in 0.4.10) def beforeReconnecting(self, *args, **kwargs): return self.before_reconnect(*args, **kwargs) @@ -209,7 +209,7 @@ class Addon(Plugin): pass - #: Deprecated method, use `after_reconnect` instead + #: Deprecated method, use `after_reconnect` instead (Remove in 0.4.10) def afterReconnecting(self, ip): return self.after_reconnect(ip, None) @@ -221,7 +221,7 @@ class Addon(Plugin): pass - #: Deprecated method, use `captcha_task` instead + #: Deprecated method, use `captcha_task` instead (Remove in 0.4.10) def newCaptchaTask(self, *args, **kwargs): return self.captcha_task(*args, **kwargs) @@ -230,7 +230,7 @@ class Addon(Plugin): pass - #: Deprecated method, use `captcha_correct` instead + #: Deprecated method, use `captcha_correct` instead (Remove in 0.4.10) def captchaCorrect(self, *args, **kwargs): return self.captcha_correct(*args, **kwargs) @@ -239,6 +239,6 @@ class Addon(Plugin): pass - #: Deprecated method, use `captcha_invalid` instead + #: Deprecated method, use `captcha_invalid` instead (Remove in 0.4.10) def captchaInvalid(self, *args, **kwargs): return self.captcha_invalid(*args, **kwargs) diff --git a/module/plugins/internal/CaptchaService.py b/module/plugins/internal/CaptchaService.py index 971158a36..d3eef43c8 100644 --- a/module/plugins/internal/CaptchaService.py +++ b/module/plugins/internal/CaptchaService.py @@ -3,8 +3,8 @@ from module.plugins.internal.Plugin import Plugin -class Captcha(Plugin): - __name__ = "Captcha" +class CaptchaService(Plugin): + __name__ = "CaptchaService" __type__ = "captcha" __version__ = "0.31" __status__ = "testing" diff --git a/module/plugins/internal/Container.py b/module/plugins/internal/Container.py index cc732247e..c0135fb1f 100644 --- a/module/plugins/internal/Container.py +++ b/module/plugins/internal/Container.py @@ -39,7 +39,7 @@ class Container(Crypter): self._create_packages() - #: Deprecated method, use `_load2disk` instead + #: Deprecated method, use `_load2disk` instead (Remove in 0.4.10) def loadToDisk(self, *args, **kwargs): return self._load2disk(*args, **kwargs) @@ -68,7 +68,7 @@ class Container(Crypter): self.fail(_("File not exists")) - #: Deprecated method, use `delete_tmp` instead + #: Deprecated method, use `delete_tmp` instead (Remove in 0.4.10) def deleteTmp(self, *args, **kwargs): return self.delete_tmp(*args, **kwargs) diff --git a/module/plugins/internal/Hoster.py b/module/plugins/internal/Hoster.py index 0d2e4dcc4..1d2728bd3 100644 --- a/module/plugins/internal/Hoster.py +++ b/module/plugins/internal/Hoster.py @@ -96,10 +96,10 @@ class Hoster(Plugin): self.account = None if self.account: - self.user, data = self.account.select_account() + self.user, data = self.account.select() #: Browser instance, see `network.Browser` - self.req = self.account.get_account_request(self.user) + self.req = self.account.get_request(self.user) self.chunk_limit = -1 #: Chunk limit, -1 for unlimited #: Enables resume (will be ignored if server dont accept chunks) @@ -593,7 +593,7 @@ class Hoster(Plugin): if not self.account: return True - traffic = self.account.get_account_info(self.user, True)['trafficleft'] + traffic = self.account.get_data(self.user, True)['trafficleft'] if traffic is None: return False @@ -612,7 +612,7 @@ class Hoster(Plugin): return self.pyfile.package().password or "" - #: Deprecated method, use `check_for_same_files` instead + #: 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) diff --git a/module/plugins/internal/SimpleCrypter.py b/module/plugins/internal/SimpleCrypter.py index f5cfa289d..308ba2966 100644 --- a/module/plugins/internal/SimpleCrypter.py +++ b/module/plugins/internal/SimpleCrypter.py @@ -57,8 +57,8 @@ class SimpleCrypter(Crypter, SimpleHoster): account = self.pyload.accountManager.getAccountPlugin(account_name) if account and account.can_use(): - self.user, data = account.select_account() - self.req = account.get_account_request(self.user) + self.user, data = account.select() + self.req = account.get_request(self.user) self.premium = account.is_premium(self.user) self.account = account diff --git a/module/plugins/internal/SimpleHoster.py b/module/plugins/internal/SimpleHoster.py index 5ba207934..4a293b703 100644 --- a/module/plugins/internal/SimpleHoster.py +++ b/module/plugins/internal/SimpleHoster.py @@ -101,7 +101,7 @@ class SimpleHoster(Hoster): ('Html file' , r'\A\s*<!DOCTYPE html' )] CHECK_FILE = True #: Set to False to not check the last downloaded file with declared error patterns - CHECK_TRAFFIC = False #: Set to True to force checking traffic left for premium account + CHECK_TRAFFIC = False #: Set to True to reload checking traffic left for premium account COOKIES = True #: or False or list of tuples [(domain, name, value)] DIRECT_LINK = None #: Set to True to looking for direct link (as defined in handle_direct method), set to None to do it if self.account is True else False DISPOSITION = True #: Set to True to use any content-disposition value in http header as file name @@ -499,7 +499,7 @@ class SimpleHoster(Hoster): self.check_status(getinfo=False) - #: Deprecated method + #: Deprecated method (Remove in 0.4.10) def get_fileInfo(self): self.info = {} self.check_info() diff --git a/module/plugins/internal/XFSAccount.py b/module/plugins/internal/XFSAccount.py index 8612bad63..7df169ee9 100644 --- a/module/plugins/internal/XFSAccount.py +++ b/module/plugins/internal/XFSAccount.py @@ -53,7 +53,7 @@ class XFSAccount(Account): set_cookies(req.cj, self.COOKIES) - def load_account_info(self, user, req): + def parse_info(self, user, req): validuntil = None trafficleft = None leechtraffic = None @@ -150,7 +150,7 @@ class XFSAccount(Account): 'premium' : premium} - def login(self, user, data, req): + def login(self, user, password, info, req): if not self.HOSTER_URL: #@TODO: Remove in 0.4.10 raise Exception(_("Missing HOSTER_DOMAIN")) @@ -174,4 +174,4 @@ class XFSAccount(Account): html = self.load(url, post=inputs) if re.search(self.LOGIN_FAIL_PATTERN, html): - self.wrong_password() + self.fail() |