twitter-openapi-python 0.0.45__py3-none-any.whl → 0.1.1__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.
- twitter_openapi_python/api/post_api.py +161 -0
- twitter_openapi_python/api/tweet_api.py +231 -21
- twitter_openapi_python/api/user_api.py +55 -1
- twitter_openapi_python/api/user_list_api.py +155 -22
- twitter_openapi_python/client.py +1 -1
- twitter_openapi_python/models/__init__.py +1 -0
- twitter_openapi_python/models/timeline.py +7 -2
- twitter_openapi_python/utils/__init__.py +7 -0
- twitter_openapi_python/utils/api.py +70 -9
- {twitter_openapi_python-0.0.45.dist-info → twitter_openapi_python-0.1.1.dist-info}/METADATA +2 -2
- twitter_openapi_python-0.1.1.dist-info/RECORD +27 -0
- twitter_openapi_python-0.0.45.dist-info/RECORD +0 -27
- {twitter_openapi_python-0.0.45.dist-info → twitter_openapi_python-0.1.1.dist-info}/WHEEL +0 -0
- {twitter_openapi_python-0.0.45.dist-info → twitter_openapi_python-0.1.1.dist-info}/licenses/LICENSE +0 -0
- {twitter_openapi_python-0.0.45.dist-info → twitter_openapi_python-0.1.1.dist-info}/licenses/LICENSE.AGPL +0 -0
|
@@ -164,3 +164,164 @@ class PostApiUtils:
|
|
|
164
164
|
_headers=get_headers(self.flag["UnfavoriteTweet"], self.ct),
|
|
165
165
|
)
|
|
166
166
|
return build_response(res, res.data)
|
|
167
|
+
|
|
168
|
+
def post_create_bookmark(
|
|
169
|
+
self,
|
|
170
|
+
tweet_id: str,
|
|
171
|
+
) -> ResponseType[models.CreateBookmarkResponse]:
|
|
172
|
+
variables = non_nullable(
|
|
173
|
+
twitter.PostCreateBookmarkRequestVariables.from_dict(self.flag["CreateBookmark"]["variables"])
|
|
174
|
+
)
|
|
175
|
+
variables.tweet_id = tweet_id
|
|
176
|
+
|
|
177
|
+
res = self.api.post_create_bookmark_with_http_info(
|
|
178
|
+
path_query_id=self.flag["CreateBookmark"]["queryId"],
|
|
179
|
+
post_create_bookmark_request=twitter.PostCreateBookmarkRequest(
|
|
180
|
+
queryId=self.flag["CreateBookmark"]["queryId"],
|
|
181
|
+
variables=variables,
|
|
182
|
+
),
|
|
183
|
+
_headers=get_headers(self.flag["CreateBookmark"], self.ct),
|
|
184
|
+
)
|
|
185
|
+
return build_response(res, res.data)
|
|
186
|
+
|
|
187
|
+
def post_delete_bookmark(
|
|
188
|
+
self,
|
|
189
|
+
tweet_id: str,
|
|
190
|
+
) -> ResponseType[models.DeleteBookmarkResponse]:
|
|
191
|
+
variables = non_nullable(
|
|
192
|
+
twitter.PostCreateBookmarkRequestVariables.from_dict(self.flag["DeleteBookmark"]["variables"])
|
|
193
|
+
)
|
|
194
|
+
variables.tweet_id = tweet_id
|
|
195
|
+
|
|
196
|
+
res = self.api.post_delete_bookmark_with_http_info(
|
|
197
|
+
path_query_id=self.flag["DeleteBookmark"]["queryId"],
|
|
198
|
+
post_delete_bookmark_request=twitter.PostDeleteBookmarkRequest(
|
|
199
|
+
queryId=self.flag["DeleteBookmark"]["queryId"],
|
|
200
|
+
variables=variables,
|
|
201
|
+
),
|
|
202
|
+
_headers=get_headers(self.flag["DeleteBookmark"], self.ct),
|
|
203
|
+
)
|
|
204
|
+
return build_response(res, res.data)
|
|
205
|
+
|
|
206
|
+
def post_create_list(
|
|
207
|
+
self,
|
|
208
|
+
name: str,
|
|
209
|
+
description: str = "",
|
|
210
|
+
is_private: bool = False,
|
|
211
|
+
) -> ResponseType[models.ListResponse]:
|
|
212
|
+
variables = non_nullable(twitter.PostCreateListRequestVariables.from_dict(self.flag["CreateList"]["variables"]))
|
|
213
|
+
features = non_nullable(twitter.PostCreateListRequestFeatures.from_dict(self.flag["CreateList"]["features"]))
|
|
214
|
+
variables.name = name
|
|
215
|
+
variables.description = description
|
|
216
|
+
variables.is_private = is_private
|
|
217
|
+
|
|
218
|
+
res = self.api.post_create_list_with_http_info(
|
|
219
|
+
path_query_id=self.flag["CreateList"]["queryId"],
|
|
220
|
+
post_create_list_request=twitter.PostCreateListRequest(
|
|
221
|
+
queryId=self.flag["CreateList"]["queryId"],
|
|
222
|
+
variables=variables,
|
|
223
|
+
features=features,
|
|
224
|
+
),
|
|
225
|
+
_headers=get_headers(self.flag["CreateList"], self.ct),
|
|
226
|
+
)
|
|
227
|
+
return build_response(res, res.data)
|
|
228
|
+
|
|
229
|
+
def post_delete_list(
|
|
230
|
+
self,
|
|
231
|
+
list_id: str,
|
|
232
|
+
) -> ResponseType[models.DeleteListResponse]:
|
|
233
|
+
variables = non_nullable(twitter.PostDeleteListRequestVariables.from_dict(self.flag["DeleteList"]["variables"]))
|
|
234
|
+
variables.list_id = list_id
|
|
235
|
+
|
|
236
|
+
res = self.api.post_delete_list_with_http_info(
|
|
237
|
+
path_query_id=self.flag["DeleteList"]["queryId"],
|
|
238
|
+
post_delete_list_request=twitter.PostDeleteListRequest(
|
|
239
|
+
queryId=self.flag["DeleteList"]["queryId"],
|
|
240
|
+
variables=variables,
|
|
241
|
+
),
|
|
242
|
+
_headers=get_headers(self.flag["DeleteList"], self.ct),
|
|
243
|
+
)
|
|
244
|
+
return build_response(res, res.data)
|
|
245
|
+
|
|
246
|
+
def post_list_add_member(
|
|
247
|
+
self,
|
|
248
|
+
list_id: str,
|
|
249
|
+
user_id: str,
|
|
250
|
+
) -> ResponseType[models.ListResponse]:
|
|
251
|
+
variables = non_nullable(
|
|
252
|
+
twitter.PostListAddMemberRequestVariables.from_dict(self.flag["ListAddMember"]["variables"])
|
|
253
|
+
)
|
|
254
|
+
features = non_nullable(twitter.PostCreateListRequestFeatures.from_dict(self.flag["ListAddMember"]["features"]))
|
|
255
|
+
variables.list_id = list_id
|
|
256
|
+
variables.user_id = user_id
|
|
257
|
+
|
|
258
|
+
res = self.api.post_list_add_member_with_http_info(
|
|
259
|
+
path_query_id=self.flag["ListAddMember"]["queryId"],
|
|
260
|
+
post_list_add_member_request=twitter.PostListAddMemberRequest(
|
|
261
|
+
queryId=self.flag["ListAddMember"]["queryId"],
|
|
262
|
+
variables=variables,
|
|
263
|
+
features=features,
|
|
264
|
+
),
|
|
265
|
+
_headers=get_headers(self.flag["ListAddMember"], self.ct),
|
|
266
|
+
)
|
|
267
|
+
return build_response(res, res.data)
|
|
268
|
+
|
|
269
|
+
def post_list_remove_member(
|
|
270
|
+
self,
|
|
271
|
+
list_id: str,
|
|
272
|
+
user_id: str,
|
|
273
|
+
) -> ResponseType[models.ListResponse]:
|
|
274
|
+
variables = non_nullable(
|
|
275
|
+
twitter.PostListAddMemberRequestVariables.from_dict(self.flag["ListRemoveMember"]["variables"])
|
|
276
|
+
)
|
|
277
|
+
features = non_nullable(
|
|
278
|
+
twitter.PostCreateListRequestFeatures.from_dict(self.flag["ListRemoveMember"]["features"])
|
|
279
|
+
)
|
|
280
|
+
variables.list_id = list_id
|
|
281
|
+
variables.user_id = user_id
|
|
282
|
+
|
|
283
|
+
res = self.api.post_list_remove_member_with_http_info(
|
|
284
|
+
path_query_id=self.flag["ListRemoveMember"]["queryId"],
|
|
285
|
+
post_list_remove_member_request=twitter.PostListRemoveMemberRequest(
|
|
286
|
+
queryId=self.flag["ListRemoveMember"]["queryId"],
|
|
287
|
+
variables=variables,
|
|
288
|
+
features=features,
|
|
289
|
+
),
|
|
290
|
+
_headers=get_headers(self.flag["ListRemoveMember"], self.ct),
|
|
291
|
+
)
|
|
292
|
+
return build_response(res, res.data)
|
|
293
|
+
|
|
294
|
+
def post_create_draft_tweet(
|
|
295
|
+
self,
|
|
296
|
+
status: str,
|
|
297
|
+
) -> ResponseType[models.CreateDraftTweetResponse]:
|
|
298
|
+
variables = non_nullable(
|
|
299
|
+
twitter.PostCreateDraftTweetRequestVariables.from_dict(self.flag["CreateDraftTweet"]["variables"])
|
|
300
|
+
)
|
|
301
|
+
variables.post_tweet_request.status = status
|
|
302
|
+
|
|
303
|
+
res = self.api.post_create_draft_tweet_with_http_info(
|
|
304
|
+
path_query_id=self.flag["CreateDraftTweet"]["queryId"],
|
|
305
|
+
post_create_draft_tweet_request=twitter.PostCreateDraftTweetRequest(
|
|
306
|
+
queryId=self.flag["CreateDraftTweet"]["queryId"],
|
|
307
|
+
variables=variables,
|
|
308
|
+
),
|
|
309
|
+
_headers=get_headers(self.flag["CreateDraftTweet"], self.ct),
|
|
310
|
+
)
|
|
311
|
+
return build_response(res, res.data)
|
|
312
|
+
|
|
313
|
+
def post_delete_draft_tweets(
|
|
314
|
+
self,
|
|
315
|
+
draft_tweet_ids: list[str],
|
|
316
|
+
) -> ResponseType[models.DeleteDraftTweetsResponse]:
|
|
317
|
+
variables = twitter.PostDeleteDraftTweetsRequestVariables(draft_tweet_ids=draft_tweet_ids)
|
|
318
|
+
|
|
319
|
+
res = self.api.post_delete_draft_tweets_with_http_info(
|
|
320
|
+
path_query_id=self.flag["DeleteDraftTweets"]["queryId"],
|
|
321
|
+
post_delete_draft_tweets_request=twitter.PostDeleteDraftTweetsRequest(
|
|
322
|
+
queryId=self.flag["DeleteDraftTweets"]["queryId"],
|
|
323
|
+
variables=variables,
|
|
324
|
+
),
|
|
325
|
+
_headers=get_headers(self.flag["DeleteDraftTweets"], self.ct),
|
|
326
|
+
)
|
|
327
|
+
return build_response(res, res.data)
|
|
@@ -5,22 +5,29 @@ import twitter_openapi_python_generated.models as models
|
|
|
5
5
|
from x_client_transaction import ClientTransaction
|
|
6
6
|
|
|
7
7
|
from twitter_openapi_python.models import (
|
|
8
|
-
|
|
8
|
+
CommunityApiUtilsData,
|
|
9
9
|
TimelineApiUtilsResponse,
|
|
10
10
|
TweetApiUtilsData,
|
|
11
11
|
TwitterApiUtilsResponse,
|
|
12
|
+
UserApiUtilsData,
|
|
12
13
|
)
|
|
13
14
|
from twitter_openapi_python.utils import (
|
|
14
|
-
|
|
15
|
-
entries_cursor,
|
|
15
|
+
community_entries_converter,
|
|
16
16
|
error_check,
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
notification_entries_converter,
|
|
18
|
+
timeline_request,
|
|
19
|
+
trend_entries_converter,
|
|
19
20
|
tweet_entries_converter,
|
|
21
|
+
user_entries_converter,
|
|
22
|
+
user_result_converter,
|
|
20
23
|
)
|
|
21
24
|
|
|
22
25
|
T = TypeVar("T")
|
|
23
26
|
ResponseType = TwitterApiUtilsResponse[TimelineApiUtilsResponse[TweetApiUtilsData]]
|
|
27
|
+
UserResponseType = TwitterApiUtilsResponse[TimelineApiUtilsResponse[UserApiUtilsData]]
|
|
28
|
+
TrendResponseType = TwitterApiUtilsResponse[TimelineApiUtilsResponse[models.TimelineTrend]]
|
|
29
|
+
NotificationResponseType = TwitterApiUtilsResponse[TimelineApiUtilsResponse[models.TimelineNotification]]
|
|
30
|
+
CommunityResponseType = TwitterApiUtilsResponse[TimelineApiUtilsResponse[CommunityApiUtilsData]]
|
|
24
31
|
ApiFnType = Callable[..., twitter.ApiResponse[T]]
|
|
25
32
|
ParamType = dict[str, Any]
|
|
26
33
|
|
|
@@ -41,21 +48,7 @@ class TweetApiUtils:
|
|
|
41
48
|
key: str,
|
|
42
49
|
param: ParamType,
|
|
43
50
|
) -> ResponseType:
|
|
44
|
-
|
|
45
|
-
res = apiFn(**args)
|
|
46
|
-
instruction = convertFn(res.data)
|
|
47
|
-
entry = instruction_to_entry(instruction)
|
|
48
|
-
tweet_list = tweet_entries_converter(entry)
|
|
49
|
-
raw = ApiUtilsRaw(
|
|
50
|
-
instruction=instruction,
|
|
51
|
-
entry=entry,
|
|
52
|
-
)
|
|
53
|
-
data = TimelineApiUtilsResponse[TweetApiUtilsData](
|
|
54
|
-
raw=raw,
|
|
55
|
-
cursor=entries_cursor(entry),
|
|
56
|
-
data=tweet_list,
|
|
57
|
-
)
|
|
58
|
-
return build_response(res, data)
|
|
51
|
+
return timeline_request(apiFn, self.flag[key], self.ct, convertFn, param, tweet_entries_converter)
|
|
59
52
|
|
|
60
53
|
def get_tweet_detail(
|
|
61
54
|
self,
|
|
@@ -100,7 +93,9 @@ class TweetApiUtils:
|
|
|
100
93
|
|
|
101
94
|
response = self.request(
|
|
102
95
|
apiFn=self.api.get_search_timeline_with_http_info,
|
|
103
|
-
convertFn=lambda e: error_check(
|
|
96
|
+
convertFn=lambda e: error_check(
|
|
97
|
+
error_check(e.data.search_by_raw_query, e.errors).search_timeline.timeline, e.errors
|
|
98
|
+
).instructions,
|
|
104
99
|
key="SearchTimeline",
|
|
105
100
|
param=param,
|
|
106
101
|
)
|
|
@@ -426,3 +421,218 @@ class TweetApiUtils:
|
|
|
426
421
|
param=param,
|
|
427
422
|
)
|
|
428
423
|
return response
|
|
424
|
+
|
|
425
|
+
def get_user_highlights_tweets(
|
|
426
|
+
self,
|
|
427
|
+
user_id: str,
|
|
428
|
+
cursor: Optional[str] = None,
|
|
429
|
+
count: Optional[int] = None,
|
|
430
|
+
extra_param: Optional[ParamType] = None,
|
|
431
|
+
) -> ResponseType:
|
|
432
|
+
param: ParamType = {"userId": user_id}
|
|
433
|
+
if cursor is not None:
|
|
434
|
+
param["cursor"] = cursor
|
|
435
|
+
if count is not None:
|
|
436
|
+
param["count"] = count
|
|
437
|
+
if extra_param is not None:
|
|
438
|
+
param.update(extra_param)
|
|
439
|
+
|
|
440
|
+
response = self.request(
|
|
441
|
+
apiFn=self.api.get_user_highlights_tweets_with_http_info,
|
|
442
|
+
convertFn=lambda e: error_check(e.data.user, e.errors).result.timeline.timeline.instructions,
|
|
443
|
+
key="UserHighlightsTweets",
|
|
444
|
+
param=param,
|
|
445
|
+
)
|
|
446
|
+
return response
|
|
447
|
+
|
|
448
|
+
def get_user_reposts_timeline(
|
|
449
|
+
self,
|
|
450
|
+
user_id: str,
|
|
451
|
+
cursor: Optional[str] = None,
|
|
452
|
+
count: Optional[int] = None,
|
|
453
|
+
extra_param: Optional[ParamType] = None,
|
|
454
|
+
) -> ResponseType:
|
|
455
|
+
param: ParamType = {"userId": user_id}
|
|
456
|
+
if cursor is not None:
|
|
457
|
+
param["cursor"] = cursor
|
|
458
|
+
if count is not None:
|
|
459
|
+
param["count"] = count
|
|
460
|
+
if extra_param is not None:
|
|
461
|
+
param.update(extra_param)
|
|
462
|
+
|
|
463
|
+
response = self.request(
|
|
464
|
+
apiFn=self.api.get_user_reposts_timeline_with_http_info,
|
|
465
|
+
convertFn=lambda e: error_check(
|
|
466
|
+
error_check(e.data.user, e.errors).result.timeline.timeline, e.errors
|
|
467
|
+
).instructions,
|
|
468
|
+
key="UserRepostsTimeline",
|
|
469
|
+
param=param,
|
|
470
|
+
)
|
|
471
|
+
return response
|
|
472
|
+
|
|
473
|
+
def get_user_super_follow_tweets(
|
|
474
|
+
self,
|
|
475
|
+
user_id: str,
|
|
476
|
+
cursor: Optional[str] = None,
|
|
477
|
+
count: Optional[int] = None,
|
|
478
|
+
extra_param: Optional[ParamType] = None,
|
|
479
|
+
) -> ResponseType:
|
|
480
|
+
"""Subscriber-only posts; without a subscription the timeline only carries a TimelineMessagePrompt."""
|
|
481
|
+
param: ParamType = {"userId": user_id}
|
|
482
|
+
if cursor is not None:
|
|
483
|
+
param["cursor"] = cursor
|
|
484
|
+
if count is not None:
|
|
485
|
+
param["count"] = count
|
|
486
|
+
if extra_param is not None:
|
|
487
|
+
param.update(extra_param)
|
|
488
|
+
|
|
489
|
+
response = self.request(
|
|
490
|
+
apiFn=self.api.get_user_super_follow_tweets_with_http_info,
|
|
491
|
+
convertFn=lambda e: error_check(
|
|
492
|
+
error_check(e.data.user, e.errors).result.timeline.timeline, e.errors
|
|
493
|
+
).instructions,
|
|
494
|
+
key="UserSuperFollowTweets",
|
|
495
|
+
param=param,
|
|
496
|
+
)
|
|
497
|
+
return response
|
|
498
|
+
|
|
499
|
+
def get_explore_page(
|
|
500
|
+
self,
|
|
501
|
+
cursor: Optional[str] = None,
|
|
502
|
+
extra_param: Optional[ParamType] = None,
|
|
503
|
+
) -> TrendResponseType:
|
|
504
|
+
"""Trends of the first explore tab; the other tabs are GenericTimelineById timelines."""
|
|
505
|
+
param: ParamType = {}
|
|
506
|
+
if cursor is not None:
|
|
507
|
+
param["cursor"] = cursor
|
|
508
|
+
if extra_param is not None:
|
|
509
|
+
param.update(extra_param)
|
|
510
|
+
|
|
511
|
+
return timeline_request(
|
|
512
|
+
self.api.get_explore_page_with_http_info,
|
|
513
|
+
self.flag["ExplorePage"],
|
|
514
|
+
self.ct,
|
|
515
|
+
lambda e: error_check(e.data.explore_page.body.initial_timeline.timeline.timeline, e.errors).instructions,
|
|
516
|
+
param,
|
|
517
|
+
trend_entries_converter,
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
def get_generic_timeline_by_id(
|
|
521
|
+
self,
|
|
522
|
+
timeline_id: str,
|
|
523
|
+
cursor: Optional[str] = None,
|
|
524
|
+
count: Optional[int] = None,
|
|
525
|
+
extra_param: Optional[ParamType] = None,
|
|
526
|
+
) -> TrendResponseType:
|
|
527
|
+
"""Explore tab timelines (trending, news, sports, ...)."""
|
|
528
|
+
param: ParamType = {"timelineId": timeline_id}
|
|
529
|
+
if cursor is not None:
|
|
530
|
+
param["cursor"] = cursor
|
|
531
|
+
if count is not None:
|
|
532
|
+
param["count"] = count
|
|
533
|
+
if extra_param is not None:
|
|
534
|
+
param.update(extra_param)
|
|
535
|
+
|
|
536
|
+
return timeline_request(
|
|
537
|
+
self.api.get_generic_timeline_by_id_with_http_info,
|
|
538
|
+
self.flag["GenericTimelineById"],
|
|
539
|
+
self.ct,
|
|
540
|
+
lambda e: error_check(e.data.timeline.timeline, e.errors).instructions,
|
|
541
|
+
param,
|
|
542
|
+
trend_entries_converter,
|
|
543
|
+
)
|
|
544
|
+
|
|
545
|
+
def get_notifications_timeline(
|
|
546
|
+
self,
|
|
547
|
+
timeline_type: Optional[Literal["All", "Verified", "Mentions"]] = None,
|
|
548
|
+
cursor: Optional[str] = None,
|
|
549
|
+
count: Optional[int] = None,
|
|
550
|
+
extra_param: Optional[ParamType] = None,
|
|
551
|
+
) -> NotificationResponseType:
|
|
552
|
+
"""Notification items only; the tweets of the Mentions tab are in data.raw.entry (tweet_entries_converter)."""
|
|
553
|
+
param: ParamType = {}
|
|
554
|
+
if timeline_type is not None:
|
|
555
|
+
param["timeline_type"] = timeline_type
|
|
556
|
+
if cursor is not None:
|
|
557
|
+
param["cursor"] = cursor
|
|
558
|
+
if count is not None:
|
|
559
|
+
param["count"] = count
|
|
560
|
+
if extra_param is not None:
|
|
561
|
+
param.update(extra_param)
|
|
562
|
+
|
|
563
|
+
return timeline_request(
|
|
564
|
+
self.api.get_notifications_timeline_with_http_info,
|
|
565
|
+
self.flag["NotificationsTimeline"],
|
|
566
|
+
self.ct,
|
|
567
|
+
lambda e: error_check(
|
|
568
|
+
e.data.viewer_v2.user_results.result.notification_timeline.timeline, e.errors
|
|
569
|
+
).instructions,
|
|
570
|
+
param,
|
|
571
|
+
notification_entries_converter,
|
|
572
|
+
)
|
|
573
|
+
|
|
574
|
+
def get_community_discovery_timeline(
|
|
575
|
+
self,
|
|
576
|
+
cursor: Optional[str] = None,
|
|
577
|
+
count: Optional[int] = None,
|
|
578
|
+
extra_param: Optional[ParamType] = None,
|
|
579
|
+
) -> CommunityResponseType:
|
|
580
|
+
param: ParamType = {}
|
|
581
|
+
if cursor is not None:
|
|
582
|
+
param["cursor"] = cursor
|
|
583
|
+
if count is not None:
|
|
584
|
+
param["count"] = count
|
|
585
|
+
if extra_param is not None:
|
|
586
|
+
param.update(extra_param)
|
|
587
|
+
|
|
588
|
+
return timeline_request(
|
|
589
|
+
self.api.get_community_discovery_timeline_with_http_info,
|
|
590
|
+
self.flag["CommunityDiscoveryTimeline"],
|
|
591
|
+
self.ct,
|
|
592
|
+
lambda e: error_check(e.data.viewer.community_discovery_timeline.timeline, e.errors).instructions,
|
|
593
|
+
param,
|
|
594
|
+
community_entries_converter,
|
|
595
|
+
)
|
|
596
|
+
|
|
597
|
+
def get_community_about_timeline(
|
|
598
|
+
self,
|
|
599
|
+
community_id: str,
|
|
600
|
+
extra_param: Optional[ParamType] = None,
|
|
601
|
+
) -> UserResponseType:
|
|
602
|
+
"""Moderators and members of a community."""
|
|
603
|
+
param: ParamType = {"communityId": community_id}
|
|
604
|
+
if extra_param is not None:
|
|
605
|
+
param.update(extra_param)
|
|
606
|
+
|
|
607
|
+
return timeline_request(
|
|
608
|
+
self.api.get_community_about_timeline_with_http_info,
|
|
609
|
+
self.flag["CommunityAboutTimeline"],
|
|
610
|
+
self.ct,
|
|
611
|
+
lambda e: error_check(e.data.community_results.result.about_timeline.timeline, e.errors).instructions,
|
|
612
|
+
param,
|
|
613
|
+
lambda entry: user_result_converter(user_entries_converter(entry)),
|
|
614
|
+
)
|
|
615
|
+
|
|
616
|
+
def get_connect_tab_timeline(
|
|
617
|
+
self,
|
|
618
|
+
cursor: Optional[str] = None,
|
|
619
|
+
count: Optional[int] = None,
|
|
620
|
+
extra_param: Optional[ParamType] = None,
|
|
621
|
+
) -> UserResponseType:
|
|
622
|
+
"""Who to follow."""
|
|
623
|
+
param: ParamType = {}
|
|
624
|
+
if cursor is not None:
|
|
625
|
+
param["cursor"] = cursor
|
|
626
|
+
if count is not None:
|
|
627
|
+
param["count"] = count
|
|
628
|
+
if extra_param is not None:
|
|
629
|
+
param.update(extra_param)
|
|
630
|
+
|
|
631
|
+
return timeline_request(
|
|
632
|
+
self.api.get_connect_tab_timeline_with_http_info,
|
|
633
|
+
self.flag["ConnectTabTimeline"],
|
|
634
|
+
self.ct,
|
|
635
|
+
lambda e: error_check(e.data.connect_tab_timeline.timeline, e.errors).instructions,
|
|
636
|
+
param,
|
|
637
|
+
lambda entry: user_result_converter(user_entries_converter(entry)),
|
|
638
|
+
)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Any, Callable, Optional, TypeVar
|
|
1
|
+
from typing import Any, Callable, Dict, List, Optional, TypeVar
|
|
2
2
|
|
|
3
3
|
import twitter_openapi_python_generated as twitter
|
|
4
4
|
import twitter_openapi_python_generated.models as models
|
|
@@ -7,6 +7,7 @@ from x_client_transaction import ClientTransaction
|
|
|
7
7
|
from twitter_openapi_python.models import TwitterApiUtilsResponse, UserApiUtilsData
|
|
8
8
|
from twitter_openapi_python.utils import (
|
|
9
9
|
build_response,
|
|
10
|
+
data_request,
|
|
10
11
|
error_check,
|
|
11
12
|
get_kwargs,
|
|
12
13
|
user_or_null_converter,
|
|
@@ -78,3 +79,56 @@ class UserApiUtils:
|
|
|
78
79
|
key="UserByRestId",
|
|
79
80
|
param=param,
|
|
80
81
|
)
|
|
82
|
+
|
|
83
|
+
def get_viewer_badge_counts(
|
|
84
|
+
self,
|
|
85
|
+
extra_param: Optional[ParamType] = None,
|
|
86
|
+
) -> TwitterApiUtilsResponse[models.BadgeCounts]:
|
|
87
|
+
"""Unread counts (notifications, DMs, XChat) of the authenticated account."""
|
|
88
|
+
param: ParamType = {}
|
|
89
|
+
if extra_param is not None:
|
|
90
|
+
param.update(extra_param)
|
|
91
|
+
return data_request(
|
|
92
|
+
self.api.get_viewer_badge_counts_with_http_info,
|
|
93
|
+
self.flag["ViewerBadgeCounts"],
|
|
94
|
+
self.ct,
|
|
95
|
+
lambda e: error_check(e.data, e.errors).viewer_v2.user_results.result.badge_counts,
|
|
96
|
+
param,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
def get_fetch_draft_tweets(
|
|
100
|
+
self,
|
|
101
|
+
ascending: Optional[bool] = None,
|
|
102
|
+
extra_param: Optional[ParamType] = None,
|
|
103
|
+
) -> TwitterApiUtilsResponse[List[models.DraftTweet]]:
|
|
104
|
+
param: ParamType = {}
|
|
105
|
+
if ascending is not None:
|
|
106
|
+
param["ascending"] = ascending
|
|
107
|
+
if extra_param is not None:
|
|
108
|
+
param.update(extra_param)
|
|
109
|
+
return data_request(
|
|
110
|
+
self.api.get_fetch_draft_tweets_with_http_info,
|
|
111
|
+
self.flag["FetchDraftTweets"],
|
|
112
|
+
self.ct,
|
|
113
|
+
lambda e: error_check(e.data, e.errors).viewer.draft_list.response_data,
|
|
114
|
+
param,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
def get_fetch_scheduled_tweets(
|
|
118
|
+
self,
|
|
119
|
+
ascending: Optional[bool] = None,
|
|
120
|
+
extra_param: Optional[ParamType] = None,
|
|
121
|
+
) -> TwitterApiUtilsResponse[List[Dict[str, Any]]]:
|
|
122
|
+
"""Items are untyped: no scheduled post has been recorded yet."""
|
|
123
|
+
param: ParamType = {}
|
|
124
|
+
if ascending is not None:
|
|
125
|
+
param["ascending"] = ascending
|
|
126
|
+
if extra_param is not None:
|
|
127
|
+
param.update(extra_param)
|
|
128
|
+
return data_request(
|
|
129
|
+
self.api.get_fetch_scheduled_tweets_with_http_info,
|
|
130
|
+
self.flag["FetchScheduledTweets"],
|
|
131
|
+
self.ct,
|
|
132
|
+
lambda e: error_check(e.data, e.errors).viewer.scheduled_tweet_list,
|
|
133
|
+
param,
|
|
134
|
+
)
|
|
@@ -5,23 +5,22 @@ import twitter_openapi_python_generated.models as models
|
|
|
5
5
|
from x_client_transaction import ClientTransaction
|
|
6
6
|
|
|
7
7
|
from twitter_openapi_python.models import (
|
|
8
|
-
ApiUtilsRaw,
|
|
9
8
|
TimelineApiUtilsResponse,
|
|
10
9
|
TwitterApiUtilsResponse,
|
|
11
10
|
UserApiUtilsData,
|
|
12
11
|
)
|
|
13
12
|
from twitter_openapi_python.utils import (
|
|
14
|
-
|
|
15
|
-
entries_cursor,
|
|
13
|
+
data_request,
|
|
16
14
|
error_check,
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
list_entries_converter,
|
|
16
|
+
timeline_request,
|
|
19
17
|
user_entries_converter,
|
|
20
18
|
user_result_converter,
|
|
21
19
|
)
|
|
22
20
|
|
|
23
21
|
T = TypeVar("T")
|
|
24
22
|
ResponseType = TwitterApiUtilsResponse[TimelineApiUtilsResponse[UserApiUtilsData]]
|
|
23
|
+
ListResponseType = TwitterApiUtilsResponse[TimelineApiUtilsResponse[models.TwitterList]]
|
|
25
24
|
ApiFnType = Callable[..., twitter.ApiResponse[T]]
|
|
26
25
|
ParamType = dict[str, Any]
|
|
27
26
|
|
|
@@ -42,24 +41,14 @@ class UserListApiUtils:
|
|
|
42
41
|
key: str,
|
|
43
42
|
param: ParamType,
|
|
44
43
|
) -> ResponseType:
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
raw = ApiUtilsRaw(
|
|
53
|
-
instruction=instruction,
|
|
54
|
-
entry=entry,
|
|
44
|
+
return timeline_request(
|
|
45
|
+
apiFn,
|
|
46
|
+
self.flag[key],
|
|
47
|
+
self.ct,
|
|
48
|
+
convertFn,
|
|
49
|
+
param,
|
|
50
|
+
lambda entry: user_result_converter(user_entries_converter(entry)),
|
|
55
51
|
)
|
|
56
|
-
data = TimelineApiUtilsResponse[UserApiUtilsData](
|
|
57
|
-
raw=raw,
|
|
58
|
-
cursor=entries_cursor(entry),
|
|
59
|
-
data=user,
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
return build_response(response=res, data=data)
|
|
63
52
|
|
|
64
53
|
def get_followers(
|
|
65
54
|
self,
|
|
@@ -169,3 +158,147 @@ class UserListApiUtils:
|
|
|
169
158
|
key="Retweeters",
|
|
170
159
|
param=param,
|
|
171
160
|
)
|
|
161
|
+
|
|
162
|
+
def get_blue_verified_followers(
|
|
163
|
+
self,
|
|
164
|
+
user_id: str,
|
|
165
|
+
cursor: Optional[str] = None,
|
|
166
|
+
count: Optional[int] = None,
|
|
167
|
+
extra_param: Optional[ParamType] = None,
|
|
168
|
+
) -> ResponseType:
|
|
169
|
+
param: ParamType = {"userId": user_id}
|
|
170
|
+
if cursor is not None:
|
|
171
|
+
param["cursor"] = cursor
|
|
172
|
+
if count is not None:
|
|
173
|
+
param["count"] = count
|
|
174
|
+
if extra_param is not None:
|
|
175
|
+
param.update(extra_param)
|
|
176
|
+
return self.request(
|
|
177
|
+
apiFn=self.api.get_blue_verified_followers_with_http_info,
|
|
178
|
+
convertFn=lambda e: error_check(e.data.user, e.errors).result.timeline.timeline.instructions,
|
|
179
|
+
key="BlueVerifiedFollowers",
|
|
180
|
+
param=param,
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
def get_list_members(
|
|
184
|
+
self,
|
|
185
|
+
list_id: str,
|
|
186
|
+
cursor: Optional[str] = None,
|
|
187
|
+
count: Optional[int] = None,
|
|
188
|
+
extra_param: Optional[ParamType] = None,
|
|
189
|
+
) -> ResponseType:
|
|
190
|
+
param: ParamType = {"listId": list_id}
|
|
191
|
+
if cursor is not None:
|
|
192
|
+
param["cursor"] = cursor
|
|
193
|
+
if count is not None:
|
|
194
|
+
param["count"] = count
|
|
195
|
+
if extra_param is not None:
|
|
196
|
+
param.update(extra_param)
|
|
197
|
+
return self.request(
|
|
198
|
+
apiFn=self.api.get_list_members_with_http_info,
|
|
199
|
+
convertFn=lambda e: error_check(e.data.list.members_timeline.timeline, e.errors).instructions,
|
|
200
|
+
key="ListMembers",
|
|
201
|
+
param=param,
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
def get_list_subscribers(
|
|
205
|
+
self,
|
|
206
|
+
list_id: str,
|
|
207
|
+
cursor: Optional[str] = None,
|
|
208
|
+
count: Optional[int] = None,
|
|
209
|
+
extra_param: Optional[ParamType] = None,
|
|
210
|
+
) -> ResponseType:
|
|
211
|
+
param: ParamType = {"listId": list_id}
|
|
212
|
+
if cursor is not None:
|
|
213
|
+
param["cursor"] = cursor
|
|
214
|
+
if count is not None:
|
|
215
|
+
param["count"] = count
|
|
216
|
+
if extra_param is not None:
|
|
217
|
+
param.update(extra_param)
|
|
218
|
+
return self.request(
|
|
219
|
+
apiFn=self.api.get_list_subscribers_with_http_info,
|
|
220
|
+
convertFn=lambda e: error_check(e.data.list.subscribers_timeline.timeline, e.errors).instructions,
|
|
221
|
+
key="ListSubscribers",
|
|
222
|
+
param=param,
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
def get_list_creation_recommended_users(
|
|
226
|
+
self,
|
|
227
|
+
list_id: str,
|
|
228
|
+
count: Optional[int] = None,
|
|
229
|
+
extra_param: Optional[ParamType] = None,
|
|
230
|
+
) -> ResponseType:
|
|
231
|
+
"""Empty unless list_id is one of the authenticated account's lists."""
|
|
232
|
+
param: ParamType = {"listId": list_id}
|
|
233
|
+
if count is not None:
|
|
234
|
+
param["count"] = count
|
|
235
|
+
if extra_param is not None:
|
|
236
|
+
param.update(extra_param)
|
|
237
|
+
return self.request(
|
|
238
|
+
apiFn=self.api.get_list_creation_recommended_users_with_http_info,
|
|
239
|
+
convertFn=lambda e: t.instructions if (t := e.data.list.recommended_users.timeline) else [],
|
|
240
|
+
key="ListCreationRecommendedUsers",
|
|
241
|
+
param=param,
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
def get_list_edit_recommended_users(
|
|
245
|
+
self,
|
|
246
|
+
list_id: str,
|
|
247
|
+
count: Optional[int] = None,
|
|
248
|
+
extra_param: Optional[ParamType] = None,
|
|
249
|
+
) -> ResponseType:
|
|
250
|
+
"""Empty unless list_id is one of the authenticated account's lists."""
|
|
251
|
+
param: ParamType = {"listId": list_id}
|
|
252
|
+
if count is not None:
|
|
253
|
+
param["count"] = count
|
|
254
|
+
if extra_param is not None:
|
|
255
|
+
param.update(extra_param)
|
|
256
|
+
return self.request(
|
|
257
|
+
apiFn=self.api.get_list_edit_recommended_users_with_http_info,
|
|
258
|
+
convertFn=lambda e: t.instructions if (t := e.data.list.recommended_users.timeline) else [],
|
|
259
|
+
key="ListEditRecommendedUsers",
|
|
260
|
+
param=param,
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
def get_list_ownerships(
|
|
264
|
+
self,
|
|
265
|
+
user_id: str,
|
|
266
|
+
is_list_member_target_user_id: Optional[str] = None,
|
|
267
|
+
cursor: Optional[str] = None,
|
|
268
|
+
count: Optional[int] = None,
|
|
269
|
+
extra_param: Optional[ParamType] = None,
|
|
270
|
+
) -> ListResponseType:
|
|
271
|
+
"""Lists owned by user_id; is_list_member_target_user_id marks the lists that user is a member of."""
|
|
272
|
+
param: ParamType = {"userId": user_id}
|
|
273
|
+
if is_list_member_target_user_id is not None:
|
|
274
|
+
param["isListMemberTargetUserId"] = is_list_member_target_user_id
|
|
275
|
+
if cursor is not None:
|
|
276
|
+
param["cursor"] = cursor
|
|
277
|
+
if count is not None:
|
|
278
|
+
param["count"] = count
|
|
279
|
+
if extra_param is not None:
|
|
280
|
+
param.update(extra_param)
|
|
281
|
+
return timeline_request(
|
|
282
|
+
self.api.get_list_ownerships_with_http_info,
|
|
283
|
+
self.flag["ListOwnerships"],
|
|
284
|
+
self.ct,
|
|
285
|
+
lambda e: error_check(error_check(e.data.user, e.errors).result.timeline.timeline, e.errors).instructions,
|
|
286
|
+
param,
|
|
287
|
+
list_entries_converter,
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
def get_list_by_rest_id(
|
|
291
|
+
self,
|
|
292
|
+
list_id: str,
|
|
293
|
+
extra_param: Optional[ParamType] = None,
|
|
294
|
+
) -> TwitterApiUtilsResponse[models.TwitterList]:
|
|
295
|
+
param: ParamType = {"listId": list_id}
|
|
296
|
+
if extra_param is not None:
|
|
297
|
+
param.update(extra_param)
|
|
298
|
+
return data_request(
|
|
299
|
+
self.api.get_list_by_rest_id_with_http_info,
|
|
300
|
+
self.flag["ListByRestId"],
|
|
301
|
+
self.ct,
|
|
302
|
+
lambda e: error_check(e.data, e.errors).list,
|
|
303
|
+
param,
|
|
304
|
+
)
|
twitter_openapi_python/client.py
CHANGED
|
@@ -61,7 +61,7 @@ class TwitterOpenapiPythonClient:
|
|
|
61
61
|
|
|
62
62
|
|
|
63
63
|
class TwitterOpenapiPython:
|
|
64
|
-
hash: str = "
|
|
64
|
+
hash: str = "ec7d907e12cfaca5b93dde55522dcc6045457570"
|
|
65
65
|
placeholder_url = "https://raw.githubusercontent.com/fa0311/twitter-openapi/{hash}/src/config/placeholder.json"
|
|
66
66
|
header = "https://raw.githubusercontent.com/fa0311/latest-user-agent/refs/heads/main/header.json"
|
|
67
67
|
access_token: str = (
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import Generic, List, Optional, TypeVar
|
|
2
2
|
|
|
3
3
|
# from twitter_openapi_python_generated.api_response import ApiResponse
|
|
4
4
|
import twitter_openapi_python_generated.models as models
|
|
@@ -26,7 +26,7 @@ class TweetApiUtilsData(BaseModel):
|
|
|
26
26
|
replies: List["TweetApiUtilsData"] = Field(default_factory=list)
|
|
27
27
|
quoted: Optional["TweetApiUtilsData"] = Field(default=None)
|
|
28
28
|
retweeted: Optional["TweetApiUtilsData"] = Field(default=None)
|
|
29
|
-
promoted_metadata: Optional[
|
|
29
|
+
promoted_metadata: Optional[models.PromotedMetadata] = Field(default=None)
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
class UserApiUtilsData(BaseModel):
|
|
@@ -34,6 +34,11 @@ class UserApiUtilsData(BaseModel):
|
|
|
34
34
|
user: models.User = Field()
|
|
35
35
|
|
|
36
36
|
|
|
37
|
+
class CommunityApiUtilsData(BaseModel):
|
|
38
|
+
raw: models.TimelineCommunity = Field()
|
|
39
|
+
community: models.Community = Field()
|
|
40
|
+
|
|
41
|
+
|
|
37
42
|
class TimelineApiUtilsResponse(BaseModel, Generic[T]):
|
|
38
43
|
raw: ApiUtilsRaw = Field()
|
|
39
44
|
cursor: CursorApiUtilsResponse = Field()
|
|
@@ -8,11 +8,18 @@ from twitter_openapi_python.utils.api import (
|
|
|
8
8
|
build_header,
|
|
9
9
|
build_response,
|
|
10
10
|
build_tweet_api_utils,
|
|
11
|
+
community_entries_converter,
|
|
12
|
+
data_request,
|
|
11
13
|
error_check,
|
|
12
14
|
entries_cursor,
|
|
13
15
|
get_kwargs,
|
|
14
16
|
get_legacy_kwargs,
|
|
15
17
|
instruction_to_entry,
|
|
18
|
+
item_contents,
|
|
19
|
+
list_entries_converter,
|
|
20
|
+
notification_entries_converter,
|
|
21
|
+
timeline_request,
|
|
22
|
+
trend_entries_converter,
|
|
16
23
|
tweet_entries_converter,
|
|
17
24
|
tweet_results_converter,
|
|
18
25
|
user_entries_converter,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import json
|
|
2
|
-
from typing import Any, Dict, List, Mapping, Optional, TypeGuard, TypeVar
|
|
2
|
+
from typing import Any, Callable, Dict, List, Mapping, Optional, TypeGuard, TypeVar
|
|
3
3
|
|
|
4
4
|
import twitter_openapi_python_generated as twitter
|
|
5
5
|
import twitter_openapi_python_generated.models as models
|
|
@@ -7,7 +7,10 @@ from x_client_transaction import ClientTransaction
|
|
|
7
7
|
|
|
8
8
|
from twitter_openapi_python.models import (
|
|
9
9
|
ApiUtilsHeader,
|
|
10
|
+
ApiUtilsRaw,
|
|
11
|
+
CommunityApiUtilsData,
|
|
10
12
|
CursorApiUtilsResponse,
|
|
13
|
+
TimelineApiUtilsResponse,
|
|
11
14
|
TweetApiUtilsData,
|
|
12
15
|
TwitterApiUtilsRaw,
|
|
13
16
|
TwitterApiUtilsResponse,
|
|
@@ -153,7 +156,7 @@ def user_or_null_converter(user: models.UserUnion) -> Optional[models.User]:
|
|
|
153
156
|
|
|
154
157
|
def build_tweet_api_utils(
|
|
155
158
|
result: models.ItemResult,
|
|
156
|
-
promoted_metadata: Optional[
|
|
159
|
+
promoted_metadata: Optional[models.PromotedMetadata] = None,
|
|
157
160
|
reply: Optional[List[models.TimelineTweet]] = None,
|
|
158
161
|
) -> Optional[TweetApiUtilsData]:
|
|
159
162
|
tweet = tweet_results_converter(result)
|
|
@@ -198,17 +201,45 @@ def tweet_results_converter(tweetResults: models.ItemResult) -> Optional[models.
|
|
|
198
201
|
raise Exception()
|
|
199
202
|
|
|
200
203
|
|
|
204
|
+
def item_contents(item: List[models.TimelineAddEntry]) -> List[Any]:
|
|
205
|
+
"""Every item of the entries, module items included (TimelineTweet, TimelineUser, TimelineTrend, ...)."""
|
|
206
|
+
|
|
207
|
+
def map_fn(x: models.TimelineAddEntry) -> List[Any]:
|
|
208
|
+
one_of = x.content.actual_instance
|
|
209
|
+
if isinstance(one_of, models.TimelineTimelineItem):
|
|
210
|
+
return [one_of.item_content.actual_instance]
|
|
211
|
+
elif isinstance(one_of, models.TimelineTimelineModule):
|
|
212
|
+
return [y.item.item_content.actual_instance for y in one_of.items or []]
|
|
213
|
+
return []
|
|
214
|
+
|
|
215
|
+
return flat(list(map(map_fn, item)))
|
|
216
|
+
|
|
217
|
+
|
|
201
218
|
def user_entries_converter(
|
|
202
219
|
item: list[models.TimelineAddEntry],
|
|
203
220
|
) -> list[models.UserResults]:
|
|
204
|
-
|
|
205
|
-
one_of = x.content.actual_instance
|
|
206
|
-
if isinstance(one_of, models.TimelineTimelineItem):
|
|
207
|
-
item = one_of.item_content.actual_instance
|
|
208
|
-
if isinstance(item, models.TimelineUser):
|
|
209
|
-
return item.user_results
|
|
221
|
+
return [x.user_results for x in item_contents(item) if isinstance(x, models.TimelineUser)]
|
|
210
222
|
|
|
211
|
-
|
|
223
|
+
|
|
224
|
+
def trend_entries_converter(item: List[models.TimelineAddEntry]) -> List[models.TimelineTrend]:
|
|
225
|
+
return [x for x in item_contents(item) if isinstance(x, models.TimelineTrend)]
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def notification_entries_converter(item: List[models.TimelineAddEntry]) -> List[models.TimelineNotification]:
|
|
229
|
+
return [x for x in item_contents(item) if isinstance(x, models.TimelineNotification)]
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def list_entries_converter(item: List[models.TimelineAddEntry]) -> List[models.TwitterList]:
|
|
233
|
+
return [x.list for x in item_contents(item) if isinstance(x, models.TimelineTwitterList)]
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def community_entries_converter(item: List[models.TimelineAddEntry]) -> List[CommunityApiUtilsData]:
|
|
237
|
+
def map_fn(x: models.TimelineCommunity) -> Optional[CommunityApiUtilsData]:
|
|
238
|
+
community = x.community_results.result.actual_instance
|
|
239
|
+
if isinstance(community, models.Community):
|
|
240
|
+
return CommunityApiUtilsData(raw=x, community=community)
|
|
241
|
+
|
|
242
|
+
return non_nullable_list([map_fn(x) for x in item_contents(item) if isinstance(x, models.TimelineCommunity)])
|
|
212
243
|
|
|
213
244
|
|
|
214
245
|
def user_result_converter(item: list[models.UserResults]) -> List[UserApiUtilsData]:
|
|
@@ -270,6 +301,36 @@ def build_header(headers: Dict[str, str]) -> ApiUtilsHeader:
|
|
|
270
301
|
)
|
|
271
302
|
|
|
272
303
|
|
|
304
|
+
def timeline_request(
|
|
305
|
+
api_fn: Callable[..., twitter.ApiResponse[T1]],
|
|
306
|
+
flag: ParamType,
|
|
307
|
+
ct: ClientTransaction,
|
|
308
|
+
convert_fn: Callable[[T1], List[models.InstructionUnion]],
|
|
309
|
+
param: ParamType,
|
|
310
|
+
items_fn: Callable[[List[models.TimelineAddEntry]], List[T2]],
|
|
311
|
+
) -> TwitterApiUtilsResponse[TimelineApiUtilsResponse[T2]]:
|
|
312
|
+
res = api_fn(**get_kwargs(flag=flag, additional=param, ct=ct))
|
|
313
|
+
instruction = convert_fn(res.data)
|
|
314
|
+
entry = instruction_to_entry(instruction)
|
|
315
|
+
data = TimelineApiUtilsResponse[T2](
|
|
316
|
+
raw=ApiUtilsRaw(instruction=instruction, entry=entry),
|
|
317
|
+
cursor=entries_cursor(entry),
|
|
318
|
+
data=items_fn(entry),
|
|
319
|
+
)
|
|
320
|
+
return build_response(res, data)
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def data_request(
|
|
324
|
+
api_fn: Callable[..., twitter.ApiResponse[T1]],
|
|
325
|
+
flag: ParamType,
|
|
326
|
+
ct: ClientTransaction,
|
|
327
|
+
convert_fn: Callable[[T1], T2],
|
|
328
|
+
param: ParamType,
|
|
329
|
+
) -> TwitterApiUtilsResponse[T2]:
|
|
330
|
+
res = api_fn(**get_kwargs(flag=flag, additional=param, ct=ct))
|
|
331
|
+
return build_response(res, convert_fn(res.data))
|
|
332
|
+
|
|
333
|
+
|
|
273
334
|
def build_response(response: twitter.ApiResponse, data: T1) -> TwitterApiUtilsResponse[T1]:
|
|
274
335
|
if response.headers is None:
|
|
275
336
|
raise Exception("headers is None")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: twitter_openapi_python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Twitter OpenAPI
|
|
5
5
|
Keywords: twitter,api,python,scraper
|
|
6
6
|
Author: fa0311
|
|
@@ -8,7 +8,7 @@ Author-email: fa0311 <yuki@yuki0311.com>
|
|
|
8
8
|
License-Expression: LicenseRef-Custom OR AGPL-3.0-or-later
|
|
9
9
|
License-File: LICENSE
|
|
10
10
|
License-File: LICENSE.AGPL
|
|
11
|
-
Requires-Dist: twitter-openapi-python-generated==0.
|
|
11
|
+
Requires-Dist: twitter-openapi-python-generated==0.1.1
|
|
12
12
|
Requires-Dist: pydantic>=2.6
|
|
13
13
|
Requires-Dist: requests>=2.31.0,<3.0.0
|
|
14
14
|
Requires-Dist: urllib3>=2.1.0,<3.0.0
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
twitter_openapi_python/__init__.py,sha256=IyCanHNVJtKPGaYEMBqF37VXfMtZNUJlPhSOZMvO5jg,324
|
|
2
|
+
twitter_openapi_python/api/__init__.py,sha256=m9S_EoojMhead7EToafmdHKUxpyYHm9-qaKN_auWhSM,630
|
|
3
|
+
twitter_openapi_python/api/default_api.py,sha256=34l_jG5Mq1u0StPRX-QfGYHoGVYP8EEY_-5vFG_Xz7o,2586
|
|
4
|
+
twitter_openapi_python/api/initial_state_api.py,sha256=nAkb25-btWdMoSyyncxS_VrBQ9uKDgzmG7jBubfETYo,2269
|
|
5
|
+
twitter_openapi_python/api/post_api.py,sha256=YSiGjV95AxxxSukZZESVRJ34D8hde6YRjd0Q6ElQ8fE,13166
|
|
6
|
+
twitter_openapi_python/api/tweet_api.py,sha256=VktFxYf8XLIZjIUaON_rVzuImJIrCe5s7HYKpbqTSE0,22000
|
|
7
|
+
twitter_openapi_python/api/user_api.py,sha256=CF9ST6jNI54H_ShBZLT-O1uu1h-xkaKKJmcQ0Au0H7g,4477
|
|
8
|
+
twitter_openapi_python/api/user_list_api.py,sha256=EzBHlLNsbqTiXgZJoRR8SNru8Adr5F47SoAY6SxCrgM,10539
|
|
9
|
+
twitter_openapi_python/api/users_api.py,sha256=8bcRi-kYZ9MtsgTxYDU1SnVqKtcyQ1b7QqWEVXVafqk,1750
|
|
10
|
+
twitter_openapi_python/api/v11_get_api.py,sha256=UXe34f6IBYExqWCJ8HCld_8d_ChQb92je0G5VtLxmyM,1978
|
|
11
|
+
twitter_openapi_python/api/v11_post_api.py,sha256=eErGBOo-y4E1AAMIHgeWnc0rAFmc5KgIoipJI-8V0Y8,1781
|
|
12
|
+
twitter_openapi_python/client.py,sha256=FSIArYbykUREGLISz9pcwYsux3xgDRgH_vkbM6zc2Ps,6786
|
|
13
|
+
twitter_openapi_python/models/__init__.py,sha256=pHISZJrEPBlXS25kMydl1SxXuCct-CUpnPDfL7kEEBo,588
|
|
14
|
+
twitter_openapi_python/models/base.py,sha256=3sw6wdQn9i8FoujFxhEFVWIB26-qjI6JTDuXKuebM0Y,189
|
|
15
|
+
twitter_openapi_python/models/header.py,sha256=EKujtBRZOJmeh2SD1QOCsLWaE9gdGY4wsNUgwCnbTCU,644
|
|
16
|
+
twitter_openapi_python/models/initial_state.py,sha256=XULKiYznCIG5TsLfV5RGPD_xOiE2bmKt1C8EtL-tQKM,513
|
|
17
|
+
twitter_openapi_python/models/response.py,sha256=ziBYbwdGSeCN3zfu5mFTTd8613zaZetzkZf8y_roTaI,461
|
|
18
|
+
twitter_openapi_python/models/timeline.py,sha256=dRMoc7zqyW_E2iehs4F6HfX8Iy_1b-e3Uo_c2b6Apbg,1484
|
|
19
|
+
twitter_openapi_python/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
+
twitter_openapi_python/tid.py,sha256=xjqJMyPOp62nw2MQjMGHaB4L6G6OZHuWkMR-WKJo7aU,1120
|
|
21
|
+
twitter_openapi_python/utils/__init__.py,sha256=lIEPoDqtgCvUk0A8cWqdTlTWMhkEp_NbVxL7sJ0uiu8,612
|
|
22
|
+
twitter_openapi_python/utils/api.py,sha256=ytdYSv08LYGCe8gof4DptzhjCkgIBV1uJmJXC9htQnU,12623
|
|
23
|
+
twitter_openapi_python-0.1.1.dist-info/licenses/LICENSE,sha256=sLv8EMhrPCMG_LeweYvYKS_B-cDMBwBSKZel7LSMGAs,1493
|
|
24
|
+
twitter_openapi_python-0.1.1.dist-info/licenses/LICENSE.AGPL,sha256=TfPDBt3ar0uv_f9cqCDMZ5rIzW3CY8anRRd4PkL6ejs,34522
|
|
25
|
+
twitter_openapi_python-0.1.1.dist-info/WHEEL,sha256=9IUYslYuG_asT4WlWvfk_K76nveuLvSTKDoLeL0cV-Q,80
|
|
26
|
+
twitter_openapi_python-0.1.1.dist-info/METADATA,sha256=KwMg1oNCnWMvRFro3Bh-Qi7Q88-ebem6u8b4vfoatUo,3232
|
|
27
|
+
twitter_openapi_python-0.1.1.dist-info/RECORD,,
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
twitter_openapi_python/__init__.py,sha256=IyCanHNVJtKPGaYEMBqF37VXfMtZNUJlPhSOZMvO5jg,324
|
|
2
|
-
twitter_openapi_python/api/__init__.py,sha256=m9S_EoojMhead7EToafmdHKUxpyYHm9-qaKN_auWhSM,630
|
|
3
|
-
twitter_openapi_python/api/default_api.py,sha256=34l_jG5Mq1u0StPRX-QfGYHoGVYP8EEY_-5vFG_Xz7o,2586
|
|
4
|
-
twitter_openapi_python/api/initial_state_api.py,sha256=nAkb25-btWdMoSyyncxS_VrBQ9uKDgzmG7jBubfETYo,2269
|
|
5
|
-
twitter_openapi_python/api/post_api.py,sha256=uM-TzRKJQo5mFLXk8h8eu0zfYRXAvIZ0uRWA1eCnyuU,6526
|
|
6
|
-
twitter_openapi_python/api/tweet_api.py,sha256=F-oa2FJk4ySkUPkALp3cRindjsisbkCdyZh9XTLrRnQ,14178
|
|
7
|
-
twitter_openapi_python/api/user_api.py,sha256=AmGhdLrIidDwNn9eOmA3O0kYKbyustv3ZlrZdxTcvwc,2457
|
|
8
|
-
twitter_openapi_python/api/user_list_api.py,sha256=KYNYZfBFuvvZQERJcVjj5ZYc93tuCLNNOMv7r3dknOo,5502
|
|
9
|
-
twitter_openapi_python/api/users_api.py,sha256=8bcRi-kYZ9MtsgTxYDU1SnVqKtcyQ1b7QqWEVXVafqk,1750
|
|
10
|
-
twitter_openapi_python/api/v11_get_api.py,sha256=UXe34f6IBYExqWCJ8HCld_8d_ChQb92je0G5VtLxmyM,1978
|
|
11
|
-
twitter_openapi_python/api/v11_post_api.py,sha256=eErGBOo-y4E1AAMIHgeWnc0rAFmc5KgIoipJI-8V0Y8,1781
|
|
12
|
-
twitter_openapi_python/client.py,sha256=XkjUQYmewxYeTBl_IZng5Kz7pSmtgpaRg6bK9LCwXQ4,6786
|
|
13
|
-
twitter_openapi_python/models/__init__.py,sha256=Mt28XGFXzAauvwrjFhKyKpo2ZoN7uP_TMq-d9JuM9qk,561
|
|
14
|
-
twitter_openapi_python/models/base.py,sha256=3sw6wdQn9i8FoujFxhEFVWIB26-qjI6JTDuXKuebM0Y,189
|
|
15
|
-
twitter_openapi_python/models/header.py,sha256=EKujtBRZOJmeh2SD1QOCsLWaE9gdGY4wsNUgwCnbTCU,644
|
|
16
|
-
twitter_openapi_python/models/initial_state.py,sha256=XULKiYznCIG5TsLfV5RGPD_xOiE2bmKt1C8EtL-tQKM,513
|
|
17
|
-
twitter_openapi_python/models/response.py,sha256=ziBYbwdGSeCN3zfu5mFTTd8613zaZetzkZf8y_roTaI,461
|
|
18
|
-
twitter_openapi_python/models/timeline.py,sha256=uYCQWfI6nCTV6lzYse_ckACuQN_91Ucg-kmMcsbnoFE,1352
|
|
19
|
-
twitter_openapi_python/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
-
twitter_openapi_python/tid.py,sha256=xjqJMyPOp62nw2MQjMGHaB4L6G6OZHuWkMR-WKJo7aU,1120
|
|
21
|
-
twitter_openapi_python/utils/__init__.py,sha256=dCcm68kn5uv5rCRMLRd0rpeN6hAKulIz9khp0HLgx1c,427
|
|
22
|
-
twitter_openapi_python/utils/api.py,sha256=-fqJEcLOM4Y3UniSDxNldp8NCsgJ9vDPn4mQxOSOtyU,10122
|
|
23
|
-
twitter_openapi_python-0.0.45.dist-info/licenses/LICENSE,sha256=sLv8EMhrPCMG_LeweYvYKS_B-cDMBwBSKZel7LSMGAs,1493
|
|
24
|
-
twitter_openapi_python-0.0.45.dist-info/licenses/LICENSE.AGPL,sha256=TfPDBt3ar0uv_f9cqCDMZ5rIzW3CY8anRRd4PkL6ejs,34522
|
|
25
|
-
twitter_openapi_python-0.0.45.dist-info/WHEEL,sha256=9IUYslYuG_asT4WlWvfk_K76nveuLvSTKDoLeL0cV-Q,80
|
|
26
|
-
twitter_openapi_python-0.0.45.dist-info/METADATA,sha256=_-Nw5lAAhfRaojF4MI3FYIA0E7ChFltIaIU-_oL5SDI,3234
|
|
27
|
-
twitter_openapi_python-0.0.45.dist-info/RECORD,,
|
|
File without changes
|
{twitter_openapi_python-0.0.45.dist-info → twitter_openapi_python-0.1.1.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|