[twitter] update API endpoints and parameters

This commit is contained in:
Mike Fährmann
2023-03-17 19:25:53 +01:00
parent a1ca2404f9
commit 3dcabc97ed

View File

@@ -951,6 +951,10 @@ class TwitterAPI():
self.extractor = extractor self.extractor = extractor
self.root = "https://api.twitter.com" self.root = "https://api.twitter.com"
self._nsfw_warning = True
self._syndication = self.extractor.syndication
self._json_dumps = json.JSONEncoder(separators=(",", ":")).encode
cookies = extractor.session.cookies cookies = extractor.session.cookies
cookiedomain = extractor.cookiedomain cookiedomain = extractor.cookiedomain
@@ -966,6 +970,7 @@ class TwitterAPI():
auth_token = cookies.get("auth_token", domain=cookiedomain) auth_token = cookies.get("auth_token", domain=cookiedomain)
self.headers = { self.headers = {
"Accept": "*/*",
"authorization": "Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejR" "authorization": "Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejR"
"COuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu" "COuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu"
"4FA33AGWWjCpTnA", "4FA33AGWWjCpTnA",
@@ -1019,73 +1024,112 @@ class TwitterAPI():
"collab_control,vibe", "collab_control,vibe",
} }
self.variables = { self.variables = {
"includePromotedContent": False,
"withSuperFollowsUserFields": True,
"withBirdwatchPivots": False,
"withDownvotePerspective": False, "withDownvotePerspective": False,
"withReactionsMetadata": False, "withReactionsMetadata": False,
"withReactionsPerspective": False, "withReactionsPerspective": False,
"withSuperFollowsTweetFields": True, }
"withClientEventToken": False, self.features = {
"withBirdwatchNotes": False, "responsive_web_twitter_blue_verified_badge_is_enabled": True,
"withVoice": True, "responsive_web_graphql_exclude_directive_enabled": True,
"withV2Timeline": False, "verified_phone_label_enabled": False,
"__fs_interactive_text": False, "responsive_web_graphql_skip_user_profile_"
"__fs_dont_mention_me_view_api_enabled": False, "image_extensions_enabled": False,
"responsive_web_graphql_timeline_navigation_enabled": True,
}
self.features_pagination = {
"responsive_web_twitter_blue_verified_badge_is_enabled": True,
"responsive_web_graphql_exclude_directive_enabled": True,
"verified_phone_label_enabled": False,
"responsive_web_graphql_timeline_navigation_enabled": True,
"responsive_web_graphql_skip_user_profile_"
"image_extensions_enabled": False,
"tweetypie_unmention_optimization_enabled": True,
"vibe_api_enabled": True,
"responsive_web_edit_tweet_api_enabled": True,
"graphql_is_translatable_rweb_tweet_is_translatable_enabled": True,
"view_counts_everywhere_api_enabled": True,
"longform_notetweets_consumption_enabled": True,
"tweet_awards_web_tipping_enabled": False,
"freedom_of_speech_not_reach_fetch_enabled": False,
"standardized_nudges_misinfo": True,
"tweet_with_visibility_results_prefer_gql_"
"limited_actions_policy_enabled": False,
"interactive_text_enabled": True,
"responsive_web_text_conversations_enabled": False,
"longform_notetweets_richtext_consumption_enabled": False,
"responsive_web_enhance_cards_enabled": False,
} }
self._nsfw_warning = True
self._syndication = self.extractor.syndication
self._json_dumps = json.JSONEncoder(separators=(",", ":")).encode
def tweet_detail(self, tweet_id): def tweet_detail(self, tweet_id):
endpoint = "/graphql/ItejhtHVxU7ksltgMmyaLA/TweetDetail" endpoint = "/graphql/zXaXQgfyR4GxE21uwYQSyA/TweetDetail"
variables = { variables = {
"focalTweetId": tweet_id, "focalTweetId": tweet_id,
"referrer": "profile",
"with_rux_injections": False, "with_rux_injections": False,
"includePromotedContent": True,
"withCommunity": True, "withCommunity": True,
"withQuickPromoteEligibilityTweetFields": True, "withQuickPromoteEligibilityTweetFields": True,
"withBirdwatchNotes": False, "withBirdwatchNotes": False,
"withSuperFollowsUserFields": True,
"withSuperFollowsTweetFields": True,
"withVoice": True,
"withV2Timeline": True,
} }
return self._pagination_tweets( return self._pagination_tweets(
endpoint, variables, ("threaded_conversation_with_injections",)) endpoint, variables, ("threaded_conversation_with_injections_v2",))
def user_tweets(self, screen_name): def user_tweets(self, screen_name):
endpoint = "/graphql/WZT7sCTrLvSOaWOXLDsWbQ/UserTweets" endpoint = "/graphql/9rys0A7w1EyqVd2ME0QCJg/UserTweets"
variables = { variables = {
"userId": self._user_id_by_screen_name(screen_name), "userId": self._user_id_by_screen_name(screen_name),
"count": 100, "count": 100,
"includePromotedContent": True,
"withQuickPromoteEligibilityTweetFields": True, "withQuickPromoteEligibilityTweetFields": True,
"withVoice": True,
"withV2Timeline": True,
} }
return self._pagination_tweets(endpoint, variables) return self._pagination_tweets(endpoint, variables)
def user_tweets_and_replies(self, screen_name): def user_tweets_and_replies(self, screen_name):
endpoint = "/graphql/t4wEKVulW4Mbv1P0kgxTEw/UserTweetsAndReplies" endpoint = "/graphql/ehMCHF3Mkgjsfz_aImqOsg/UserTweetsAndReplies"
variables = { variables = {
"userId": self._user_id_by_screen_name(screen_name), "userId": self._user_id_by_screen_name(screen_name),
"count": 100, "count": 100,
"includePromotedContent": True,
"withCommunity": True, "withCommunity": True,
"withVoice": True,
"withV2Timeline": True,
} }
return self._pagination_tweets(endpoint, variables) return self._pagination_tweets(endpoint, variables)
def user_media(self, screen_name): def user_media(self, screen_name):
endpoint = "/graphql/nRybED9kRbN-TOWioHq1ng/UserMedia" endpoint = "/graphql/MA_EP2a21zpzNWKRkaPBMg/UserMedia"
variables = { variables = {
"userId": self._user_id_by_screen_name(screen_name), "userId": self._user_id_by_screen_name(screen_name),
"count": 100, "count": 100,
"includePromotedContent": False,
"withClientEventToken": False,
"withBirdwatchNotes": False,
"withVoice": True,
"withV2Timeline": True,
} }
return self._pagination_tweets(endpoint, variables) return self._pagination_tweets(endpoint, variables)
def user_likes(self, screen_name): def user_likes(self, screen_name):
endpoint = "/graphql/9MSTt44HoGjVFSg_u3rHDw/Likes" endpoint = "/graphql/XbHBYpgURwtklXj8NNxTDw/Likes"
variables = { variables = {
"userId": self._user_id_by_screen_name(screen_name), "userId": self._user_id_by_screen_name(screen_name),
"count": 100, "count": 100,
"includePromotedContent": False,
"withClientEventToken": False,
"withBirdwatchNotes": False,
"withVoice": True,
"withV2Timeline": True,
} }
return self._pagination_tweets(endpoint, variables) return self._pagination_tweets(endpoint, variables)
def user_bookmarks(self): def user_bookmarks(self):
endpoint = "/graphql/uKP9v_I31k0_VSBmlpq2Xg/Bookmarks" endpoint = "/graphql/Xq0wQSWHlcfnXARLJGqTxg/Bookmarks"
variables = { variables = {
"count": 100, "count": 100,
} }
@@ -1093,7 +1137,7 @@ class TwitterAPI():
endpoint, variables, ("bookmark_timeline", "timeline"), False) endpoint, variables, ("bookmark_timeline", "timeline"), False)
def list_latest_tweets_timeline(self, list_id): def list_latest_tweets_timeline(self, list_id):
endpoint = "/graphql/z3l-EHlx-fyg8OvGO4JN8A/ListLatestTweetsTimeline" endpoint = "/graphql/FDI9EiIp54KxEOWGiv3B4A/ListLatestTweetsTimeline"
variables = { variables = {
"listId": list_id, "listId": list_id,
"count": 100, "count": 100,
@@ -1128,18 +1172,21 @@ class TwitterAPI():
["twitter_objects"]["live_events"][event_id]) ["twitter_objects"]["live_events"][event_id])
def list_by_rest_id(self, list_id): def list_by_rest_id(self, list_id):
endpoint = "/graphql/BWEhzAk7k8TwbU4lKH2dpw/ListByRestId" endpoint = "/graphql/KlGpwq5CAt9tCfHkV2mwYQ/ListByRestId"
params = {"variables": self._json_dumps({ params = {
"listId": list_id, "variables": self._json_dumps({
"withSuperFollowsUserFields": True, "listId": list_id,
})} "withSuperFollowsUserFields": True,
}),
"features": self._json_dumps(self.features),
}
try: try:
return self._call(endpoint, params)["data"]["list"] return self._call(endpoint, params)["data"]["list"]
except KeyError: except KeyError:
raise exception.NotFoundError("list") raise exception.NotFoundError("list")
def list_members(self, list_id): def list_members(self, list_id):
endpoint = "/graphql/snESM0DPs3c7M1SBm4rvVw/ListMembers" endpoint = "/graphql/XsAJX17RLgLYU8GALIWg2g/ListMembers"
variables = { variables = {
"listId": list_id, "listId": list_id,
"count": 100, "count": 100,
@@ -1149,29 +1196,34 @@ class TwitterAPI():
endpoint, variables, ("list", "members_timeline", "timeline")) endpoint, variables, ("list", "members_timeline", "timeline"))
def user_following(self, screen_name): def user_following(self, screen_name):
endpoint = "/graphql/mIwX8GogcobVlRwlgpHNYA/Following" endpoint = "/graphql/vTZwBbd_gz6aI8v6Wze21A/Following"
variables = { variables = {
"userId": self._user_id_by_screen_name(screen_name), "userId": self._user_id_by_screen_name(screen_name),
"count": 100, "count": 100,
"includePromotedContent": False,
} }
return self._pagination_users(endpoint, variables) return self._pagination_users(endpoint, variables)
def user_by_rest_id(self, rest_id): def user_by_rest_id(self, rest_id):
endpoint = "/graphql/I5nvpI91ljifos1Y3Lltyg/UserByRestId" endpoint = "/graphql/QPSxc9lxrmrwnBzYkJI8eA/UserByRestId"
params = {"variables": self._json_dumps({ params = {
"userId": rest_id, "variables": self._json_dumps({
"withSafetyModeUserFields": True, "userId": rest_id,
"withSuperFollowsUserFields": True, "withSafetyModeUserFields": True,
})} }),
"features": self._json_dumps(self.features),
}
return self._call(endpoint, params)["data"]["user"]["result"] return self._call(endpoint, params)["data"]["user"]["result"]
def user_by_screen_name(self, screen_name): def user_by_screen_name(self, screen_name):
endpoint = "/graphql/7mjxD3-C6BxitPMVQ6w0-Q/UserByScreenName" endpoint = "/graphql/nZjSkpOpSL5rWyIVdsKeLA/UserByScreenName"
params = {"variables": self._json_dumps({ params = {
"screen_name": screen_name, "variables": self._json_dumps({
"withSafetyModeUserFields": True, "screen_name": screen_name,
"withSuperFollowsUserFields": True, "withSafetyModeUserFields": True,
})} }),
"features": self._json_dumps(self.features),
}
return self._call(endpoint, params)["data"]["user"]["result"] return self._call(endpoint, params)["data"]["user"]["result"]
def _user_id_by_screen_name(self, screen_name): def _user_id_by_screen_name(self, screen_name):
@@ -1344,12 +1396,13 @@ class TwitterAPI():
pinned_tweet = extr.pinned pinned_tweet = extr.pinned
while True: while True:
params = {"variables": self._json_dumps(variables)} params = {"variables": self._json_dumps(variables),
"features" : self._json_dumps(self.features_pagination)}
data = self._call(endpoint, params)["data"] data = self._call(endpoint, params)["data"]
try: try:
if path is None: if path is None:
instructions = (data["user"]["result"]["timeline"] instructions = (data["user"]["result"]["timeline_v2"]
["timeline"]["instructions"]) ["timeline"]["instructions"])
else: else:
instructions = data instructions = data
@@ -1490,7 +1543,8 @@ class TwitterAPI():
while True: while True:
cursor = entry = stop = None cursor = entry = stop = None
params = {"variables": self._json_dumps(variables)} params = {"variables": self._json_dumps(variables),
"features" : self._json_dumps(self.features_pagination)}
data = self._call(endpoint, params)["data"] data = self._call(endpoint, params)["data"]
try: try: