tweety-temp 2.4.2__tar.gz

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.
Files changed (55) hide show
  1. tweety_temp-2.4.2/PKG-INFO +6 -0
  2. tweety_temp-2.4.2/README.md +39 -0
  3. tweety_temp-2.4.2/pyproject.toml +9 -0
  4. tweety_temp-2.4.2/setup.cfg +20 -0
  5. tweety_temp-2.4.2/setup.py +20 -0
  6. tweety_temp-2.4.2/src/tweety/__init__.py +45 -0
  7. tweety_temp-2.4.2/src/tweety/auth.py +205 -0
  8. tweety_temp-2.4.2/src/tweety/bot.py +926 -0
  9. tweety_temp-2.4.2/src/tweety/builder.py +2583 -0
  10. tweety_temp-2.4.2/src/tweety/captcha/__init__.py +3 -0
  11. tweety_temp-2.4.2/src/tweety/captcha/anticaptcha.py +54 -0
  12. tweety_temp-2.4.2/src/tweety/captcha/base.py +144 -0
  13. tweety_temp-2.4.2/src/tweety/captcha/capsolver.py +43 -0
  14. tweety_temp-2.4.2/src/tweety/captcha/two_captcha.py +39 -0
  15. tweety_temp-2.4.2/src/tweety/constants.py +75 -0
  16. tweety_temp-2.4.2/src/tweety/events/__init__.py +2 -0
  17. tweety_temp-2.4.2/src/tweety/events/base.py +3 -0
  18. tweety_temp-2.4.2/src/tweety/events/newmessage.py +84 -0
  19. tweety_temp-2.4.2/src/tweety/events/stream_event.py +2 -0
  20. tweety_temp-2.4.2/src/tweety/exceptions.py +280 -0
  21. tweety_temp-2.4.2/src/tweety/exceptions_.py +5 -0
  22. tweety_temp-2.4.2/src/tweety/filters.py +96 -0
  23. tweety_temp-2.4.2/src/tweety/http.py +916 -0
  24. tweety_temp-2.4.2/src/tweety/session.py +90 -0
  25. tweety_temp-2.4.2/src/tweety/transaction.py +316 -0
  26. tweety_temp-2.4.2/src/tweety/types/__init__.py +72 -0
  27. tweety_temp-2.4.2/src/tweety/types/base.py +97 -0
  28. tweety_temp-2.4.2/src/tweety/types/bookmarks.py +38 -0
  29. tweety_temp-2.4.2/src/tweety/types/community.py +149 -0
  30. tweety_temp-2.4.2/src/tweety/types/follow.py +177 -0
  31. tweety_temp-2.4.2/src/tweety/types/gifs.py +38 -0
  32. tweety_temp-2.4.2/src/tweety/types/grok.py +89 -0
  33. tweety_temp-2.4.2/src/tweety/types/inbox.py +697 -0
  34. tweety_temp-2.4.2/src/tweety/types/likes.py +48 -0
  35. tweety_temp-2.4.2/src/tweety/types/lists.py +181 -0
  36. tweety_temp-2.4.2/src/tweety/types/mentions.py +45 -0
  37. tweety_temp-2.4.2/src/tweety/types/n_types.py +306 -0
  38. tweety_temp-2.4.2/src/tweety/types/notification.py +41 -0
  39. tweety_temp-2.4.2/src/tweety/types/places.py +42 -0
  40. tweety_temp-2.4.2/src/tweety/types/retweets.py +42 -0
  41. tweety_temp-2.4.2/src/tweety/types/search.py +134 -0
  42. tweety_temp-2.4.2/src/tweety/types/topic.py +44 -0
  43. tweety_temp-2.4.2/src/tweety/types/twDataTypes.py +2053 -0
  44. tweety_temp-2.4.2/src/tweety/types/usertweet.py +458 -0
  45. tweety_temp-2.4.2/src/tweety/updates.py +41 -0
  46. tweety_temp-2.4.2/src/tweety/user.py +1436 -0
  47. tweety_temp-2.4.2/src/tweety/utils.py +636 -0
  48. tweety_temp-2.4.2/src/tweety_temp.egg-info/PKG-INFO +6 -0
  49. tweety_temp-2.4.2/src/tweety_temp.egg-info/SOURCES.txt +54 -0
  50. tweety_temp-2.4.2/src/tweety_temp.egg-info/dependency_links.txt +1 -0
  51. tweety_temp-2.4.2/src/tweety_temp.egg-info/top_level.txt +1 -0
  52. tweety_temp-2.4.2/tests/test_authenticated.py +260 -0
  53. tweety_temp-2.4.2/tests/test_basic.py +207 -0
  54. tweety_temp-2.4.2/tests/test_comprehensive.py +392 -0
  55. tweety_temp-2.4.2/tests/test_profile_images.py +210 -0
