🐛 Fix twitter web api

This commit is contained in:
xtaodada 2023-09-03 15:55:29 +08:00
parent 29a66ca0d3
commit 3f25dec676
Signed by: xtaodada
GPG Key ID: 4CBB3F4FA8C85659
4 changed files with 27 additions and 88 deletions

View File

@ -117,11 +117,7 @@ def get_twitter_status(tweet: Tweet):
async def fetch_tweet(tweet_id: int) -> Optional[Tweet]: async def fetch_tweet(tweet_id: int) -> Optional[Tweet]:
try: try:
tweet = await twitter_client.tweet_detail(tweet_id) return await twitter_client.tweet_detail(tweet_id)
for t in tweet:
if t.id_str == str(tweet_id):
return t
return tweet[0]
except TwitterError as e: except TwitterError as e:
logs.error(f"Twitter Error: {e}") logs.error(f"Twitter Error: {e}")
return None return None

View File

@ -1,7 +1,7 @@
import base64 import base64
import json import json
import random import random
from typing import Dict, Any, List from typing import Dict, Any
from httpx import AsyncClient, Cookies from httpx import AsyncClient, Cookies
@ -149,8 +149,7 @@ class TwitterClient:
self, self,
endpoint: str, endpoint: str,
variables: Dict[str, Any], variables: Dict[str, Any],
path: List[str], ) -> Tweet:
):
_variables = self._variables.copy() _variables = self._variables.copy()
_variables.update(variables) _variables.update(variables)
data = await self.func( data = await self.func(
@ -160,89 +159,32 @@ class TwitterClient:
"features": json.dumps(self._features["tweets"]), "features": json.dumps(self._features["tweets"]),
}, },
) )
if not path: result = data.json()["data"]["tweetResult"]["result"]
instructions = data.json()["data"]["user"]["result"]["timeline"][ type_name = result["__typename"]
"timeline" if type_name != "Tweet":
]["instructions"] raise TwitterError(400, result.get("reason"))
else: tweet_legacy = result["legacy"]
instructions = data.json()["data"] user = User(**result["core"]["user_results"]["result"]["legacy"])
for key in path: tweet = Tweet(**tweet_legacy, **{"user": user})
_instructions = instructions.get(key) if tweet_legacy.get("quoted_status_id_str"):
if _instructions is not None: try:
instructions = _instructions tweet.quoted = await self.tweet_detail(
break int(tweet_legacy["quoted_status_id_str"])
instructions = instructions["instructions"] )
for i in instructions: except TwitterError:
if i["type"] == "TimelineAddEntries": pass
return i["entries"] return tweet
@staticmethod async def tweet_detail(self, tid: int) -> Tweet:
def gather_legacy_from_data(entries: List[Dict], filters: str = "tweet-"): return await self.pagination_tweets(
tweets: List[Tweet] = [] "/graphql/0hWvDhmW8YQ-S_ib3azIrw/TweetResultByRestId",
filter_entries = []
for entry in entries:
entry_id: str = entry.get("entryId")
if entry_id:
if filters == "none":
if entry_id.startswith("tweet-"):
filter_entries.append(entry)
elif entry_id.startswith(
"homeConversation-"
) or entry_id.startswith("conversationthread-"):
filter_entries.extend(entry["content"]["items"])
else:
if entry_id.startswith(filters):
filter_entries.append(entry)
for entry in filter_entries:
retweet = None
quoted = None
content = entry.get("content") or entry.get("item")
tweet = (
content.get("itemContent", {})
.get("tweet_results", {})
.get("result", {})
)
if tweet and tweet.get("tweet"):
tweet = tweet["tweet"]
if tweet:
retweet = tweet.get("retweeted_status_result", {}).get("result")
quoted = tweet.get("quoted_status_result", {}).get("result")
if (not tweet) or (not tweet.get("legacy")):
continue
if retweet and not retweet.get("legacy"):
retweet = None
if quoted and not quoted.get("legacy"):
quoted = None
tweet = Tweet(
**tweet["legacy"],
**{"user": tweet["core"]["user_results"]["result"]["legacy"]},
)
if retweet:
tweet.retweet = Tweet(
**retweet["legacy"],
**{"user": retweet["core"]["user_results"]["result"]["legacy"]},
)
if quoted:
tweet.quoted = Tweet(
**quoted["legacy"],
**{"user": quoted["core"]["user_results"]["result"]["legacy"]},
)
tweets.append(tweet)
return tweets
async def tweet_detail(self, tid: int):
data = await self.pagination_tweets(
"/graphql/3XDB26fBve-MmjHaWTUZxA/TweetDetail",
variables={ variables={
"focalTweetId": tid, "tweetId": tid,
"with_rux_injections": False,
"withCommunity": True, "withCommunity": True,
"withQuickPromoteEligibilityTweetFields": True, "includePromotedContent": False,
"withBirdwatchNotes": False, "withVoice": False,
}, },
path=["threaded_conversation_with_injections"],
) )
return self.gather_legacy_from_data(data, filters="none")
async def user_by_screen_name(self, username: str): async def user_by_screen_name(self, username: str):
_variables = {"screen_name": username, "withHighlightedLabel": True} _variables = {"screen_name": username, "withHighlightedLabel": True}

View File

@ -59,7 +59,7 @@ class User(BaseModel):
""" 正在关注 """ """ 正在关注 """
location: str location: str
name: str name: str
profile_banner_url: Optional[str] profile_banner_url: Optional[str] = None
profile_image_url_https: str profile_image_url_https: str
screen_name: str screen_name: str
verified: bool = False verified: bool = False
@ -95,7 +95,7 @@ class Tweet(BaseModel):
""" 书签次数 """ """ 书签次数 """
created_at: str created_at: str
conversation_id_str: str conversation_id_str: str
extended_entities: Optional[ExtendedEntities] extended_entities: Optional[ExtendedEntities] = None
favorite_count: int favorite_count: int
""" 喜欢次数 """ """ 喜欢次数 """
full_text: str full_text: str

View File

@ -14,6 +14,7 @@ from defs.twitter_api import (
twitter_user_link, twitter_user_link,
twitter_medias, twitter_medias,
) )
from init import bot
from models.apis.twitter.model import MediaItem from models.apis.twitter.model import MediaItem
@ -84,7 +85,7 @@ async def process_user(message: Message, username: str):
) )
# @Client.on_message(filters.incoming & filters.text & filters.regex(r"twitter.com/")) @bot.on_message(filters.incoming & filters.text & filters.regex(r"twitter.com/"))
async def twitter_share(_: Client, message: Message): async def twitter_share(_: Client, message: Message):
if not message.text: if not message.text:
return return