use crate::config::MastodonConfig; use crate::config::TwitterConfig; use crate::util::cache_media; use crate::ScootalooError; use egg_mode::{ entities::{MediaEntity, MediaType}, tweet::{user_timeline, Tweet}, user::UserID, KeyPair, Token, }; use std::error::Error; /// Gets Twitter oauth2 token pub fn get_oauth2_token(config: &TwitterConfig) -> Token { let con_token = KeyPair::new( config.consumer_key.to_owned(), config.consumer_secret.to_owned(), ); let access_token = KeyPair::new( config.access_key.to_owned(), config.access_secret.to_owned(), ); Token::Access { consumer: con_token, access: access_token, } } /// Gets Twitter user timeline pub async fn get_user_timeline( config: &MastodonConfig, token: &Token, lid: Option, ) -> Result, Box> { // fix the page size to 200 as it is the maximum Twitter authorizes let (_, feed) = user_timeline( UserID::from(config.twitter_screen_name.to_owned()), true, false, token, ) .with_page_size(200) .older(lid) .await?; Ok(feed.to_vec()) } /// Retrieves a single media from a tweet and store it in a temporary file pub async fn get_tweet_media(m: &MediaEntity, t: &str) -> Result> { match m.media_type { MediaType::Photo => cache_media(&m.media_url_https, t).await, _ => match &m.video_info { Some(v) => match &v.variants.iter().find(|&x| x.content_type == "video/mp4") { Some(u) => cache_media(&u.url, t).await, None => Err(ScootalooError::new(&format!( "Media Type for {} is video but no mp4 file URL is available", &m.url )) .into()), }, None => Err(ScootalooError::new(&format!( "Media Type for {} is video but does not contain any video_info", &m.url )) .into()), }, } } #[cfg(test)] mod tests { use super::*; use egg_mode::entities::{ MediaSize, MediaSizes, MediaType::{Gif, Photo}, ResizeMode::Crop, ResizeMode::Fit, VideoInfo, VideoVariant, }; use std::fs::remove_dir_all; const TMP_DIR: &'static str = "/tmp/scootaloo_get_tweet_media_test"; #[tokio::test] async fn test_get_tweet_media() { let m_photo = MediaEntity { display_url: "pic.twitter.com/sHrwmP69Yv".to_string(), expanded_url: "https://twitter.com/NintendojoFR/status/1555473821121056771/photo/1" .to_string(), id: 1555473771280080896, range: (91, 114), media_url: "http://pbs.twimg.com/media/FZYnJ1qWIAAReHt.jpg".to_string(), media_url_https: "https://pbs.twimg.com/media/FZYnJ1qWIAAReHt.jpg" .to_string(), sizes: MediaSizes { thumb: MediaSize { w: 150, h: 150, resize: Crop }, small: MediaSize { w: 680, h: 510, resize: Fit }, medium: MediaSize { w: 1200, h: 900, resize: Fit }, large: MediaSize { w: 1280, h: 960, resize: Fit } }, source_status_id: None, media_type: Photo, url: "https://t.co/sHrwmP69Yv".to_string(), video_info: None, ext_alt_text: Some("Le menu «\u{a0}Classes » du jeu vidéo Xenoblade Chronicles 3 (Switch). L’affinité du personnage pour la classe est notée par quatre lettres : C, A, C, A (caca)." .to_string()) }; let m_video = MediaEntity { display_url: "pic.twitter.com/xDln0RrkjU".to_string(), expanded_url: "https://twitter.com/NintendojoFR/status/1551822196833673218/photo/1" .to_string(), id: 1551822189711790081, range: (275, 298), media_url: "http://pbs.twimg.com/tweet_video_thumb/FYkuD0RXEAE-iDx.jpg".to_string(), media_url_https: "https://pbs.twimg.com/tweet_video_thumb/FYkuD0RXEAE-iDx.jpg" .to_string(), sizes: MediaSizes { thumb: MediaSize { w: 150, h: 150, resize: Crop, }, small: MediaSize { w: 320, h: 240, resize: Fit, }, medium: MediaSize { w: 320, h: 240, resize: Fit, }, large: MediaSize { w: 320, h: 240, resize: Fit, }, }, source_status_id: None, media_type: Gif, url: "https://t.co/xDln0RrkjU".to_string(), video_info: Some(VideoInfo { aspect_ratio: (4, 3), duration_millis: None, variants: vec![VideoVariant { bitrate: Some(0), content_type: "video/mp4".parse::().unwrap(), url: "https://video.twimg.com/tweet_video/FYkuD0RXEAE-iDx.mp4".to_string(), }], }), ext_alt_text: Some("Scared Nintendo GIF".to_string()), }; let tweet_media_photo = get_tweet_media(&m_photo, TMP_DIR).await.unwrap(); let tweet_media_video = get_tweet_media(&m_video, TMP_DIR).await.unwrap(); assert_eq!( tweet_media_photo, format!("{}/FZYnJ1qWIAAReHt.jpg", TMP_DIR) ); assert_eq!( tweet_media_video, format!("{}/FYkuD0RXEAE-iDx.mp4", TMP_DIR) ); remove_dir_all(TMP_DIR).unwrap(); } }