diff options
| author | 2012-08-02 01:37:54 +0200 | |
|---|---|---|
| committer | 2012-08-02 01:37:54 +0200 | |
| commit | b0e1d4a508746972ba92fb35a0616c2208fdd131 (patch) | |
| tree | cf712ea9cf2c0099f538ea3e6771b53995917da5 | |
| parent | CaptchaBrotherhood plugin (diff) | |
| download | pyload-b0e1d4a508746972ba92fb35a0616c2208fdd131.tar.xz | |
DeathByCaptcha plugin
| -rw-r--r-- | module/plugins/hooks/DeathByCaptcha.py | 190 | 
1 files changed, 190 insertions, 0 deletions
| diff --git a/module/plugins/hooks/DeathByCaptcha.py b/module/plugins/hooks/DeathByCaptcha.py new file mode 100644 index 000000000..ab64299dd --- /dev/null +++ b/module/plugins/hooks/DeathByCaptcha.py @@ -0,0 +1,190 @@ +# -*- 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: mkaay, RaNaN, zoidberg +""" + +from thread import start_new_thread +from pycurl import FORM_FILE, HTTPHEADER, RESPONSE_CODE +from time import sleep + +from module.network.RequestFactory import getURL, getRequest +from module.network.HTTPRequest import BadHeader +from module.plugins.Hook import Hook +from module.common.json_layer import json_loads + +class DeathByCaptchaException(Exception): +    DBC_ERRORS = {'not-logged-in': 'Access denied, check your credentials', +                  'invalid-credentials': 'Access denied, check your credentials', +                  'banned': 'Access denied, account is suspended', +                  'insufficient-funds': 'Insufficient account balance to decrypt CAPTCHA', +                  'invalid-captcha': 'CAPTCHA is not a valid image', +                  'service-overload': 'CAPTCHA was rejected due to service overload, try again later', +                  'invalid-request': 'Invalid request', +                  'timed-out': 'No CAPTCHA solution received in time' }  +     +    def __init__(self, err): +        self.err = err + +    def getCode(self): +        return self.err +         +    def getDesc(self): +        if self.err in self.DBC_ERRORS.keys(): +            return self.DBC_ERRORS[self.err] +        else: +            return self.err + +    def __str__(self): +        return "<DeathByCaptchaException %s>" % self.err + +    def __repr__(self): +        return "<DeathByCaptchaException %s>" % self.err + +class DeathByCaptcha(Hook): +    __name__ = "DeathByCaptcha" +    __version__ = "0.02" +    __description__ = """send captchas to DeathByCaptcha.com""" +    __config__ = [("activated", "bool", "Activated", False), +                  ("username", "str", "Username", ""), +                  ("passkey", "password", "Password", ""), +                  ("force", "bool", "Force DBC even if client is connected", False)] +    __author_name__ = ("RaNaN", "zoidberg") +    __author_mail__ = ("RaNaN@pyload.org", "zoidberg@mujmail.cz") + +    API_URL = "http://api.dbcapi.me/api/" + +    def setup(self): +        self.info = {} + +    def call_api(self, api="captcha", post=False, multipart=False): +        req = getRequest() +        req.c.setopt(HTTPHEADER, ["Accept: application/json",  +                                  "User-Agent: pyLoad %s" % self.core.version]) +         +        if post: +            if not isinstance(post, dict): +                post = {} +            post.update({"username": self.getConfig("username"), +                         "password": self.getConfig("passkey")})                           +         +        response = None +        try: +            json = req.load("%s%s" % (self.API_URL, api),  +                            post = post, +                            multipart=multipart) +            self.logDebug(json)             +            response = json_loads(json) +             +            if "error" in response: +                raise DeathByCaptchaException(response['error']) +            elif "status" not in response: +                raise DeathByCaptchaException(str(response)) +             +        except BadHeader, e: +            if 403 == e.code: +                raise DeathByCaptchaException('not-logged-in')             +            elif 413 == e.code: +                raise DeathByCaptchaException('invalid-captcha') +            elif 503 == e.code: +                raise DeathByCaptchaException('service-overload') +            elif e.code in (400, 405): +                raise DeathByCaptchaException('invalid-request') +            else: +                raise +                                                    +        finally: +            req.close() +             +        return response +         +    def getCredits(self): +        response = self.call_api("user", True) + +        if 'is_banned' in response and response['is_banned']: +            raise DeathByCaptchaException('banned') +        elif 'balance' in response and 'rate' in response: +            self.info.update(response) +        else: +            raise DeathByCaptchaException(response) + +    def submit(self, captcha, captchaType="file", match=None): +        response = self.call_api("captcha", {"captchafile": (FORM_FILE, captcha)}, True) +         +        if "captcha" not in response: +            raise DeathByCaptchaException(response) +        ticket = response['captcha'] +         +        for i in range(24): +            sleep(5) +            response = self.call_api("captcha/%d" % ticket, False)                +            if response['text'] and response['is_correct']: +                break +        else: +            raise DeathByCaptchaException('timed-out')             +                 +        result = response['text'] +        self.logDebug("result %s : %s" % (ticket,result)) + +        return ticket, result + +    def newCaptchaTask(self, task): +        if "service" in task.data: +            return False +     +        if not task.isTextual(): +            return False + +        if not self.getConfig("username") or not self.getConfig("passkey"): +            return False + +        if self.core.isClientConnected() and not self.getConfig("force"): +            return False +         +        try: +            self.getCredits()                                                          +        except DeathByCaptchaException, e: +            self.logError(e.getDesc()) +            return False +         +        balance, rate = self.info["balance"], self.info["rate"] +        self.logInfo("Account balance: US$%.3f (%d captchas left at %.2f cents each)" % (balance / 100, balance // rate, rate)) +             +        if balance > rate:             +            task.handler.append(self) +            task.data['service'] = self.__name__ +            task.setWaiting(180) +            start_new_thread(self.processCaptcha, (task,))         + +    def captchaInvalid(self, task): +        if task.data['service'] == self.__name__ and "ticket" in task.data: +            try: +                response = self.call_api("captcha/%d/report" % task.data["ticket"], True) +            except DeathByCaptchaException, e: +                self.logError(e.getDesc()) +            except Exception, e: +                self.logError(e) + +    def processCaptcha(self, task): +        c = task.captchaFile +        try: +            ticket, result = self.submit(c) +        except DeathByCaptchaException, e: +            task.error = e.getCode() +            self.logError(e.getDesc()) +            return + +        task.data["ticket"] = ticket +        task.setResult(result)
\ No newline at end of file | 
