Skip to content

Commit

Permalink
feat: tweet edit information (#101)
Browse files Browse the repository at this point in the history
  • Loading branch information
karashiiro authored Jul 13, 2024
1 parent 872a03e commit d706d4a
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/timeline-search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export function parseSearchTimelineTweets(
const tweetResult = parseLegacyTweet(
tweetResultRaw?.core?.user_results?.result?.legacy,
tweetResultRaw?.legacy,
tweetResultRaw?.edit_control?.edit_control_initial,
);

if (tweetResult.success) {
Expand Down
10 changes: 10 additions & 0 deletions src/timeline-v1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ export interface TimelineMediaExtendedRaw {
ext_alt_text: string | undefined;
}

export interface EditControlInitialRaw {
edit_tweet_ids?: string[];
editable_until_msecs?: `${number}`;
edits_remaining?: `${number}`;
is_edit_eligible?: boolean;
}

export interface SearchResultRaw {
rest_id?: string;
__typename?: string;
Expand All @@ -60,6 +67,9 @@ export interface SearchResultRaw {
};
};
};
edit_control?: {
edit_control_initial?: EditControlInitialRaw;
};
views?: {
count?: string;
};
Expand Down
8 changes: 8 additions & 0 deletions src/timeline-v2.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { LegacyUserRaw } from './profile';
import { parseMediaGroups, reconstructTweetHtml } from './timeline-tweet-util';
import {
EditControlInitialRaw,
LegacyTweetRaw,
ParseTweetResult,
QueryTweetsResponse,
Expand Down Expand Up @@ -114,6 +115,7 @@ function getLegacyTweetId(tweet: Readonly<LegacyTweetRaw>): string | undefined {
export function parseLegacyTweet(
user?: Readonly<LegacyUserRaw>,
tweet?: Readonly<LegacyTweetRaw>,
editControl?: Readonly<EditControlInitialRaw>,
): ParseTweetResult {
if (tweet == null) {
return {
Expand Down Expand Up @@ -146,6 +148,10 @@ export function parseLegacyTweet(
const urls = tweet.entities?.urls ?? [];
const { photos, videos, sensitiveContent } = parseMediaGroups(media);

// The edit tweets array always contains the original tweet, even if it has not been edited
const tweetVersions = editControl?.edit_tweet_ids ?? [tweetId];
const editIds = tweetVersions.filter((id) => id !== tweetId);

const tw: Tweet = {
__raw_UNSTABLE: tweet,
bookmarkCount: tweet.bookmark_count,
Expand Down Expand Up @@ -175,6 +181,8 @@ export function parseLegacyTweet(
videos,
isQuoted: false,
isReply: false,
isEdited: editIds.length > 1,
versions: tweetVersions,
isRetweet: false,
isPin: false,
sensitiveContent: false,
Expand Down
16 changes: 16 additions & 0 deletions src/tweets.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@ test('scraper can get tweet', async () => {
videos: [],
isQuoted: false,
isReply: false,
isEdited: false,
versions: ['1585338303800578049'],
isRetweet: false,
isPin: false,
sensitiveContent: false,
};

const scraper = await getScraper();
const actual = await scraper.getTweet('1585338303800578049');
delete actual?.__raw_UNSTABLE;
delete actual?.likes;
delete actual?.replies;
delete actual?.retweets;
Expand Down Expand Up @@ -154,6 +157,8 @@ test('scraper can get tweet quotes without logging in', async () => {
videos: [],
isQuoted: false,
isReply: false,
isEdited: false,
versions: ['1237110546383724547'],
isRetweet: false,
isPin: false,
sensitiveContent: false,
Expand All @@ -162,6 +167,7 @@ test('scraper can get tweet quotes without logging in', async () => {
const scraper = await getScraper({ authMethod: 'anonymous' });
const quote = await scraper.getTweet('1237110897597976576');
expect(quote?.isQuoted).toBeTruthy();
delete quote?.quotedStatus?.__raw_UNSTABLE;
delete quote?.quotedStatus?.likes;
delete quote?.quotedStatus?.replies;
delete quote?.quotedStatus?.retweets;
Expand Down Expand Up @@ -196,6 +202,8 @@ test('scraper can get tweet quotes and replies', async () => {
videos: [],
isQuoted: false,
isReply: false,
isEdited: false,
versions: ['1237110546383724547'],
isRetweet: false,
isPin: false,
sensitiveContent: false,
Expand All @@ -204,6 +212,7 @@ test('scraper can get tweet quotes and replies', async () => {
const scraper = await getScraper();
const quote = await scraper.getTweet('1237110897597976576');
expect(quote?.isQuoted).toBeTruthy();
delete quote?.quotedStatus?.__raw_UNSTABLE;
delete quote?.quotedStatus?.likes;
delete quote?.quotedStatus?.replies;
delete quote?.quotedStatus?.retweets;
Expand All @@ -216,6 +225,7 @@ test('scraper can get tweet quotes and replies', async () => {
if (reply != null) {
reply.isReply = false;
}
delete reply?.inReplyToStatus?.__raw_UNSTABLE;
delete reply?.inReplyToStatus?.likes;
delete reply?.inReplyToStatus?.replies;
delete reply?.inReplyToStatus?.retweets;
Expand Down Expand Up @@ -251,6 +261,8 @@ test('scraper can get retweet', async () => {
],
isQuoted: false,
isReply: false,
isEdited: false,
versions: ['1776276954435481937'],
isRetweet: false,
isPin: false,
sensitiveContent: false,
Expand All @@ -259,6 +271,7 @@ test('scraper can get retweet', async () => {
const scraper = await getScraper();
const retweet = await scraper.getTweet('1776285549566808397');
expect(retweet?.isRetweet).toBeTruthy();
delete retweet?.retweetedStatus?.__raw_UNSTABLE;
delete retweet?.retweetedStatus?.likes;
delete retweet?.retweetedStatus?.replies;
delete retweet?.retweetedStatus?.retweets;
Expand Down Expand Up @@ -287,6 +300,8 @@ test('scraper can get tweet views', async () => {
videos: [],
isQuoted: false,
isReply: false,
isEdited: false,
versions: ['1606055187348688896'],
isRetweet: false,
isPin: false,
sensitiveContent: false,
Expand All @@ -295,6 +310,7 @@ test('scraper can get tweet views', async () => {
const scraper = await getScraper();
const actual = await scraper.getTweet('1606055187348688896');
expect(actual?.views).toBeTruthy();
delete actual?.__raw_UNSTABLE;
delete actual?.likes;
delete actual?.replies;
delete actual?.retweets;
Expand Down
2 changes: 2 additions & 0 deletions src/tweets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ export interface Tweet {
id?: string;
inReplyToStatus?: Tweet;
inReplyToStatusId?: string;
isEdited?: boolean;
versions?: string[];
isQuoted?: boolean;
isPin?: boolean;
isReply?: boolean;
Expand Down

0 comments on commit d706d4a

Please sign in to comment.