commit a7de875f12d8bea5915533fd70152b88681c305c Author: Óscar M. Lage Date: Thu Nov 17 21:57:35 2022 +0100 First commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6985cf1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..e05a9c5 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "masto-rss" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +reqwest = { version = "0.11.12", features = ["blocking"] } +rss = "2.0.1" +chrono = "0.4.23" diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e2c5d85 --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +bash: + docker-compose run --rm dev + +build: + cargo build + +run: + cargo run diff --git a/README.md b/README.md new file mode 100644 index 0000000..eb2d3e7 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# masto-rss + +A rust utility used to convert some RSS information (toots mainly) from Mastodon to Markdown. The destination directory is able to be imported into Hugo (The world’s fastest framework for building websites). diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..ef72277 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,8 @@ +version: "3.8" + +services: + + dev: + image: "rust:1.65" + volumes: + - .:/app diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..1e717a7 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,93 @@ +extern crate reqwest; + +use std::path::Path; +use std::fs::File; +use std::io::Write; +use std::io::copy; +use rss::Channel; + +#[derive(Debug)] +struct Config { + url: String, + author: String, + path: String, +} + +#[derive(Debug)] +struct Toot { + title: String, + date: String, + text: String, + author: String, + tags: Vec, + media: Vec, +} + +fn download_media(url: String, path: String) { + print!("Downloading media images: {:?}", url); + let mut file = reqwest::blocking::get(url.clone()).unwrap(); + let filename = Path::new(&url).file_name().unwrap().to_str().unwrap(); + println!("file: {:?}", file); + 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() { + // Configure RSS url, author and path where the .md will be stored + let config = Config { + // url: "https://mastodon.bofhers.es/@oscarmlage.rss", + url: "https://mastodon.bofhers.es/tags/micropost.rss".to_string(), + author: "oscarmlage".to_string(), + path: "temp/".to_string(), + }; + 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"); + } + } + } +} +