x-reader 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +206 -0
- package/dist/api/client.d.ts +65 -0
- package/dist/api/client.js +527 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/constants.d.ts +23 -0
- package/dist/api/constants.js +60 -0
- package/dist/api/constants.js.map +1 -0
- package/dist/api/features.d.ts +14 -0
- package/dist/api/features.js +158 -0
- package/dist/api/features.js.map +1 -0
- package/dist/api/parser.d.ts +23 -0
- package/dist/api/parser.js +236 -0
- package/dist/api/parser.js.map +1 -0
- package/dist/api/query-ids.d.ts +31 -0
- package/dist/api/query-ids.js +201 -0
- package/dist/api/query-ids.js.map +1 -0
- package/dist/api/types.d.ts +91 -0
- package/dist/api/types.js +3 -0
- package/dist/api/types.js.map +1 -0
- package/dist/cli/index.d.ts +15 -0
- package/dist/cli/index.js +258 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/auth.d.ts +21 -0
- package/dist/utils/auth.js +128 -0
- package/dist/utils/auth.js.map +1 -0
- package/dist/utils/format.d.ts +15 -0
- package/dist/utils/format.js +62 -0
- package/dist/utils/format.js.map +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature flags for different GraphQL operations.
|
|
3
|
+
* Extracted from Bird CLI v0.8.0 — X rotates these less frequently than query IDs.
|
|
4
|
+
*/
|
|
5
|
+
/** Features for TweetDetail operation */
|
|
6
|
+
export declare function tweetDetailFeatures(): Record<string, boolean>;
|
|
7
|
+
/** Features for SearchTimeline operation */
|
|
8
|
+
export declare function searchFeatures(): Record<string, boolean>;
|
|
9
|
+
/** Features for UserTweets operation */
|
|
10
|
+
export declare function userTweetsFeatures(): Record<string, boolean>;
|
|
11
|
+
/** Features for Bookmarks operation */
|
|
12
|
+
export declare function bookmarksFeatures(): Record<string, boolean>;
|
|
13
|
+
/** Field toggles for TweetDetail */
|
|
14
|
+
export declare function tweetDetailFieldToggles(): Record<string, boolean>;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature flags for different GraphQL operations.
|
|
3
|
+
* Extracted from Bird CLI v0.8.0 — X rotates these less frequently than query IDs.
|
|
4
|
+
*/
|
|
5
|
+
/** Features for TweetDetail operation */
|
|
6
|
+
export function tweetDetailFeatures() {
|
|
7
|
+
return {
|
|
8
|
+
rweb_video_screen_enabled: true,
|
|
9
|
+
profile_label_improvements_pcf_label_in_post_enabled: true,
|
|
10
|
+
responsive_web_profile_redirect_enabled: true,
|
|
11
|
+
rweb_tipjar_consumption_enabled: true,
|
|
12
|
+
verified_phone_label_enabled: false,
|
|
13
|
+
creator_subscriptions_tweet_preview_api_enabled: true,
|
|
14
|
+
responsive_web_graphql_timeline_navigation_enabled: true,
|
|
15
|
+
responsive_web_graphql_exclude_directive_enabled: true,
|
|
16
|
+
responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
|
|
17
|
+
premium_content_api_read_enabled: false,
|
|
18
|
+
communities_web_enable_tweet_community_results_fetch: true,
|
|
19
|
+
c9s_tweet_anatomy_moderator_badge_enabled: true,
|
|
20
|
+
responsive_web_grok_analyze_button_fetch_trends_enabled: false,
|
|
21
|
+
responsive_web_grok_analyze_post_followups_enabled: false,
|
|
22
|
+
responsive_web_grok_annotations_enabled: false,
|
|
23
|
+
responsive_web_jetfuel_frame: true,
|
|
24
|
+
post_ctas_fetch_enabled: true,
|
|
25
|
+
responsive_web_grok_share_attachment_enabled: true,
|
|
26
|
+
articles_preview_enabled: true,
|
|
27
|
+
responsive_web_edit_tweet_api_enabled: true,
|
|
28
|
+
graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
|
|
29
|
+
view_counts_everywhere_api_enabled: true,
|
|
30
|
+
longform_notetweets_consumption_enabled: true,
|
|
31
|
+
responsive_web_twitter_article_tweet_consumption_enabled: true,
|
|
32
|
+
tweet_awards_web_tipping_enabled: false,
|
|
33
|
+
responsive_web_grok_show_grok_translated_post: false,
|
|
34
|
+
responsive_web_grok_analysis_button_from_backend: true,
|
|
35
|
+
creator_subscriptions_quote_tweet_preview_enabled: false,
|
|
36
|
+
freedom_of_speech_not_reach_fetch_enabled: true,
|
|
37
|
+
standardized_nudges_misinfo: true,
|
|
38
|
+
tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
|
|
39
|
+
longform_notetweets_rich_text_read_enabled: true,
|
|
40
|
+
longform_notetweets_inline_media_enabled: true,
|
|
41
|
+
responsive_web_grok_image_annotation_enabled: true,
|
|
42
|
+
responsive_web_grok_imagine_annotation_enabled: true,
|
|
43
|
+
responsive_web_grok_community_note_auto_translation_is_enabled: false,
|
|
44
|
+
responsive_web_enhance_cards_enabled: false,
|
|
45
|
+
responsive_web_twitter_article_plain_text_enabled: true,
|
|
46
|
+
responsive_web_twitter_article_seed_tweet_detail_enabled: true,
|
|
47
|
+
responsive_web_twitter_article_seed_tweet_summary_enabled: true,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/** Features for SearchTimeline operation */
|
|
51
|
+
export function searchFeatures() {
|
|
52
|
+
return {
|
|
53
|
+
rweb_video_screen_enabled: true,
|
|
54
|
+
profile_label_improvements_pcf_label_in_post_enabled: true,
|
|
55
|
+
responsive_web_profile_redirect_enabled: true,
|
|
56
|
+
rweb_tipjar_consumption_enabled: true,
|
|
57
|
+
verified_phone_label_enabled: false,
|
|
58
|
+
creator_subscriptions_tweet_preview_api_enabled: true,
|
|
59
|
+
responsive_web_graphql_timeline_navigation_enabled: true,
|
|
60
|
+
responsive_web_graphql_exclude_directive_enabled: true,
|
|
61
|
+
responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
|
|
62
|
+
premium_content_api_read_enabled: false,
|
|
63
|
+
communities_web_enable_tweet_community_results_fetch: true,
|
|
64
|
+
c9s_tweet_anatomy_moderator_badge_enabled: true,
|
|
65
|
+
responsive_web_grok_analyze_button_fetch_trends_enabled: false,
|
|
66
|
+
responsive_web_grok_analyze_post_followups_enabled: false,
|
|
67
|
+
responsive_web_grok_annotations_enabled: false,
|
|
68
|
+
responsive_web_jetfuel_frame: true,
|
|
69
|
+
post_ctas_fetch_enabled: true,
|
|
70
|
+
responsive_web_grok_share_attachment_enabled: true,
|
|
71
|
+
responsive_web_edit_tweet_api_enabled: true,
|
|
72
|
+
graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
|
|
73
|
+
view_counts_everywhere_api_enabled: true,
|
|
74
|
+
longform_notetweets_consumption_enabled: true,
|
|
75
|
+
responsive_web_twitter_article_tweet_consumption_enabled: true,
|
|
76
|
+
tweet_awards_web_tipping_enabled: false,
|
|
77
|
+
responsive_web_grok_show_grok_translated_post: false,
|
|
78
|
+
responsive_web_grok_analysis_button_from_backend: true,
|
|
79
|
+
creator_subscriptions_quote_tweet_preview_enabled: false,
|
|
80
|
+
freedom_of_speech_not_reach_fetch_enabled: true,
|
|
81
|
+
standardized_nudges_misinfo: true,
|
|
82
|
+
tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
|
|
83
|
+
rweb_video_timestamps_enabled: true,
|
|
84
|
+
longform_notetweets_rich_text_read_enabled: true,
|
|
85
|
+
longform_notetweets_inline_media_enabled: true,
|
|
86
|
+
responsive_web_grok_image_annotation_enabled: true,
|
|
87
|
+
responsive_web_grok_imagine_annotation_enabled: true,
|
|
88
|
+
responsive_web_grok_community_note_auto_translation_is_enabled: false,
|
|
89
|
+
articles_preview_enabled: true,
|
|
90
|
+
responsive_web_enhance_cards_enabled: false,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** Features for UserTweets operation */
|
|
94
|
+
export function userTweetsFeatures() {
|
|
95
|
+
return {
|
|
96
|
+
rweb_video_screen_enabled: false,
|
|
97
|
+
profile_label_improvements_pcf_label_in_post_enabled: true,
|
|
98
|
+
responsive_web_profile_redirect_enabled: false,
|
|
99
|
+
rweb_tipjar_consumption_enabled: true,
|
|
100
|
+
verified_phone_label_enabled: false,
|
|
101
|
+
creator_subscriptions_tweet_preview_api_enabled: true,
|
|
102
|
+
responsive_web_graphql_timeline_navigation_enabled: true,
|
|
103
|
+
responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
|
|
104
|
+
premium_content_api_read_enabled: false,
|
|
105
|
+
communities_web_enable_tweet_community_results_fetch: true,
|
|
106
|
+
c9s_tweet_anatomy_moderator_badge_enabled: true,
|
|
107
|
+
responsive_web_grok_analyze_button_fetch_trends_enabled: false,
|
|
108
|
+
responsive_web_grok_analyze_post_followups_enabled: true,
|
|
109
|
+
responsive_web_jetfuel_frame: true,
|
|
110
|
+
post_ctas_fetch_enabled: true,
|
|
111
|
+
responsive_web_grok_share_attachment_enabled: true,
|
|
112
|
+
responsive_web_grok_annotations_enabled: false,
|
|
113
|
+
articles_preview_enabled: true,
|
|
114
|
+
responsive_web_edit_tweet_api_enabled: true,
|
|
115
|
+
graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
|
|
116
|
+
view_counts_everywhere_api_enabled: true,
|
|
117
|
+
longform_notetweets_consumption_enabled: true,
|
|
118
|
+
responsive_web_twitter_article_tweet_consumption_enabled: true,
|
|
119
|
+
tweet_awards_web_tipping_enabled: false,
|
|
120
|
+
responsive_web_grok_show_grok_translated_post: true,
|
|
121
|
+
responsive_web_grok_analysis_button_from_backend: true,
|
|
122
|
+
creator_subscriptions_quote_tweet_preview_enabled: false,
|
|
123
|
+
freedom_of_speech_not_reach_fetch_enabled: true,
|
|
124
|
+
standardized_nudges_misinfo: true,
|
|
125
|
+
tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
|
|
126
|
+
longform_notetweets_rich_text_read_enabled: true,
|
|
127
|
+
longform_notetweets_inline_media_enabled: true,
|
|
128
|
+
responsive_web_grok_image_annotation_enabled: true,
|
|
129
|
+
responsive_web_grok_imagine_annotation_enabled: true,
|
|
130
|
+
responsive_web_grok_community_note_auto_translation_is_enabled: false,
|
|
131
|
+
responsive_web_enhance_cards_enabled: false,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/** Features for Bookmarks operation */
|
|
135
|
+
export function bookmarksFeatures() {
|
|
136
|
+
return {
|
|
137
|
+
...searchFeatures(),
|
|
138
|
+
graphql_timeline_v2_bookmark_timeline: true,
|
|
139
|
+
blue_business_profile_image_shape_enabled: true,
|
|
140
|
+
responsive_web_text_conversations_enabled: false,
|
|
141
|
+
tweetypie_unmention_optimization_enabled: true,
|
|
142
|
+
vibe_api_enabled: true,
|
|
143
|
+
responsive_web_twitter_blue_verified_badge_is_enabled: true,
|
|
144
|
+
interactive_text_enabled: true,
|
|
145
|
+
longform_notetweets_richtext_consumption_enabled: true,
|
|
146
|
+
responsive_web_media_download_video_enabled: false,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/** Field toggles for TweetDetail */
|
|
150
|
+
export function tweetDetailFieldToggles() {
|
|
151
|
+
return {
|
|
152
|
+
withArticleRichContentState: true,
|
|
153
|
+
withArticlePlainText: true,
|
|
154
|
+
withGrokAnalyze: false,
|
|
155
|
+
withDisallowedReplyControls: false,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=features.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features.js","sourceRoot":"","sources":["../../src/api/features.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse Twitter/X GraphQL API responses into clean Tweet and User objects.
|
|
3
|
+
* Extracted and cleaned up from Bird CLI v0.8.0.
|
|
4
|
+
*/
|
|
5
|
+
import type { Tweet, User } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Parse a raw tweet result object into a clean Tweet.
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseTweet(result: any, quoteDepth?: number, includeRaw?: boolean): Tweet | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* Parse tweets from timeline instructions array.
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseTweetsFromInstructions(instructions: any[] | undefined, quoteDepth?: number, includeRaw?: boolean): Tweet[];
|
|
14
|
+
/**
|
|
15
|
+
* Extract cursor from timeline instructions.
|
|
16
|
+
*/
|
|
17
|
+
export declare function extractCursor(instructions: any[] | undefined, type?: string): string | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Parse users from timeline instructions (for followers/following).
|
|
20
|
+
*/
|
|
21
|
+
export declare function parseUsersFromInstructions(instructions: any[] | undefined): User[];
|
|
22
|
+
/** Find a specific tweet result by ID in instructions */
|
|
23
|
+
export declare function findTweetInInstructions(instructions: any[] | undefined, tweetId: string): any | undefined;
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse Twitter/X GraphQL API responses into clean Tweet and User objects.
|
|
3
|
+
* Extracted and cleaned up from Bird CLI v0.8.0.
|
|
4
|
+
*/
|
|
5
|
+
// ─── Text extraction ────────────────────────────────────────────
|
|
6
|
+
function firstNonEmpty(...values) {
|
|
7
|
+
for (const v of values) {
|
|
8
|
+
if (typeof v === 'string') {
|
|
9
|
+
const trimmed = v.trim();
|
|
10
|
+
if (trimmed)
|
|
11
|
+
return trimmed;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
/** Extract long-form note tweet text */
|
|
17
|
+
function extractNoteTweetText(result) {
|
|
18
|
+
const note = result?.note_tweet?.note_tweet_results?.result;
|
|
19
|
+
if (!note)
|
|
20
|
+
return undefined;
|
|
21
|
+
return firstNonEmpty(note.text, note.richtext?.text, note.rich_text?.text, note.content?.text);
|
|
22
|
+
}
|
|
23
|
+
/** Extract article text from tweet */
|
|
24
|
+
function extractArticleText(result) {
|
|
25
|
+
const article = result?.article;
|
|
26
|
+
if (!article)
|
|
27
|
+
return undefined;
|
|
28
|
+
const inner = article.article_results?.result ?? article;
|
|
29
|
+
const title = firstNonEmpty(inner.title, article.title);
|
|
30
|
+
const plainText = firstNonEmpty(inner.plain_text, article.plain_text, inner.body?.text, inner.content?.text, article.body?.text, article.content?.text);
|
|
31
|
+
if (plainText && title && !plainText.startsWith(title)) {
|
|
32
|
+
return `${title}\n${plainText}`;
|
|
33
|
+
}
|
|
34
|
+
return plainText ?? title;
|
|
35
|
+
}
|
|
36
|
+
/** Get the best text representation of a tweet */
|
|
37
|
+
function extractTweetText(result) {
|
|
38
|
+
return extractArticleText(result) ?? extractNoteTweetText(result) ?? firstNonEmpty(result?.legacy?.full_text);
|
|
39
|
+
}
|
|
40
|
+
// ─── Media extraction ───────────────────────────────────────────
|
|
41
|
+
function extractMedia(result) {
|
|
42
|
+
const mediaEntities = result?.legacy?.extended_entities?.media ?? result?.legacy?.entities?.media;
|
|
43
|
+
if (!mediaEntities?.length)
|
|
44
|
+
return undefined;
|
|
45
|
+
const items = [];
|
|
46
|
+
for (const m of mediaEntities) {
|
|
47
|
+
if (!m.type || !m.media_url_https)
|
|
48
|
+
continue;
|
|
49
|
+
const item = { type: m.type, url: m.media_url_https };
|
|
50
|
+
const sizes = m.sizes;
|
|
51
|
+
if (sizes?.large) {
|
|
52
|
+
item.width = sizes.large.w;
|
|
53
|
+
item.height = sizes.large.h;
|
|
54
|
+
}
|
|
55
|
+
else if (sizes?.medium) {
|
|
56
|
+
item.width = sizes.medium.w;
|
|
57
|
+
item.height = sizes.medium.h;
|
|
58
|
+
}
|
|
59
|
+
if (sizes?.small) {
|
|
60
|
+
item.previewUrl = `${m.media_url_https}:small`;
|
|
61
|
+
}
|
|
62
|
+
if ((m.type === 'video' || m.type === 'animated_gif') && m.video_info?.variants) {
|
|
63
|
+
const mp4s = m.video_info.variants.filter((v) => v.content_type === 'video/mp4' && typeof v.url === 'string');
|
|
64
|
+
const best = mp4s
|
|
65
|
+
.filter((v) => typeof v.bitrate === 'number')
|
|
66
|
+
.sort((a, b) => b.bitrate - a.bitrate)[0] ?? mp4s[0];
|
|
67
|
+
if (best)
|
|
68
|
+
item.videoUrl = best.url;
|
|
69
|
+
if (typeof m.video_info.duration_millis === 'number') {
|
|
70
|
+
item.durationMs = m.video_info.duration_millis;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
items.push(item);
|
|
74
|
+
}
|
|
75
|
+
return items.length > 0 ? items : undefined;
|
|
76
|
+
}
|
|
77
|
+
// ─── Article preview ────────────────────────────────────────────
|
|
78
|
+
function extractArticlePreview(result) {
|
|
79
|
+
const article = result?.article;
|
|
80
|
+
if (!article)
|
|
81
|
+
return undefined;
|
|
82
|
+
const inner = article.article_results?.result ?? article;
|
|
83
|
+
const title = firstNonEmpty(inner.title, article.title);
|
|
84
|
+
if (!title)
|
|
85
|
+
return undefined;
|
|
86
|
+
const previewText = firstNonEmpty(inner.preview_text, article.preview_text);
|
|
87
|
+
return { title, previewText };
|
|
88
|
+
}
|
|
89
|
+
// ─── Tweet parsing ──────────────────────────────────────────────
|
|
90
|
+
function unwrapTweet(obj) {
|
|
91
|
+
if (!obj)
|
|
92
|
+
return undefined;
|
|
93
|
+
if (obj.tweet)
|
|
94
|
+
return obj.tweet;
|
|
95
|
+
return obj;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Parse a raw tweet result object into a clean Tweet.
|
|
99
|
+
*/
|
|
100
|
+
export function parseTweet(result, quoteDepth = 1, includeRaw = false) {
|
|
101
|
+
const userResult = result?.core?.user_results?.result;
|
|
102
|
+
const legacy = userResult?.legacy;
|
|
103
|
+
const core = userResult?.core;
|
|
104
|
+
const username = legacy?.screen_name ?? core?.screen_name;
|
|
105
|
+
const name = legacy?.name ?? core?.name ?? username;
|
|
106
|
+
const userId = userResult?.rest_id;
|
|
107
|
+
if (!result?.rest_id || !username)
|
|
108
|
+
return undefined;
|
|
109
|
+
const text = extractTweetText(result);
|
|
110
|
+
if (!text)
|
|
111
|
+
return undefined;
|
|
112
|
+
let quotedTweet;
|
|
113
|
+
if (quoteDepth > 0) {
|
|
114
|
+
const quotedRaw = unwrapTweet(result.quoted_status_result?.result);
|
|
115
|
+
if (quotedRaw) {
|
|
116
|
+
quotedTweet = parseTweet(quotedRaw, quoteDepth - 1, includeRaw);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const tweet = {
|
|
120
|
+
id: result.rest_id,
|
|
121
|
+
text,
|
|
122
|
+
createdAt: result.legacy?.created_at,
|
|
123
|
+
replyCount: result.legacy?.reply_count,
|
|
124
|
+
retweetCount: result.legacy?.retweet_count,
|
|
125
|
+
likeCount: result.legacy?.favorite_count,
|
|
126
|
+
conversationId: result.legacy?.conversation_id_str,
|
|
127
|
+
inReplyToStatusId: result.legacy?.in_reply_to_status_id_str ?? undefined,
|
|
128
|
+
author: { username, name: name || username },
|
|
129
|
+
authorId: userId,
|
|
130
|
+
quotedTweet,
|
|
131
|
+
media: extractMedia(result),
|
|
132
|
+
article: extractArticlePreview(result),
|
|
133
|
+
};
|
|
134
|
+
if (includeRaw)
|
|
135
|
+
tweet._raw = result;
|
|
136
|
+
return tweet;
|
|
137
|
+
}
|
|
138
|
+
// ─── Timeline instruction parsing ───────────────────────────────
|
|
139
|
+
function extractTweetResultsFromEntry(entry) {
|
|
140
|
+
const results = [];
|
|
141
|
+
const push = (r) => { if (r?.rest_id)
|
|
142
|
+
results.push(r); };
|
|
143
|
+
const content = entry.content;
|
|
144
|
+
push(content?.itemContent?.tweet_results?.result);
|
|
145
|
+
push(content?.item?.itemContent?.tweet_results?.result);
|
|
146
|
+
for (const item of content?.items ?? []) {
|
|
147
|
+
push(item?.item?.itemContent?.tweet_results?.result);
|
|
148
|
+
push(item?.itemContent?.tweet_results?.result);
|
|
149
|
+
push(item?.content?.itemContent?.tweet_results?.result);
|
|
150
|
+
}
|
|
151
|
+
return results;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Parse tweets from timeline instructions array.
|
|
155
|
+
*/
|
|
156
|
+
export function parseTweetsFromInstructions(instructions, quoteDepth = 1, includeRaw = false) {
|
|
157
|
+
const tweets = [];
|
|
158
|
+
const seen = new Set();
|
|
159
|
+
for (const inst of instructions ?? []) {
|
|
160
|
+
for (const entry of inst.entries ?? []) {
|
|
161
|
+
const rawTweets = extractTweetResultsFromEntry(entry);
|
|
162
|
+
for (const raw of rawTweets) {
|
|
163
|
+
const tweet = parseTweet(raw, quoteDepth, includeRaw);
|
|
164
|
+
if (!tweet || seen.has(tweet.id))
|
|
165
|
+
continue;
|
|
166
|
+
seen.add(tweet.id);
|
|
167
|
+
tweets.push(tweet);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return tweets;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Extract cursor from timeline instructions.
|
|
175
|
+
*/
|
|
176
|
+
export function extractCursor(instructions, type = 'Bottom') {
|
|
177
|
+
for (const inst of instructions ?? []) {
|
|
178
|
+
for (const entry of inst.entries ?? []) {
|
|
179
|
+
const content = entry.content;
|
|
180
|
+
if (content?.cursorType === type && typeof content.value === 'string' && content.value.length > 0) {
|
|
181
|
+
return content.value;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Parse users from timeline instructions (for followers/following).
|
|
189
|
+
*/
|
|
190
|
+
export function parseUsersFromInstructions(instructions) {
|
|
191
|
+
if (!instructions)
|
|
192
|
+
return [];
|
|
193
|
+
const users = [];
|
|
194
|
+
for (const inst of instructions) {
|
|
195
|
+
if (!inst.entries)
|
|
196
|
+
continue;
|
|
197
|
+
for (const entry of inst.entries) {
|
|
198
|
+
const userResult = entry?.content?.itemContent?.user_results?.result;
|
|
199
|
+
const resolved = userResult?.__typename === 'UserWithVisibilityResults' && userResult.user
|
|
200
|
+
? userResult.user
|
|
201
|
+
: userResult;
|
|
202
|
+
if (!resolved || resolved.__typename !== 'User')
|
|
203
|
+
continue;
|
|
204
|
+
const { legacy, core } = resolved;
|
|
205
|
+
const username = legacy?.screen_name ?? core?.screen_name;
|
|
206
|
+
if (!resolved.rest_id || !username)
|
|
207
|
+
continue;
|
|
208
|
+
users.push({
|
|
209
|
+
id: resolved.rest_id,
|
|
210
|
+
username,
|
|
211
|
+
name: legacy?.name ?? core?.name ?? username,
|
|
212
|
+
description: legacy?.description,
|
|
213
|
+
followersCount: legacy?.followers_count,
|
|
214
|
+
followingCount: legacy?.friends_count,
|
|
215
|
+
isBlueVerified: resolved.is_blue_verified,
|
|
216
|
+
profileImageUrl: legacy?.profile_image_url_https ?? resolved.avatar?.image_url,
|
|
217
|
+
createdAt: legacy?.created_at ?? core?.created_at,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return users;
|
|
222
|
+
}
|
|
223
|
+
/** Find a specific tweet result by ID in instructions */
|
|
224
|
+
export function findTweetInInstructions(instructions, tweetId) {
|
|
225
|
+
if (!instructions)
|
|
226
|
+
return undefined;
|
|
227
|
+
for (const inst of instructions) {
|
|
228
|
+
for (const entry of inst.entries ?? []) {
|
|
229
|
+
const raw = entry.content?.itemContent?.tweet_results?.result;
|
|
230
|
+
if (raw?.rest_id === tweetId)
|
|
231
|
+
return raw;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return undefined;
|
|
235
|
+
}
|
|
236
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/api/parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-discovery of Twitter/X GraphQL query IDs.
|
|
3
|
+
*
|
|
4
|
+
* X periodically rotates the query IDs embedded in their JS bundles.
|
|
5
|
+
* This module scrapes x.com pages to find the current bundle URLs,
|
|
6
|
+
* then parses those bundles to extract queryId ↔ operationName mappings.
|
|
7
|
+
*
|
|
8
|
+
* Falls back to hardcoded defaults if discovery fails.
|
|
9
|
+
*/
|
|
10
|
+
import type { QueryIdCache } from './types.js';
|
|
11
|
+
export interface SnapshotInfo {
|
|
12
|
+
snapshot: QueryIdCache;
|
|
13
|
+
cachePath: string;
|
|
14
|
+
ageMs: number;
|
|
15
|
+
isFresh: boolean;
|
|
16
|
+
}
|
|
17
|
+
export declare function getSnapshotInfo(): Promise<SnapshotInfo | null>;
|
|
18
|
+
/**
|
|
19
|
+
* Get a single query ID by operation name.
|
|
20
|
+
* Returns cached value, or falls back to hardcoded default.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getQueryId(operation: string): Promise<string>;
|
|
23
|
+
/**
|
|
24
|
+
* Refresh query IDs by scraping x.com JS bundles.
|
|
25
|
+
* Saves results to disk cache.
|
|
26
|
+
*/
|
|
27
|
+
export declare function refreshQueryIds(options?: {
|
|
28
|
+
force?: boolean;
|
|
29
|
+
}): Promise<SnapshotInfo | null>;
|
|
30
|
+
/** Clear in-memory cache (for testing) */
|
|
31
|
+
export declare function clearMemory(): void;
|