agent_twitter_client/
scraper.rs

1use crate::api::client::TwitterClient;
2use crate::auth::user_auth::TwitterUserAuth;
3use crate::constants::BEARER_TOKEN;
4use crate::error::Result;
5use crate::error::TwitterError;
6use crate::models::{Profile, Tweet};
7use crate::search::{fetch_search_tweets, SearchMode};
8use crate::timeline::v1::{QueryProfilesResponse, QueryTweetsResponse};
9use crate::timeline::v2::QueryTweetsResponse as V2QueryTweetsResponse;
10use serde_json::Value;
11use crate::messages::DirectMessagesResponse;
12
13pub struct Scraper {
14    pub twitter_client: TwitterClient,
15}
16
17impl Scraper {
18    pub async fn new() -> Result<Self> {
19        let auth = Box::new(TwitterUserAuth::new(BEARER_TOKEN.to_string()).await?);
20        let twitter_client = TwitterClient::new(auth.clone())?;
21        Ok(Self { twitter_client })
22    }
23
24    pub async fn login(
25        &mut self,
26        username: String,
27        password: String,
28        email: Option<String>,
29        two_factor_secret: Option<String>,
30    ) -> Result<()> {
31        if let Some(user_auth) = self.twitter_client.auth.as_any().downcast_ref::<TwitterUserAuth>() {
32            let mut auth = user_auth.clone();
33            auth.login(
34                &self.twitter_client.client,
35                &username,
36                &password,
37                email.as_deref(),
38                two_factor_secret.as_deref(),
39            )
40            .await?;
41
42            self.twitter_client.auth = Box::new(auth.clone());
43            //self.client = TwitterClient::new(Box::new(auth))?;
44            Ok(())
45        } else {
46            Err(TwitterError::Auth("Invalid auth type".into()))
47        }
48    }
49
50    pub async fn get_profile(&self, username: &str) -> Result<crate::models::Profile> {
51        crate::profile::get_profile(&self.twitter_client, username).await
52    }
53    pub async fn send_tweet(
54        &self,
55        text: &str,
56        reply_to: Option<&str>,
57        media_data: Option<Vec<(Vec<u8>, String)>>,
58    ) -> Result<Value> {
59        crate::tweets::create_tweet_request(&self.twitter_client, text, reply_to, media_data).await
60    }
61
62    pub async fn get_home_timeline(
63        &self,
64        count: i32,
65        seen_tweet_ids: Vec<String>,
66    ) -> Result<Vec<Value>> {
67        crate::timeline::home::fetch_home_timeline(&self.twitter_client, count, seen_tweet_ids).await
68    }
69
70    pub async fn save_cookies(&self, cookie_file: &str) -> Result<()> {
71        if let Some(user_auth) = self.twitter_client.auth.as_any().downcast_ref::<TwitterUserAuth>() {
72            user_auth.save_cookies_to_file(cookie_file).await
73        } else {
74            Err(TwitterError::Auth("Invalid auth type".into()))
75        }
76    }
77
78    pub async fn get_cookie_string(&self) -> Result<String> {
79        if let Some(user_auth) = self.twitter_client.auth.as_any().downcast_ref::<TwitterUserAuth>() {
80            user_auth.get_cookie_string().await
81        } else {
82            Err(TwitterError::Auth("Invalid auth type".into()))
83        }
84    }
85
86    pub async fn set_cookies(&mut self, json_str: &str) -> Result<()> {
87        if let Some(user_auth) = self.twitter_client.auth.as_any().downcast_ref::<TwitterUserAuth>() {
88            let mut auth = user_auth.clone();
89            auth.set_cookies(json_str).await?;
90
91            self.twitter_client.auth = Box::new(auth.clone());
92            self.twitter_client = TwitterClient::new(Box::new(auth))?;
93            Ok(())
94        } else {
95            Err(TwitterError::Auth("Invalid auth type".into()))
96        }
97    }
98
99    pub async fn set_from_cookie_string(&mut self, cookie_string: &str) -> Result<()> {
100        if let Some(user_auth) = self.twitter_client.auth.as_any().downcast_ref::<TwitterUserAuth>() {
101            let mut auth = user_auth.clone();
102            auth.set_from_cookie_string(cookie_string).await?;
103
104            self.twitter_client.auth = Box::new(auth.clone());
105            self.twitter_client = TwitterClient::new(Box::new(auth))?;
106            Ok(())
107        } else {
108            Err(TwitterError::Auth("Invalid auth type".into()))
109        }
110    }
111    
112    pub async fn get_followers(
113        &self,
114        user_id: &str,
115        count: i32,
116        cursor: Option<String>,
117    ) -> Result<(Vec<Profile>, Option<String>)> {
118        crate::relationships::get_followers(&self.twitter_client, user_id, count, cursor).await
119    }
120
121    pub async fn get_following(
122        &self,
123        user_id: &str,
124        count: i32,
125        cursor: Option<String>,
126    ) -> Result<(Vec<Profile>, Option<String>)> {
127        crate::relationships::get_following(&self.twitter_client, user_id, count, cursor).await
128    }
129
130    pub async fn follow_user(&self, username: &str) -> Result<()> {
131        crate::relationships::follow_user(&self.twitter_client, username).await
132    }
133
134    pub async fn unfollow_user(&self, username: &str) -> Result<()> {
135        crate::relationships::unfollow_user(&self.twitter_client, username).await
136    }
137
138    pub async fn send_quote_tweet(
139        &self,
140        text: &str,
141        quoted_tweet_id: &str,
142        media_data: Option<Vec<(Vec<u8>, String)>>,
143    ) -> Result<Value> {
144        crate::tweets::create_quote_tweet(&self.twitter_client, text, quoted_tweet_id, media_data).await
145    }
146
147    pub async fn fetch_tweets_and_replies(
148        &self,
149        username: &str,
150        max_tweets: i32,
151        cursor: Option<&str>,
152    ) -> Result<V2QueryTweetsResponse> {
153            crate::tweets::fetch_tweets_and_replies(&self.twitter_client, username, max_tweets, cursor).await
154    }
155    pub async fn fetch_tweets_and_replies_by_user_id(
156        &self,
157        user_id: &str,
158        max_tweets: i32,
159        cursor: Option<&str>,
160    ) -> Result<V2QueryTweetsResponse> {
161        crate::tweets::fetch_tweets_and_replies_by_user_id(&self.twitter_client, user_id, max_tweets, cursor).await
162    }
163    pub async fn fetch_list_tweets(
164        &self,
165        list_id: &str,
166        max_tweets: i32,
167        cursor: Option<&str>,
168    ) -> Result<Value> {
169        crate::tweets::fetch_list_tweets(&self.twitter_client, list_id, max_tweets, cursor).await
170    }
171
172    pub async fn like_tweet(&self, tweet_id: &str) -> Result<Value> {
173        crate::tweets::like_tweet(&self.twitter_client, tweet_id).await
174    }
175
176    pub async fn retweet(&self, tweet_id: &str) -> Result<Value> {
177        crate::tweets::retweet(&self.twitter_client, tweet_id).await
178    }
179
180    pub async fn create_long_tweet(
181        &self,
182        text: &str,
183        reply_to: Option<&str>,
184        media_ids: Option<Vec<String>>,
185    ) -> Result<Value> {
186        crate::tweets::create_long_tweet(&self.twitter_client, text, reply_to, media_ids).await
187    }
188
189    pub async fn get_tweet(&self, id: &str) -> Result<Tweet> {
190        crate::tweets::get_tweet(&self.twitter_client, id).await
191    }
192
193    pub async fn search_tweets(
194        &self,
195        query: &str,
196        max_tweets: i32,
197        search_mode: SearchMode,
198        cursor: Option<String>,
199    ) -> Result<QueryTweetsResponse> {
200        fetch_search_tweets(&self.twitter_client, query, max_tweets, search_mode, cursor).await
201    }
202
203    pub async fn search_profiles(
204        &self,
205        query: &str,
206        max_profiles: i32,
207        cursor: Option<String>,
208    ) -> Result<QueryProfilesResponse> {
209        crate::search::search_profiles(&self.twitter_client, query, max_profiles, cursor).await
210    }
211
212    pub async fn get_user_tweets(
213        &self,
214        user_id: &str,
215        count: i32,
216        cursor: Option<String>,
217    ) -> Result<V2QueryTweetsResponse> {
218        crate::tweets::fetch_user_tweets(&self.twitter_client, user_id, count, cursor.as_deref()).await
219    }
220
221    pub async fn get_direct_message_conversations(
222        &self,
223        screen_name: &str,
224        cursor: Option<&str>,
225    ) -> Result<DirectMessagesResponse> {
226        crate::messages::get_direct_message_conversations(&self.twitter_client, screen_name, cursor).await
227    }
228
229    pub async fn send_direct_message(
230        &self,
231        conversation_id: &str,
232        text: &str,
233    ) -> Result<Value> {
234        crate::messages::send_direct_message(&self.twitter_client, conversation_id, text).await
235    }
236}