@the-convocation/twitter-scraper 0.16.0 → 0.16.1
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/dist/default/cjs/index.js +98 -94
- package/dist/default/cjs/index.js.map +1 -1
- package/dist/default/esm/index.mjs +98 -94
- package/dist/default/esm/index.mjs.map +1 -1
- package/dist/node/cjs/index.cjs +98 -94
- package/dist/node/cjs/index.cjs.map +1 -1
- package/dist/node/esm/index.mjs +98 -94
- package/dist/node/esm/index.mjs.map +1 -1
- package/dist/types/index.d.ts +7 -1
- package/package.json +1 -1
|
@@ -29,24 +29,39 @@ function _interopNamespaceDefault(e) {
|
|
|
29
29
|
var OTPAuth__namespace = /*#__PURE__*/_interopNamespaceDefault(OTPAuth);
|
|
30
30
|
|
|
31
31
|
class ApiError extends Error {
|
|
32
|
-
constructor(response, data
|
|
33
|
-
super(
|
|
32
|
+
constructor(response, data) {
|
|
33
|
+
super(
|
|
34
|
+
`Response status: ${response.status} | headers: ${JSON.stringify(
|
|
35
|
+
headersToString(response.headers)
|
|
36
|
+
)} | data: ${data}`
|
|
37
|
+
);
|
|
34
38
|
this.response = response;
|
|
35
39
|
this.data = data;
|
|
36
40
|
}
|
|
37
41
|
static async fromResponse(response) {
|
|
38
42
|
let data = void 0;
|
|
39
43
|
try {
|
|
40
|
-
|
|
44
|
+
if (response.headers.get("content-type")?.includes("application/json")) {
|
|
45
|
+
data = await response.json();
|
|
46
|
+
} else {
|
|
47
|
+
data = await response.text();
|
|
48
|
+
}
|
|
41
49
|
} catch {
|
|
42
50
|
try {
|
|
43
51
|
data = await response.text();
|
|
44
52
|
} catch {
|
|
45
53
|
}
|
|
46
54
|
}
|
|
47
|
-
return new ApiError(response, data
|
|
55
|
+
return new ApiError(response, data);
|
|
48
56
|
}
|
|
49
57
|
}
|
|
58
|
+
function headersToString(headers) {
|
|
59
|
+
const result = [];
|
|
60
|
+
headers.forEach((value, key) => {
|
|
61
|
+
result.push(`${key}: ${value}`);
|
|
62
|
+
});
|
|
63
|
+
return result.join("\n");
|
|
64
|
+
}
|
|
50
65
|
class AuthenticationError extends Error {
|
|
51
66
|
constructor(message) {
|
|
52
67
|
super(message || "Authentication failed");
|
|
@@ -109,6 +124,10 @@ async function updateCookieJar(cookieJar, headers) {
|
|
|
109
124
|
}
|
|
110
125
|
|
|
111
126
|
const bearerToken = "AAAAAAAAAAAAAAAAAAAAAFQODgEAAAAAVHTp76lzh3rFzcHbmHVvQxYYpTw%3DckAlMINMjmCwxUcaXbAN4XqJVdgMJaHqNOFgPMK0zN1qLqLQCF";
|
|
127
|
+
async function jitter(maxMs) {
|
|
128
|
+
const jitter2 = Math.random() * maxMs;
|
|
129
|
+
await new Promise((resolve) => setTimeout(resolve, jitter2));
|
|
130
|
+
}
|
|
112
131
|
async function requestApi(url, auth, method = "GET", platform = new Platform()) {
|
|
113
132
|
const headers = new headersPolyfill.Headers();
|
|
114
133
|
await auth.installTo(headers, url);
|
|
@@ -650,7 +669,7 @@ class TwitterUserAuth extends TwitterGuestAuth {
|
|
|
650
669
|
});
|
|
651
670
|
await updateCookieJar(this.jar, res.headers);
|
|
652
671
|
if (!res.ok) {
|
|
653
|
-
return { status: "error", err:
|
|
672
|
+
return { status: "error", err: await ApiError.fromResponse(res) };
|
|
654
673
|
}
|
|
655
674
|
const flow = await res.json();
|
|
656
675
|
if (flow?.flow_token == null) {
|
|
@@ -688,6 +707,63 @@ class TwitterUserAuth extends TwitterGuestAuth {
|
|
|
688
707
|
}
|
|
689
708
|
}
|
|
690
709
|
|
|
710
|
+
const endpoints = {
|
|
711
|
+
// TODO: Migrate other endpoint URLs here
|
|
712
|
+
UserTweets: "https://x.com/i/api/graphql/Li2XXGESVev94TzFtntrgA/UserTweets?variables=%7B%22userId%22%3A%221806359170830172162%22%2C%22count%22%3A20%2C%22includePromotedContent%22%3Atrue%2C%22withQuickPromoteEligibilityTweetFields%22%3Atrue%2C%22withVoice%22%3Atrue%7D&features=%7B%22rweb_video_screen_enabled%22%3Afalse%2C%22profile_label_improvements_pcf_label_in_post_enabled%22%3Atrue%2C%22rweb_tipjar_consumption_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Afalse%2C%22creator_subscriptions_tweet_preview_api_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22responsive_web_graphql_skip_user_profile_image_extensions_enabled%22%3Afalse%2C%22premium_content_api_read_enabled%22%3Afalse%2C%22communities_web_enable_tweet_community_results_fetch%22%3Atrue%2C%22c9s_tweet_anatomy_moderator_badge_enabled%22%3Atrue%2C%22responsive_web_grok_analyze_button_fetch_trends_enabled%22%3Afalse%2C%22responsive_web_grok_analyze_post_followups_enabled%22%3Atrue%2C%22responsive_web_jetfuel_frame%22%3Afalse%2C%22responsive_web_grok_share_attachment_enabled%22%3Atrue%2C%22articles_preview_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Atrue%2C%22responsive_web_twitter_article_tweet_consumption_enabled%22%3Atrue%2C%22tweet_awards_web_tipping_enabled%22%3Afalse%2C%22responsive_web_grok_show_grok_translated_post%22%3Afalse%2C%22responsive_web_grok_analysis_button_from_backend%22%3Atrue%2C%22creator_subscriptions_quote_tweet_preview_enabled%22%3Afalse%2C%22freedom_of_speech_not_reach_fetch_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Atrue%2C%22longform_notetweets_rich_text_read_enabled%22%3Atrue%2C%22longform_notetweets_inline_media_enabled%22%3Atrue%2C%22responsive_web_grok_image_annotation_enabled%22%3Atrue%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D&fieldToggles=%7B%22withArticlePlainText%22%3Afalse%7D",
|
|
713
|
+
UserTweetsAndReplies: "https://x.com/i/api/graphql/Hk4KlJ-ONjlJsucqR55P7g/UserTweetsAndReplies?variables=%7B%22userId%22%3A%221806359170830172162%22%2C%22count%22%3A20%2C%22includePromotedContent%22%3Atrue%2C%22withCommunity%22%3Atrue%2C%22withVoice%22%3Atrue%7D&features=%7B%22rweb_video_screen_enabled%22%3Afalse%2C%22profile_label_improvements_pcf_label_in_post_enabled%22%3Atrue%2C%22rweb_tipjar_consumption_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Afalse%2C%22creator_subscriptions_tweet_preview_api_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22responsive_web_graphql_skip_user_profile_image_extensions_enabled%22%3Afalse%2C%22premium_content_api_read_enabled%22%3Afalse%2C%22communities_web_enable_tweet_community_results_fetch%22%3Atrue%2C%22c9s_tweet_anatomy_moderator_badge_enabled%22%3Atrue%2C%22responsive_web_grok_analyze_button_fetch_trends_enabled%22%3Afalse%2C%22responsive_web_grok_analyze_post_followups_enabled%22%3Atrue%2C%22responsive_web_jetfuel_frame%22%3Afalse%2C%22responsive_web_grok_share_attachment_enabled%22%3Atrue%2C%22articles_preview_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Atrue%2C%22responsive_web_twitter_article_tweet_consumption_enabled%22%3Atrue%2C%22tweet_awards_web_tipping_enabled%22%3Afalse%2C%22responsive_web_grok_show_grok_translated_post%22%3Afalse%2C%22responsive_web_grok_analysis_button_from_backend%22%3Atrue%2C%22creator_subscriptions_quote_tweet_preview_enabled%22%3Afalse%2C%22freedom_of_speech_not_reach_fetch_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Atrue%2C%22longform_notetweets_rich_text_read_enabled%22%3Atrue%2C%22longform_notetweets_inline_media_enabled%22%3Atrue%2C%22responsive_web_grok_image_annotation_enabled%22%3Atrue%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D&fieldToggles=%7B%22withArticlePlainText%22%3Afalse%7D",
|
|
714
|
+
UserLikedTweets: "https://x.com/i/api/graphql/XHTMjDbiTGLQ9cP1em-aqQ/Likes?variables=%7B%22userId%22%3A%222244196397%22%2C%22count%22%3A20%2C%22includePromotedContent%22%3Afalse%2C%22withClientEventToken%22%3Afalse%2C%22withBirdwatchNotes%22%3Afalse%2C%22withVoice%22%3Atrue%7D&features=%7B%22rweb_video_screen_enabled%22%3Afalse%2C%22profile_label_improvements_pcf_label_in_post_enabled%22%3Atrue%2C%22rweb_tipjar_consumption_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Afalse%2C%22creator_subscriptions_tweet_preview_api_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22responsive_web_graphql_skip_user_profile_image_extensions_enabled%22%3Afalse%2C%22premium_content_api_read_enabled%22%3Afalse%2C%22communities_web_enable_tweet_community_results_fetch%22%3Atrue%2C%22c9s_tweet_anatomy_moderator_badge_enabled%22%3Atrue%2C%22responsive_web_grok_analyze_button_fetch_trends_enabled%22%3Afalse%2C%22responsive_web_grok_analyze_post_followups_enabled%22%3Atrue%2C%22responsive_web_jetfuel_frame%22%3Afalse%2C%22responsive_web_grok_share_attachment_enabled%22%3Atrue%2C%22articles_preview_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Atrue%2C%22responsive_web_twitter_article_tweet_consumption_enabled%22%3Atrue%2C%22tweet_awards_web_tipping_enabled%22%3Afalse%2C%22responsive_web_grok_show_grok_translated_post%22%3Afalse%2C%22responsive_web_grok_analysis_button_from_backend%22%3Atrue%2C%22creator_subscriptions_quote_tweet_preview_enabled%22%3Afalse%2C%22freedom_of_speech_not_reach_fetch_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Atrue%2C%22longform_notetweets_rich_text_read_enabled%22%3Atrue%2C%22longform_notetweets_inline_media_enabled%22%3Atrue%2C%22responsive_web_grok_image_annotation_enabled%22%3Atrue%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D&fieldToggles=%7B%22withArticlePlainText%22%3Afalse%7D",
|
|
715
|
+
UserByScreenName: "https://x.com/i/api/graphql/xWw45l6nX7DP2FKRyePXSw/UserByScreenName?variables=%7B%22screen_name%22%3A%22geminiapp%22%7D&features=%7B%22hidden_profile_subscriptions_enabled%22%3Atrue%2C%22profile_label_improvements_pcf_label_in_post_enabled%22%3Atrue%2C%22rweb_tipjar_consumption_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Afalse%2C%22subscriptions_verification_info_is_identity_verified_enabled%22%3Atrue%2C%22subscriptions_verification_info_verified_since_enabled%22%3Atrue%2C%22highlights_tweets_tab_ui_enabled%22%3Atrue%2C%22responsive_web_twitter_article_notes_tab_enabled%22%3Atrue%2C%22subscriptions_feature_can_gift_premium%22%3Atrue%2C%22creator_subscriptions_tweet_preview_api_enabled%22%3Atrue%2C%22responsive_web_graphql_skip_user_profile_image_extensions_enabled%22%3Afalse%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%7D&fieldToggles=%7B%22withAuxiliaryUserLabels%22%3Atrue%7D",
|
|
716
|
+
TweetDetail: "https://x.com/i/api/graphql/u5Tij6ERlSH2LZvCUqallw/TweetDetail?variables=%7B%22focalTweetId%22%3A%221924893675529900467%22%2C%22referrer%22%3A%22profile%22%2C%22with_rux_injections%22%3Afalse%2C%22rankingMode%22%3A%22Relevance%22%2C%22includePromotedContent%22%3Atrue%2C%22withCommunity%22%3Atrue%2C%22withQuickPromoteEligibilityTweetFields%22%3Atrue%2C%22withBirdwatchNotes%22%3Atrue%2C%22withVoice%22%3Atrue%7D&features=%7B%22rweb_video_screen_enabled%22%3Afalse%2C%22profile_label_improvements_pcf_label_in_post_enabled%22%3Atrue%2C%22rweb_tipjar_consumption_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Afalse%2C%22creator_subscriptions_tweet_preview_api_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22responsive_web_graphql_skip_user_profile_image_extensions_enabled%22%3Afalse%2C%22premium_content_api_read_enabled%22%3Afalse%2C%22communities_web_enable_tweet_community_results_fetch%22%3Atrue%2C%22c9s_tweet_anatomy_moderator_badge_enabled%22%3Atrue%2C%22responsive_web_grok_analyze_button_fetch_trends_enabled%22%3Afalse%2C%22responsive_web_grok_analyze_post_followups_enabled%22%3Atrue%2C%22responsive_web_jetfuel_frame%22%3Afalse%2C%22responsive_web_grok_share_attachment_enabled%22%3Atrue%2C%22articles_preview_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Atrue%2C%22responsive_web_twitter_article_tweet_consumption_enabled%22%3Atrue%2C%22tweet_awards_web_tipping_enabled%22%3Afalse%2C%22responsive_web_grok_show_grok_translated_post%22%3Afalse%2C%22responsive_web_grok_analysis_button_from_backend%22%3Atrue%2C%22creator_subscriptions_quote_tweet_preview_enabled%22%3Afalse%2C%22freedom_of_speech_not_reach_fetch_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Atrue%2C%22longform_notetweets_rich_text_read_enabled%22%3Atrue%2C%22longform_notetweets_inline_media_enabled%22%3Atrue%2C%22responsive_web_grok_image_annotation_enabled%22%3Atrue%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D&fieldToggles=%7B%22withArticleRichContentState%22%3Atrue%2C%22withArticlePlainText%22%3Afalse%2C%22withGrokAnalyze%22%3Afalse%2C%22withDisallowedReplyControls%22%3Afalse%7D",
|
|
717
|
+
TweetResultByRestId: "https://api.x.com/graphql/Opujkru5iJSDWj4DuJISOw/TweetResultByRestId?variables=%7B%22tweetId%22%3A%221924893675529900467%22%2C%22withCommunity%22%3Afalse%2C%22includePromotedContent%22%3Afalse%2C%22withVoice%22%3Afalse%7D&features=%7B%22creator_subscriptions_tweet_preview_api_enabled%22%3Atrue%2C%22premium_content_api_read_enabled%22%3Afalse%2C%22communities_web_enable_tweet_community_results_fetch%22%3Atrue%2C%22c9s_tweet_anatomy_moderator_badge_enabled%22%3Atrue%2C%22responsive_web_grok_analyze_button_fetch_trends_enabled%22%3Afalse%2C%22responsive_web_grok_analyze_post_followups_enabled%22%3Afalse%2C%22responsive_web_jetfuel_frame%22%3Afalse%2C%22responsive_web_grok_share_attachment_enabled%22%3Atrue%2C%22articles_preview_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Atrue%2C%22responsive_web_twitter_article_tweet_consumption_enabled%22%3Atrue%2C%22tweet_awards_web_tipping_enabled%22%3Afalse%2C%22responsive_web_grok_show_grok_translated_post%22%3Afalse%2C%22responsive_web_grok_analysis_button_from_backend%22%3Atrue%2C%22creator_subscriptions_quote_tweet_preview_enabled%22%3Afalse%2C%22freedom_of_speech_not_reach_fetch_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Atrue%2C%22longform_notetweets_rich_text_read_enabled%22%3Atrue%2C%22longform_notetweets_inline_media_enabled%22%3Atrue%2C%22profile_label_improvements_pcf_label_in_post_enabled%22%3Atrue%2C%22rweb_tipjar_consumption_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Afalse%2C%22responsive_web_grok_image_annotation_enabled%22%3Atrue%2C%22responsive_web_graphql_skip_user_profile_image_extensions_enabled%22%3Afalse%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D&fieldToggles=%7B%22withArticleRichContentState%22%3Atrue%2C%22withArticlePlainText%22%3Afalse%2C%22withGrokAnalyze%22%3Afalse%2C%22withDisallowedReplyControls%22%3Afalse%7D",
|
|
718
|
+
ListTweets: "https://x.com/i/api/graphql/S1Sm3_mNJwa-fnY9htcaAQ/ListLatestTweetsTimeline?variables=%7B%22listId%22%3A%221736495155002106192%22%2C%22count%22%3A20%7D&features=%7B%22rweb_video_screen_enabled%22%3Afalse%2C%22profile_label_improvements_pcf_label_in_post_enabled%22%3Atrue%2C%22rweb_tipjar_consumption_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Afalse%2C%22creator_subscriptions_tweet_preview_api_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22responsive_web_graphql_skip_user_profile_image_extensions_enabled%22%3Afalse%2C%22premium_content_api_read_enabled%22%3Afalse%2C%22communities_web_enable_tweet_community_results_fetch%22%3Atrue%2C%22c9s_tweet_anatomy_moderator_badge_enabled%22%3Atrue%2C%22responsive_web_grok_analyze_button_fetch_trends_enabled%22%3Afalse%2C%22responsive_web_grok_analyze_post_followups_enabled%22%3Atrue%2C%22responsive_web_jetfuel_frame%22%3Afalse%2C%22responsive_web_grok_share_attachment_enabled%22%3Atrue%2C%22articles_preview_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Atrue%2C%22responsive_web_twitter_article_tweet_consumption_enabled%22%3Atrue%2C%22tweet_awards_web_tipping_enabled%22%3Afalse%2C%22responsive_web_grok_show_grok_translated_post%22%3Afalse%2C%22responsive_web_grok_analysis_button_from_backend%22%3Atrue%2C%22creator_subscriptions_quote_tweet_preview_enabled%22%3Afalse%2C%22freedom_of_speech_not_reach_fetch_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Atrue%2C%22longform_notetweets_rich_text_read_enabled%22%3Atrue%2C%22longform_notetweets_inline_media_enabled%22%3Atrue%2C%22responsive_web_grok_image_annotation_enabled%22%3Atrue%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D"
|
|
719
|
+
};
|
|
720
|
+
class ApiRequest {
|
|
721
|
+
constructor(info) {
|
|
722
|
+
this.url = info.url;
|
|
723
|
+
this.variables = info.variables;
|
|
724
|
+
this.features = info.features;
|
|
725
|
+
this.fieldToggles = info.fieldToggles;
|
|
726
|
+
}
|
|
727
|
+
toRequestUrl() {
|
|
728
|
+
const params = new URLSearchParams();
|
|
729
|
+
if (this.variables) {
|
|
730
|
+
params.set("variables", stringify(this.variables));
|
|
731
|
+
}
|
|
732
|
+
if (this.features) {
|
|
733
|
+
params.set("features", stringify(this.features));
|
|
734
|
+
}
|
|
735
|
+
if (this.fieldToggles) {
|
|
736
|
+
params.set("fieldToggles", stringify(this.fieldToggles));
|
|
737
|
+
}
|
|
738
|
+
return `${this.url}?${params.toString()}`;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
function parseEndpointExample(example) {
|
|
742
|
+
const { protocol, host, pathname, searchParams: query } = new URL(example);
|
|
743
|
+
const base = `${protocol}//${host}${pathname}`;
|
|
744
|
+
const variables = query.get("variables");
|
|
745
|
+
const features = query.get("features");
|
|
746
|
+
const fieldToggles = query.get("fieldToggles");
|
|
747
|
+
return new ApiRequest({
|
|
748
|
+
url: base,
|
|
749
|
+
variables: variables ? JSON.parse(variables) : void 0,
|
|
750
|
+
features: features ? JSON.parse(features) : void 0,
|
|
751
|
+
fieldToggles: fieldToggles ? JSON.parse(fieldToggles) : void 0
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
function createApiRequestFactory(endpoints2) {
|
|
755
|
+
return Object.entries(endpoints2).map(([endpointName, endpointExample]) => {
|
|
756
|
+
return {
|
|
757
|
+
[`create${endpointName}Request`]: () => {
|
|
758
|
+
return parseEndpointExample(endpointExample);
|
|
759
|
+
}
|
|
760
|
+
};
|
|
761
|
+
}).reduce((agg, next) => {
|
|
762
|
+
return Object.assign(agg, next);
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
const apiRequestFactory = createApiRequestFactory(endpoints);
|
|
766
|
+
|
|
691
767
|
function getAvatarOriginalSizeUrl(avatarUrl) {
|
|
692
768
|
return avatarUrl ? avatarUrl.replace("_normal", "") : void 0;
|
|
693
769
|
}
|
|
@@ -724,35 +800,12 @@ function parseProfile(user, isBlueVerified) {
|
|
|
724
800
|
return profile;
|
|
725
801
|
}
|
|
726
802
|
async function getProfile(username, auth) {
|
|
727
|
-
const
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
})
|
|
734
|
-
);
|
|
735
|
-
params.set(
|
|
736
|
-
"features",
|
|
737
|
-
stringify({
|
|
738
|
-
hidden_profile_likes_enabled: false,
|
|
739
|
-
hidden_profile_subscriptions_enabled: false,
|
|
740
|
-
// Auth-restricted
|
|
741
|
-
responsive_web_graphql_exclude_directive_enabled: true,
|
|
742
|
-
verified_phone_label_enabled: false,
|
|
743
|
-
subscriptions_verification_info_is_identity_verified_enabled: false,
|
|
744
|
-
subscriptions_verification_info_verified_since_enabled: true,
|
|
745
|
-
highlights_tweets_tab_ui_enabled: true,
|
|
746
|
-
creator_subscriptions_tweet_preview_api_enabled: true,
|
|
747
|
-
responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
|
|
748
|
-
responsive_web_graphql_timeline_navigation_enabled: true
|
|
749
|
-
})
|
|
750
|
-
);
|
|
751
|
-
params.set("fieldToggles", stringify({ withAuxiliaryUserLabels: false }));
|
|
752
|
-
const res = await requestApi(
|
|
753
|
-
`https://twitter.com/i/api/graphql/G3KGOASz96M-Qu0nwmGXNg/UserByScreenName?${params.toString()}`,
|
|
754
|
-
auth
|
|
755
|
-
);
|
|
803
|
+
const request = apiRequestFactory.createUserByScreenNameRequest();
|
|
804
|
+
request.variables.screen_name = username;
|
|
805
|
+
request.variables.withSafetyModeUserFields = true;
|
|
806
|
+
request.features.hidden_profile_subscriptions_enabled = false;
|
|
807
|
+
request.fieldToggles.withAuxiliaryUserLabels = false;
|
|
808
|
+
const res = await requestApi(request.toRequestUrl(), auth);
|
|
756
809
|
if (!res.success) {
|
|
757
810
|
return res;
|
|
758
811
|
}
|
|
@@ -836,6 +889,7 @@ async function* getUserTimeline(query, maxProfiles, fetchFunc) {
|
|
|
836
889
|
nProfiles++;
|
|
837
890
|
}
|
|
838
891
|
if (!next) break;
|
|
892
|
+
await jitter(1e3);
|
|
839
893
|
}
|
|
840
894
|
}
|
|
841
895
|
async function* getTweetTimeline(query, maxTweets, fetchFunc) {
|
|
@@ -860,6 +914,7 @@ async function* getTweetTimeline(query, maxTweets, fetchFunc) {
|
|
|
860
914
|
}
|
|
861
915
|
nTweets++;
|
|
862
916
|
}
|
|
917
|
+
await jitter(1e3);
|
|
863
918
|
}
|
|
864
919
|
}
|
|
865
920
|
|
|
@@ -982,7 +1037,7 @@ function getLegacyTweetId(tweet) {
|
|
|
982
1037
|
}
|
|
983
1038
|
return tweet.conversation_id_str;
|
|
984
1039
|
}
|
|
985
|
-
function parseLegacyTweet(user, tweet, editControl) {
|
|
1040
|
+
function parseLegacyTweet(coreUser, user, tweet, editControl) {
|
|
986
1041
|
if (tweet == null) {
|
|
987
1042
|
return {
|
|
988
1043
|
success: false,
|
|
@@ -1012,6 +1067,8 @@ function parseLegacyTweet(user, tweet, editControl) {
|
|
|
1012
1067
|
const { photos, videos, sensitiveContent } = parseMediaGroups(media);
|
|
1013
1068
|
const tweetVersions = editControl?.edit_tweet_ids ?? [tweetId];
|
|
1014
1069
|
const editIds = tweetVersions.filter((id) => id !== tweetId);
|
|
1070
|
+
const name = user.name ?? coreUser?.name;
|
|
1071
|
+
const username = user.screen_name ?? coreUser?.screen_name;
|
|
1015
1072
|
const tw = {
|
|
1016
1073
|
__raw_UNSTABLE: tweet,
|
|
1017
1074
|
bookmarkCount: tweet.bookmark_count,
|
|
@@ -1024,8 +1081,8 @@ function parseLegacyTweet(user, tweet, editControl) {
|
|
|
1024
1081
|
username: mention.screen_name,
|
|
1025
1082
|
name: mention.name
|
|
1026
1083
|
})),
|
|
1027
|
-
name
|
|
1028
|
-
permanentUrl: `https://twitter.com/${
|
|
1084
|
+
name,
|
|
1085
|
+
permanentUrl: `https://twitter.com/${username}/status/${tweetId}`,
|
|
1029
1086
|
photos,
|
|
1030
1087
|
replies: tweet.reply_count,
|
|
1031
1088
|
retweets: tweet.retweet_count,
|
|
@@ -1033,7 +1090,7 @@ function parseLegacyTweet(user, tweet, editControl) {
|
|
|
1033
1090
|
thread: [],
|
|
1034
1091
|
urls: urls.filter(isFieldDefined("expanded_url")).map((url) => url.expanded_url),
|
|
1035
1092
|
userId: tweet.user_id_str,
|
|
1036
|
-
username
|
|
1093
|
+
username,
|
|
1037
1094
|
videos,
|
|
1038
1095
|
isQuoted: false,
|
|
1039
1096
|
isReply: false,
|
|
@@ -1067,6 +1124,7 @@ function parseLegacyTweet(user, tweet, editControl) {
|
|
|
1067
1124
|
tw.retweetedStatusId = retweetedStatusIdStr;
|
|
1068
1125
|
if (retweetedStatusResult) {
|
|
1069
1126
|
const parsedResult = parseLegacyTweet(
|
|
1127
|
+
retweetedStatusResult?.core?.user_results?.result?.core,
|
|
1070
1128
|
retweetedStatusResult?.core?.user_results?.result?.legacy,
|
|
1071
1129
|
retweetedStatusResult?.legacy
|
|
1072
1130
|
);
|
|
@@ -1094,6 +1152,7 @@ function parseResult(result) {
|
|
|
1094
1152
|
result.legacy.full_text = noteTweetResultText;
|
|
1095
1153
|
}
|
|
1096
1154
|
const tweetResult = parseLegacyTweet(
|
|
1155
|
+
result?.core?.user_results?.result?.core,
|
|
1097
1156
|
result?.core?.user_results?.result?.legacy,
|
|
1098
1157
|
result?.legacy
|
|
1099
1158
|
);
|
|
@@ -1244,6 +1303,7 @@ function parseSearchTimelineTweets(timeline) {
|
|
|
1244
1303
|
if (itemContent?.tweetDisplayType === "Tweet") {
|
|
1245
1304
|
const tweetResultRaw = itemContent.tweet_results?.result;
|
|
1246
1305
|
const tweetResult = parseLegacyTweet(
|
|
1306
|
+
tweetResultRaw?.core?.user_results?.result?.core,
|
|
1247
1307
|
tweetResultRaw?.core?.user_results?.result?.legacy,
|
|
1248
1308
|
tweetResultRaw?.legacy,
|
|
1249
1309
|
tweetResultRaw?.edit_control?.edit_control_initial
|
|
@@ -1585,62 +1645,6 @@ async function getTrends(auth) {
|
|
|
1585
1645
|
return trends;
|
|
1586
1646
|
}
|
|
1587
1647
|
|
|
1588
|
-
const endpoints = {
|
|
1589
|
-
// TODO: Migrate other endpoint URLs here
|
|
1590
|
-
UserTweets: "https://twitter.com/i/api/graphql/V7H0Ap3_Hh2FyS75OCDO3Q/UserTweets?variables=%7B%22userId%22%3A%224020276615%22%2C%22count%22%3A20%2C%22includePromotedContent%22%3Atrue%2C%22withQuickPromoteEligibilityTweetFields%22%3Atrue%2C%22withVoice%22%3Atrue%2C%22withV2Timeline%22%3Atrue%7D&features=%7B%22rweb_tipjar_consumption_enabled%22%3Atrue%2C%22responsive_web_graphql_exclude_directive_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Afalse%2C%22creator_subscriptions_tweet_preview_api_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22responsive_web_graphql_skip_user_profile_image_extensions_enabled%22%3Afalse%2C%22communities_web_enable_tweet_community_results_fetch%22%3Atrue%2C%22c9s_tweet_anatomy_moderator_badge_enabled%22%3Atrue%2C%22articles_preview_enabled%22%3Atrue%2C%22tweetypie_unmention_optimization_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Atrue%2C%22responsive_web_twitter_article_tweet_consumption_enabled%22%3Atrue%2C%22tweet_awards_web_tipping_enabled%22%3Afalse%2C%22creator_subscriptions_quote_tweet_preview_enabled%22%3Afalse%2C%22freedom_of_speech_not_reach_fetch_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Atrue%2C%22rweb_video_timestamps_enabled%22%3Atrue%2C%22longform_notetweets_rich_text_read_enabled%22%3Atrue%2C%22longform_notetweets_inline_media_enabled%22%3Atrue%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D&fieldToggles=%7B%22withArticlePlainText%22%3Afalse%7D",
|
|
1591
|
-
UserTweetsAndReplies: "https://twitter.com/i/api/graphql/E4wA5vo2sjVyvpliUffSCw/UserTweetsAndReplies?variables=%7B%22userId%22%3A%224020276615%22%2C%22count%22%3A40%2C%22cursor%22%3A%22DAABCgABGPWl-F-ATiIKAAIY9YfiF1rRAggAAwAAAAEAAA%22%2C%22includePromotedContent%22%3Atrue%2C%22withCommunity%22%3Atrue%2C%22withVoice%22%3Atrue%2C%22withV2Timeline%22%3Atrue%7D&features=%7B%22rweb_tipjar_consumption_enabled%22%3Atrue%2C%22responsive_web_graphql_exclude_directive_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Afalse%2C%22creator_subscriptions_tweet_preview_api_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22responsive_web_graphql_skip_user_profile_image_extensions_enabled%22%3Afalse%2C%22communities_web_enable_tweet_community_results_fetch%22%3Atrue%2C%22c9s_tweet_anatomy_moderator_badge_enabled%22%3Atrue%2C%22articles_preview_enabled%22%3Atrue%2C%22tweetypie_unmention_optimization_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Atrue%2C%22responsive_web_twitter_article_tweet_consumption_enabled%22%3Atrue%2C%22tweet_awards_web_tipping_enabled%22%3Afalse%2C%22creator_subscriptions_quote_tweet_preview_enabled%22%3Afalse%2C%22freedom_of_speech_not_reach_fetch_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Atrue%2C%22rweb_video_timestamps_enabled%22%3Atrue%2C%22longform_notetweets_rich_text_read_enabled%22%3Atrue%2C%22longform_notetweets_inline_media_enabled%22%3Atrue%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D&fieldToggles=%7B%22withArticlePlainText%22%3Afalse%7D",
|
|
1592
|
-
UserLikedTweets: "https://twitter.com/i/api/graphql/eSSNbhECHHWWALkkQq-YTA/Likes?variables=%7B%22userId%22%3A%222244196397%22%2C%22count%22%3A20%2C%22includePromotedContent%22%3Afalse%2C%22withClientEventToken%22%3Afalse%2C%22withBirdwatchNotes%22%3Afalse%2C%22withVoice%22%3Atrue%2C%22withV2Timeline%22%3Atrue%7D&features=%7B%22responsive_web_graphql_exclude_directive_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Afalse%2C%22creator_subscriptions_tweet_preview_api_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22responsive_web_graphql_skip_user_profile_image_extensions_enabled%22%3Afalse%2C%22c9s_tweet_anatomy_moderator_badge_enabled%22%3Atrue%2C%22tweetypie_unmention_optimization_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Atrue%2C%22responsive_web_twitter_article_tweet_consumption_enabled%22%3Atrue%2C%22tweet_awards_web_tipping_enabled%22%3Afalse%2C%22freedom_of_speech_not_reach_fetch_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Atrue%2C%22rweb_video_timestamps_enabled%22%3Atrue%2C%22longform_notetweets_rich_text_read_enabled%22%3Atrue%2C%22longform_notetweets_inline_media_enabled%22%3Atrue%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D",
|
|
1593
|
-
TweetDetail: "https://twitter.com/i/api/graphql/xOhkmRac04YFZmOzU9PJHg/TweetDetail?variables=%7B%22focalTweetId%22%3A%221237110546383724547%22%2C%22with_rux_injections%22%3Afalse%2C%22includePromotedContent%22%3Atrue%2C%22withCommunity%22%3Atrue%2C%22withQuickPromoteEligibilityTweetFields%22%3Atrue%2C%22withBirdwatchNotes%22%3Atrue%2C%22withVoice%22%3Atrue%2C%22withV2Timeline%22%3Atrue%7D&features=%7B%22responsive_web_graphql_exclude_directive_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Afalse%2C%22creator_subscriptions_tweet_preview_api_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22responsive_web_graphql_skip_user_profile_image_extensions_enabled%22%3Afalse%2C%22tweetypie_unmention_optimization_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Atrue%2C%22responsive_web_twitter_article_tweet_consumption_enabled%22%3Afalse%2C%22tweet_awards_web_tipping_enabled%22%3Afalse%2C%22freedom_of_speech_not_reach_fetch_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Atrue%2C%22longform_notetweets_rich_text_read_enabled%22%3Atrue%2C%22longform_notetweets_inline_media_enabled%22%3Atrue%2C%22responsive_web_media_download_video_enabled%22%3Afalse%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D&fieldToggles=%7B%22withArticleRichContentState%22%3Afalse%7D",
|
|
1594
|
-
TweetResultByRestId: "https://twitter.com/i/api/graphql/DJS3BdhUhcaEpZ7B7irJDg/TweetResultByRestId?variables=%7B%22tweetId%22%3A%221237110546383724547%22%2C%22withCommunity%22%3Afalse%2C%22includePromotedContent%22%3Afalse%2C%22withVoice%22%3Afalse%7D&features=%7B%22creator_subscriptions_tweet_preview_api_enabled%22%3Atrue%2C%22tweetypie_unmention_optimization_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Atrue%2C%22responsive_web_twitter_article_tweet_consumption_enabled%22%3Afalse%2C%22tweet_awards_web_tipping_enabled%22%3Afalse%2C%22freedom_of_speech_not_reach_fetch_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Atrue%2C%22longform_notetweets_rich_text_read_enabled%22%3Atrue%2C%22longform_notetweets_inline_media_enabled%22%3Atrue%2C%22responsive_web_graphql_exclude_directive_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Afalse%2C%22responsive_web_media_download_video_enabled%22%3Afalse%2C%22responsive_web_graphql_skip_user_profile_image_extensions_enabled%22%3Afalse%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D",
|
|
1595
|
-
ListTweets: "https://twitter.com/i/api/graphql/whF0_KH1fCkdLLoyNPMoEw/ListLatestTweetsTimeline?variables=%7B%22listId%22%3A%221736495155002106192%22%2C%22count%22%3A20%7D&features=%7B%22responsive_web_graphql_exclude_directive_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Afalse%2C%22creator_subscriptions_tweet_preview_api_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22responsive_web_graphql_skip_user_profile_image_extensions_enabled%22%3Afalse%2C%22c9s_tweet_anatomy_moderator_badge_enabled%22%3Atrue%2C%22tweetypie_unmention_optimization_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Atrue%2C%22responsive_web_twitter_article_tweet_consumption_enabled%22%3Afalse%2C%22tweet_awards_web_tipping_enabled%22%3Afalse%2C%22freedom_of_speech_not_reach_fetch_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Atrue%2C%22rweb_video_timestamps_enabled%22%3Atrue%2C%22longform_notetweets_rich_text_read_enabled%22%3Atrue%2C%22longform_notetweets_inline_media_enabled%22%3Atrue%2C%22responsive_web_media_download_video_enabled%22%3Afalse%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D"
|
|
1596
|
-
};
|
|
1597
|
-
class ApiRequest {
|
|
1598
|
-
constructor(info) {
|
|
1599
|
-
this.url = info.url;
|
|
1600
|
-
this.variables = info.variables;
|
|
1601
|
-
this.features = info.features;
|
|
1602
|
-
this.fieldToggles = info.fieldToggles;
|
|
1603
|
-
}
|
|
1604
|
-
toRequestUrl() {
|
|
1605
|
-
const params = new URLSearchParams();
|
|
1606
|
-
if (this.variables) {
|
|
1607
|
-
params.set("variables", stringify(this.variables));
|
|
1608
|
-
}
|
|
1609
|
-
if (this.features) {
|
|
1610
|
-
params.set("features", stringify(this.features));
|
|
1611
|
-
}
|
|
1612
|
-
if (this.fieldToggles) {
|
|
1613
|
-
params.set("fieldToggles", stringify(this.fieldToggles));
|
|
1614
|
-
}
|
|
1615
|
-
return `${this.url}?${params.toString()}`;
|
|
1616
|
-
}
|
|
1617
|
-
}
|
|
1618
|
-
function parseEndpointExample(example) {
|
|
1619
|
-
const { protocol, host, pathname, searchParams: query } = new URL(example);
|
|
1620
|
-
const base = `${protocol}//${host}${pathname}`;
|
|
1621
|
-
const variables = query.get("variables");
|
|
1622
|
-
const features = query.get("features");
|
|
1623
|
-
const fieldToggles = query.get("fieldToggles");
|
|
1624
|
-
return new ApiRequest({
|
|
1625
|
-
url: base,
|
|
1626
|
-
variables: variables ? JSON.parse(variables) : void 0,
|
|
1627
|
-
features: features ? JSON.parse(features) : void 0,
|
|
1628
|
-
fieldToggles: fieldToggles ? JSON.parse(fieldToggles) : void 0
|
|
1629
|
-
});
|
|
1630
|
-
}
|
|
1631
|
-
function createApiRequestFactory(endpoints2) {
|
|
1632
|
-
return Object.entries(endpoints2).map(([endpointName, endpointExample]) => {
|
|
1633
|
-
return {
|
|
1634
|
-
[`create${endpointName}Request`]: () => {
|
|
1635
|
-
return parseEndpointExample(endpointExample);
|
|
1636
|
-
}
|
|
1637
|
-
};
|
|
1638
|
-
}).reduce((agg, next) => {
|
|
1639
|
-
return Object.assign(agg, next);
|
|
1640
|
-
});
|
|
1641
|
-
}
|
|
1642
|
-
const apiRequestFactory = createApiRequestFactory(endpoints);
|
|
1643
|
-
|
|
1644
1648
|
function parseListTimelineTweets(timeline) {
|
|
1645
1649
|
let bottomCursor;
|
|
1646
1650
|
let topCursor;
|