tweepy-self 1.6.3__py3-none-any.whl → 1.10.0b1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tweepy-self
3
- Version: 1.6.3
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 (==1.1.1)
14
- Requires-Dist: curl_cffi (==0.6.0b9)
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: python3-capsolver (>=0.9,<0.10)
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.request_user_data()
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.request_user_data("@elonmusk")
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.request_user_data()
122
- print(f"New username: {account.data.username}")
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.request_user_data("@username")
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 Account, AccountStatus, load_accounts_from_file, extract_accounts_to_file
10
- from .models import Tweet, UserData
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('ignore', module='curl_cffi')
36
+ warnings.filterwarnings("ignore", module="curl_cffi")
27
37
 
38
+ from loguru import logger
28
39
 
29
- from python3_capsolver.core import config
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
+ )