extern crate reqwest; use std::path::Path; use std::fs::File; use std::io::Write; use std::io::copy; use rss::Channel; use serde::{Serialize, Deserialize}; use toml; #[derive(Debug, Serialize, Deserialize)] struct Config { url: String, author: String, path: String, version: String, description: String, } impl Config { pub fn default() -> Config { Config { url: "https://mastodon.bofhers.es/tags/micropost.rss".to_string(), author: "oscarmlage".to_string(), path: "temp/".to_string(), version: "0.0.1".to_string(), description: "Just another tool to convert RSS from Mastodon to Markdown".to_string(), } } pub fn parse(&mut self, config_file: String) -> Config { let i = std::fs::read_to_string(config_file).expect("Error reading the file"); let myconfig: Self = toml::from_str(&i).unwrap(); myconfig } } #[derive(Debug)] struct Toot { title: String, date: String, text: String, author: String, tags: Vec, media: Vec, } fn download_media(url: String, path: String) { println!(" - Downloading media images: {:?}", url); let mut file = reqwest::blocking::get(url.clone()).unwrap(); let filename = Path::new(&url).file_name().unwrap().to_str().unwrap(); let mut out = File::create(format!("{}/{}", path, filename)).unwrap(); copy(&mut file, &mut out).expect("Error copying file"); } fn write_to_disk(toot: &Toot, path: String, title: String) { let mut file = File::create(format!("{}{}/index.md", path, title)).expect("Error creating file"); writeln!(&mut file, "---\ntitle: {}\ndate: {}\ndraft: false\ntags: [micropost]\nimage:\n---\n\n{}\n\n", toot.title, toot.date, toot.text).expect("Error appending content to file"); } fn main() { // Default config file let default_config = ".config/masto-rss/masto-rss.ini"; let home = std::env::var("HOME").unwrap(); let cfg = format!("{}/{}", home, default_config); // Read the config file let mut default_config = Config::default(); let config = default_config.parse(cfg.to_string()); println!("\n✨ masto-rss v.{} - {}\n", config.version, config.description); let rss = reqwest::blocking::get(config.url).unwrap().bytes(); let rss2 = rss.unwrap(); let channel = Channel::read_from(&rss2[..]).unwrap(); for item in channel.items.iter() { // let link_str = item.link.as_ref().unwrap().to_string(); // let (_, title) = link_str.rsplit_once('/').unwrap(); let dt = item.pub_date.as_ref().unwrap(); let datetime = chrono::DateTime::parse_from_rfc2822(dt.as_str()).unwrap(); let title = datetime.format("%Y%m%d-%H%M").to_string(); println!("➡️ {:?}", title); let mut toot = Toot{ title: title.to_string(), date: datetime.to_string(), text: item.description.as_ref().unwrap().to_string(), author: config.author.to_string(), tags: vec![], media: vec![], }; for tag in item.categories.iter() { toot.tags.push(tag.name.to_string()); } // Write the markdown std::fs::create_dir_all(format!("{}{}", config.path, title)) .expect("Error creating dir"); write_to_disk(&toot, config.path.to_string(), title.to_string()); // Deal with attachments for media in item.extensions.iter() { // let () = media.1; std::fs::create_dir_all(format!("{}{}/gallery", config.path, title)) .expect("Error creating gallery dir"); for image in media.1.get("content").unwrap().iter() { let img = image.attrs.get("url").unwrap().to_string(); toot.media.push(img.clone()); download_media(img, format!("{}{}/gallery", config.path, title).to_string()); // Add gallery syntax to the markdown let mut file = std::fs::OpenOptions::new().read(true).write(true) .append(true).open(format!("{}{}/index.md", config.path, title)).unwrap(); writeln!(&mut file, "{{{{< gallery match=\"gallery/*\" sortOrder=\"asc\" rowHeight=\"150\" margins=\"5\" thumbnailResizeOptions=\"600x600 q90 Lanczos\" previewType=\"blur\" embedPreview=\"true\" >}}}}") .expect("Error appending gallery content to file"); } } } }