@@ -0,0 +1,6 @@
1
+ Metadata-Version: 2.4
2
+ Name: tweety-temp
3
+ Version: 2.4.2
4
+ License: MIT
5
+ Requires-Python: >=3.9
6
+ Dynamic: license
@@ -0,0 +1,39 @@
1
+ # tweety
2
+ Reverse Engineered Twitter Frontend API.
3
+
4
+ [![Downloads](https://static.pepy.tech/personalized-badge/tweety-ns?period=total&units=international_system&left_color=orange&right_color=blue&left_text=Downloads)](https://pepy.tech/project/tweety-ns) [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/mahrtayyab/tweety)
5
+
6
+ ## Installation:
7
+ ```bash
8
+ pip install tweety-ns
9
+ ```
10
+
11
+ ## Keep synced with latest fixes
12
+
13
+ ##### **Pip might not be always updated , so to keep everything synced.**
14
+
15
+ ```bash
16
+ pip install https://github.com/mahrtayyab/tweety/archive/main.zip --upgrade
17
+ ```
18
+
19
+ ## A Quick Example:
20
+ ```python
21
+ from tweety import TwitterAsync
22
+ import asyncio
23
+
24
+ async def main():
25
+
26
+ app = TwitterAsync("session")
27
+ all_tweets = await app.get_tweets("elonmusk")
28
+ for tweet in all_tweets:
29
+ print(tweet)
30
+
31
+ asyncio.run(main())
32
+ ```
33
+
34
+ > [!IMPORTANT]
35
+ > Even Twitter Web Client has a lot of rate limits now, Abusing tweety can lead to `read_only` Twitter account.
36
+
37
+ Do check [FAQs](https://github.com/mahrtayyab/tweety/wiki/FAQs)
38
+
39
+ Full Documentation and Changelogs are [here](https://mahrtayyab.github.io/tweety_docs/)
@@ -0,0 +1,9 @@
1
+ [build-system]
2
+ requires = [
3
+ "setuptools>=42",
4
+ "wheel"
5
+ ]
6
+ build-backend = "setuptools.build_meta"
7
+
8
+ [tool.poetry.extras]
9
+ windows = ["python-magic-bin"]
@@ -0,0 +1,20 @@
1
+ [metadata]
2
+ name = tweety-temp
3
+ version = 2.4.2
4
+
5
+ [options]
6
+ package_dir =
7
+ = src
8
+ packages = find:
9
+ python_requires = >=3.9
10
+
11
+ [options.packages.find]
12
+ where = src
13
+
14
+ [project]
15
+ license = "MIT AND (Apache-2.0 OR BSD-2-Clause)"
16
+
17
+ [egg_info]
18
+ tag_build =
19
+ tag_date = 0
20
+
@@ -0,0 +1,20 @@
1
+ from distutils.core import setup
2
+
3
+ install_requires = [
4
+ "beautifulsoup4[lxml]~=4.12",
5
+ "openpyxl",
6
+ "httpx[http2]",
7
+ "dateutils",
8
+ "anticaptchaofficial",
9
+ "capsolver",
10
+ "2captcha-python",
11
+ "python-magic",
12
+ "python-magic-bin; platform_system == 'Windows'"
13
+ ]
14
+
15
+ setup(
16
+ name='tweety-temp',
17
+ packages=['tweety', 'tweety.types', 'tweety.events', 'tweety.captcha'],
18
+ version='2.4.2',
19
+ license='MIT',
20
+ )
@@ -0,0 +1,45 @@
1
+ __version__ = "2.4.1"
2
+ __author__ = "mahrtayyab"
3
+
4
+
5
+ import inspect
6
+ from .bot import BotMethods
7
+ from .updates import UpdateMethods
8
+ from .auth import AuthMethods
9
+ from .user import UserMethods
10
+ from .utils import get_running_loop
11
+
12
+
13
+ def SyncWrap(cls):
14
+ def method_wrapper_decorator(method_):
15
+ def wrapper(self, *args, **kwargs):
16
+ coro = method_(self, *args, **kwargs)
17
+ loop = get_running_loop()
18
+ if loop.is_running():
19
+ return coro
20
+ else:
21
+ return loop.run_until_complete(coro)
22
+
23
+ return wrapper
24
+
25
+ if inspect.isclass(cls):
26
+ for name in dir(cls):
27
+ if not name.startswith('_') or name != '__init__':
28
+ if inspect.iscoroutinefunction(getattr(cls, name)):
29
+ setattr(cls, name, method_wrapper_decorator(getattr(cls, name)))
30
+
31
+ return cls
32
+ return method_wrapper_decorator(cls)
33
+
34
+
35
+ class TwitterAsync(
36
+ UserMethods, BotMethods, UpdateMethods, AuthMethods
37
+ ):
38
+ pass
39
+
40
+
41
+ @SyncWrap
42
+ class Twitter(TwitterAsync):
43
+ pass
44
+
45
+
@@ -0,0 +1,205 @@
1
+ import getpass
2
+ from http.cookiejar import MozillaCookieJar
3
+ from typing import Union
4
+ from .exceptions import InvalidCredentials, DeniedLogin, ActionRequired, ArkoseLoginRequired
5
+ from .builder import FlowData
6
+ from .types.n_types import Cookies
7
+ from .utils import find_objects, get_url_parts
8
+ from . import constants
9
+
10
+
11
+ class AuthMethods:
12
+
13
+ async def connect(self):
14
+ """
15
+ This method will be used to connect to already saved session in disk
16
+ """
17
+
18
+ if not self.session.logged_in:
19
+ return
20
+
21
+ self.request.cookies = self.session.cookies_dict()
22
+ self.user = await self.request.verify_cookies()
23
+ await self.session.save_session(self.cookies, self.user)
24
+ self.is_user_authorized = True
25
+ return self.user
26
+
27
+ async def start(
28
+ self,
29
+ username=None,
30
+ password=None,
31
+ *,
32
+ extra=None
33
+ ):
34
+ """
35
+ Interactive Version of `sign_in` which will ask user for inputs
36
+ Most of the time , this would be the only method you will be working with,
37
+ it will check for existing sessions and login to it if available
38
+
39
+ :param username: (`str`) Username of the user
40
+ :param password: (`str`) Password of the user
41
+ :param extra: (`str`) If you have 2-Factor authentication enabled and already have a code ,
42
+ or any other action required for completing the login process
43
+ it will be passed to this parameter
44
+ :return: .types.twDataTypes.User (the user which is authenticated)
45
+ """
46
+
47
+ username = input('Please enter the Username: ') if not username else username
48
+ password = getpass.getpass('Please enter your password: ') if not password else password
49
+
50
+ _extra = extra
51
+ _extra_once = False
52
+ while not self.logged_in:
53
+ try:
54
+ return await self.sign_in(username, password, extra=_extra)
55
+ except ActionRequired as e:
56
+ _extra = input(f"\rAction Required :> {str(e.message)} : ")
57
+ _extra_once = True
58
+ except InvalidCredentials as ask_info:
59
+ if _extra_once:
60
+ _extra = input(f"\rAction Required :> {str(ask_info.message)} : ")
61
+ else:
62
+ raise ask_info
63
+
64
+ async def sign_in(
65
+ self,
66
+ username,
67
+ password,
68
+ *,
69
+ extra=None
70
+ ):
71
+ """
72
+ - This method can be used to sign in to Twitter using username and password
73
+ - It will also check for the saved session for the username in the disk
74
+
75
+ :param username: (`str`) Username of the user
76
+ :param password: (`str`) Password of the user
77
+ :param extra: (`str`) If you have 2-Factor authentication enabled and already have a code ,
78
+ or any other action required for completing the login process
79
+ it will be passed to this parameter
80
+ :return: .types.twDataTypes.User (the user which is authenticated)
81
+ """
82
+
83
+ if self.session.logged_in and self.session.user['username'].lower() == username.lower():
84
+ try:
85
+ return await self.connect()
86
+ except InvalidCredentials:
87
+ self.request.cookies = None
88
+ pass
89
+
90
+ self._username = username
91
+ self._password = password
92
+ self._extra = extra
93
+ self._captcha_token = None
94
+
95
+ if not self._login_flow:
96
+ self._login_flow = FlowData()
97
+
98
+ if not self._login_flow_state:
99
+ self._login_flow_state = self._login_flow.initial_state
100
+
101
+ return await self._login()
102
+
103
+ async def load_cookies(
104
+ self,
105
+ cookies: Union[str, dict, MozillaCookieJar]
106
+ ):
107
+ """
108
+ This method can be used to load the already authenticated cookies from Twitter
109
+
110
+ :param cookies: (`str`, `dict`, `MozillaCookieJar`) The Cookies to load
111
+ :return: .types.twDataTypes.User (the user which is authenticated)
112
+ """
113
+ self.cookies = Cookies(cookies)
114
+ await self.session.save_session(self.cookies, None)
115
+ return await self.connect()
116
+
117
+ async def load_auth_token(self, auth_token):
118
+ URL = "https://business.x.com/en"
119
+ temp_cookie = {"auth_token": auth_token}
120
+ temp_headers = {'authorization': constants.DEFAULT_BEARER_TOKEN}
121
+ res = await self.request.session.get(URL, cookies=temp_cookie)
122
+ ct0 = res.cookies.get('ct0')
123
+
124
+ if not ct0:
125
+ res = await self.request.session.get(URL, cookies=temp_cookie, headers=temp_headers)
126
+ ct0 = res.cookies.get('ct0')
127
+
128
+ if not ct0:
129
+ raise DeniedLogin(response=res, message="Auth Token isn't Valid")
130
+
131
+ temp_cookie.update(dict(res.cookies))
132
+ return await self.load_cookies(temp_cookie)
133
+
134
+ @staticmethod
135
+ def _get_action_text(response):
136
+ primary_message = find_objects(response, 'primary_text', None, none_value={})
137
+ secondary_message = find_objects(response, 'secondary_text', None, none_value={})
138
+ if primary_message:
139
+ if isinstance(primary_message, list):
140
+ primary_message = primary_message[0]
141
+
142
+ primary_message = primary_message.get('text', '')
143
+
144
+ if secondary_message:
145
+ if isinstance(secondary_message, list):
146
+ secondary_message = secondary_message[0]
147
+ secondary_message = secondary_message.get('text', '')
148
+ return f"{primary_message}. {secondary_message}"
149
+
150
+ async def _login(self):
151
+
152
+ while not self.logged_in:
153
+ _login_payload = self._login_flow.get(
154
+ self._login_flow_state,
155
+ json_=self._last_json,
156
+ username=self._username,
157
+ password=self._password,
158
+ extra=self._extra,
159
+ captcha_token=self._captcha_token
160
+ )
161
+
162
+ # Twitter now often asks for multiple verifications
163
+ if self._login_flow_state in constants.AUTH_ACTION_REQUIRED_KEYS:
164
+ self._extra = None
165
+
166
+ response = await self.request.login(self._login_url, _payload=_login_payload)
167
+
168
+ self._last_json = response.json()
169
+
170
+ if response.cookies.get("att"):
171
+ self.request.headers = {"att": response.cookies.get("att")}
172
+
173
+ if self._last_json.get('status') != "success":
174
+ raise DeniedLogin(response=response, message=response.text)
175
+
176
+ subtask = self._last_json["subtasks"][0].get("subtask_id")
177
+ self._login_url = self._login_url.split("?")[0]
178
+ self._login_flow_state = subtask
179
+
180
+ if subtask in constants.AUTH_ACTION_REQUIRED_KEYS and not self._extra:
181
+ message = self._get_action_text(self._last_json)
182
+ raise ActionRequired(0, "ActionRequired", response, message)
183
+
184
+ if subtask == "ArkoseLogin":
185
+ # if self._captcha_solver is None:
186
+ raise ArkoseLoginRequired(response=response)
187
+
188
+ # token = await self.request.solve_captcha(websiteUrl="https://iframe.arkoselabs.com")
189
+ # token = self.request.solve_captcha(websiteUrl="https://twitter.com/i/flow/login", blob_data=data[0])
190
+ # self._captcha_token = token
191
+
192
+ if subtask == "DenyLoginSubtask":
193
+ reason = self._get_action_text(self._last_json)
194
+ raise DeniedLogin(response=response, message=reason)
195
+
196
+ if subtask == "LoginSuccessSubtask":
197
+ self.request.remove_header("att")
198
+ self.cookies = Cookies(dict(response.cookies))
199
+ await self.session.save_session(self.cookies, None)
200
+ return await self.connect()
201
+
202
+ raise DeniedLogin(response=response, message="Unknown Error Occurred")
203
+
204
+
205
+