diff --git a/Cargo.lock b/Cargo.lock index cb23115..c801a9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2016,7 +2016,7 @@ dependencies = [ [[package]] name = "scootaloo" -version = "0.7.1" +version = "0.7.2" dependencies = [ "chrono", "clap", diff --git a/Cargo.toml b/Cargo.toml index ec236f3..d866bd5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "scootaloo" -version = "0.7.1" +version = "0.7.2" authors = ["VC "] edition = "2021" diff --git a/src/lib.rs b/src/lib.rs index 93d45ff..4c68bb7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,16 +13,17 @@ mod twitter; use twitter::*; mod util; +use crate::util::generate_media_ids; mod state; pub use state::{init_db, migrate_db}; use state::{read_state, write_state, TweetToToot}; use elefren::{prelude::*, status_builder::StatusBuilder}; -use log::{debug, error, info, warn}; +use log::{debug, info}; use rusqlite::Connection; -use std::{borrow::Cow, sync::Arc}; -use tokio::{fs::remove_file, spawn, sync::Mutex, task::JoinHandle}; +use std::sync::Arc; +use tokio::{spawn, sync::Mutex, task::JoinHandle}; /// This is where the magic happens #[tokio::main] @@ -106,46 +107,11 @@ pub async fn run(config: Config) { // build basic status by just yielding text and dereferencing contained urls let mut status_text = build_basic_status(tweet); - let mut status_medias: Vec = vec![]; - // reupload the attachments if any - if let Some(m) = &tweet.extended_entities { - for media in &m.media { - let local_tweet_media_path = - match get_tweet_media(media, &scootaloo_cache_path).await { - Ok(m) => m, - Err(e) => { - error!("Cannot get tweet media for {}: {}", &media.url, e); - continue; - } - }; + // building associative media list + let (media_url, status_medias) = + generate_media_ids(tweet, &scootaloo_cache_path, &mastodon).await; - let mastodon_media_ids = match mastodon - .media(Cow::from(local_tweet_media_path.to_owned())) - { - Ok(m) => { - remove_file(&local_tweet_media_path) - .await - .unwrap_or_else(|e| - warn!("Attachment for {} has been uploaded, but I’m unable to remove the existing file: {}", &local_tweet_media_path, e) - ); - m.id - } - Err(e) => { - error!( - "Attachment {} cannot be uploaded to Mastodon Instance: {}", - &local_tweet_media_path, e - ); - continue; - } - }; - - status_medias.push(mastodon_media_ids); - - // last step, removing the reference to the media from with the toot’s text - status_text = status_text.replace(&media.url, ""); - } - } - // finished reuploading attachments, now let’s do the toot baby! + status_text = status_text.replace(&media_url, ""); debug!("Building corresponding Mastodon status"); @@ -157,6 +123,9 @@ pub async fn run(config: Config) { status_builder.in_reply_to(&i); } + // can be activated for test purposes + // status_builder.visibility(elefren::status_builder::Visibility::Private); + let status = status_builder .build() .unwrap_or_else(|_| panic!("Cannot build status with text {}", &status_text)); diff --git a/src/twitter.rs b/src/twitter.rs index e9a1816..50e4ac8 100644 --- a/src/twitter.rs +++ b/src/twitter.rs @@ -35,7 +35,7 @@ pub async fn get_user_timeline( ) -> Result, Box> { // fix the page size to 200 as it is the maximum Twitter authorizes let (_, feed) = user_timeline(UserID::from(screen_name.to_owned()), true, false, token) - .with_page_size(20) + .with_page_size(200) .older(lid) .await?; diff --git a/src/util.rs b/src/util.rs index 1517718..8aa34a8 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,11 +1,62 @@ -use crate::ScootalooError; +use crate::{twitter::get_tweet_media, ScootalooError}; +use egg_mode::tweet::Tweet; +use elefren::prelude::*; +use log::{error, warn}; use reqwest::Url; -use std::error::Error; +use std::{borrow::Cow, error::Error}; use tokio::{ - fs::{create_dir_all, File}, + fs::{create_dir_all, remove_file, File}, io::copy, }; +/// Generate associative table between media ids and tweet extended entities +pub async fn generate_media_ids( + tweet: &Tweet, + cache_path: &str, + mastodon: &Mastodon, +) -> (String, Vec) { + let mut media_ids: Vec = vec![]; + let mut media_url: String = "".to_string(); + + if let Some(m) = &tweet.extended_entities { + for media in &m.media { + // attribute the media url + media_url = media.url.clone(); + let local_tweet_media_path = match get_tweet_media(media, cache_path).await { + Ok(m) => m, + Err(e) => { + error!("Cannot get tweet media for {}: {}", &media.url, e); + continue; + } + }; + + let mastodon_media_ids = match mastodon + .media(Cow::from(local_tweet_media_path.to_owned())) + { + Ok(m) => { + remove_file(&local_tweet_media_path).await.unwrap_or_else(|e| + warn!("Attachment for {} has been uploaded, but I’m unable to remove the existing file: {}", &local_tweet_media_path, e)); + m.id + } + Err(e) => { + error!( + "Attachment {} cannot be uploaded to Mastodon Instance: {}", + &local_tweet_media_path, e + ); + // file is no longer useful, deleting + remove_file(&local_tweet_media_path).await.unwrap_or_else(|e| + warn!("Attachment for {} has been uploaded, but I’m unable to remove the existing file: {}", &local_tweet_media_path, e)); + continue; + } + }; + + media_ids.push(mastodon_media_ids); + } + } + + (media_url, media_ids) +} + /// Gets and caches Twitter Media inside the determined temp dir pub async fn cache_media(u: &str, t: &str) -> Result> { // create dir