diff --git a/src/api/status.ts b/src/api/status.ts index 545f8fb..0adfa67 100644 --- a/src/api/status.ts +++ b/src/api/status.ts @@ -18,6 +18,12 @@ const populateTweetProperties = async ( ): Promise => { const apiTweet = {} as APITweet; + if (typeof tweet.core === 'undefined' && typeof tweet.result !== 'undefined') { + tweet = tweet.result; + } else { + console.log('tweet core exists'); + } + /* With v2 conversation API we re-add the user object ot the tweet because Twitter stores it separately in the conversation API. This is to consolidate it in case a user appears multiple times in a thread. */ diff --git a/src/types/twitterTypes.d.ts b/src/types/twitterTypes.d.ts index 2086021..dffbcb7 100644 --- a/src/types/twitterTypes.d.ts +++ b/src/types/twitterTypes.d.ts @@ -304,3 +304,168 @@ type GraphQLUser = { }; }; }; + +type GraphQLTweet = { + // Workaround + result: GraphQLTweet; + __typename: 'Tweet'; + rest_id: string; // "1674824189176590336", + has_birdwatch_notes: false, + core: { + user_results: { + result: GraphQLUser; + } + } + edit_control: unknown, + edit_perspective: unknown, + is_translatable: false, + views: { + count: string; // "562" + state: string; // "EnabledWithCount" + } + source: string; // "Twitter Web App" + quoted_status_result?: GraphQLTweet; + legacy: { + created_at: string; // "Tue Sep 14 20:00:00 +0000 2021" + conversation_id_str: string; // "1674824189176590336" + bookmark_count: number; // 0 + bookmarked: boolean; // false + favorite_count: number; // 28 + full_text: string; // "This is a test tweet" + in_reply_to_screen_name: string; // "username" + in_reply_to_status_id_str: string; // "1674824189176590336" + in_reply_to_user_id_str: string; // "783214" + is_quote_status: boolean; // false + quote_count: number; // 39 + quoted_status_id_str: string; // "1674824189176590336" + quoted_status_permalink: { + url: string; // "https://t.co/aBcDeFgHiJ" + expanded: string; // "https://twitter.com/username/status/1674824189176590336" + display: string; // "twitter.com/username/statu…" + }; + reply_count: number; // 1 + retweet_count: number; // 4 + lang: string; // "en" + possibly_sensitive: boolean; // false + possibly_sensitive_editable: boolean; // false + entities: { + media: { + display_url: string; // "pic.twitter.com/1X2X3X4X5X" + expanded_url: string; // "https://twitter.com/username/status/1674824189176590336/photo/1" "https://twitter.com/username/status/1674824189176590336/video/1" + id_str: string; // "1674824189176590336" + indices: [number, number]; // [number, number] + media_url_https: string; // "https://pbs.twimg.com/media/FAKESCREENSHOT.jpg" With videos appears to be the thumbnail + type: string; // "photo" Seems to be photo even with videos + }[] + user_mentions: unknown[]; + urls: TcoExpansion[]; + hashtags: unknown[]; + symbols: unknown[]; + } + extended_entities: { + media: TweetMedia[] + } + } + card: { + rest_id: string; // "card://1674824189176590336", + legacy: { + binding_values: { + key: `choice${1|2|3|4}_label`|'counts_are_final'|`choice${1|2|3|4}_count`|'last_updated_datetime_utc'|'duration_minutes'|'api'|'card_url' + value: { + string_value: string; // "Option text" + type: 'STRING' + }|{ + boolean_value: boolean; // true + type: 'BOOLEAN' + } + }[] + } + } +} +type TweetTombstone = { + __typename: 'TweetTombstone'; + tombstone: { + __typename: 'TextTombstone'; + text: { + rtl: boolean; // false; + text: string; // "You’re unable to view this Tweet because this account owner limits who can view their Tweets. Learn more" + entities: unknown[]; + } + } +} +type GraphQLTimelineTweetEntry = { + /** The entryID contains the tweet ID */ + entryId: `tweet-${number}`; // "tweet-1674824189176590336" + sortIndex: string; + content: { + entryType: 'TimelineTimelineItem', + __typename: 'TimelineTimelineItem', + itemContent: { + item: 'TimelineTweet', + __typename: 'TimelineTweet', + tweet_results: { + result: GraphQLTweet|TweetTombstone; + } + } + } +} +type GraphQLConversationThread = { + entryId: `conversationthread-${number}`; // "conversationthread-1674824189176590336" + sortIndex: string; +} + +type GraphQLTimelineEntry = GraphQLTimelineTweetEntry|GraphQLConversationThread|unknown; + +type V2ThreadInstruction = TimeLineAddEntriesInstruction | TimeLineTerminateTimelineInstruction; + +type TimeLineAddEntriesInstruction = { + type: 'TimelineAddEntries'; + entries: GraphQLTimelineEntry[]; +} + +type TimeLineTerminateTimelineInstruction = { + type: 'TimelineTerminateTimeline'; + direction: 'Top'; +} +type GraphQLTweetNotFoundResponse = { + errors: [{ + message: string; // "_Missing: No status found with that ID" + locations: unknown[]; + path: string[]; // ["threaded_conversation_with_injections_v2"] + extensions: { + name: string; // "GenericError" + source: string; // "Server" + code: number; // 144 + kind: string; // "NonFatal" + tracing: { + trace_id: string; // "2e39ff747de237db" + } + } + code: number; // 144 + kind: string; // "NonFatal" + name: string; // "GenericError" + source: string; // "Server" + tracing: { + trace_id: string; // "2e39ff747de237db" + } + }] + data: Record; +} +type GraphQLTweetFoundResponse = { + data: { + threaded_conversation_with_injections_v2: { + instructions: V2ThreadInstruction[] + } + } +} +type TweetResultsByRestIdResult = { + errors?: unknown[]; + data?: { + tweetResult?: { + result?: { + __typename: 'TweetUnavailable'; + reason: 'NsfwLoggedOut'|'Protected'; + }|GraphQLTweet + } + } +} \ No newline at end of file