commit 46f44a2336309e746db316fa3a6d8abb3bb27def from: witcher date: Sun Mar 6 21:07:30 2022 UTC proper pub_date support, url file support commit - b5eca9ca3490fd1dd3df30c8a31913bc80c36b94 commit + 46f44a2336309e746db316fa3a6d8abb3bb27def blob - 5fce90c85a729c4f1ec763052fe0571160e8346a blob + c8ac3cd8601f38e70158d4179be3b92664d9ca54 --- Cargo.lock +++ Cargo.lock @@ -22,6 +22,17 @@ dependencies = [ ] [[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -75,11 +86,29 @@ version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" dependencies = [ + "libc", "num-integer", "num-traits", + "time", + "winapi", ] [[package]] +name = "clap" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5177fac1ab67102d8989464efd043c6ff44191b1557ec1ddd489b4f7e1447e77" +dependencies = [ + "atty", + "bitflags", + "indexmap", + "os_str_bytes", + "strsim", + "termcolor", + "textwrap", +] + +[[package]] name = "core-foundation" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -630,6 +659,15 @@ dependencies = [ ] [[package]] +name = "os_str_bytes" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" +dependencies = [ + "memchr", +] + +[[package]] name = "percent-encoding" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -748,10 +786,12 @@ dependencies = [ ] [[package]] -name = "rss-mail" +name = "rss-email" version = "0.1.0" dependencies = [ "anyhow", + "chrono", + "clap", "diesel", "dotenv", "reqwest", @@ -874,6 +914,32 @@ dependencies = [ ] [[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi", + "winapi", +] + +[[package]] name = "tinyvec" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1010,6 +1076,12 @@ dependencies = [ ] [[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] name = "wasm-bindgen" version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1102,6 +1174,15 @@ source = "registry+https://github.com/rust-lang/crates checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" blob - 73b5f8baab3fcb9ebafd8e24c7cab83a9e51feb7 blob + 2f8d72c87940a2bef0ba4e74760e846b48b2cfef --- Cargo.toml +++ Cargo.toml @@ -1,6 +1,7 @@ [package] -name = "rss-mail" +name = "rss-email" version = "0.1.0" +authors = ["witcher "] edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -11,3 +12,5 @@ dotenv = "0.15" rss = "2.0" anyhow = "1.0" reqwest = { version = "0.11", features = ["blocking"] } +clap = "3" +chrono = "0.4" blob - 97fd07066e280a7b36184cd5bf5ac87930dd9b6b blob + 87c7854151cf92a4ad352f7928fdd0ee37909e7b --- migrations/2022-02-22-214045_create_posts/up.sql +++ migrations/2022-02-22-214045_create_posts/up.sql @@ -5,7 +5,7 @@ CREATE TABLE posts ( author TEXT, url TEXT, feedurl TEXT, - pub_date TEXT, + pub_date BIGINT, content TEXT, sent BOOLEAN NOT NULL DEFAULT 0 ) blob - e791b274d0d884818031b67854c71c4a44036760 blob + 4c94182ff2167e7ae6de0ab51f0807c2f2823e0e --- src/db.rs +++ src/db.rs @@ -3,6 +3,7 @@ use diesel::sqlite::SqliteConnection; use dotenv::dotenv; use rss::Item; use std::env; +use chrono::DateTime; use crate::models::NewPost; use crate::schema::posts; @@ -16,13 +17,15 @@ pub fn establish_connection() -> anyhow::Result anyhow::Result { + let time = item.pub_date().map(|date| DateTime::parse_from_rfc2822(date).unwrap().timestamp()); + let new_post = NewPost { guid: item.guid().ok_or(anyhow!("No guid found"))?.value(), title: item.title(), author: item.author(), url: item.link(), feedurl: item.source().map(|s| s.url()), - pub_date: item.pub_date(), + pub_date: time, content: item.content(), }; blob - /dev/null blob + fcda3636a99e5ee3ee6c5684c9d791eda3294123 (mode 644) --- /dev/null +++ src/clap.rs @@ -0,0 +1,16 @@ +use clap::{Arg, Command}; + +pub fn build_app<'a>() -> Command<'a> { + let urls_path = Arg::new("urls_path") + .help("Path to the urls.") + .required(true) + .validator(|p| { + if std::path::Path::new(p).exists() { + Ok(()) + } else { + Err(format!("config file does not exist: {}", p)) + } + }); + + Command::new("rss-email").arg(urls_path) +} blob - 788d431e23f514e3e86b694117cca11daf02a7c5 blob + c6500ad8074f891d843a81b230fd47d60596650f --- src/main.rs +++ src/main.rs @@ -7,19 +7,37 @@ pub mod db; pub mod models; pub mod rss; pub mod schema; +pub mod clap; +use std::fs::File; +use std::io::BufReader; +use std::io::BufRead; + fn main() -> anyhow::Result<()> { use self::diesel::prelude::*; use schema::posts::dsl::*; + let app = clap::build_app(); + let matches = app.get_matches(); + + // positional argument "urls_path" is required to be present + let urls_path = matches.value_of("urls_path").unwrap(); + // urls_path is required to be a present file by clap + let urls = BufReader::new(File::open(urls_path).unwrap()).lines().map(|l| l.unwrap()); + let conn = db::establish_connection()?; - let new = rss::fetch_new("https://wiredspace.de/index.xml")?; - let _ = db::insert_post(&conn, new.items().first().unwrap()); + for u in urls { + let new = rss::fetch_new(u)?; + for i in new.items() { + let _ = db::insert_post(&conn, i)?; + } + } let results = posts .filter(sent.eq(false)) .limit(5) + .order(pub_date.desc()) .load::(&conn)?; dbg!(results); blob - 2f40a58698e68b0fd2d3f16fb97aaed66b9ea4a9 blob + 903f08c6a1557affb789da7f92d7d48750ff8df0 --- src/models.rs +++ src/models.rs @@ -7,7 +7,7 @@ pub struct Post { pub author: Option, pub url: Option, pub feedurl: Option, - pub pub_date: Option, + pub pub_date: Option, pub content: Option, pub sent: bool, } @@ -20,6 +20,6 @@ pub struct NewPost<'a> { pub author: Option<&'a str>, pub url: Option<&'a str>, pub feedurl: Option<&'a str>, - pub pub_date: Option<&'a str>, + pub pub_date: Option, pub content: Option<&'a str>, } blob - a353a599e1ea3bfee7074fe42a3a02b3adc802de blob + f30fc90dc34796b218720eae7dde22c7fde207f9 --- src/schema.rs +++ src/schema.rs @@ -5,7 +5,7 @@ table! { author -> Nullable, url -> Nullable, feedurl -> Nullable, - pub_date -> Nullable, + pub_date -> Nullable, content -> Nullable, sent -> Bool, } blob - /dev/null blob + b96abe1f85a068a3271dc3cf83ff7d2f1193703a (mode 644) --- /dev/null +++ urls @@ -0,0 +1,2 @@ +https://wiredspace.de/index.xml +https://drewdevault.com/blog/index.xml