diff options
| author | 2013-08-08 17:38:35 +0200 | |
|---|---|---|
| committer | 2013-08-08 17:38:35 +0200 | |
| commit | 52f6599748ef61219112111dc5db71f3342b076d (patch) | |
| tree | e3627ded64b7e98493ca1ec7bd182aaa1774252e /pyload/plugins | |
| parent | MultiHosters: moved settings to addon plugins. (diff) | |
| download | pyload-52f6599748ef61219112111dc5db71f3342b076d.tar.xz | |
adapted account api to multi user, fixed http referer bug
Diffstat (limited to 'pyload/plugins')
| -rw-r--r-- | pyload/plugins/Account.py | 118 | ||||
| -rw-r--r-- | pyload/plugins/Base.py | 2 | ||||
| -rw-r--r-- | pyload/plugins/Hoster.py | 8 | ||||
| -rw-r--r-- | pyload/plugins/ReCaptcha.py | 22 | ||||
| -rw-r--r-- | pyload/plugins/accounts/Http.py | 7 | ||||
| -rw-r--r-- | pyload/plugins/addons/MultiHoster.py | 8 | ||||
| -rw-r--r-- | pyload/plugins/internal/CaptchaService.py | 2 | ||||
| -rw-r--r-- | pyload/plugins/network/CurlRequest.py | 2 | ||||
| -rw-r--r-- | pyload/plugins/network/XDCCRequest.py | 162 | 
9 files changed, 245 insertions, 86 deletions
| diff --git a/pyload/plugins/Account.py b/pyload/plugins/Account.py index 4492dfa18..b3e26ce58 100644 --- a/pyload/plugins/Account.py +++ b/pyload/plugins/Account.py @@ -1,12 +1,12 @@  # -*- coding: utf-8 -*-  from time import time -from traceback import print_exc  from threading import RLock -from pyload.utils import compare_time, format_size, parseFileSize, lock, to_bool -from pyload.Api import AccountInfo +from pyload.Api import AccountInfo, ConfigItem  from pyload.network.CookieJar import CookieJar +from pyload.config.convert import from_string, to_configdata +from pyload.utils import to_string, compare_time, format_size, parseFileSize, lock  from Base import Base @@ -29,40 +29,30 @@ class Account(Base):      UNLIMITED = -2      # Default values -    owner = None      valid = True      validuntil = -1      trafficleft = -1      maxtraffic = -1      premium = True -    activated = True -    shared = False      #: after that time [in minutes] pyload will relogin the account      login_timeout = 600      #: account data will be reloaded after this time      info_threshold = 600 -    # known options -    known_opt = ("time", "limitDL") +    @classmethod +    def fromInfoData(cls, m, info, password, options): +        return cls(m, info.loginname, info.owner, +                   True if info.activated else False, True if info.shared else False, password, options) -    def __init__(self, manager, loginname, password, options): -        Base.__init__(self, manager.core) - -        if "activated" in options: -            self.activated = to_bool(options["activated"]) -        else: -            self.activated = Account.activated - -        for opt in self.known_opt: -            if opt not in options: -                options[opt] = "" - -        for opt in options.keys(): -            if opt not in self.known_opt: -                del options[opt] +    def __init__(self, manager, loginname, owner, activated, shared, password, options): +        Base.__init__(self, manager.core, owner)          self.loginname = loginname +        self.owner = owner +        self.activated = activated +        self.shared = shared +        self.password = password          self.options = options          self.manager = manager @@ -71,25 +61,58 @@ class Account(Base):          self.timestamp = 0          self.login_ts = 0 # timestamp for login          self.cj = CookieJar() -        self.password = password          self.error = None +        try: +            self.config_data = dict(to_configdata(x) for x in self.__config__) +        except Exception, e: +            self.logError("Invalid config: %s" % e) +            self.config_data = {} +          self.init()      def toInfoData(self): -        return AccountInfo(self.__name__, self.loginname, self.owner, self.valid, self.validuntil, self.trafficleft, -                           self.maxtraffic, -                           self.premium, self.activated, self.shared, self.options) +        info = AccountInfo(self.__name__, self.loginname, self.owner, self.valid, self.validuntil, self.trafficleft, +                           self.maxtraffic, self.premium, self.activated, self.shared, self.options) + +        info.config = [ConfigItem(name, item.label, item.description, item.input, +                                  to_string(self.getConfig(name))) for name, item in +                       self.config_data.iteritems()] +        return info      def init(self):          pass +    def getConfig(self, option): +        """ Gets an option that was configured via the account options dialog and +        is only valid for this specific instance.""" +        if option not in self.config_data: +            return Base.getConfig(self, option) + +        if option in self.options: +            return self.options[option] + +        return self.config_data[option].input.default_value + +    def setConfig(self, option, value): +        """ Sets a config value for this account instance. Fallsback """ +        if option not in self.config_data: +            return Base.setConfig(self, option, value) + +        value = from_string(value, self.config_data[option].input.type) +        # given value is the default value and does not need to be saved at all +        if value == self.config_data[option].input.default_value: +            if option in self.options: +                del self.options[option] +        else: +            self.options[option] = from_string(value, self.config_data[option].input.type) +      def login(self, req):          """login into account, the cookies will be saved so the user can be recognized          :param req: `Request` instance          """ -        raise NotImplemented +        raise NotImplementedError      def relogin(self):          """ Force a login. """ @@ -123,8 +146,7 @@ class Account(Base):                  _("Could not login with account %(user)s | %(msg)s") % {"user": self.loginname                      , "msg": e})              self.valid = False -            if self.core.debug: -                print_exc() +            self.core.print_exc()          return self.valid @@ -134,28 +156,24 @@ class Account(Base):          self.maxtraffic = Account.maxtraffic          self.premium = Account.premium -    def update(self, password=None, options=None): -        """ updates the account and returns true if anything changed """ - -        self.login_ts = 0 -        self.valid = True #set valid, so the login will be retried +    def setPassword(self, password): +        """ updates the password and returns true if anything changed """ -        if "activated" in options: -            self.activated = True if options["activated"] == "True" else False +        if password != self.password: +            self.login_ts = 0 +            self.valid = True #set valid, so the login will be retried -        if password:              self.password = password -            self.relogin()              return True -        if options: -            # remove unknown options -            for opt in options.keys(): -                if opt not in self.known_opt: -                    del options[opt] -            before = self.options -            self.options.update(options) -            return self.options != before +        return False + +    def updateConfig(self, items): +        """  Updates the accounts options from config items """ +        for item in items: +            # Check if a valid option +            if item.name in self.config_data: +                self.setConfig(item.name, item.value)      def getAccountRequest(self):          return self.core.requestFactory.getRequest(self.cj) @@ -163,7 +181,7 @@ class Account(Base):      def getDownloadSettings(self):          """ Can be overwritten to change download settings. Default is no chunkLimit, max dl limit, resumeDownload -        :return: (chunkLimit, limitDL, resumeDownload) / (int, int ,bool) +        :return: (chunkLimit, limitDL, resumeDownload) / (int, int, bool)          """          return -1, 0, True @@ -229,9 +247,11 @@ class Account(Base):      def isUsable(self):          """Check several constraints to determine if account should be used""" +          if not self.valid or not self.activated: return False -        if self.options["time"]: +        # TODO: not in ui currently +        if "time" in self.options and self.options["time"]:              time_data = ""              try:                  time_data = self.options["time"] diff --git a/pyload/plugins/Base.py b/pyload/plugins/Base.py index cd4831d82..3ca8abdd0 100644 --- a/pyload/plugins/Base.py +++ b/pyload/plugins/Base.py @@ -92,7 +92,7 @@ class Base(object):          self.evm = core.eventManager          #: :class:`InteractionManager`          self.im = core.interactionManager -        if user: +        if user is not None:              #: :class:`Api`, user api when user is set              self.api = self.core.api.withUserContext(user)              if not self.api: diff --git a/pyload/plugins/Hoster.py b/pyload/plugins/Hoster.py index 44b10899d..b3be7a9e9 100644 --- a/pyload/plugins/Hoster.py +++ b/pyload/plugins/Hoster.py @@ -82,17 +82,13 @@ class Hoster(Base):          self.ocr = None  #captcha reader instance          #: account handler instance, see :py:class:`Account` -        self.account = self.core.accountManager.getAccountForPlugin(self.__name__) +        self.account = self.core.accountManager.selectAccount(self.__name__, self.user)          #: premium status          self.premium = False -        #: username/login -        self.user = None -        if self.account and not self.account.isUsable(): self.account = None          if self.account: -            self.user = self.account.loginname -            #: Browser instance, see `network.Browser` +            #: Request instance bound to account              self.req = self.account.getAccountRequest()              # Default:  -1, True, True              self.chunkLimit, self.limitDL, self.resumeDownload = self.account.getDownloadSettings() diff --git a/pyload/plugins/ReCaptcha.py b/pyload/plugins/ReCaptcha.py deleted file mode 100644 index e47522b4a..000000000 --- a/pyload/plugins/ReCaptcha.py +++ /dev/null @@ -1,22 +0,0 @@ -import re - -class ReCaptcha(): -    def __init__(self, plugin): -        self.plugin = plugin -        self.plugin.logDebug("Deprecated usage of ReCaptcha: Use CaptchaService instead") -     -    def challenge(self, id): -        js = self.plugin.req.load("http://www.google.com/recaptcha/api/challenge", get={"k":id}, cookies=True) -         -        try: -            challenge = re.search("challenge : '(.*?)',", js).group(1) -            server = re.search("server : '(.*?)',", js).group(1) -        except: -            self.plugin.fail("recaptcha error") -        result = self.result(server,challenge) -         -        return challenge, result - -    def result(self, server, challenge): -        return self.plugin.decryptCaptcha("%simage"%server, get={"c":challenge}, cookies=True, imgtype="jpg") -         diff --git a/pyload/plugins/accounts/Http.py b/pyload/plugins/accounts/Http.py index 5701d1f03..de9490b2c 100644 --- a/pyload/plugins/accounts/Http.py +++ b/pyload/plugins/accounts/Http.py @@ -1,6 +1,6 @@  # -*- coding: utf-8 -*- -from module.plugins.Account import Account +from pyload.plugins.Account import Account  class Http(Account): @@ -11,4 +11,9 @@ class Http(Account):      __author_name__ = ("zoidberg")      __author_mail__ = ("zoidberg@mujmail.cz") +    __config__ = [("domain", "str", "Domain", "")] +      login_timeout = info_threshold = 1000000 + +    def login(self, req): +        pass
\ No newline at end of file diff --git a/pyload/plugins/addons/MultiHoster.py b/pyload/plugins/addons/MultiHoster.py index 329a87e4a..446dfe922 100644 --- a/pyload/plugins/addons/MultiHoster.py +++ b/pyload/plugins/addons/MultiHoster.py @@ -72,18 +72,18 @@ class MultiHoster(Addon):      @AddEventListener("account:deleted") -    def refreshAccounts(self, plugin=None, user=None): +    def refreshAccounts(self, plugin=None, loginname=None):          self.logDebug("Re-checking accounts")          self.plugins = {} -        for name, account in self.core.accountManager.iterAccounts(): +        for plugin, account in self.core.accountManager.iterAccounts():              if isinstance(account, MultiHosterAccount) and account.isUsable():                  self.addHoster(account)      @AddEventListener("account:updated") -    def refreshAccount(self, plugin, user): +    def refreshAccount(self, plugin, loginname): -        account = self.core.accountManager.getAccount(plugin, user) +        account = self.core.accountManager.getAccount(plugin, loginname)          if isinstance(account, MultiHosterAccount) and account.isUsable():              self.addHoster(account) diff --git a/pyload/plugins/internal/CaptchaService.py b/pyload/plugins/internal/CaptchaService.py index b912436a7..4f903e3e6 100644 --- a/pyload/plugins/internal/CaptchaService.py +++ b/pyload/plugins/internal/CaptchaService.py @@ -60,8 +60,6 @@ class AdsCaptcha(CaptchaService):          return self.plugin.decryptCaptcha("%sChallenge.aspx" % server, get={"cid": challenge, "dummy": random()}, cookies=True, imgtype="jpg")  class SolveMedia(CaptchaService): -    def __init__(self,plugin): -        self.plugin = plugin      def challenge(self, src):          html = self.plugin.req.load("http://api.solvemedia.com/papi/challenge.noscript?k=%s" % src, cookies=True) diff --git a/pyload/plugins/network/CurlRequest.py b/pyload/plugins/network/CurlRequest.py index 775c98522..b7e37900b 100644 --- a/pyload/plugins/network/CurlRequest.py +++ b/pyload/plugins/network/CurlRequest.py @@ -152,7 +152,6 @@ class CurlRequest(Request):              url = "%s?%s" % (url, get)          self.c.setopt(pycurl.URL, url) -        self.lastURL = url          if post:              self.c.setopt(pycurl.POST, 1) @@ -222,6 +221,7 @@ class CurlRequest(Request):              rep = self.getResponse()          self.c.setopt(pycurl.POSTFIELDS, "") +        self.lastURL = url          self.lastEffectiveURL = self.c.getinfo(pycurl.EFFECTIVE_URL)          self.code = self.verifyHeader() diff --git a/pyload/plugins/network/XDCCRequest.py b/pyload/plugins/network/XDCCRequest.py new file mode 100644 index 000000000..6b692ab38 --- /dev/null +++ b/pyload/plugins/network/XDCCRequest.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +    This program is free software; you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation; either version 3 of the License, +    or (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +    See the GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program; if not, see <http://www.gnu.org/licenses/>. +     +    @author: jeix +""" + +import socket +import re + +from os import remove +from os.path import exists + +from time import time + +import struct +from select import select + +from pyload.plugins.Plugin import Abort + +# TODO: This must be adapted to the new request interfaces +class XDCCRequest(): +    def __init__(self, timeout=30, proxies={}): +         +        self.proxies = proxies +        self.timeout = timeout +         +        self.filesize = 0 +        self.recv = 0 +        self.speed = 0 +         +        self.abort = False + +     +    def createSocket(self): +        # proxytype = None +        # proxy = None +        # if self.proxies.has_key("socks5"): +            # proxytype = socks.PROXY_TYPE_SOCKS5 +            # proxy = self.proxies["socks5"] +        # elif self.proxies.has_key("socks4"): +            # proxytype = socks.PROXY_TYPE_SOCKS4 +            # proxy = self.proxies["socks4"] +        # if proxytype: +            # sock = socks.socksocket() +            # t = _parse_proxy(proxy) +            # sock.setproxy(proxytype, addr=t[3].split(":")[0], port=int(t[3].split(":")[1]), username=t[1], password=t[2]) +        # else: +            # sock = socket.socket() +        # return sock +         +        return socket.socket() +     +    def download(self, ip, port, filename, irc, progressNotify=None): + +        ircbuffer = "" +        lastUpdate = time() +        cumRecvLen = 0 +         +        dccsock = self.createSocket() +         +        dccsock.settimeout(self.timeout) +        dccsock.connect((ip, port)) +         +        if exists(filename): +            i = 0 +            nameParts = filename.rpartition(".") +            while True: +                newfilename = "%s-%d%s%s" % (nameParts[0], i, nameParts[1], nameParts[2]) +                i += 1 +                 +                if not exists(newfilename): +                    filename = newfilename +                    break +         +        fh = open(filename, "wb") +         +        # recv loop for dcc socket +        while True: +            if self.abort: +                dccsock.close() +                fh.close() +                remove(filename) +                raise Abort() +             +            self._keepAlive(irc, ircbuffer) +             +            data = dccsock.recv(4096) +            dataLen = len(data) +            self.recv += dataLen +             +            cumRecvLen += dataLen +             +            now = time() +            timespan = now - lastUpdate +            if timespan > 1:             +                self.speed = cumRecvLen / timespan +                cumRecvLen = 0 +                lastUpdate = now +                 +                if progressNotify: +                    progressNotify(self.percent) +             +             +            if not data: +                break +             +            fh.write(data) +             +            # acknowledge data by sending number of received bytes +            dccsock.send(struct.pack('!I', self.recv)) +         +        dccsock.close() +        fh.close() +         +        return filename +     +    def _keepAlive(self, sock, readbuffer): +        fdset = select([sock], [], [], 0) +        if sock not in fdset[0]: +            return +             +        readbuffer += sock.recv(1024) +        temp = readbuffer.split("\n") +        readbuffer = temp.pop() + +        for line in temp: +            line  = line.rstrip() +            first = line.split() +            if first[0] == "PING": +                sock.send("PONG %s\r\n" % first[1]) + +    def abortDownloads(self): +        self.abort = True +     +    @property +    def size(self): +        return self.filesize + +    @property +    def arrived(self): +        return self.recv + +    @property +    def percent(self): +        if not self.filesize: return 0 +        return (self.recv * 100) / self.filesize + +    def close(self): +        pass | 
