Skip to main content

twitter_internal_api/api/params/
search_time_line.rs

1use crate::utils::headers::RateLimitHeaders;
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4
5#[derive(Clone, Serialize, Deserialize, Default)]
6#[serde(rename_all = "camelCase")]
7pub struct SearchTimelineParams {
8    pub variables: Variables,
9    pub features: Features,
10    pub field_toggles: FieldToggles,
11}
12#[derive(Clone, Serialize, Deserialize)]
13pub struct Features(Value);
14
15impl Default for Features {
16    fn default() -> Self {
17        Self(serde_json::json!({
18        "articles_preview_enabled": true,
19        "c9s_tweet_anatomy_moderator_badge_enabled": true,
20        "communities_web_enable_tweet_community_results_fetch": true,
21        "creator_subscriptions_quote_tweet_preview_enabled": false,
22        "creator_subscriptions_tweet_preview_api_enabled": true,
23        "freedom_of_speech_not_reach_fetch_enabled": true,
24        "graphql_is_translatable_rweb_tweet_is_translatable_enabled": true,
25        "longform_notetweets_consumption_enabled": true,
26        "longform_notetweets_inline_media_enabled": true,
27        "longform_notetweets_rich_text_read_enabled": true,
28        "payments_enabled": false,
29        "premium_content_api_read_enabled": false,
30        "profile_label_improvements_pcf_label_in_post_enabled": true,
31        "responsive_web_edit_tweet_api_enabled": true,
32        "responsive_web_enhance_cards_enabled": false,
33        "responsive_web_graphql_exclude_directive_enabled": true,
34        "responsive_web_graphql_skip_user_profile_image_extensions_enabled": false,
35        "responsive_web_graphql_timeline_navigation_enabled": true,
36        "responsive_web_grok_analysis_button_from_backend": true,
37        "responsive_web_grok_analyze_button_fetch_trends_enabled": false,
38        "responsive_web_grok_analyze_post_followups_enabled": true,
39        "responsive_web_grok_image_annotation_enabled": true,
40        "responsive_web_grok_share_attachment_enabled": true,
41        "responsive_web_grok_show_grok_translated_post": false,
42        "responsive_web_jetfuel_frame": false,
43        "responsive_web_media_download_video_enabled": false,
44        "responsive_web_twitter_article_tweet_consumption_enabled": false,
45        "responsive_web_twitter_article_tweet_consumption_enabled": true,
46        "rweb_lists_timeline_redesign_enabled": true,
47        "rweb_tipjar_consumption_enabled": true,
48        "rweb_video_screen_enabled": false,
49        "standardized_nudges_misinfo": true,
50        "tweet_awards_web_tipping_enabled": false,
51        "tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled": true,
52        "tweetypie_unmention_optimization_enabled": true,
53        "verified_phone_label_enabled": false,
54        "view_counts_everywhere_api_enabled": true,
55        }))
56    }
57}
58
59#[derive(Clone, Serialize, Deserialize)]
60#[serde(rename_all = "camelCase")]
61#[derive(Default)]
62pub struct FieldToggles {
63    pub with_article_rich_content_state: bool,
64}
65
66#[derive(Clone, Serialize, Deserialize, Default)]
67#[serde(rename_all = "camelCase")]
68pub struct Variables {
69    pub raw_query: String,
70    pub count: u32,
71    #[serde(skip_serializing_if = "Option::is_none")]
72    pub cursor: Option<String>,
73    pub query_source: QuerySource,
74    pub product: Product,
75}
76
77#[derive(Clone, Serialize, Deserialize, Default)]
78pub enum QuerySource {
79    #[serde(rename = "typed_query")]
80    #[default]
81    TypedQuery,
82}
83
84#[derive(Clone, Serialize, Deserialize, Default, Debug, strum::EnumString, strum::Display)]
85pub enum Product {
86    #[default]
87    #[serde(rename = "Top")]
88    Top,
89    #[serde(rename = "Latest")]
90    Latest,
91    #[serde(rename = "Photos")]
92    Photos,
93    #[serde(rename = "People")]
94    People,
95    #[serde(rename = "Videos")]
96    Videos,
97}
98
99impl SearchTimelineParams {
100    pub fn params(&self) -> anyhow::Result<Vec<(&str, String)>> {
101        let params = &[
102            ("variables", serde_json::to_string(&self.variables)?),
103            ("features", serde_json::to_string(&self.features)?),
104            ("fieldToggles", serde_json::to_string(&self.field_toggles)?),
105        ];
106        Ok(params.to_vec())
107    }
108
109    pub fn update_cursor(&mut self, cursor: Option<String>) {
110        if let Some(cursor) = cursor {
111            self.variables.cursor = Some(cursor);
112        }
113    }
114
115    pub fn update_raw_query(&mut self, raw_query: &str) {
116        self.variables.raw_query = raw_query.to_string();
117    }
118
119    pub fn update_count(&mut self, count: u32) {
120        if count > 50 {
121            self.variables.count = 50
122        } else {
123            self.variables.count = count;
124        }
125    }
126
127    pub fn update_product(&mut self, product: Product) {
128        self.variables.product = product;
129    }
130}
131
132#[derive(Deserialize, Serialize, Debug)]
133pub enum SearchTimeLineResponseType {
134    Success,
135    AuthError,
136    RateLimit,
137}
138
139#[derive(Deserialize, Serialize, Debug)]
140pub struct SearchTimeLineResponse {
141    pub response_type: SearchTimeLineResponseType,
142    pub response_content: Option<Value>,
143    pub response_headers: RateLimitHeaders,
144}