diff --git a/src/timeline-v1.ts b/src/timeline-v1.ts index d9b4661..be00cb9 100644 --- a/src/timeline-v1.ts +++ b/src/timeline-v1.ts @@ -229,19 +229,21 @@ export type ParseTweetResult = function parseTimelineTweet( timeline: TimelineV1, - id: string, + tweetId: string, ): ParseTweetResult { const tweets = timeline.globalObjects?.tweets ?? {}; - const tweet = tweets[id]; + const tweet: Readonly | undefined = tweets[tweetId]; if (tweet?.user_id_str == null) { return { success: false, - err: new Error(`Tweet "${id}" was not found in the timeline object.`), + err: new Error( + `Tweet "${tweetId}" was not found in the timeline object.`, + ), }; } const users = timeline.globalObjects?.users ?? {}; - const user = users[tweet.user_id_str]; + const user: Readonly | undefined = users[tweet.user_id_str]; if (user?.screen_name == null) { return { success: false, @@ -259,8 +261,9 @@ function parseTimelineTweet( const { photos, videos, sensitiveContent } = parseMediaGroups(media); const tw: Tweet = { + __raw_UNSTABLE: tweet, conversationId: tweet.conversation_id_str, - id, + id: tweetId, hashtags: hashtags .filter(isFieldDefined('text')) .map((hashtag) => hashtag.text), @@ -271,7 +274,7 @@ function parseTimelineTweet( name: mention.name, })), name: user.name, - permanentUrl: `https://twitter.com/${user.screen_name}/status/${id}`, + permanentUrl: `https://twitter.com/${user.screen_name}/status/${tweetId}`, photos, replies: tweet.reply_count, retweets: tweet.retweet_count, diff --git a/src/timeline-v2.ts b/src/timeline-v2.ts index 61bf4b8..d3caa70 100644 --- a/src/timeline-v2.ts +++ b/src/timeline-v2.ts @@ -103,9 +103,17 @@ export interface ThreadedConversation { }; } +function getLegacyTweetId(tweet: Readonly): string | undefined { + if (tweet.id_str) { + return tweet.id_str; + } + + return tweet.conversation_id_str; +} + export function parseLegacyTweet( - user?: LegacyUserRaw, - tweet?: LegacyTweetRaw, + user?: Readonly, + tweet?: Readonly, ): ParseTweetResult { if (tweet == null) { return { @@ -121,15 +129,12 @@ export function parseLegacyTweet( }; } - if (!tweet.id_str) { - if (!tweet.conversation_id_str) { - return { - success: false, - err: new Error('Tweet ID was not found in object.'), - }; - } - - tweet.id_str = tweet.conversation_id_str; + const tweetId = getLegacyTweetId(tweet); + if (!tweetId) { + return { + success: false, + err: new Error('Tweet ID was not found in object.'), + }; } const hashtags = tweet.entities?.hashtags ?? []; @@ -142,9 +147,10 @@ export function parseLegacyTweet( const { photos, videos, sensitiveContent } = parseMediaGroups(media); const tw: Tweet = { + __raw_UNSTABLE: tweet, bookmarkCount: tweet.bookmark_count, conversationId: tweet.conversation_id_str, - id: tweet.id_str, + id: tweetId, hashtags: hashtags .filter(isFieldDefined('text')) .map((hashtag) => hashtag.text), @@ -155,7 +161,7 @@ export function parseLegacyTweet( name: mention.name, })), name: user.name, - permanentUrl: `https://twitter.com/${user.screen_name}/status/${tweet.id_str}`, + permanentUrl: `https://twitter.com/${user.screen_name}/status/${tweetId}`, photos, replies: tweet.reply_count, retweets: tweet.retweet_count, @@ -219,7 +225,7 @@ export function parseLegacyTweet( tw.views = views; } - if (pinnedTweets.has(tweet.id_str)) { + if (pinnedTweets.has(tweetId)) { // TODO: Update tests so this can be assigned at the tweet declaration tw.isPin = true; } diff --git a/src/tweets.test.ts b/src/tweets.test.ts index e9c1d1b..5ae28ca 100644 --- a/src/tweets.test.ts +++ b/src/tweets.test.ts @@ -1,7 +1,6 @@ import { getScraper } from './test-utils'; import { Mention, Tweet } from './tweets'; import { QueryTweetsResponse } from './timeline-v1'; -import { SearchMode } from './search'; test('scraper can get tweet', async () => { const expected: Tweet = { diff --git a/src/tweets.ts b/src/tweets.ts index a94aa39..7d34d0d 100644 --- a/src/tweets.ts +++ b/src/tweets.ts @@ -1,7 +1,7 @@ import { addApiFeatures, requestApi } from './api'; import { TwitterAuth } from './auth'; import { getUserIdByScreenName } from './profile'; -import { QueryTweetsResponse } from './timeline-v1'; +import { LegacyTweetRaw, QueryTweetsResponse } from './timeline-v1'; import { parseTimelineTweetsV2, TimelineV2, @@ -49,6 +49,7 @@ export interface PlaceRaw { * A parsed Tweet object. */ export interface Tweet { + __raw_UNSTABLE?: LegacyTweetRaw; bookmarkCount?: number; conversationId?: string; hashtags: string[];