tweepy-self 1.6.3__py3-none-any.whl → 1.10.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tweepy_self-1.6.3.dist-info → tweepy_self-1.10.0b1.dist-info}/METADATA +16 -9
- tweepy_self-1.10.0b1.dist-info/RECORD +23 -0
- twitter/__init__.py +15 -5
- twitter/_capsolver/__init__.py +0 -0
- twitter/_capsolver/core/__init__.py +0 -0
- twitter/_capsolver/core/base.py +227 -0
- twitter/_capsolver/core/config.py +36 -0
- twitter/_capsolver/core/enum.py +66 -0
- twitter/_capsolver/core/serializer.py +85 -0
- twitter/_capsolver/fun_captcha.py +260 -0
- twitter/account.py +17 -13
- twitter/base/__init__.py +2 -2
- twitter/base/client.py +4 -4
- twitter/client.py +388 -222
- twitter/errors.py +14 -7
- twitter/models.py +126 -50
- twitter/utils/__init__.py +2 -0
- twitter/utils/other.py +13 -0
- tweepy_self-1.6.3.dist-info/RECORD +0 -16
- {tweepy_self-1.6.3.dist-info → tweepy_self-1.10.0b1.dist-info}/WHEEL +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: tweepy-self
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.10.0b1
|
4
4
|
Summary: Twitter (selfbot) for Python!
|
5
5
|
Home-page: https://github.com/alenkimov/tweepy-self
|
6
6
|
Author: Alen
|
@@ -9,15 +9,19 @@ Requires-Python: >=3.11,<4.0
|
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
10
10
|
Classifier: Programming Language :: Python :: 3.11
|
11
11
|
Classifier: Programming Language :: Python :: 3.12
|
12
|
+
Requires-Dist: aiohttp (>=3.9,<4.0)
|
12
13
|
Requires-Dist: beautifulsoup4 (>=4,<5)
|
13
|
-
Requires-Dist: better-proxy (
|
14
|
-
Requires-Dist: curl_cffi (==0.6.
|
14
|
+
Requires-Dist: better-proxy (>=1.1,<2.0)
|
15
|
+
Requires-Dist: curl_cffi (==0.6.2)
|
16
|
+
Requires-Dist: loguru (>=0.7,<0.8)
|
15
17
|
Requires-Dist: lxml (>=5,<6)
|
16
18
|
Requires-Dist: pydantic (>=1)
|
17
19
|
Requires-Dist: pyotp (>=2,<3)
|
18
|
-
Requires-Dist:
|
20
|
+
Requires-Dist: requests (>=2,<3)
|
21
|
+
Requires-Dist: tenacity (>=8,<9)
|
19
22
|
Requires-Dist: yarl (>=1,<2)
|
20
23
|
Project-URL: Repository, https://github.com/alenkimov/tweepy-self
|
24
|
+
Project-URL: Source, https://github.com/alenkimov/tweepy-self
|
21
25
|
Description-Content-Type: text/markdown
|
22
26
|
|
23
27
|
# Tweepy-self
|
@@ -99,9 +103,10 @@ Automating user accounts is against the Twitter ToS. This library is a proof of
|
|
99
103
|
|
100
104
|
### Примеры работы
|
101
105
|
Запрос информации о пользователе:
|
106
|
+
|
102
107
|
```python
|
103
108
|
# Запрос информации о текущем пользователе:
|
104
|
-
me = await twitter_client.
|
109
|
+
me = await twitter_client.request_user()
|
105
110
|
print(f"[{account.short_auth_token}] {me}")
|
106
111
|
print(f"Аккаунт создан: {me.created_at}")
|
107
112
|
print(f"Following (подписан ты): {me.followings_count}")
|
@@ -109,17 +114,18 @@ print(f"Followers (подписаны на тебя): {me.followers_count}")
|
|
109
114
|
print(f"Прочая информация: {me.raw_data}")
|
110
115
|
|
111
116
|
# Запрос информации об ином пользователе:
|
112
|
-
elonmusk = await twitter.
|
117
|
+
elonmusk = await twitter.request_user("@elonmusk")
|
113
118
|
print(elonmusk)
|
114
119
|
```
|
115
120
|
|
116
121
|
Смена имени пользователя и пароля:
|
122
|
+
|
117
123
|
```python
|
118
124
|
account = twitter.Account("auth_token", password="password")
|
119
125
|
...
|
120
126
|
await twitter_client.change_username("new_username")
|
121
|
-
await twitter_client.
|
122
|
-
print(f"New username: {account.
|
127
|
+
await twitter_client.request_user()
|
128
|
+
print(f"New username: {account.username}")
|
123
129
|
|
124
130
|
await twitter_client.change_password("new_password")
|
125
131
|
print(f"New password: {account.password}")
|
@@ -165,8 +171,9 @@ bind_code = await twitter_client.oauth_2(**bind_data)
|
|
165
171
|
```
|
166
172
|
|
167
173
|
Отправка сообщения:
|
174
|
+
|
168
175
|
```python
|
169
|
-
bro = await twitter_client.
|
176
|
+
bro = await twitter_client.request_user("@username")
|
170
177
|
await twitter_client.send_message(bro.id, "I love you!")
|
171
178
|
```
|
172
179
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
twitter/__init__.py,sha256=-CmcPdm1z-OkG8LkJVe75PwdYKBqBfMpD9WdoXcnGuc,732
|
2
|
+
twitter/_capsolver/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
+
twitter/_capsolver/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
|
+
twitter/_capsolver/core/base.py,sha256=In3qDLgRh1z1UZLaLFgYcDEdnqW3d62PVzgEjU2S4BU,8883
|
5
|
+
twitter/_capsolver/core/config.py,sha256=8_eXT6N2hBheN2uCMNhqk8tLZRJjLDTYLK208fqIkhM,1054
|
6
|
+
twitter/_capsolver/core/enum.py,sha256=ivfAEN6jrg3iaq5C3H7CuRqsvOloX1b8lF8cLa3zaiY,1741
|
7
|
+
twitter/_capsolver/core/serializer.py,sha256=xPEUIPgytuw2wM1ubTY3RMhJGVyp_d3bokPTx0BjF0c,2602
|
8
|
+
twitter/_capsolver/fun_captcha.py,sha256=VVbTmn08cGnvPMGdJmPxaLfAIPxyA68oTSAyEL8RWnU,10974
|
9
|
+
twitter/account.py,sha256=joAB5Zw-Le5E3kOZ-1nb4DPGlTqWYv2Vs6gJ3cwu7is,3175
|
10
|
+
twitter/base/__init__.py,sha256=Q2ko0HeOS5tiBnDVKxxaZYetwRR3YXJ67ujL3oThGd4,141
|
11
|
+
twitter/base/client.py,sha256=J_iL4ZGfwTbZ2gpjtFCbBxNgt7weJ55EeMGzYsLtjf4,500
|
12
|
+
twitter/base/session.py,sha256=JFPS-9Qae1iY3NfNcywxvWWmRDijaU_Rjs3WaQ00iFA,2071
|
13
|
+
twitter/client.py,sha256=CySQ-hTFiPGFKhPBNw4nn_xnO5hdpjmXK90QpSEzRG4,66878
|
14
|
+
twitter/enums.py,sha256=-OH6Ibxarq5qt4E2AhkProVawcEyIf5YG_h_G5xiV9Y,270
|
15
|
+
twitter/errors.py,sha256=oNa0Neos80ZK4-0FBzqgxXonH564qFnoN-kavHalfR4,5274
|
16
|
+
twitter/models.py,sha256=7yObMPUUEwJEbraHzFwmUKd91UhR2-zyfJTm4xIqrSQ,4834
|
17
|
+
twitter/utils/__init__.py,sha256=usxpfcRQ7zxTTgZ-i425tT7hIz73Pwh9FDj4t6O3dYg,663
|
18
|
+
twitter/utils/file.py,sha256=Sz2KEF9DnL04aOP1XabuMYMMF4VR8dJ_KWMEVvQ666Y,1120
|
19
|
+
twitter/utils/html.py,sha256=hVtIRFI2yRAdWEaShFNBG-_ZWxd16og8i8OVDnFy5Hc,1971
|
20
|
+
twitter/utils/other.py,sha256=9RIYF2AMdmNKIwClG3jBP7zlvxZPEgYfuHaIiOhURzM,1061
|
21
|
+
tweepy_self-1.10.0b1.dist-info/METADATA,sha256=FRxYUeZHlrxUB9Jr_nbxlhEkLc1pjO-ik_XiShkwARg,9438
|
22
|
+
tweepy_self-1.10.0b1.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
23
|
+
tweepy_self-1.10.0b1.dist-info/RECORD,,
|
twitter/__init__.py
CHANGED
@@ -6,14 +6,23 @@ A basic wrapper for the Twitter user API.
|
|
6
6
|
"""
|
7
7
|
|
8
8
|
from .client import Client
|
9
|
-
from .account import
|
10
|
-
|
9
|
+
from .account import (
|
10
|
+
Account,
|
11
|
+
AccountStatus,
|
12
|
+
load_accounts_from_file,
|
13
|
+
extract_accounts_to_file,
|
14
|
+
)
|
15
|
+
from .models import Tweet, User, Media, Image
|
11
16
|
from . import errors, utils
|
12
17
|
|
13
18
|
__all__ = [
|
14
19
|
"Client",
|
15
20
|
"Account",
|
16
21
|
"AccountStatus",
|
22
|
+
"Tweet",
|
23
|
+
"User",
|
24
|
+
"Media",
|
25
|
+
"Image",
|
17
26
|
"utils",
|
18
27
|
"errors",
|
19
28
|
"load_accounts_from_file",
|
@@ -22,9 +31,10 @@ __all__ = [
|
|
22
31
|
|
23
32
|
|
24
33
|
import warnings
|
34
|
+
|
25
35
|
# HACK: Ignore event loop warnings from curl_cffi
|
26
|
-
warnings.filterwarnings(
|
36
|
+
warnings.filterwarnings("ignore", module="curl_cffi")
|
27
37
|
|
38
|
+
from loguru import logger
|
28
39
|
|
29
|
-
|
30
|
-
config.APP_ID = "6F895B2F-F454-44D1-8FE0-77ACAD3DBDC8"
|
40
|
+
logger.disable("twitter")
|
File without changes
|
File without changes
|
@@ -0,0 +1,227 @@
|
|
1
|
+
import time
|
2
|
+
import asyncio
|
3
|
+
import logging
|
4
|
+
from typing import Any, Dict, Type
|
5
|
+
from urllib import parse
|
6
|
+
|
7
|
+
import aiohttp
|
8
|
+
import requests
|
9
|
+
from pydantic import BaseModel
|
10
|
+
from requests.adapters import HTTPAdapter
|
11
|
+
|
12
|
+
from .enum import ResponseStatusEnm, EndpointPostfixEnm
|
13
|
+
from .config import RETRIES, REQUEST_URL, VALID_STATUS_CODES, attempts_generator
|
14
|
+
from .serializer import (
|
15
|
+
CaptchaOptionsSer,
|
16
|
+
CaptchaResponseSer,
|
17
|
+
RequestCreateTaskSer,
|
18
|
+
RequestGetTaskResultSer,
|
19
|
+
)
|
20
|
+
|
21
|
+
|
22
|
+
class BaseCaptcha:
|
23
|
+
"""
|
24
|
+
Basic Captcha solving class
|
25
|
+
|
26
|
+
Args:
|
27
|
+
api_key: Capsolver API key
|
28
|
+
captcha_type: Captcha type name, like `ReCaptchaV2Task` and etc.
|
29
|
+
sleep_time: The waiting time between requests to get the result of the Captcha
|
30
|
+
request_url: API address for sending requests
|
31
|
+
"""
|
32
|
+
|
33
|
+
def __init__(
|
34
|
+
self,
|
35
|
+
api_key: str,
|
36
|
+
sleep_time: int = 5,
|
37
|
+
request_url: str = REQUEST_URL,
|
38
|
+
**kwargs,
|
39
|
+
):
|
40
|
+
# assign args to validator
|
41
|
+
self.__params = CaptchaOptionsSer(**locals())
|
42
|
+
self.__request_url = request_url
|
43
|
+
|
44
|
+
# prepare session
|
45
|
+
self.__session = requests.Session()
|
46
|
+
self.__session.mount("http://", HTTPAdapter(max_retries=RETRIES))
|
47
|
+
self.__session.mount("https://", HTTPAdapter(max_retries=RETRIES))
|
48
|
+
|
49
|
+
def _prepare_create_task_payload(self, serializer: Type[BaseModel], create_params: Dict[str, Any] = None) -> None:
|
50
|
+
"""
|
51
|
+
Method prepare `createTask` payload
|
52
|
+
|
53
|
+
Args:
|
54
|
+
serializer: Serializer for task creation
|
55
|
+
create_params: Parameters for task creation payload
|
56
|
+
|
57
|
+
Examples:
|
58
|
+
|
59
|
+
>>> self._prepare_create_task_payload(serializer=PostRequestSer, create_params={})
|
60
|
+
|
61
|
+
"""
|
62
|
+
self.task_payload = serializer(clientKey=self.__params.api_key)
|
63
|
+
# added task params to payload
|
64
|
+
self.task_payload.task = {**create_params} if create_params else {}
|
65
|
+
|
66
|
+
def __enter__(self):
|
67
|
+
return self
|
68
|
+
|
69
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
70
|
+
if exc_type:
|
71
|
+
return False
|
72
|
+
return True
|
73
|
+
|
74
|
+
async def __aenter__(self):
|
75
|
+
return self
|
76
|
+
|
77
|
+
async def __aexit__(self, exc_type, exc_value, traceback):
|
78
|
+
if exc_type:
|
79
|
+
return False
|
80
|
+
return True
|
81
|
+
|
82
|
+
"""
|
83
|
+
Sync part
|
84
|
+
"""
|
85
|
+
|
86
|
+
def _processing_captcha(
|
87
|
+
self, create_params: dict, serializer: Type[BaseModel] = RequestCreateTaskSer
|
88
|
+
) -> CaptchaResponseSer:
|
89
|
+
self._prepare_create_task_payload(serializer=serializer, create_params=create_params)
|
90
|
+
self.created_task_data = CaptchaResponseSer(**self._create_task())
|
91
|
+
|
92
|
+
# if task created and ready - return result
|
93
|
+
if self.created_task_data.status == ResponseStatusEnm.Ready.value:
|
94
|
+
return self.created_task_data
|
95
|
+
# if captcha is not ready but task success created - waiting captcha result
|
96
|
+
elif self.created_task_data.errorId == 0:
|
97
|
+
return self._get_result()
|
98
|
+
return self.created_task_data
|
99
|
+
|
100
|
+
def _create_task(self, url_postfix: str = EndpointPostfixEnm.CREATE_TASK.value) -> dict:
|
101
|
+
"""
|
102
|
+
Function send SYNC request to service and wait for result
|
103
|
+
"""
|
104
|
+
try:
|
105
|
+
resp = self.__session.post(
|
106
|
+
parse.urljoin(self.__request_url, url_postfix), json=self.task_payload.dict(exclude_none=True)
|
107
|
+
)
|
108
|
+
if resp.status_code in VALID_STATUS_CODES:
|
109
|
+
return resp.json()
|
110
|
+
else:
|
111
|
+
raise ValueError(resp.raise_for_status())
|
112
|
+
except Exception as error:
|
113
|
+
logging.exception(error)
|
114
|
+
raise
|
115
|
+
|
116
|
+
def _get_result(self, url_postfix: str = EndpointPostfixEnm.GET_TASK_RESULT.value) -> CaptchaResponseSer:
|
117
|
+
"""
|
118
|
+
Method send SYNC request to service and wait for result
|
119
|
+
"""
|
120
|
+
# initial waiting
|
121
|
+
time.sleep(self.__params.sleep_time)
|
122
|
+
|
123
|
+
get_result_payload = RequestGetTaskResultSer(
|
124
|
+
clientKey=self.__params.api_key, taskId=self.created_task_data.taskId
|
125
|
+
)
|
126
|
+
attempts = attempts_generator()
|
127
|
+
for _ in attempts:
|
128
|
+
try:
|
129
|
+
resp = self.__session.post(
|
130
|
+
parse.urljoin(self.__request_url, url_postfix), json=get_result_payload.dict(exclude_none=True)
|
131
|
+
)
|
132
|
+
if resp.status_code in VALID_STATUS_CODES:
|
133
|
+
result_data = CaptchaResponseSer(**resp.json())
|
134
|
+
if result_data.status in (ResponseStatusEnm.Ready, ResponseStatusEnm.Failed):
|
135
|
+
# if captcha ready\failed or have unknown status - return exist data
|
136
|
+
return result_data
|
137
|
+
else:
|
138
|
+
raise ValueError(resp.raise_for_status())
|
139
|
+
except Exception as error:
|
140
|
+
logging.exception(error)
|
141
|
+
raise
|
142
|
+
|
143
|
+
# if captcha just created or in processing now - wait
|
144
|
+
time.sleep(self.__params.sleep_time)
|
145
|
+
# default response if server is silent
|
146
|
+
return CaptchaResponseSer(
|
147
|
+
errorId=1,
|
148
|
+
errorCode="ERROR_CAPTCHA_UNSOLVABLE",
|
149
|
+
errorDescription="Captcha not recognized",
|
150
|
+
taskId=self.created_task_data.taskId,
|
151
|
+
status=ResponseStatusEnm.Failed,
|
152
|
+
)
|
153
|
+
|
154
|
+
"""
|
155
|
+
Async part
|
156
|
+
"""
|
157
|
+
|
158
|
+
async def _aio_processing_captcha(
|
159
|
+
self, create_params: dict, serializer: Type[BaseModel] = RequestCreateTaskSer
|
160
|
+
) -> CaptchaResponseSer:
|
161
|
+
self._prepare_create_task_payload(serializer=serializer, create_params=create_params)
|
162
|
+
self.created_task_data = CaptchaResponseSer(**await self._aio_create_task())
|
163
|
+
|
164
|
+
# if task created and already ready - return result
|
165
|
+
if self.created_task_data.status == ResponseStatusEnm.Ready.value:
|
166
|
+
return self.created_task_data
|
167
|
+
# if captcha is not ready but task success created - waiting captcha result
|
168
|
+
elif self.created_task_data.errorId == 0:
|
169
|
+
return await self._aio_get_result()
|
170
|
+
return self.created_task_data
|
171
|
+
|
172
|
+
async def _aio_create_task(self, url_postfix: str = EndpointPostfixEnm.CREATE_TASK.value) -> dict:
|
173
|
+
"""
|
174
|
+
Function send the ASYNC request to service and wait for result
|
175
|
+
"""
|
176
|
+
async with aiohttp.ClientSession() as session:
|
177
|
+
try:
|
178
|
+
async with session.post(
|
179
|
+
parse.urljoin(self.__request_url, url_postfix), json=self.task_payload.dict(exclude_none=True)
|
180
|
+
) as resp:
|
181
|
+
if resp.status in VALID_STATUS_CODES:
|
182
|
+
return await resp.json()
|
183
|
+
else:
|
184
|
+
raise ValueError(resp.reason)
|
185
|
+
except Exception as error:
|
186
|
+
logging.exception(error)
|
187
|
+
raise
|
188
|
+
|
189
|
+
async def _aio_get_result(self, url_postfix: str = EndpointPostfixEnm.GET_TASK_RESULT.value) -> CaptchaResponseSer:
|
190
|
+
"""
|
191
|
+
Function send the ASYNC request to service and wait for result
|
192
|
+
"""
|
193
|
+
# initial waiting
|
194
|
+
await asyncio.sleep(self.__params.sleep_time)
|
195
|
+
|
196
|
+
get_result_payload = RequestGetTaskResultSer(
|
197
|
+
clientKey=self.__params.api_key, taskId=self.created_task_data.taskId
|
198
|
+
)
|
199
|
+
attempts = attempts_generator()
|
200
|
+
async with aiohttp.ClientSession() as session:
|
201
|
+
for _ in attempts:
|
202
|
+
try:
|
203
|
+
async with session.post(
|
204
|
+
parse.urljoin(self.__request_url, url_postfix), json=get_result_payload.dict(exclude_none=True)
|
205
|
+
) as resp:
|
206
|
+
if resp.status in VALID_STATUS_CODES:
|
207
|
+
result_data = CaptchaResponseSer(**await resp.json())
|
208
|
+
if result_data.status in (ResponseStatusEnm.Ready, ResponseStatusEnm.Failed):
|
209
|
+
# if captcha ready\failed or have unknown status - return exist data
|
210
|
+
return result_data
|
211
|
+
else:
|
212
|
+
raise ValueError(resp.reason)
|
213
|
+
except Exception as error:
|
214
|
+
logging.exception(error)
|
215
|
+
raise
|
216
|
+
|
217
|
+
# if captcha just created or in processing now - wait
|
218
|
+
await asyncio.sleep(self.__params.sleep_time)
|
219
|
+
|
220
|
+
# default response if server is silent
|
221
|
+
return CaptchaResponseSer(
|
222
|
+
errorId=1,
|
223
|
+
errorCode="ERROR_CAPTCHA_UNSOLVABLE",
|
224
|
+
errorDescription="Captcha not recognized",
|
225
|
+
taskId=self.created_task_data.taskId,
|
226
|
+
status=ResponseStatusEnm.Failed,
|
227
|
+
)
|
@@ -0,0 +1,36 @@
|
|
1
|
+
from typing import Generator
|
2
|
+
|
3
|
+
from tenacity import AsyncRetrying, wait_fixed, stop_after_attempt
|
4
|
+
from requests.adapters import Retry
|
5
|
+
|
6
|
+
RETRIES = Retry(total=5, backoff_factor=0.9, status_forcelist=[500, 502, 503, 504])
|
7
|
+
ASYNC_RETRIES = AsyncRetrying(wait=wait_fixed(5), stop=stop_after_attempt(5), reraise=True)
|
8
|
+
|
9
|
+
REQUEST_URL = "https://api.capsolver.com"
|
10
|
+
VALID_STATUS_CODES = (200, 202, 400, 401, 405)
|
11
|
+
|
12
|
+
APP_ID = "6F895B2F-F454-44D1-8FE0-77ACAD3DBDC8"
|
13
|
+
|
14
|
+
|
15
|
+
# Connection retry generator
|
16
|
+
def attempts_generator(amount: int = 16) -> Generator:
|
17
|
+
"""
|
18
|
+
Function generates a generator of length equal to `amount`
|
19
|
+
|
20
|
+
Args:
|
21
|
+
amount: number of attempts generated
|
22
|
+
|
23
|
+
Yields:
|
24
|
+
int: The next number in the range of 1 to ``amount`` - 1.
|
25
|
+
|
26
|
+
Examples:
|
27
|
+
Examples should be written in doctest format, and should illustrate how
|
28
|
+
to use the function.
|
29
|
+
|
30
|
+
>>> print([i for i in attempts_generator(5)])
|
31
|
+
[1, 2, 3, 4]
|
32
|
+
|
33
|
+
Returns:
|
34
|
+
Attempt number
|
35
|
+
"""
|
36
|
+
yield from range(1, amount)
|
@@ -0,0 +1,66 @@
|
|
1
|
+
from enum import Enum
|
2
|
+
from types import DynamicClassAttribute
|
3
|
+
from typing import List
|
4
|
+
|
5
|
+
|
6
|
+
class MyEnum(Enum):
|
7
|
+
@classmethod
|
8
|
+
def list(cls) -> List[Enum]:
|
9
|
+
return list(map(lambda c: c, cls))
|
10
|
+
|
11
|
+
@classmethod
|
12
|
+
def list_values(cls) -> List[str]:
|
13
|
+
return list(map(lambda c: c.value, cls))
|
14
|
+
|
15
|
+
@classmethod
|
16
|
+
def list_names(cls) -> List[str]:
|
17
|
+
return list(map(lambda c: c.name, cls))
|
18
|
+
|
19
|
+
@DynamicClassAttribute
|
20
|
+
def name(self) -> str:
|
21
|
+
"""
|
22
|
+
The name of the Enum member
|
23
|
+
"""
|
24
|
+
return self._name_
|
25
|
+
|
26
|
+
@DynamicClassAttribute
|
27
|
+
def value(self) -> str:
|
28
|
+
"""
|
29
|
+
The name of the Enum member
|
30
|
+
"""
|
31
|
+
return self._value_
|
32
|
+
|
33
|
+
|
34
|
+
class EndpointPostfixEnm(str, MyEnum):
|
35
|
+
"""
|
36
|
+
Enum stored URL postfixes for API endpoints
|
37
|
+
"""
|
38
|
+
|
39
|
+
GET_BALANCE = "getBalance"
|
40
|
+
CREATE_TASK = "createTask"
|
41
|
+
GET_TASK_RESULT = "getTaskResult"
|
42
|
+
AKAMAI_BMP_INVOKE = "akamaibmp/invoke"
|
43
|
+
AKAMAI_WEB_INVOKE = "akamaiweb/invoke"
|
44
|
+
|
45
|
+
|
46
|
+
class FunCaptchaTypeEnm(str, MyEnum):
|
47
|
+
FunCaptchaTask = "FunCaptchaTask"
|
48
|
+
FunCaptchaTaskProxyLess = "FunCaptchaTaskProxyLess"
|
49
|
+
|
50
|
+
|
51
|
+
class FunCaptchaClassificationTypeEnm(str, MyEnum):
|
52
|
+
FunCaptchaClassification = "FunCaptchaClassification"
|
53
|
+
|
54
|
+
|
55
|
+
class ResponseStatusEnm(str, MyEnum):
|
56
|
+
"""
|
57
|
+
Enum store results `status` field variants
|
58
|
+
|
59
|
+
Notes:
|
60
|
+
https://docs.capsolver.com/guide/api-createtask.html
|
61
|
+
"""
|
62
|
+
|
63
|
+
Idle = "idle" # Task created
|
64
|
+
Processing = "processing" # Task is not ready yet
|
65
|
+
Ready = "ready" # Task completed, solution object can be found in solution property
|
66
|
+
Failed = "failed" # Task failed, check the errorDescription to know why failed.
|
@@ -0,0 +1,85 @@
|
|
1
|
+
from typing import Any, Dict, List, Literal, Optional
|
2
|
+
|
3
|
+
from pydantic import Field, BaseModel, conint
|
4
|
+
|
5
|
+
from .enum import ResponseStatusEnm
|
6
|
+
from .config import APP_ID
|
7
|
+
|
8
|
+
"""
|
9
|
+
HTTP API Request ser
|
10
|
+
"""
|
11
|
+
|
12
|
+
|
13
|
+
class PostRequestSer(BaseModel):
|
14
|
+
clientKey: str = Field(..., description="Client account key, can be found in user account")
|
15
|
+
task: dict = Field(None, description="Task object")
|
16
|
+
|
17
|
+
|
18
|
+
class TaskSer(BaseModel):
|
19
|
+
type: str = Field(..., description="Task type name", alias="captcha_type")
|
20
|
+
|
21
|
+
|
22
|
+
class RequestCreateTaskSer(PostRequestSer):
|
23
|
+
appId: Literal[APP_ID] = APP_ID
|
24
|
+
|
25
|
+
|
26
|
+
class RequestGetTaskResultSer(PostRequestSer):
|
27
|
+
taskId: Optional[str] = Field(None, description="ID created by the createTask method")
|
28
|
+
|
29
|
+
|
30
|
+
"""
|
31
|
+
HTTP API Response ser
|
32
|
+
"""
|
33
|
+
|
34
|
+
|
35
|
+
class ResponseSer(BaseModel):
|
36
|
+
errorId: int = Field(..., description="Error message: `False` - no error, `True` - with error")
|
37
|
+
# error info
|
38
|
+
errorCode: Optional[str] = Field(None, description="Error code")
|
39
|
+
errorDescription: Optional[str] = Field(None, description="Error description")
|
40
|
+
|
41
|
+
|
42
|
+
class CaptchaResponseSer(ResponseSer):
|
43
|
+
taskId: Optional[str] = Field(None, description="Task ID for future use in getTaskResult method.")
|
44
|
+
status: ResponseStatusEnm = Field(ResponseStatusEnm.Processing, description="Task current status")
|
45
|
+
solution: Dict[str, Any] = Field(None, description="Task result data. Different for each type of task.")
|
46
|
+
|
47
|
+
class Config:
|
48
|
+
populate_by_name = True
|
49
|
+
|
50
|
+
|
51
|
+
class ControlResponseSer(ResponseSer):
|
52
|
+
balance: Optional[float] = Field(0, description="Account balance value in USD")
|
53
|
+
|
54
|
+
|
55
|
+
"""
|
56
|
+
Other ser
|
57
|
+
"""
|
58
|
+
|
59
|
+
|
60
|
+
class CaptchaOptionsSer(BaseModel):
|
61
|
+
api_key: str
|
62
|
+
sleep_time: conint(ge=5) = 5
|
63
|
+
|
64
|
+
|
65
|
+
"""
|
66
|
+
Captcha tasks ser
|
67
|
+
"""
|
68
|
+
|
69
|
+
|
70
|
+
class FunCaptchaClassificationOptionsSer(TaskSer):
|
71
|
+
images: List[str] = Field(..., description="Base64-encoded images, do not include 'data:image/***;base64,'")
|
72
|
+
question: str = Field(
|
73
|
+
...,
|
74
|
+
description="Question name. this param value from API response game_variant field. Exmaple: maze,maze2,flockCompass,3d_rollball_animals",
|
75
|
+
)
|
76
|
+
|
77
|
+
|
78
|
+
class FunCaptchaSer(TaskSer):
|
79
|
+
websiteURL: str = Field(..., description="Address of a webpage with Funcaptcha")
|
80
|
+
websitePublicKey: str = Field(..., description="Funcaptcha website key.")
|
81
|
+
funcaptchaApiJSSubdomain: Optional[str] = Field(
|
82
|
+
None,
|
83
|
+
description="A special subdomain of funcaptcha.com, from which the JS captcha widget should be loaded."
|
84
|
+
"Most FunCaptcha installations work from shared domains.",
|
85
|
+
)
|