Skip to content

Commit fdbb209

Browse files
committed
[Twitter] Update API endpoints and structures
1 parent 3fd5d70 commit fdbb209

File tree

2 files changed

+49
-21
lines changed

2 files changed

+49
-21
lines changed

src/platform/twitter/request.rs

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,27 +45,29 @@ impl TwitterRequester {
4545

4646
let variables = json!({
4747
"screen_name": screen_name,
48-
"withSafetyModeUserFields": true
48+
"withGrokTranslatedBio": false
4949
});
5050
let features = json!({
5151
"hidden_profile_subscriptions_enabled": true,
52+
"payments_enabled": false,
53+
"rweb_xchat_enabled": false,
54+
"profile_label_improvements_pcf_label_in_post_enabled": true,
5255
"rweb_tipjar_consumption_enabled": true,
53-
"responsive_web_graphql_exclude_directive_enabled": true,
5456
"verified_phone_label_enabled": false,
5557
"subscriptions_verification_info_is_identity_verified_enabled": true,
5658
"subscriptions_verification_info_verified_since_enabled": true,
5759
"highlights_tweets_tab_ui_enabled": true,
5860
"responsive_web_twitter_article_notes_tab_enabled": true,
59-
"subscriptions_feature_can_gift_premium": false,
61+
"subscriptions_feature_can_gift_premium": true,
6062
"creator_subscriptions_tweet_preview_api_enabled": true,
6163
"responsive_web_graphql_skip_user_profile_image_extensions_enabled": false,
6264
"responsive_web_graphql_timeline_navigation_enabled": true
6365
});
6466
let field_toggles = json!({
65-
"withAuxiliaryUserLabels": false
67+
"withAuxiliaryUserLabels": true
6668
});
6769
let mut url =
68-
Url::from_str("https://x.com/i/api/graphql/xmU6X_CKVnQ5lSrCbAmJsg/UserByScreenName")?;
70+
Url::from_str("https://x.com/i/api/graphql/gEyDv8Fmv2BVTYIAf32nbA/UserByScreenName")?;
6971
{
7072
let mut query = url.query_pairs_mut();
7173
query.append_pair("variables", &json::to_string(&variables)?);
@@ -83,43 +85,53 @@ impl TwitterRequester {
8385

8486
let variables = json!({
8587
"userId": user_id,
86-
"count": 20,
88+
"count": 40,
8789
"includePromotedContent": true,
8890
"withQuickPromoteEligibilityTweetFields": true,
8991
"withVoice": true,
90-
"withV2Timeline": true
9192
});
9293
let features = json!({
94+
"rweb_video_screen_enabled": false,
95+
"payments_enabled": false,
96+
"rweb_xchat_enabled": false,
97+
"profile_label_improvements_pcf_label_in_post_enabled": true,
9398
"rweb_tipjar_consumption_enabled": true,
94-
"responsive_web_graphql_exclude_directive_enabled": true,
9599
"verified_phone_label_enabled": false,
96100
"creator_subscriptions_tweet_preview_api_enabled": true,
97101
"responsive_web_graphql_timeline_navigation_enabled": true,
98102
"responsive_web_graphql_skip_user_profile_image_extensions_enabled": false,
103+
"premium_content_api_read_enabled": false,
99104
"communities_web_enable_tweet_community_results_fetch": true,
100105
"c9s_tweet_anatomy_moderator_badge_enabled": true,
106+
"responsive_web_grok_analyze_button_fetch_trends_enabled": false,
107+
"responsive_web_grok_analyze_post_followups_enabled": true,
108+
"responsive_web_jetfuel_frame": true,
109+
"responsive_web_grok_share_attachment_enabled": true,
101110
"articles_preview_enabled": true,
102-
"tweetypie_unmention_optimization_enabled": true,
103111
"responsive_web_edit_tweet_api_enabled": true,
104112
"graphql_is_translatable_rweb_tweet_is_translatable_enabled": true,
105113
"view_counts_everywhere_api_enabled": true,
106114
"longform_notetweets_consumption_enabled": true,
107115
"responsive_web_twitter_article_tweet_consumption_enabled": true,
108116
"tweet_awards_web_tipping_enabled": false,
117+
"responsive_web_grok_show_grok_translated_post": false,
118+
"responsive_web_grok_analysis_button_from_backend": true,
109119
"creator_subscriptions_quote_tweet_preview_enabled": false,
110120
"freedom_of_speech_not_reach_fetch_enabled": true,
111121
"standardized_nudges_misinfo": true,
112122
"tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled": true,
113-
"rweb_video_timestamps_enabled": true,
114123
"longform_notetweets_rich_text_read_enabled": true,
115124
"longform_notetweets_inline_media_enabled": true,
125+
"responsive_web_grok_image_annotation_enabled": true,
126+
"responsive_web_grok_imagine_annotation_enabled": true,
127+
"responsive_web_grok_community_note_auto_translation_is_enabled": false,
116128
"responsive_web_enhance_cards_enabled": false
117129
});
118130
let field_toggles = json!({
119131
"withArticlePlainText": false
120132
});
121133
let mut url =
122-
Url::from_str("https://x.com/i/api/graphql/V7H0Ap3_Hh2FyS75OCDO3Q/UserTweets")?;
134+
Url::from_str("https://x.com/i/api/graphql/BqvqNsqColIQbpX1_NmEwg/UserTweets")?;
123135
{
124136
let mut query = url.query_pairs_mut();
125137
query.append_pair("variables", &json::to_string(&variables)?);

src/platform/twitter/source/mod.rs

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -124,35 +124,51 @@ mod data {
124124
#[derive(Clone, Debug, PartialEq, Deserialize)]
125125
pub struct UserByScreenName {
126126
pub rest_id: String,
127+
pub avatar: Avatar,
128+
pub core: UserByScreenNameCore,
127129
pub legacy: UserByScreenNameLegacy,
130+
pub location: Location,
128131
}
129132

130133
impl From<UserByScreenName> for User {
131134
fn from(user: UserByScreenName) -> Self {
132135
Self {
133-
nickname: user.legacy.name,
134-
profile_url: format!("https://x.com/{}", user.legacy.screen_name),
135-
avatar_url: Some(user.legacy.profile_image_url_https),
136+
nickname: user.core.name,
137+
profile_url: format!("https://x.com/{}", user.core.screen_name),
138+
avatar_url: Some(user.avatar.image_url),
136139
}
137140
}
138141
}
139142

143+
#[derive(Clone, Debug, PartialEq, Deserialize)]
144+
pub struct UserByScreenNameCore {
145+
pub created_at: String,
146+
pub name: String,
147+
pub screen_name: String,
148+
}
149+
150+
#[derive(Clone, Debug, PartialEq, Deserialize)]
151+
pub struct Avatar {
152+
pub image_url: String,
153+
}
154+
140155
#[derive(Clone, Debug, PartialEq, Deserialize)]
141156
pub struct UserByScreenNameLegacy {
142157
pub description: String,
143-
pub location: String,
144-
pub name: String,
145158
pub pinned_tweet_ids_str: Vec<String>,
146159
pub profile_banner_url: Option<String>,
147-
pub profile_image_url_https: String, // Very small..
148-
pub screen_name: String,
160+
}
161+
162+
#[derive(Clone, Debug, PartialEq, Deserialize)]
163+
pub struct Location {
164+
pub location: String,
149165
}
150166

151167
//
152168

153169
#[derive(Clone, Debug, PartialEq, Deserialize)]
154170
pub struct UserTweets {
155-
pub timeline_v2: UserTweetsTimelineV2,
171+
pub timeline: UserTweetsTimelineV2,
156172
}
157173

158174
#[derive(Clone, Debug, PartialEq, Deserialize)]
@@ -431,7 +447,7 @@ impl FetcherInner {
431447

432448
let posts = resp
433449
.into_inner()
434-
.timeline_v2
450+
.timeline
435451
.timeline
436452
.instructions
437453
.into_iter()
@@ -474,7 +490,7 @@ fn parse_tweet(tweet: data::Tweet) -> anyhow::Result<Post> {
474490
let urls = PostUrls::new(PostUrl::Clickable(PostUrlClickable {
475491
url: format!(
476492
"https://x.com/{}/status/{}",
477-
tweet.core.user_results.result.legacy.screen_name, tweet.rest_id
493+
tweet.core.user_results.result.core.screen_name, tweet.rest_id
478494
),
479495
display: "View Tweet".into(),
480496
}));

0 commit comments

Comments
 (0)