From b73a8afa2ff8fe7af20ea2516a5f86299238e720 Mon Sep 17 00:00:00 2001 From: VC Date: Sun, 1 Mar 2020 17:02:10 +0100 Subject: [PATCH] Dereferences Twitter short url (t.co) to the real URLs + add Error handling (not used at the moment) --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/lib.rs | 71 +++++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 67 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 373c206..706b58c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1249,7 +1249,7 @@ dependencies = [ [[package]] name = "scootaloo" -version = "0.1.0" +version = "0.1.1" dependencies = [ "clap", "egg-mode", diff --git a/Cargo.toml b/Cargo.toml index 3f2b57f..32e1d97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "scootaloo" -version = "0.1.0" +version = "0.1.1" authors = ["VC "] edition = "2018" diff --git a/src/lib.rs b/src/lib.rs index 9857cf4..3289d37 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,9 @@ // std use std::{ borrow::Cow, + collections::HashMap, io, + fmt, fs::{read_to_string, write}, error::Error, }; @@ -13,6 +15,7 @@ use serde::Deserialize; use egg_mode::{ Token, KeyPair, + entities::UrlEntity, tweet::{ Tweet, user_timeline, @@ -28,8 +31,6 @@ use mammut::status_builder::StatusBuilder; /********** * Generic usage functions ***********/ - - /* * Those functions are related to the Twitter side of things */ @@ -85,10 +86,64 @@ fn get_mastodon_token(masto: &MastodonConfig) -> Mastodon { Mastodon::from_data(data) } + +/// build toot from tweet +fn build_status(tweet: &Tweet) -> Result> { + let mut toot = String::from(&tweet.text); + + let decoded_urls = decode_urls(&tweet.entities.urls); + + for decoded_url in decoded_urls { + toot = toot.replace(&decoded_url.0, &decoded_url.1); + } + + Ok(StatusBuilder::new(toot)) +} + +fn decode_urls(urls: &Vec) -> HashMap { + let mut decoded_urls = HashMap::new(); + + for url in urls { + if url.expanded_url.is_some() { + // unwrap is safe here as we just verified that there is something inside expanded_url + decoded_urls.insert(String::from(&url.url), String::from(url.expanded_url.as_deref().unwrap())); + } + } + + decoded_urls +} + +/********** + * local error handler +**********/ +#[derive(Debug)] +struct ScootalooError { + details: String, +} + +impl ScootalooError { + fn new(msg: &str) -> ScootalooError { + ScootalooError { + details: String::from(msg), + } + } +} + +impl fmt::Display for ScootalooError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.details) + } +} + +impl std::error::Error for ScootalooError { + fn description(&self) -> &str { + &self.details + } +} + /********** * Config structure ***********/ - /// General configuration Struct #[derive(Debug, Deserialize)] pub struct Config { @@ -118,7 +173,6 @@ struct MastodonConfig { /********* * Main functions *********/ - /// Parses the TOML file into a Config Struct pub fn parse_toml(toml_file: &str) -> Config { let toml_config = read_to_string(toml_file).unwrap_or_else(|e| @@ -187,8 +241,13 @@ pub fn run(config: Config) { feed.reverse(); for tweet in &feed { - // build status based upon the original tweet - let status = StatusBuilder::new(String::from(&tweet.text)); + let status = match build_status(tweet) { + Ok(t) => t, + Err(e) => { + println!("Could not create status from tweet {}: {}", tweet.id ,e); + continue; + }, + }; // publish status mastodon.new_status(status).unwrap();