mirror of
https://github.com/morpheus65535/bazarr
synced 2024-12-22 15:54:26 +00:00
213 lines
7.2 KiB
Python
213 lines
7.2 KiB
Python
|
from __future__ import absolute_import
|
||
|
|
||
|
import re
|
||
|
import requests
|
||
|
|
||
|
try:
|
||
|
import polling
|
||
|
except ImportError:
|
||
|
raise ImportError(
|
||
|
"Please install the python module 'polling' via pip or download it from "
|
||
|
"https://github.com/justiniso/polling/"
|
||
|
)
|
||
|
|
||
|
from ..exceptions import (
|
||
|
reCaptchaServiceUnavailable,
|
||
|
reCaptchaAPIError,
|
||
|
reCaptchaTimeout,
|
||
|
reCaptchaParameter,
|
||
|
reCaptchaBadJobID
|
||
|
)
|
||
|
|
||
|
from . import reCaptcha
|
||
|
|
||
|
|
||
|
class captchaSolver(reCaptcha):
|
||
|
|
||
|
def __init__(self):
|
||
|
super(captchaSolver, self).__init__('9kw')
|
||
|
self.host = 'https://www.9kw.eu/index.cgi'
|
||
|
self.maxtimeout = 180
|
||
|
self.session = requests.Session()
|
||
|
|
||
|
# ------------------------------------------------------------------------------- #
|
||
|
|
||
|
@staticmethod
|
||
|
def checkErrorStatus(response):
|
||
|
if response.status_code in [500, 502]:
|
||
|
raise reCaptchaServiceUnavailable(
|
||
|
f'9kw: Server Side Error {response.status_code}'
|
||
|
)
|
||
|
|
||
|
error_codes = {
|
||
|
1: 'No API Key available.',
|
||
|
2: 'No API key found.',
|
||
|
3: 'No active API key found.',
|
||
|
4: 'API Key has been disabled by the operator. ',
|
||
|
5: 'No user found.',
|
||
|
6: 'No data found.',
|
||
|
7: 'Found No ID.',
|
||
|
8: 'found No captcha.',
|
||
|
9: 'No image found.',
|
||
|
10: 'Image size not allowed.',
|
||
|
11: 'credit is not sufficient.',
|
||
|
12: 'what was done.',
|
||
|
13: 'No answer contain.',
|
||
|
14: 'Captcha already been answered.',
|
||
|
15: 'Captcha to quickly filed.',
|
||
|
16: 'JD check active.',
|
||
|
17: 'Unknown problem.',
|
||
|
18: 'Found No ID.',
|
||
|
19: 'Incorrect answer.',
|
||
|
20: 'Do not timely filed (Incorrect UserID).',
|
||
|
21: 'Link not allowed.',
|
||
|
22: 'Prohibited submit.',
|
||
|
23: 'Entering prohibited.',
|
||
|
24: 'Too little credit.',
|
||
|
25: 'No entry found.',
|
||
|
26: 'No Conditions accepted.',
|
||
|
27: 'No coupon code found in the database.',
|
||
|
28: 'Already unused voucher code.',
|
||
|
29: 'maxTimeout under 60 seconds.',
|
||
|
30: 'User not found.',
|
||
|
31: 'An account is not yet 24 hours in system.',
|
||
|
32: 'An account does not have the full rights.',
|
||
|
33: 'Plugin needed a update.',
|
||
|
34: 'No HTTPS allowed.',
|
||
|
35: 'No HTTP allowed.',
|
||
|
36: 'Source not allowed.',
|
||
|
37: 'Transfer denied.',
|
||
|
38: 'Incorrect answer without space',
|
||
|
39: 'Incorrect answer with space',
|
||
|
40: 'Incorrect answer with not only numbers',
|
||
|
41: 'Incorrect answer with not only A-Z, a-z',
|
||
|
42: 'Incorrect answer with not only 0-9, A-Z, a-z',
|
||
|
43: 'Incorrect answer with not only [0-9,- ]',
|
||
|
44: 'Incorrect answer with not only [0-9A-Za-z,- ]',
|
||
|
45: 'Incorrect answer with not only coordinates',
|
||
|
46: 'Incorrect answer with not only multiple coordinates',
|
||
|
47: 'Incorrect answer with not only data',
|
||
|
48: 'Incorrect answer with not only rotate number',
|
||
|
49: 'Incorrect answer with not only text',
|
||
|
50: 'Incorrect answer with not only text and too short',
|
||
|
51: 'Incorrect answer with not enough chars',
|
||
|
52: 'Incorrect answer with too many chars',
|
||
|
53: 'Incorrect answer without no or yes',
|
||
|
54: 'Assignment was not found.'
|
||
|
}
|
||
|
|
||
|
if response.text.startswith('{'):
|
||
|
if response.json().get('error'):
|
||
|
raise reCaptchaAPIError(error_codes.get(int(response.json().get('error'))))
|
||
|
else:
|
||
|
error_code = int(re.search(r'^00(?P<error_code>\d+)', response.text).groupdict().get('error_code', 0))
|
||
|
if error_code:
|
||
|
raise reCaptchaAPIError(error_codes.get(error_code))
|
||
|
|
||
|
# ------------------------------------------------------------------------------- #
|
||
|
|
||
|
def requestJob(self, jobID):
|
||
|
if not jobID:
|
||
|
raise reCaptchaBadJobID(
|
||
|
"9kw: Error bad job id to request reCaptcha against."
|
||
|
)
|
||
|
|
||
|
def _checkRequest(response):
|
||
|
if response.ok and response.json().get('answer') != 'NO DATA':
|
||
|
return response
|
||
|
|
||
|
self.checkErrorStatus(response)
|
||
|
|
||
|
return None
|
||
|
|
||
|
response = polling.poll(
|
||
|
lambda: self.session.get(
|
||
|
self.host,
|
||
|
params={
|
||
|
'apikey': self.api_key,
|
||
|
'action': 'usercaptchacorrectdata',
|
||
|
'id': jobID,
|
||
|
'info': 1,
|
||
|
'json': 1
|
||
|
}
|
||
|
),
|
||
|
check_success=_checkRequest,
|
||
|
step=10,
|
||
|
timeout=(self.maxtimeout + 10)
|
||
|
)
|
||
|
|
||
|
if response:
|
||
|
return response.json().get('answer')
|
||
|
else:
|
||
|
raise reCaptchaTimeout("9kw: Error failed to solve reCaptcha.")
|
||
|
|
||
|
# ------------------------------------------------------------------------------- #
|
||
|
|
||
|
def requestSolve(self, captchaType, url, siteKey):
|
||
|
def _checkRequest(response):
|
||
|
if response.ok and response.text.startswith('{') and response.json().get('captchaid'):
|
||
|
return response
|
||
|
|
||
|
self.checkErrorStatus(response)
|
||
|
|
||
|
return None
|
||
|
|
||
|
captchaMap = {
|
||
|
'reCaptcha': 'recaptchav2',
|
||
|
'hCaptcha': 'hcaptcha'
|
||
|
}
|
||
|
|
||
|
response = polling.poll(
|
||
|
lambda: self.session.post(
|
||
|
self.host,
|
||
|
data={
|
||
|
'apikey': self.api_key,
|
||
|
'action': 'usercaptchaupload',
|
||
|
'interactive': 1,
|
||
|
'file-upload-01': siteKey,
|
||
|
'oldsource': captchaMap[captchaType],
|
||
|
'pageurl': url,
|
||
|
'maxtimeout': self.maxtimeout,
|
||
|
'json': 1
|
||
|
},
|
||
|
allow_redirects=False
|
||
|
),
|
||
|
check_success=_checkRequest,
|
||
|
step=5,
|
||
|
timeout=(self.maxtimeout + 10)
|
||
|
)
|
||
|
|
||
|
if response:
|
||
|
return response.json().get('captchaid')
|
||
|
else:
|
||
|
raise reCaptchaBadJobID('9kw: Error no valid job id was returned.')
|
||
|
|
||
|
# ------------------------------------------------------------------------------- #
|
||
|
|
||
|
def getCaptchaAnswer(self, captchaType, url, siteKey, reCaptchaParams):
|
||
|
jobID = None
|
||
|
|
||
|
if not reCaptchaParams.get('api_key'):
|
||
|
raise reCaptchaParameter("9kw: Missing api_key parameter.")
|
||
|
|
||
|
self.api_key = reCaptchaParams.get('api_key')
|
||
|
|
||
|
if reCaptchaParams.get('maxtimeout'):
|
||
|
self.maxtimeout = reCaptchaParams.get('maxtimeout')
|
||
|
|
||
|
if reCaptchaParams.get('proxy'):
|
||
|
self.session.proxies = reCaptchaParams.get('proxies')
|
||
|
|
||
|
try:
|
||
|
jobID = self.requestSolve(captchaType, url, siteKey)
|
||
|
return self.requestJob(jobID)
|
||
|
except polling.TimeoutException:
|
||
|
raise reCaptchaTimeout(
|
||
|
f"9kw: reCaptcha solve took to long to execute 'captchaid' {jobID}, aborting."
|
||
|
)
|
||
|
|
||
|
# ------------------------------------------------------------------------------- #
|
||
|
|
||
|
|
||
|
captchaSolver()
|