1111 LIST_FEATURES ,
1212 NOTE_TWEET_FEATURES ,
1313 SIMILAR_POSTS_FEATURES ,
14- USER_FEATURES
14+ TWEET_RESULT_BY_REST_ID_FEATURES ,
15+ USER_FEATURES ,
16+ USER_HIGHLIGHTS_TWEETS_FEATURES
1517)
1618from ..utils import flatten_params , get_query_id
1719
1820if TYPE_CHECKING :
21+ from ..guest .client import GuestClient
1922 from .client import Client
2023
24+ ClientType = Client | GuestClient
25+
2126
2227class Endpoint :
2328 @staticmethod
@@ -33,6 +38,7 @@ def url(path):
3338 USER_BY_SCREEN_NAME = url ('NimuplG1OB7Fd2btCLdBOw/UserByScreenName' )
3439 USER_BY_REST_ID = url ('tD8zKvQzwY3kdx5yz6YmOw/UserByRestId' )
3540 TWEET_DETAIL = url ('U0HTv-bAWTBYylwEMT7x5A/TweetDetail' )
41+ TWEET_RESULT_BY_REST_ID = url ('Xl5pC_lBk_gcO2ItU39DQw/TweetResultByRestId' )
3642 FETCH_SCHEDULED_TWEETS = url ('ITtjAzvlZni2wWXwf295Qg/FetchScheduledTweets' )
3743 DELETE_SCHEDULED_TWEET = url ('CTOVqej0JBXAZSwkp1US0g/DeleteScheduledTweet' )
3844 RETWEETERS = url ('X-XEqG5qHQSAwmvy00xfyQ/Retweeters' )
@@ -42,6 +48,7 @@ def url(path):
4248 USER_TWEETS_AND_REPLIES = url ('vMkJyzx1wdmvOeeNG0n6Wg/UserTweetsAndReplies' )
4349 USER_MEDIA = url ('2tLOJWwGuCTytDrGBg8VwQ/UserMedia' )
4450 USER_LIKES = url ('IohM3gxQHfvWePH5E3KuNA/Likes' )
51+ USER_HIGHLIGHTS_TWEETS = url ('tHFm_XZc_NNi-CfUThwbNw/UserHighlightsTweets' )
4552 HOME_TIMELINE = url ('-X_hcgQzmHGl29-UXxz4sw/HomeTimeline' )
4653 HOME_LATEST_TIMELINE = url ('U0cdisy7QFIoTfu3-Okw0A/HomeLatestTimeline' )
4754 FAVORITE_TWEET = url ('lI07N6Otwv1PhnEgXILM7A/FavoriteTweet' )
@@ -92,7 +99,7 @@ def url(path):
9299
93100
94101class GQLClient :
95- def __init__ (self , base : Client ) -> None :
102+ def __init__ (self , base : ClientType ) -> None :
96103 self .base = base
97104
98105 async def gql_get (
@@ -320,27 +327,43 @@ async def user_media(self, user_id, count, cursor):
320327 async def user_likes (self , user_id , count , cursor ):
321328 return await self ._get_user_tweets (user_id , count , cursor , Endpoint .USER_LIKES )
322329
330+ async def user_highlights_tweets (self , user_id , count , cursor ):
331+ variables = {
332+ 'userId' : user_id ,
333+ 'count' : count ,
334+ 'includePromotedContent' : True ,
335+ 'withVoice' : True
336+ }
337+ if cursor is not None :
338+ variables ['cursor' ] = cursor
339+ return await self .gql_get (
340+ Endpoint .USER_HIGHLIGHTS_TWEETS ,
341+ variables ,
342+ USER_HIGHLIGHTS_TWEETS_FEATURES ,
343+ self .base ._base_headers
344+ )
345+
323346 async def home_timeline (self , count , seen_tweet_ids , cursor ):
324347 variables = {
325- " count" : count ,
326- " includePromotedContent" : True ,
327- " latestControlAvailable" : True ,
328- " requestContext" : " launch" ,
329- " withCommunity" : True ,
330- " seenTweetIds" : seen_tweet_ids or []
348+ ' count' : count ,
349+ ' includePromotedContent' : True ,
350+ ' latestControlAvailable' : True ,
351+ ' requestContext' : ' launch' ,
352+ ' withCommunity' : True ,
353+ ' seenTweetIds' : seen_tweet_ids or []
331354 }
332355 if cursor is not None :
333356 variables ['cursor' ] = cursor
334357 return await self .gql_post (Endpoint .HOME_TIMELINE , variables , FEATURES )
335358
336359 async def home_latest_timeline (self , count , seen_tweet_ids , cursor ):
337360 variables = {
338- " count" : count ,
339- " includePromotedContent" : True ,
340- " latestControlAvailable" : True ,
341- " requestContext" : " launch" ,
342- " withCommunity" : True ,
343- " seenTweetIds" : seen_tweet_ids or []
361+ ' count' : count ,
362+ ' includePromotedContent' : True ,
363+ ' latestControlAvailable' : True ,
364+ ' requestContext' : ' launch' ,
365+ ' withCommunity' : True ,
366+ ' seenTweetIds' : seen_tweet_ids or []
344367 }
345368 if cursor is not None :
346369 variables ['cursor' ] = cursor
@@ -632,16 +655,38 @@ async def moderators_slice_timeline_query(self, community_id, count, cursor):
632655
633656 async def community_tweet_search_module_query (self , community_id , query , count , cursor ):
634657 variables = {
635- " count" : count ,
636- " query" : query ,
637- " communityId" : community_id ,
638- " includePromotedContent" : False ,
639- " withBirdwatchNotes" : True ,
640- " withVoice" : False ,
641- " isListMemberTargetUserId" : "0" ,
642- " withCommunity" : False ,
643- " withSafetyModeUserFields" : True
658+ ' count' : count ,
659+ ' query' : query ,
660+ ' communityId' : community_id ,
661+ ' includePromotedContent' : False ,
662+ ' withBirdwatchNotes' : True ,
663+ ' withVoice' : False ,
664+ ' isListMemberTargetUserId' : '0' ,
665+ ' withCommunity' : False ,
666+ ' withSafetyModeUserFields' : True
644667 }
645668 if cursor is not None :
646669 variables ['cursor' ] = cursor
647670 return await self .gql_get (Endpoint .COMMUNITY_TWEET_SEARCH_MODULE_QUERY , variables , COMMUNITY_TWEETS_FEATURES )
671+
672+ ####################
673+ # For guest client
674+ ####################
675+
676+ async def tweet_result_by_rest_id (self , tweet_id ):
677+ variables = {
678+ 'tweetId' : tweet_id ,
679+ 'withCommunity' : False ,
680+ 'includePromotedContent' : False ,
681+ 'withVoice' : False
682+ }
683+ params = {
684+ 'fieldToggles' : {
685+ 'withArticleRichContentState' : True ,
686+ 'withArticlePlainText' : False ,
687+ 'withGrokAnalyze' : False
688+ }
689+ }
690+ return await self .gql_get (
691+ Endpoint .TWEET_RESULT_BY_REST_ID , variables , TWEET_RESULT_BY_REST_ID_FEATURES , extra_params = params
692+ )
0 commit comments