From 4e939021e0ce4d4e9ac1925cc56046b7a8309eca Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 8 Jan 2024 21:08:38 +0100 Subject: [PATCH 01/43] Create tobooks module file --- src/fetchers/tobooks.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/fetchers/tobooks.rs diff --git a/src/fetchers/tobooks.rs b/src/fetchers/tobooks.rs new file mode 100644 index 0000000..e69de29 From 36b59240d960da77e58518854110b97a24bade96 Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 6 May 2024 20:51:31 +0200 Subject: [PATCH 02/43] Use macros over functions for error logging --- src/bot.rs | 60 ++++++++++++++++++++++++++++++++---------- src/fetchers/jnovel.rs | 24 ++++++++++++----- src/lemmy.rs | 30 ++++++++++++++------- src/post_history.rs | 26 ++++++++++++++++-- 4 files changed, 107 insertions(+), 33 deletions(-) diff --git a/src/bot.rs b/src/bot.rs index eef7e6a..f8fe71d 100644 --- a/src/bot.rs +++ b/src/bot.rs @@ -12,8 +12,34 @@ use std::sync::Arc; use tokio::sync::RwLock; use tokio::time::sleep; use crate::fetchers::Fetcher; +use systemd_journal_logger::connected_to_journal; -pub(crate) async fn run(data: Arc<RwLock<SharedData>>) { +macro_rules! info { + ($msg:tt) => { + match connected_to_journal() { + true => log::info!("[INFO] {}", $msg), + false => println!("[INFO] {}", $msg), + } + }; +} + +macro_rules! warn { + ($msg:tt) => { + match connected_to_journal() { + true => log::warn!("[WARN] {}", $msg), + false => println!("[WARN] {}", $msg), + } + }; +} + +macro_rules! error { + ($msg:tt) => { + match connected_to_journal() { + true => log::error!("[ERROR] {}", $msg), + false => eprintln!("[ERROR] {}", $msg), + } + }; +} let mut last_reload: DateTime<Utc>; let mut lemmy: Lemmy; let mut login_error: bool; @@ -47,7 +73,7 @@ pub(crate) async fn run(data: Arc<RwLock<SharedData>>) { } let info_msg = "Bot init successful, starting normal operations".to_owned(); - write_info(info_msg); + info!(info_msg); loop { idle(&data).await; @@ -56,8 +82,8 @@ pub(crate) async fn run(data: Arc<RwLock<SharedData>>) { let mut write = data.write().await; write.start = Utc::now(); - - if write.start - last_reload >= Duration::seconds(write.config.config_reload_seconds as i64) { + let message = "Config reloaded".to_owned(); + info!(message); write.config = Config::load(); let message = "Config reloaded".to_owned(); write_info(message); @@ -65,9 +91,9 @@ pub(crate) async fn run(data: Arc<RwLock<SharedData>>) { } { - let read = data.read().await; - if login_error { - lemmy = match lemmy::login(&read.config).await { + let info_msg = "Login invalid, refreshing session"; + info!(info_msg); + lemmy = match lemmy::login(&config).await { Ok(data) => data, Err(_) => continue, }; @@ -83,9 +109,9 @@ pub(crate) async fn run(data: Arc<RwLock<SharedData>>) { Err(_) => { login_error = true; continue; - } - }; - let message = "Communities reloaded".to_owned(); + let message = "Communities reloaded".to_owned(); + info!(message); + last_reload = Utc::now(); write_info(message); last_reload = Utc::now(); } @@ -127,7 +153,7 @@ async fn idle(data: &Arc<RwLock<SharedData>>) { Ok(_) => {} Err(e) => { let err_msg = format!("{e}"); - write_error(err_msg); + error!(err_msg); } } }; @@ -143,6 +169,11 @@ async fn handle_series(series: &SeriesConfig, communities: &HashMap<String, Comm Ok(data) => data, Err(_) => return Err(()), }; + + if post_list.is_empty() && Utc::now().minute() % 10 == 0 { + let info_msg = "No Updates found"; + info!(info_msg); + } for post_info in post_list.clone().iter() { // todo .clone() likely not needed @@ -190,7 +221,7 @@ async fn handle_series(series: &SeriesConfig, communities: &HashMap<String, Comm post_lemmy_info.title.as_str(), post_series_config.name.as_str() ); - write_info(info); + info!(info); let post_id = lemmy.post(post_data).await?; { @@ -199,7 +230,7 @@ async fn handle_series(series: &SeriesConfig, communities: &HashMap<String, Comm && !read .config .protected_communities - .contains(&post_series_config.name) + info!(info); { let info = format!( "Pinning '{}' to {}", @@ -226,12 +257,13 @@ async fn handle_series(series: &SeriesConfig, communities: &HashMap<String, Comm ); write_warn(message); } + warn!(message); } let read = data.read().await; if post_series_config.pin_settings.pin_new_post_local { let info = format!("Pinning '{}' to Instance", post_lemmy_info.title); - write_info(info); + info!(info); let pinned_posts = lemmy.get_local_pinned().await?; if !pinned_posts.is_empty() { for pinned_post in pinned_posts { diff --git a/src/fetchers/jnovel.rs b/src/fetchers/jnovel.rs index 6bebc7d..f24d018 100644 --- a/src/fetchers/jnovel.rs +++ b/src/fetchers/jnovel.rs @@ -1,4 +1,4 @@ -use crate::{write_error, HTTP_CLIENT, lemmy}; +use crate::{HTTP_CLIENT, lemmy}; use chrono::{DateTime, Duration, Utc}; use serde_derive::{Deserialize, Serialize}; use std::cmp::Ordering; @@ -10,6 +10,16 @@ use crate::fetchers::Fetcher; use crate::fetchers::jnovel::JPostInfo::{Chapter, Volume}; use crate::fetchers::jnovel::PartInfo::{NoParts, Part}; use crate::lemmy::{PostInfo, PostInfoInner}; +use systemd_journal_logger::connected_to_journal; + +macro_rules! error { + ($msg:tt) => { + match connected_to_journal() { + true => log::error!("[ERROR] {}", $msg), + false => eprintln!("[ERROR] {}", $msg), + } + }; +} static PAST_DAYS_ELIGIBLE: u8 = 4; @@ -266,13 +276,13 @@ impl Fetcher for JFetcherOptions { Ok(data) => data, Err(e) => { let err_msg = format!("{e}"); - write_error(err_msg); + error!(err_msg); return Err(()); } }, Err(e) => { let err_msg = format!("{e}"); - write_error(err_msg); + error!(err_msg); return Err(()); } }; @@ -281,7 +291,7 @@ impl Fetcher for JFetcherOptions { Ok(data) => data, Err(e) => { let err_msg = format!("{e}"); - write_error(err_msg); + error!(err_msg); return Err(()); } }; @@ -392,13 +402,13 @@ async fn get_latest_prepub(volume_slug: &str) -> Result<Option<lemmy::PostInfoIn Ok(data) => data, Err(e) => { let err_msg = format!("{e}"); - write_error(err_msg); + error!(err_msg); return Err(()); } }, Err(e) => { let err_msg = format!("{e}"); - write_error(err_msg); + error!(err_msg); return Err(()); } }; @@ -407,7 +417,7 @@ async fn get_latest_prepub(volume_slug: &str) -> Result<Option<lemmy::PostInfoIn Ok(data) => data, Err(e) => { let err_msg = format!("{e}"); - write_error(err_msg); + error!(err_msg); return Err(()); } }; diff --git a/src/lemmy.rs b/src/lemmy.rs index a07b901..df6d61a 100644 --- a/src/lemmy.rs +++ b/src/lemmy.rs @@ -1,5 +1,5 @@ use crate::config::Config; -use crate::{write_error, HTTP_CLIENT}; +use crate::{HTTP_CLIENT}; use lemmy_api_common::community::{ListCommunities, ListCommunitiesResponse}; use lemmy_api_common::lemmy_db_views::structs::PostView; use lemmy_api_common::person::{Login, LoginResponse}; @@ -10,6 +10,16 @@ use lemmy_db_schema::{ListingType, PostFeatureType}; use reqwest::StatusCode; use std::collections::HashMap; use url::Url; +use systemd_journal_logger::connected_to_journal; + +macro_rules! error { + ($msg:tt) => { + match connected_to_journal() { + true => log::error!("[ERROR] {}", $msg), + false => eprintln!("[ERROR] {}", $msg), + } + }; +} pub(crate) struct Lemmy { jwt_token: Sensitive<String>, @@ -45,7 +55,7 @@ pub(crate) async fn login(config: &Config) -> Result<Lemmy, ()> { Ok(data) => data, Err(e) => { let err_msg = format!("{e}"); - write_error(err_msg); + error!(err_msg); return Err(()); } }; @@ -63,14 +73,14 @@ pub(crate) async fn login(config: &Config) -> Result<Lemmy, ()> { }), None => { let err_msg = "Login did not return JWT token. Are the credentials valid?".to_owned(); - write_error(err_msg); + error!(err_msg); Err(()) } } } status => { let err_msg = format!("Unexpected HTTP Status '{}' during Login", status); - write_error(err_msg); + error!(err_msg); Err(()) } } @@ -273,14 +283,14 @@ impl Lemmy { Ok(data) => data, Err(e) => { let err_msg = format!("{e}"); - write_error(err_msg); - return Err(()); + error!(err_msg); + Err(()) } }, Err(e) => { let err_msg = format!("{e}"); - write_error(err_msg); - return Err(()); + error!(err_msg); + Err(()) } }; @@ -288,8 +298,8 @@ impl Lemmy { Ok(data) => data, Err(e) => { let err_msg = format!("{e}"); - write_error(err_msg); - return Err(()); + error!(err_msg); + Err(()) } }; diff --git a/src/post_history.rs b/src/post_history.rs index 5e3b57e..71499b8 100644 --- a/src/post_history.rs +++ b/src/post_history.rs @@ -1,6 +1,24 @@ -use crate::write_error; use serde_derive::{Deserialize, Serialize}; use std::collections::HashMap; +use systemd_journal_logger::connected_to_journal; + +macro_rules! info { + ($msg:tt) => { + match connected_to_journal() { + true => log::info!("[INFO] {}", $msg), + false => println!("[INFO] {}", $msg), + } + }; +} + +macro_rules! error { + ($msg:tt) => { + match connected_to_journal() { + true => log::error!("[ERROR] {}", $msg), + false => eprintln!("[ERROR] {}", $msg), + } + }; +} #[derive(Serialize, Deserialize, Default, Clone, Debug)] pub(crate) struct SeriesHistory { @@ -9,6 +27,8 @@ pub(crate) struct SeriesHistory { impl SeriesHistory { pub(crate) fn load_history() -> Self { + let info_msg = "Loading History"; + info!(info_msg); match confy::load(env!("CARGO_PKG_NAME"), "history") { Ok(data) => data, Err(e) => panic!("history.toml not found: {e}"), @@ -16,9 +36,11 @@ impl SeriesHistory { } pub(crate) fn save_history(&self) { + let info_msg = "Saving History"; + info!(info_msg); if let Err(e) = confy::store(env!("CARGO_PKG_NAME"), "history", self) { let err_msg = format!("Unexpected error saving to history.toml: {e}"); - write_error(err_msg); + error!(err_msg); } } From 962d90fe1d7c891ecd4a0182256636fbae724035 Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 6 May 2024 20:53:38 +0200 Subject: [PATCH 03/43] Remove unnecessary thread structure --- src/bot.rs | 218 +++++++++++++++++++++------------------------------- src/main.rs | 82 +------------------- 2 files changed, 92 insertions(+), 208 deletions(-) diff --git a/src/bot.rs b/src/bot.rs index f8fe71d..7916920 100644 --- a/src/bot.rs +++ b/src/bot.rs @@ -1,15 +1,12 @@ -use crate::config::{Config, PostBody, SeriesConfig}; +use crate::{config::{Config, PostBody, SeriesConfig}, fetchers::{jnovel}, lemmy}; use crate::fetchers::jnovel::JPostInfo; use crate::lemmy::{Lemmy, PostInfo}; use crate::post_history::SeriesHistory; -use crate::{fetchers::{jnovel}, lemmy, write_error, write_info, write_warn, SharedData}; -use chrono::{DateTime, Duration, Utc}; +use chrono::{DateTime, Duration, Timelike, Utc}; use lemmy_api_common::post::CreatePost; use lemmy_db_schema::newtypes::{CommunityId, LanguageId}; use lemmy_db_schema::PostFeatureType; use std::collections::HashMap; -use std::sync::Arc; -use tokio::sync::RwLock; use tokio::time::sleep; use crate::fetchers::Fetcher; use systemd_journal_logger::connected_to_journal; @@ -40,115 +37,91 @@ macro_rules! error { } }; } + +pub(crate) async fn run() { let mut last_reload: DateTime<Utc>; let mut lemmy: Lemmy; let mut login_error: bool; - let mut communities; - { - let mut write = data.write().await; + let mut communities: HashMap<String, CommunityId>; + let mut post_history: SeriesHistory; + let mut start: DateTime<Utc>; + let mut config: Config = Config::load(); + last_reload = Utc::now(); - // Errors during bot init are likely unrecoverable and therefore should panic the bot - // Does not really matter since the bot will get restarted anyway but this way the uptime url logs a downtime - write.config = Config::load(); - last_reload = Utc::now(); - } + lemmy = match lemmy::login(&config).await { + Ok(data) => data, + Err(_) => panic!(), + }; + login_error = false; - { - let read = data.read().await; - lemmy = match lemmy::login(&read.config).await { - Ok(data) => data, - Err(_) => panic!(), - }; - login_error = false; + communities = match lemmy.get_communities().await { + Ok(data) => data, + Err(_) => panic!(), + }; - communities = match lemmy.get_communities().await { - Ok(data) => data, - Err(_) => panic!(), - }; - } - - { - let mut write = data.write().await; - write.start = Utc::now(); - } + start = Utc::now(); let info_msg = "Bot init successful, starting normal operations".to_owned(); info!(info_msg); loop { - idle(&data).await; + idle(&start, &config).await; + start = Utc::now(); - { - let mut write = data.write().await; - - write.start = Utc::now(); + // replace with watcher + if start - last_reload >= Duration::seconds(config.config_reload_seconds as i64) { + config = Config::load(); let message = "Config reloaded".to_owned(); info!(message); - write.config = Config::load(); - let message = "Config reloaded".to_owned(); - write_info(message); - } } - { + if login_error { let info_msg = "Login invalid, refreshing session"; info!(info_msg); lemmy = match lemmy::login(&config).await { - Ok(data) => data, - Err(_) => continue, - }; - login_error = false; - } + Ok(data) => data, + Err(_) => continue, + }; + login_error = false; } - { - let read = data.read().await; - if read.start - last_reload >= Duration::seconds(read.config.config_reload_seconds as i64) { - communities = match lemmy.get_communities().await { - Ok(data) => data, - Err(_) => { - login_error = true; - continue; + if start - last_reload >= Duration::seconds(config.config_reload_seconds as i64) { + communities = match lemmy.get_communities().await { + Ok(data) => data, + Err(_) => { + login_error = true; + continue; + } + }; let message = "Communities reloaded".to_owned(); info!(message); last_reload = Utc::now(); - write_info(message); - last_reload = Utc::now(); - } } - { - let mut write = data.write().await; - write.post_history = SeriesHistory::load_history(); + post_history = SeriesHistory::load_history(); + + let series = config.series.clone(); + for series in series { + if handle_series(&series, &communities, &lemmy, &config, &mut post_history) + .await + .is_err() + { + login_error = true; + continue; + }; } - { - let read = data.read().await; - let series = read.config.series.clone(); - drop(read); - for series in series { - if handle_series(&series, &communities, &lemmy, &data) - .await - .is_err() - { - login_error = true; - continue; - }; - } - } - - idle(&data).await; + idle(&start, &config).await; } } -async fn idle(data: &Arc<RwLock<SharedData>>) { - let read = data.read().await; +async fn idle(start: &DateTime<Utc>, config: &Config) { let mut sleep_duration = Duration::seconds(30); - if Utc::now() - read.start > sleep_duration { + if Utc::now() - start > sleep_duration { sleep_duration = Duration::seconds(60); } - if let Some(status_url) = read.config.status_post_url.clone() { + if let Some(status_url) = config.status_post_url.clone() { match reqwest::get(status_url).await { Ok(_) => {} Err(e) => { @@ -158,12 +131,12 @@ async fn idle(data: &Arc<RwLock<SharedData>>) { } }; - while Utc::now() - read.start < sleep_duration { + while Utc::now() - start < sleep_duration { sleep(Duration::milliseconds(100).to_std().unwrap()).await; } } -async fn handle_series(series: &SeriesConfig, communities: &HashMap<String, CommunityId>, lemmy: &Lemmy, data: &Arc<RwLock<SharedData>>) -> Result<(), ()> { +async fn handle_series(series: &SeriesConfig, communities: &HashMap<String, CommunityId>, lemmy: &Lemmy, config: &Config, post_history: &mut SeriesHistory ) -> Result<(), ()> { let jnc = jnovel::JFetcherOptions::new(series.slug.clone(), series.parted); let post_list = match jnc.check_feed().await { Ok(data) => data, @@ -176,19 +149,15 @@ async fn handle_series(series: &SeriesConfig, communities: &HashMap<String, Comm } for post_info in post_list.clone().iter() { - // todo .clone() likely not needed let post_part_info = post_info.get_part_info(); let post_lemmy_info = post_info.get_info(); - { - let read = data.read().await; - if read.post_history.check_for_post( - series.slug.as_str(), - post_part_info.as_string().as_str(), - post_lemmy_info.title.as_str(), - ) { - continue; - } + if post_history.check_for_post( + series.slug.as_str(), + post_part_info.as_string().as_str(), + post_lemmy_info.title.as_str(), + ) { + continue; } let post_series_config = match post_info { @@ -224,51 +193,43 @@ async fn handle_series(series: &SeriesConfig, communities: &HashMap<String, Comm info!(info); let post_id = lemmy.post(post_data).await?; + if post_series_config.pin_settings.pin_new_post_community + && config + .protected_communities + .contains(&post_series_config.name) { - let read = data.read().await; - if post_series_config.pin_settings.pin_new_post_community - && !read - .config - .protected_communities + let info = format!( + "Pinning '{}' to {}", + post_lemmy_info.title, + post_series_config.name.as_str() + ); info!(info); - { - let info = format!( - "Pinning '{}' to {}", - post_lemmy_info.title, - post_series_config.name.as_str() - ); - write_info(info); - let pinned_posts = lemmy.get_community_pinned(community_id).await?; - if !pinned_posts.is_empty() { - let community_pinned_post = &pinned_posts[0]; - lemmy - .unpin(community_pinned_post.post.id, PostFeatureType::Community) - .await?; - } - lemmy.pin(post_id, PostFeatureType::Community).await?; - } else if read - .config - .protected_communities - .contains(&post_series_config.name) - { - let message = format!( - "Community '{}' for Series '{}' is protected. Is this intended?", - &post_series_config.name, series.slug - ); - write_warn(message); + let pinned_posts = lemmy.get_community_pinned(community_id).await?; + if !pinned_posts.is_empty() { + let community_pinned_post = &pinned_posts[0]; + lemmy + .unpin(community_pinned_post.post.id, PostFeatureType::Community) + .await?; } + lemmy.pin(post_id, PostFeatureType::Community).await?; + } else if config + .protected_communities + .contains(&post_series_config.name) + { + let message = format!( + "Community '{}' for Series '{}' is protected. Is this intended?", + &post_series_config.name, series.slug + ); warn!(message); } - let read = data.read().await; if post_series_config.pin_settings.pin_new_post_local { let info = format!("Pinning '{}' to Instance", post_lemmy_info.title); info!(info); let pinned_posts = lemmy.get_local_pinned().await?; if !pinned_posts.is_empty() { for pinned_post in pinned_posts { - if read - .config + if config .protected_communities .contains(&pinned_post.community.name) { @@ -285,9 +246,8 @@ async fn handle_series(series: &SeriesConfig, communities: &HashMap<String, Comm lemmy.pin(post_id, PostFeatureType::Local).await?; } - let mut series_history = read.post_history.get_series(series.slug.as_str()); + let mut series_history = post_history.get_series(series.slug.as_str()); let mut part_history = series_history.get_part(post_part_info.as_string().as_str()); - drop(read); match post_info { JPostInfo::Chapter { .. } => part_history.chapter = post_info.get_info().title, @@ -295,11 +255,9 @@ async fn handle_series(series: &SeriesConfig, communities: &HashMap<String, Comm } series_history.set_part(post_part_info.as_string().as_str(), part_history); - let mut write = data.write().await; - write - .post_history + post_history .set_series(series.slug.as_str(), series_history); - write.post_history.save_history(); + post_history.save_history(); } Ok(()) } diff --git a/src/main.rs b/src/main.rs index 6e077df..880e658 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,9 @@ -use crate::config::Config; -use crate::post_history::SeriesHistory; -use chrono::{DateTime, Duration, Utc}; -use log::{error, info, warn, LevelFilter}; +use chrono::{Duration}; +use log::{LevelFilter}; use once_cell::sync::Lazy; use reqwest::Client; -use std::collections::HashMap; use std::fmt::Debug; -use std::sync::Arc; -use systemd_journal_logger::{connected_to_journal, JournalLog}; -use tokio::sync::RwLock; -use tokio::time::sleep; +use systemd_journal_logger::{JournalLog}; mod bot; mod config; @@ -17,27 +11,6 @@ mod lemmy; mod post_history; mod fetchers; -pub(crate) fn write_error(err_msg: String) { - match connected_to_journal() { - true => error!("[ERROR] {err_msg}"), - false => println!("[ERROR] {err_msg}"), - } -} - -pub(crate) fn write_warn(warn_msg: String) { - match connected_to_journal() { - true => warn!("[WARN] {warn_msg}"), - false => println!("[WARN] {warn_msg}"), - } -} - -pub(crate) fn write_info(info_msg: String) { - match connected_to_journal() { - true => info!("[INFO] {info_msg}"), - false => println!("[INFO] {info_msg}"), - } -} - pub static HTTP_CLIENT: Lazy<Client> = Lazy::new(|| { Client::builder() .timeout(Duration::seconds(30).to_std().unwrap()) @@ -46,25 +19,6 @@ pub static HTTP_CLIENT: Lazy<Client> = Lazy::new(|| { .expect("build client") }); -#[derive(Clone, Debug)] -pub(crate) struct SharedData { - config: Config, - post_history: SeriesHistory, - start: DateTime<Utc>, -} - -impl SharedData { - pub(crate) fn new() -> Self { - SharedData { - config: Config::default(), - post_history: SeriesHistory { - series: HashMap::new(), - }, - start: Utc::now(), - } - } -} - #[tokio::main] async fn main() { JournalLog::new() @@ -72,33 +26,5 @@ async fn main() { .install() .expect("Systemd-Logger crate error"); log::set_max_level(LevelFilter::Info); - - let mut data = SharedData::new(); - - loop { - let write_data = Arc::new(RwLock::new(data.clone())); - //let read_data = write_data.clone(); - let persistent_data = write_data.clone(); - - let bot_thread = tokio::spawn(async move { bot::run(write_data).await }); - - let _ = bot_thread.await; - - data = persistent_data.read().await.clone(); - - { - let err_msg = "Bot crashed due to unknown Error, restarting thread after wait..."; - match connected_to_journal() { - true => error!("[ERROR] {err_msg}"), - false => println!("[ERROR] {err_msg}"), - } - } - - sleep( - Duration::seconds(5) - .to_std() - .expect("Conversion should always work since static"), - ) - .await; - } + bot::run().await; } From c8d7053b87089055060a393b35c2abdb3124aede Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 6 May 2024 20:53:50 +0200 Subject: [PATCH 04/43] De-duplicate Code --- src/lemmy.rs | 176 ++++++++++++++------------------------------------- 1 file changed, 49 insertions(+), 127 deletions(-) diff --git a/src/lemmy.rs b/src/lemmy.rs index df6d61a..5d250e7 100644 --- a/src/lemmy.rs +++ b/src/lemmy.rs @@ -9,6 +9,7 @@ use lemmy_db_schema::newtypes::{CommunityId, PostId}; use lemmy_db_schema::{ListingType, PostFeatureType}; use reqwest::StatusCode; use std::collections::HashMap; +use serde::{Deserialize, Serialize}; use url::Url; use systemd_journal_logger::connected_to_journal; @@ -88,68 +89,21 @@ pub(crate) async fn login(config: &Config) -> Result<Lemmy, ()> { impl Lemmy { pub(crate) async fn post(&self, post: CreatePost) -> Result<PostId, ()> { - let response = match HTTP_CLIENT - .post(format!("{}/api/v3/post", &self.instance)) - .bearer_auth(&self.jwt_token.to_string()) - .json(&post) - .send() - .await - { - Ok(data) => match data.text().await { - Ok(data) => data, - Err(e) => { - let err_msg = format!("{e}"); - write_error(err_msg); - return Err(()); - } - }, - Err(e) => { - let err_msg = format!("{e}"); - write_error(err_msg); - return Err(()); - } - }; + let response = self.fetch_data_json("/api/v3/post", &post).await?; - let json_data = match serde_json::from_str::<HashMap<&str, PostView>>(&response) { - Ok(mut data) => data.remove("post_view").expect("Element should be present"), - Err(e) => { - let err_msg = format!("{e}"); - write_error(err_msg); - return Err(()); - } - }; + let json_data: PostView = self.parse_json(&response).await?; Ok(json_data.post.id) } async fn feature(&self, params: FeaturePost) -> Result<PostView, ()> { - let response = match HTTP_CLIENT - .post(format!("{}/api/v3/post/feature", &self.instance)) - .bearer_auth(&self.jwt_token.to_string()) - .json(¶ms) - .send() - .await - { - Ok(data) => match data.text().await { - Ok(data) => data, - Err(e) => { - let err_msg = format!("{e}"); - write_error(err_msg); - return Err(()); - } - }, - Err(e) => { - let err_msg = format!("{e}"); - write_error(err_msg); - return Err(()); - } - }; + let response = self.fetch_data_json("/api/v3/post/feature", ¶ms).await?; let json_data = match serde_json::from_str::<HashMap<&str, PostView>>(&response) { Ok(mut data) => data.remove("post_view").expect("Element should be present"), Err(e) => { let err_msg = format!("{e}"); - write_error(err_msg); + error!(err_msg); return Err(()); } }; @@ -182,36 +136,9 @@ impl Lemmy { ..Default::default() }; - let response = match HTTP_CLIENT - .get(format!("{}/api/v3/post/list", &self.instance)) - .bearer_auth(&self.jwt_token.to_string()) - .query(&list_params) - .send() - .await - { - Ok(data) => match data.text().await { - Ok(data) => data, - Err(e) => { - let err_msg = format!("{e}"); - write_error(err_msg); - return Err(()); - } - }, - Err(e) => { - let err_msg = format!("{e}"); - write_error(err_msg); - return Err(()); - } - }; + let response = self.fetch_data_query("/api/v3/post/list", &list_params).await?; - let json_data: GetPostsResponse = match serde_json::from_str(&response) { - Ok(data) => data, - Err(e) => { - let err_msg = format!("{e}"); - write_error(err_msg); - return Err(()); - } - }; + let json_data: GetPostsResponse = self.parse_json(&response).await?; Ok(json_data .posts @@ -227,36 +154,9 @@ impl Lemmy { ..Default::default() }; - let response = match HTTP_CLIENT - .get(format!("{}/api/v3/post/list", &self.instance)) - .bearer_auth(&self.jwt_token.to_string()) - .query(&list_params) - .send() - .await - { - Ok(data) => match data.text().await { - Ok(data) => data, - Err(e) => { - let err_msg = format!("{e}"); - write_error(err_msg); - return Err(()); - } - }, - Err(e) => { - let err_msg = format!("{e}"); - write_error(err_msg); - return Err(()); - } - }; + let response = self.fetch_data_query("/api/v3/post/list", &list_params).await?; - let json_data: GetPostsResponse = match serde_json::from_str(&response) { - Ok(data) => data, - Err(e) => { - let err_msg = format!("{e}"); - write_error(err_msg); - return Err(()); - } - }; + let json_data: GetPostsResponse = self.parse_json(&response).await?; Ok(json_data .posts @@ -272,15 +172,43 @@ impl Lemmy { ..Default::default() }; - let response = match HTTP_CLIENT - .get(format!("{}/api/v3/community/list", &self.instance)) + let response = self.fetch_data_query("/api/v3/community/list", &list_params).await?; + + let json_data: ListCommunitiesResponse = self.parse_json(&response).await?; + + let mut communities: HashMap<String, CommunityId> = HashMap::new(); + for community_view in json_data.communities { + let community = community_view.community; + communities.insert(community.name, community.id); + } + + Ok(communities) + } + + async fn fetch_data_json<T: Serialize>(&self, route: &str, json: &T ) -> Result<String,()> { + let res = HTTP_CLIENT + .post(format!("{}{route}", self.instance)) .bearer_auth(&self.jwt_token.to_string()) - .query(&list_params) + .json(&json) .send() - .await - { + .await; + self.extract_data(res).await + } + + async fn fetch_data_query<T: Serialize>(&self, route: &str, json: &T ) -> Result<String,()> { + let res = HTTP_CLIENT + .post(format!("{}{route}", self.instance)) + .bearer_auth(&self.jwt_token.to_string()) + .query(&json) + .send() + .await; + self.extract_data(res).await + } + + async fn extract_data(&self, response: Result<reqwest::Response, reqwest::Error>) -> Result<String,()> { + match response { Ok(data) => match data.text().await { - Ok(data) => data, + Ok(data) => Ok(data), Err(e) => { let err_msg = format!("{e}"); error!(err_msg); @@ -292,23 +220,17 @@ impl Lemmy { error!(err_msg); Err(()) } - }; - - let json_data: ListCommunitiesResponse = match serde_json::from_str(&response) { - Ok(data) => data, + } + } + + async fn parse_json<'a, T: Deserialize<'a>>(&self, response: &'a str) -> Result<T,()> { + match serde_json::from_str::<HashMap<&str, T>>(response) { + Ok(mut data) => Ok(data.remove("post_view").expect("Element should be present")), Err(e) => { let err_msg = format!("{e}"); error!(err_msg); Err(()) } - }; - - let mut communities: HashMap<String, CommunityId> = HashMap::new(); - for community_view in json_data.communities { - let community = community_view.community; - communities.insert(community.name, community.id); } - - Ok(communities) } } From d50bf01db6be8aa4f8a9f76ca69dd563a35c3ff8 Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 6 May 2024 20:55:30 +0200 Subject: [PATCH 05/43] Fix erroneous print statement to use logger --- src/fetchers/jnovel.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/fetchers/jnovel.rs b/src/fetchers/jnovel.rs index f24d018..83ac5ff 100644 --- a/src/fetchers/jnovel.rs +++ b/src/fetchers/jnovel.rs @@ -21,6 +21,15 @@ macro_rules! error { }; } +macro_rules! info { + ($msg:tt) => { + match connected_to_journal() { + true => log::info!("[INFO] {}", $msg), + false => println!("[INFO] {}", $msg), + } + }; +} + static PAST_DAYS_ELIGIBLE: u8 = 4; macro_rules! api_url { @@ -328,7 +337,7 @@ impl Fetcher for JFetcherOptions { match part_number { Some(number) => new_part_info = Part(number), None => { - println!("No Part found, assuming 1"); + info!("No Part found, assuming 1"); new_part_info = Part(1); } } From 85f3044224fcfcb9ef6bfdcdfd8c1f6d8193b755 Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 6 May 2024 20:55:48 +0200 Subject: [PATCH 06/43] Lemmy API Crate bump --- Cargo.lock | 20 ++++++++++---------- Cargo.toml | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1a765e1..c691268 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -618,9 +618,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lemmy_api_common" -version = "0.19.1" +version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bed97d80c606745807e7a41d2e7a54912e6dc73b17f847453717cfa1e6693b31" +checksum = "17366fcde90b07f4e5a8fefa62378fe348424ba79c8e9fb3ddc63ef76d687493" dependencies = [ "chrono", "enum-map", @@ -637,9 +637,9 @@ dependencies = [ [[package]] name = "lemmy_db_schema" -version = "0.19.1" +version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a17c613a84befef3daadc179e2069e02848b83dfd80d7955ca825bdca92869b" +checksum = "5e2d9a0c6f8f3df4664f9479ceca138ee6217b89653bafb753a498cabc5f3ab5" dependencies = [ "async-trait", "chrono", @@ -656,9 +656,9 @@ dependencies = [ [[package]] name = "lemmy_db_views" -version = "0.19.1" +version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e360aaee508cb057c6df0160b27aeb8b845a3725127b2d7e4e4c877397418539" +checksum = "02659eb474ab54da6296d4edb5a974c0affa5cfcf8a2fa31bb52793dedef9d5a" dependencies = [ "lemmy_db_schema", "serde", @@ -667,9 +667,9 @@ dependencies = [ [[package]] name = "lemmy_db_views_actor" -version = "0.19.1" +version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "606962be1df35bf9214a22cea819cec181ecd4e71dfe693b92428291b69a7cd6" +checksum = "5187730858dc808b5cf06aadbb1d1f8ca360d4ed3c375e5606e63be4c9e24e06" dependencies = [ "chrono", "lemmy_db_schema", @@ -681,9 +681,9 @@ dependencies = [ [[package]] name = "lemmy_db_views_moderator" -version = "0.19.1" +version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e64669a695c855143be2a9d4a662d481d235d7470621793db0607f60190be80" +checksum = "18f6fab36e1dcadc043b81c5916044ee65219d837f5d221a908296f9c55f3872" dependencies = [ "lemmy_db_schema", "serde", diff --git a/Cargo.toml b/Cargo.toml index 3bab39f..2001f73 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,8 +17,8 @@ systemd-units = { enable = false } [dependencies] chrono = "^0.4.26" -lemmy_api_common = "0.19.1" -lemmy_db_schema = "0.19.1" +lemmy_api_common = "0.19.3" +lemmy_db_schema = "0.19.3" once_cell = "^1.18.0" reqwest = { version = "^0.11.18", features = ["blocking", "json"] } serde = "^1.0.164" From fc4ce74567d493a2ed5a4edb39b8dd60ca73747e Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 6 May 2024 21:00:55 +0200 Subject: [PATCH 07/43] Clippy changes --- src/fetchers/mod.rs | 1 - src/main.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/fetchers/mod.rs b/src/fetchers/mod.rs index fd143fb..126aeb2 100644 --- a/src/fetchers/mod.rs +++ b/src/fetchers/mod.rs @@ -1,7 +1,6 @@ use async_trait::async_trait; pub mod jnovel; -mod tobooks; #[async_trait] pub(crate) trait Fetcher { diff --git a/src/main.rs b/src/main.rs index 880e658..fc93d6a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,6 @@ use chrono::{Duration}; use log::{LevelFilter}; use once_cell::sync::Lazy; use reqwest::Client; -use std::fmt::Debug; use systemd_journal_logger::{JournalLog}; mod bot; From 34b3bb45c5206373ab7cca61d705a484863f2c1d Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 6 May 2024 21:06:17 +0200 Subject: [PATCH 08/43] Release 2.2.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c691268..ebc0f89 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,7 +43,7 @@ dependencies = [ [[package]] name = "aob-lemmy-bot" -version = "2.2.0" +version = "2.2.1" dependencies = [ "async-trait", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 2001f73..439f50f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Neshura"] name = "aob-lemmy-bot" -version = "2.2.0" +version = "2.2.1" edition = "2021" description = "Bot for automatically posting new chapters of 'Ascendance of a Bookworm' released by J-Novel Club" license = "GPL-3.0-or-later" From 45bfca8cc561bd382612f9a6ad55e166c95abeaf Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 6 May 2024 21:16:53 +0200 Subject: [PATCH 09/43] Bugfix due to bad deduplication --- src/lemmy.rs | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/src/lemmy.rs b/src/lemmy.rs index 5d250e7..e3a1f56 100644 --- a/src/lemmy.rs +++ b/src/lemmy.rs @@ -89,24 +89,15 @@ pub(crate) async fn login(config: &Config) -> Result<Lemmy, ()> { impl Lemmy { pub(crate) async fn post(&self, post: CreatePost) -> Result<PostId, ()> { - let response = self.fetch_data_json("/api/v3/post", &post).await?; - + let response: String = self.post_data_json("/api/v3/post", &post).await?; let json_data: PostView = self.parse_json(&response).await?; Ok(json_data.post.id) } async fn feature(&self, params: FeaturePost) -> Result<PostView, ()> { - let response = self.fetch_data_json("/api/v3/post/feature", ¶ms).await?; - - let json_data = match serde_json::from_str::<HashMap<&str, PostView>>(&response) { - Ok(mut data) => data.remove("post_view").expect("Element should be present"), - Err(e) => { - let err_msg = format!("{e}"); - error!(err_msg); - return Err(()); - } - }; + let response: String = self.post_data_json("/api/v3/post/feature", ¶ms).await?; + let json_data: PostView = self.parse_json(&response).await?; Ok(json_data) } @@ -136,8 +127,7 @@ impl Lemmy { ..Default::default() }; - let response = self.fetch_data_query("/api/v3/post/list", &list_params).await?; - + let response: String = self.get_data_query("/api/v3/post/list", &list_params).await?; let json_data: GetPostsResponse = self.parse_json(&response).await?; Ok(json_data @@ -154,8 +144,7 @@ impl Lemmy { ..Default::default() }; - let response = self.fetch_data_query("/api/v3/post/list", &list_params).await?; - + let response: String = self.get_data_query("/api/v3/post/list", &list_params).await?; let json_data: GetPostsResponse = self.parse_json(&response).await?; Ok(json_data @@ -172,8 +161,7 @@ impl Lemmy { ..Default::default() }; - let response = self.fetch_data_query("/api/v3/community/list", &list_params).await?; - + let response: String = self.get_data_query("/api/v3/community/list", &list_params).await?; let json_data: ListCommunitiesResponse = self.parse_json(&response).await?; let mut communities: HashMap<String, CommunityId> = HashMap::new(); @@ -185,9 +173,9 @@ impl Lemmy { Ok(communities) } - async fn fetch_data_json<T: Serialize>(&self, route: &str, json: &T ) -> Result<String,()> { + async fn post_data_json<T: Serialize>(&self, route: &str, json: &T ) -> Result<String,()> { let res = HTTP_CLIENT - .post(format!("{}{route}", self.instance)) + .post(format!("{}{route}", &self.instance)) .bearer_auth(&self.jwt_token.to_string()) .json(&json) .send() @@ -195,11 +183,11 @@ impl Lemmy { self.extract_data(res).await } - async fn fetch_data_query<T: Serialize>(&self, route: &str, json: &T ) -> Result<String,()> { + async fn get_data_query<T: Serialize>(&self, route: &str, param: &T ) -> Result<String,()> { let res = HTTP_CLIENT - .post(format!("{}{route}", self.instance)) + .get(format!("{}{route}", &self.instance)) .bearer_auth(&self.jwt_token.to_string()) - .query(&json) + .query(¶m) .send() .await; self.extract_data(res).await From 534a8022a9153898cfe2008962af2142c4f76478 Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 6 May 2024 21:17:08 +0200 Subject: [PATCH 10/43] Release 2.2.2 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ebc0f89..337a7ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,7 +43,7 @@ dependencies = [ [[package]] name = "aob-lemmy-bot" -version = "2.2.1" +version = "2.2.2" dependencies = [ "async-trait", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 439f50f..5a43675 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Neshura"] name = "aob-lemmy-bot" -version = "2.2.1" +version = "2.2.2" edition = "2021" description = "Bot for automatically posting new chapters of 'Ascendance of a Bookworm' released by J-Novel Club" license = "GPL-3.0-or-later" From 2dc695577e251bf852d73d1acf7fc0287e65424c Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 6 May 2024 21:27:47 +0200 Subject: [PATCH 11/43] Further Bugfixing --- src/lemmy.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/lemmy.rs b/src/lemmy.rs index e3a1f56..e9c0ad8 100644 --- a/src/lemmy.rs +++ b/src/lemmy.rs @@ -90,14 +90,14 @@ pub(crate) async fn login(config: &Config) -> Result<Lemmy, ()> { impl Lemmy { pub(crate) async fn post(&self, post: CreatePost) -> Result<PostId, ()> { let response: String = self.post_data_json("/api/v3/post", &post).await?; - let json_data: PostView = self.parse_json(&response).await?; + let json_data: PostView = self.parse_json_map(&response).await?; Ok(json_data.post.id) } async fn feature(&self, params: FeaturePost) -> Result<PostView, ()> { let response: String = self.post_data_json("/api/v3/post/feature", ¶ms).await?; - let json_data: PostView = self.parse_json(&response).await?; + let json_data: PostView = self.parse_json_map(&response).await?; Ok(json_data) } @@ -212,6 +212,17 @@ impl Lemmy { } async fn parse_json<'a, T: Deserialize<'a>>(&self, response: &'a str) -> Result<T,()> { + match serde_json::from_str::<T>(response) { + Ok(data) => Ok(data), + Err(e) => { + let err_msg = format!("{e}"); + error!(err_msg); + Err(()) + } + } + } + + async fn parse_json_map<'a, T: Deserialize<'a>>(&self, response: &'a str) -> Result<T,()> { match serde_json::from_str::<HashMap<&str, T>>(response) { Ok(mut data) => Ok(data.remove("post_view").expect("Element should be present")), Err(e) => { From 23ac0de189459b7f95dabb94bdd725602f05b8e1 Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 6 May 2024 21:28:00 +0200 Subject: [PATCH 12/43] Release 2.2.3 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 337a7ea..8ca9ab8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,7 +43,7 @@ dependencies = [ [[package]] name = "aob-lemmy-bot" -version = "2.2.2" +version = "2.2.3" dependencies = [ "async-trait", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 5a43675..88edf4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Neshura"] name = "aob-lemmy-bot" -version = "2.2.2" +version = "2.2.3" edition = "2021" description = "Bot for automatically posting new chapters of 'Ascendance of a Bookworm' released by J-Novel Club" license = "GPL-3.0-or-later" From 9ee9db5792585dd6e517343cad7b07cfa51630e1 Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 6 May 2024 21:53:02 +0200 Subject: [PATCH 13/43] Dependency bumps --- Cargo.lock | 248 ++++++++++++++++++++++++++++++++++++----------------- Cargo.toml | 26 +++--- 2 files changed, 181 insertions(+), 93 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8ca9ab8..de6929b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -56,10 +56,10 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "strum_macros", + "strum_macros 0.26.2", "systemd-journal-logger", "tokio", - "toml 0.8.8", + "toml", "url", ] @@ -101,6 +101,12 @@ version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bitflags" version = "1.3.2" @@ -157,14 +163,14 @@ dependencies = [ [[package]] name = "confy" -version = "0.5.1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e37668cb35145dcfaa1931a5f37fde375eeae8068b4c0d2f289da28a270b2d2c" +checksum = "45b1f4c00870f07dc34adcac82bb6a72cc5aabca8536ba1797e01df51d2ce9a0" dependencies = [ "directories", "serde", "thiserror", - "toml 0.5.11", + "toml", ] [[package]] @@ -230,22 +236,23 @@ dependencies = [ [[package]] name = "directories" -version = "4.0.1" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210" +checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" dependencies = [ "dirs-sys", ] [[package]] name = "dirs-sys" -version = "0.3.7" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", + "option-ext", "redox_users", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -336,6 +343,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -382,6 +390,7 @@ dependencies = [ "futures-core", "futures-io", "futures-macro", + "futures-sink", "futures-task", "memchr", "pin-project-lite", @@ -410,9 +419,9 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "h2" -version = "0.3.22" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" +checksum = "816ec7294445779408f36fe57bc5b7fc1cf59664059096c65f905c1c61f58069" dependencies = [ "bytes", "fnv", @@ -459,9 +468,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "http" -version = "0.2.11" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" dependencies = [ "bytes", "fnv", @@ -470,12 +479,24 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" dependencies = [ "bytes", "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", "pin-project-lite", ] @@ -485,47 +506,60 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - [[package]] name = "hyper" -version = "0.14.27" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" dependencies = [ "bytes", "futures-channel", - "futures-core", "futures-util", "h2", "http", "http-body", "httparse", - "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.10", + "smallvec", "tokio", - "tower-service", - "tracing", "want", ] [[package]] name = "hyper-tls" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", + "http-body-util", "hyper", + "hyper-util", "native-tls", "tokio", "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "socket2", + "tokio", + "tower", + "tower-service", + "tracing", ] [[package]] @@ -647,7 +681,7 @@ dependencies = [ "serde", "serde_with", "strum", - "strum_macros", + "strum_macros 0.25.3", "tracing", "typed-builder", "url", @@ -676,7 +710,7 @@ dependencies = [ "serde", "serde_with", "strum", - "strum_macros", + "strum_macros 0.25.3", ] [[package]] @@ -850,12 +884,38 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -949,20 +1009,23 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.22" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "encoding_rs", + "futures-channel", "futures-core", "futures-util", "h2", "http", "http-body", + "http-body-util", "hyper", "hyper-tls", + "hyper-util", "ipnet", "js-sys", "log", @@ -971,9 +1034,11 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", "system-configuration", "tokio", "tokio-native-tls", @@ -1004,6 +1069,22 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls-pemfile" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "beb461507cee2c2ff151784c52762cf4d9ff6a61f3e80968600ed24fa837fa54" + [[package]] name = "rustversion" version = "1.0.14" @@ -1106,7 +1187,7 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23" dependencies = [ - "base64", + "base64 0.21.5", "chrono", "hex", "indexmap 1.9.3", @@ -1139,14 +1220,10 @@ dependencies = [ ] [[package]] -name = "socket2" -version = "0.4.10" +name = "smallvec" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" @@ -1183,6 +1260,19 @@ dependencies = [ "syn", ] +[[package]] +name = "strum_macros" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + [[package]] name = "syn" version = "2.0.48" @@ -1194,6 +1284,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "system-configuration" version = "0.5.1" @@ -1304,9 +1400,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.35.0" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", "bytes", @@ -1314,7 +1410,7 @@ dependencies = [ "mio", "num_cpus", "pin-project-lite", - "socket2 0.5.5", + "socket2", "tokio-macros", "windows-sys 0.48.0", ] @@ -1354,15 +1450,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - [[package]] name = "toml" version = "0.8.8" @@ -1397,6 +1484,28 @@ dependencies = [ "winnow", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + [[package]] name = "tower-service" version = "0.3.2" @@ -1409,6 +1518,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -1606,28 +1716,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - [[package]] name = "windows-core" version = "0.51.1" @@ -1780,9 +1868,9 @@ dependencies = [ [[package]] name = "winreg" -version = "0.50.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" dependencies = [ "cfg-if", "windows-sys 0.48.0", diff --git a/Cargo.toml b/Cargo.toml index 88edf4c..e458a71 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,19 +16,19 @@ systemd-units = { enable = false } # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -chrono = "^0.4.26" +chrono = "^0.4" lemmy_api_common = "0.19.3" lemmy_db_schema = "0.19.3" -once_cell = "^1.18.0" -reqwest = { version = "^0.11.18", features = ["blocking", "json"] } -serde = "^1.0.164" -serde_derive = "^1.0.164" -serde_json = "^1.0.97" -strum_macros = "^0.25.0" -tokio = { version = "^1.32.0", features = ["rt", "rt-multi-thread", "macros"] } -url = "^2.4.0" -confy = "^0.5.1" -toml = "^0.8.8" +once_cell = "^1.19" +reqwest = { version = "^0.12", features = ["blocking", "json"] } +serde = "^1.0" +serde_derive = "^1.0" +serde_json = "^1.0" +strum_macros = "^0.26" +tokio = { version = "^1.37", features = ["rt", "rt-multi-thread", "macros"] } +url = "^2.5" +confy = "^0.6" +toml = "^0.8" systemd-journal-logger = "^2.1.1" -log = "^0.4.20" -async-trait = "^0.1.77" \ No newline at end of file +log = "^0.4" +async-trait = "^0.1" \ No newline at end of file From 22bbaaa002612da141676692593b43c91b6deb1d Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 6 May 2024 21:53:14 +0200 Subject: [PATCH 14/43] Release 2.2.4 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index de6929b..1f1fff2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,7 +43,7 @@ dependencies = [ [[package]] name = "aob-lemmy-bot" -version = "2.2.3" +version = "2.2.4" dependencies = [ "async-trait", "chrono", diff --git a/Cargo.toml b/Cargo.toml index e458a71..26055b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Neshura"] name = "aob-lemmy-bot" -version = "2.2.3" +version = "2.2.4" edition = "2021" description = "Bot for automatically posting new chapters of 'Ascendance of a Bookworm' released by J-Novel Club" license = "GPL-3.0-or-later" From cd78d3c1c7668dbde6503aaff4576ddea04e6222 Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 6 May 2024 22:21:04 +0200 Subject: [PATCH 15/43] Reduced connection timeouts and added some logging --- src/bot.rs | 2 ++ src/lemmy.rs | 4 ++-- src/main.rs | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/bot.rs b/src/bot.rs index 7916920..5a598f6 100644 --- a/src/bot.rs +++ b/src/bot.rs @@ -102,6 +102,8 @@ pub(crate) async fn run() { let series = config.series.clone(); for series in series { + let info_msg = format!("Handling Series {}", series.slug); + info!(info_msg); if handle_series(&series, &communities, &lemmy, &config, &mut post_history) .await .is_err() diff --git a/src/lemmy.rs b/src/lemmy.rs index e9c0ad8..32f45ce 100644 --- a/src/lemmy.rs +++ b/src/lemmy.rs @@ -215,7 +215,7 @@ impl Lemmy { match serde_json::from_str::<T>(response) { Ok(data) => Ok(data), Err(e) => { - let err_msg = format!("{e}"); + let err_msg = format!("{e} while parsing JSON"); error!(err_msg); Err(()) } @@ -226,7 +226,7 @@ impl Lemmy { match serde_json::from_str::<HashMap<&str, T>>(response) { Ok(mut data) => Ok(data.remove("post_view").expect("Element should be present")), Err(e) => { - let err_msg = format!("{e}"); + let err_msg = format!("{e} while parsing JSON HashMap"); error!(err_msg); Err(()) } diff --git a/src/main.rs b/src/main.rs index fc93d6a..e5242da 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,8 +12,8 @@ mod fetchers; pub static HTTP_CLIENT: Lazy<Client> = Lazy::new(|| { Client::builder() - .timeout(Duration::seconds(30).to_std().unwrap()) - .connect_timeout(Duration::seconds(30).to_std().unwrap()) + .timeout(Duration::seconds(10).to_std().unwrap()) + .connect_timeout(Duration::seconds(10).to_std().unwrap()) .build() .expect("build client") }); From 92103e28baa651e36a31b7f521c38c65b14d9eec Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 6 May 2024 22:21:14 +0200 Subject: [PATCH 16/43] Release 2.2.5 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1f1fff2..f188994 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,7 +43,7 @@ dependencies = [ [[package]] name = "aob-lemmy-bot" -version = "2.2.4" +version = "2.2.5" dependencies = [ "async-trait", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 26055b9..ecdc7e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Neshura"] name = "aob-lemmy-bot" -version = "2.2.4" +version = "2.2.5" edition = "2021" description = "Bot for automatically posting new chapters of 'Ascendance of a Bookworm' released by J-Novel Club" license = "GPL-3.0-or-later" From 070eae961a7ee4e27678180b772c0ff10f2b0b56 Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 6 May 2024 22:36:17 +0200 Subject: [PATCH 17/43] Yet more logging and delay between series handling requests (should avoid potential rate limit) --- src/bot.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bot.rs b/src/bot.rs index 5a598f6..4dd40bc 100644 --- a/src/bot.rs +++ b/src/bot.rs @@ -102,6 +102,7 @@ pub(crate) async fn run() { let series = config.series.clone(); for series in series { + sleep(Duration::seconds(1).to_std().unwrap()).await; let info_msg = format!("Handling Series {}", series.slug); info!(info_msg); if handle_series(&series, &communities, &lemmy, &config, &mut post_history) @@ -122,7 +123,10 @@ async fn idle(start: &DateTime<Utc>, config: &Config) { if Utc::now() - start > sleep_duration { sleep_duration = Duration::seconds(60); } - + + let info_msg = format!("Idling for {} seconds", sleep_duration); + info!(info_msg); + if let Some(status_url) = config.status_post_url.clone() { match reqwest::get(status_url).await { Ok(_) => {} From 3928367692524d5f8769c515e841a54bf42ee543 Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 6 May 2024 22:36:33 +0200 Subject: [PATCH 18/43] Release 2.2.6 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f188994..bfda742 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,7 +43,7 @@ dependencies = [ [[package]] name = "aob-lemmy-bot" -version = "2.2.5" +version = "2.2.6" dependencies = [ "async-trait", "chrono", diff --git a/Cargo.toml b/Cargo.toml index ecdc7e8..d7431bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Neshura"] name = "aob-lemmy-bot" -version = "2.2.5" +version = "2.2.6" edition = "2021" description = "Bot for automatically posting new chapters of 'Ascendance of a Bookworm' released by J-Novel Club" license = "GPL-3.0-or-later" From 17e161bc276fe41a3326ea8e622d8f617145d2b4 Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 6 May 2024 22:54:01 +0200 Subject: [PATCH 19/43] Small fixes to logging --- src/bot.rs | 2 +- src/fetchers/jnovel.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bot.rs b/src/bot.rs index 4dd40bc..f162af3 100644 --- a/src/bot.rs +++ b/src/bot.rs @@ -124,7 +124,7 @@ async fn idle(start: &DateTime<Utc>, config: &Config) { sleep_duration = Duration::seconds(60); } - let info_msg = format!("Idling for {} seconds", sleep_duration); + let info_msg = format!("Idling for {} seconds", sleep_duration.to_string()); info!(info_msg); if let Some(status_url) = config.status_post_url.clone() { diff --git a/src/fetchers/jnovel.rs b/src/fetchers/jnovel.rs index 83ac5ff..a2fdf6d 100644 --- a/src/fetchers/jnovel.rs +++ b/src/fetchers/jnovel.rs @@ -284,7 +284,7 @@ impl Fetcher for JFetcherOptions { Ok(data) => match data.text().await { Ok(data) => data, Err(e) => { - let err_msg = format!("{e}"); + let err_msg = format!("While checking feed: {e}"); error!(err_msg); return Err(()); } @@ -410,7 +410,7 @@ async fn get_latest_prepub(volume_slug: &str) -> Result<Option<lemmy::PostInfoIn Ok(data) => match data.text().await { Ok(data) => data, Err(e) => { - let err_msg = format!("{e}"); + let err_msg = format!("While getting latest PrePub: {e}"); error!(err_msg); return Err(()); } From 966dd8f359b145469f9851ffd796acc42565227a Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 6 May 2024 22:54:15 +0200 Subject: [PATCH 20/43] Release 2.2.7 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bfda742..885436f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,7 +43,7 @@ dependencies = [ [[package]] name = "aob-lemmy-bot" -version = "2.2.6" +version = "2.2.7" dependencies = [ "async-trait", "chrono", diff --git a/Cargo.toml b/Cargo.toml index d7431bc..0a56f3c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Neshura"] name = "aob-lemmy-bot" -version = "2.2.6" +version = "2.2.7" edition = "2021" description = "Bot for automatically posting new chapters of 'Ascendance of a Bookworm' released by J-Novel Club" license = "GPL-3.0-or-later" From 85f8b97607ba2fe655858538513fb966cf173688 Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 6 May 2024 22:57:05 +0200 Subject: [PATCH 21/43] Yet another logging fix --- src/bot.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bot.rs b/src/bot.rs index f162af3..b4e2126 100644 --- a/src/bot.rs +++ b/src/bot.rs @@ -124,7 +124,7 @@ async fn idle(start: &DateTime<Utc>, config: &Config) { sleep_duration = Duration::seconds(60); } - let info_msg = format!("Idling for {} seconds", sleep_duration.to_string()); + let info_msg = format!("Idling for {} seconds", sleep_duration.num_seconds()); info!(info_msg); if let Some(status_url) = config.status_post_url.clone() { From ee5a15943195924ebbea9eb4d9b161b11bef6ffb Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 6 May 2024 22:57:41 +0200 Subject: [PATCH 22/43] Yet another another logging fix --- src/bot.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/bot.rs b/src/bot.rs index b4e2126..d756661 100644 --- a/src/bot.rs +++ b/src/bot.rs @@ -120,13 +120,12 @@ pub(crate) async fn run() { async fn idle(start: &DateTime<Utc>, config: &Config) { let mut sleep_duration = Duration::seconds(30); + let info_msg = format!("Idling for {} seconds", sleep_duration.num_seconds()); + info!(info_msg); if Utc::now() - start > sleep_duration { sleep_duration = Duration::seconds(60); } - let info_msg = format!("Idling for {} seconds", sleep_duration.num_seconds()); - info!(info_msg); - if let Some(status_url) = config.status_post_url.clone() { match reqwest::get(status_url).await { Ok(_) => {} From aefceda628ab501e120e05928a8896a817122ec4 Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 6 May 2024 22:57:55 +0200 Subject: [PATCH 23/43] Release 2.2.8 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 885436f..858ab23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,7 +43,7 @@ dependencies = [ [[package]] name = "aob-lemmy-bot" -version = "2.2.7" +version = "2.2.8" dependencies = [ "async-trait", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 0a56f3c..71b9e93 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Neshura"] name = "aob-lemmy-bot" -version = "2.2.7" +version = "2.2.8" edition = "2021" description = "Bot for automatically posting new chapters of 'Ascendance of a Bookworm' released by J-Novel Club" license = "GPL-3.0-or-later" From 6520cc65a3fdd636512ab724623c145c233cd4b5 Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Tue, 7 May 2024 22:10:21 +0200 Subject: [PATCH 24/43] Rewrite Version 3 --- Cargo.lock | 126 ++++++++++++++++- Cargo.toml | 2 +- src/bot.rs | 307 +++++++++++------------------------------ src/config.rs | 217 +++++++++++++++++++++++++++++ src/fetchers/jnovel.rs | 236 +++++-------------------------- src/fetchers/mod.rs | 32 ++++- src/lemmy.rs | 272 +++++++++++++++++++++++++++++------- src/main.rs | 4 +- 8 files changed, 715 insertions(+), 481 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 858ab23..0f45e76 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -45,12 +45,12 @@ dependencies = [ name = "aob-lemmy-bot" version = "2.2.8" dependencies = [ - "async-trait", "chrono", "confy", "lemmy_api_common", "lemmy_db_schema", "log", + "notify", "once_cell", "reqwest", "serde", @@ -189,6 +189,21 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +[[package]] +name = "crossbeam-channel" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + [[package]] name = "darling" version = "0.20.3" @@ -306,6 +321,18 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +[[package]] +name = "filetime" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "windows-sys 0.52.0", +] + [[package]] name = "fnv" version = "1.0.7" @@ -336,6 +363,15 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] + [[package]] name = "futures-channel" version = "0.3.29" @@ -623,6 +659,26 @@ dependencies = [ "serde", ] +[[package]] +name = "inotify" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" +dependencies = [ + "bitflags 1.3.2", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + [[package]] name = "ipnet" version = "2.9.0" @@ -644,6 +700,26 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kqueue" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -784,6 +860,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", + "log", "wasi", "windows-sys 0.48.0", ] @@ -806,6 +883,25 @@ dependencies = [ "tempfile", ] +[[package]] +name = "notify" +version = "6.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" +dependencies = [ + "bitflags 2.4.1", + "crossbeam-channel", + "filetime", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "log", + "mio", + "walkdir", + "windows-sys 0.48.0", +] + [[package]] name = "num-traits" version = "0.2.17" @@ -1097,6 +1193,15 @@ version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.22" @@ -1625,6 +1730,16 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -1716,6 +1831,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "winapi-util" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "windows-core" version = "0.51.1" diff --git a/Cargo.toml b/Cargo.toml index 71b9e93..fe4b32d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,4 +31,4 @@ confy = "^0.6" toml = "^0.8" systemd-journal-logger = "^2.1.1" log = "^0.4" -async-trait = "^0.1" \ No newline at end of file +notify = "6.1.1" \ No newline at end of file diff --git a/src/bot.rs b/src/bot.rs index d756661..4539351 100644 --- a/src/bot.rs +++ b/src/bot.rs @@ -1,14 +1,10 @@ -use crate::{config::{Config, PostBody, SeriesConfig}, fetchers::{jnovel}, lemmy}; -use crate::fetchers::jnovel::JPostInfo; -use crate::lemmy::{Lemmy, PostInfo}; -use crate::post_history::SeriesHistory; -use chrono::{DateTime, Duration, Timelike, Utc}; -use lemmy_api_common::post::CreatePost; -use lemmy_db_schema::newtypes::{CommunityId, LanguageId}; -use lemmy_db_schema::PostFeatureType; -use std::collections::HashMap; +use crate::{config::{Config}}; +use crate::lemmy::{Lemmy}; +use crate::post_history::{SeriesHistory}; +use chrono::{DateTime, Duration, Utc}; +use std::sync::{Arc, RwLock}; +use notify::{Event, EventKind, event::{AccessKind, AccessMode}, RecursiveMode, Watcher}; use tokio::time::sleep; -use crate::fetchers::Fetcher; use systemd_journal_logger::connected_to_journal; macro_rules! info { @@ -20,15 +16,6 @@ macro_rules! info { }; } -macro_rules! warn { - ($msg:tt) => { - match connected_to_journal() { - true => log::warn!("[WARN] {}", $msg), - false => println!("[WARN] {}", $msg), - } - }; -} - macro_rules! error { ($msg:tt) => { match connected_to_journal() { @@ -38,231 +25,97 @@ macro_rules! error { }; } -pub(crate) async fn run() { - let mut last_reload: DateTime<Utc>; - let mut lemmy: Lemmy; - let mut login_error: bool; - let mut communities: HashMap<String, CommunityId>; - let mut post_history: SeriesHistory; - let mut start: DateTime<Utc>; - let mut config: Config = Config::load(); - last_reload = Utc::now(); +pub(crate) struct Bot { + shared_config: Arc<RwLock<Config>>, + history: SeriesHistory, + run_start_time: DateTime<Utc> +} - lemmy = match lemmy::login(&config).await { - Ok(data) => data, - Err(_) => panic!(), - }; - login_error = false; +enum Wait { + Absolute, + Buffer +} - communities = match lemmy.get_communities().await { - Ok(data) => data, - Err(_) => panic!(), - }; +impl Bot { + pub(crate) fn new() -> Self { + let config = Config::load(); + let shared_config: Arc<RwLock<Config>> = Arc::new(RwLock::new(config)); - start = Utc::now(); + let shared_config_copy = shared_config.clone(); + let mut watcher = notify::recommended_watcher(move |res: Result<Event, notify::Error>| { + match res { + Ok(event) => { + if event.kind == EventKind::Access(AccessKind::Close(AccessMode::Write)) { + let mut write = shared_config_copy.write().expect("Write Lock Failed"); + let new_config = Config::load(); + write.series = new_config.series; + write.instance = new_config.instance; + write.protected_communities = new_config.protected_communities; + write.status_post_url = new_config.status_post_url; + info!("Reloaded Configuration"); + } + }, + Err(e) => { + let msg = format!("Error watching files: {e}"); + error!(msg); + } + } + }).expect("Watcher Error"); - let info_msg = "Bot init successful, starting normal operations".to_owned(); - info!(info_msg); + watcher.watch(&Config::get_path(), RecursiveMode::NonRecursive).expect("Error in watcher"); - loop { - idle(&start, &config).await; - start = Utc::now(); + let history: SeriesHistory = SeriesHistory::load_history(); - // replace with watcher - if start - last_reload >= Duration::seconds(config.config_reload_seconds as i64) { - config = Config::load(); - let message = "Config reloaded".to_owned(); - info!(message); - } - - if login_error { - let info_msg = "Login invalid, refreshing session"; - info!(info_msg); - lemmy = match lemmy::login(&config).await { + Bot { shared_config, history, run_start_time: Utc::now() } + } + pub(crate) async fn run(&mut self) { + loop { + let mut lemmy = match Lemmy::new(&self.shared_config).await { Ok(data) => data, Err(_) => continue, }; - login_error = false; - } - if start - last_reload >= Duration::seconds(config.config_reload_seconds as i64) { - communities = match lemmy.get_communities().await { - Ok(data) => data, - Err(_) => { - login_error = true; - continue; + lemmy.get_communities().await; + + let start: DateTime<Utc> = Utc::now(); + while Utc::now() - start <= Duration::minutes(60) { + self.run_start_time = Utc::now(); + self.ping_status().await; + let read_copy = self.shared_config.read().expect("Read Lock Failed").clone(); + for series in read_copy.series { + series.update(&mut self.history, &lemmy, &self.shared_config).await; + self.wait(1, Wait::Absolute).await; } - }; - let message = "Communities reloaded".to_owned(); - info!(message); - last_reload = Utc::now(); - } - - post_history = SeriesHistory::load_history(); - - let series = config.series.clone(); - for series in series { - sleep(Duration::seconds(1).to_std().unwrap()).await; - let info_msg = format!("Handling Series {}", series.slug); - info!(info_msg); - if handle_series(&series, &communities, &lemmy, &config, &mut post_history) - .await - .is_err() - { - login_error = true; - continue; - }; - } - - idle(&start, &config).await; - } -} - -async fn idle(start: &DateTime<Utc>, config: &Config) { - let mut sleep_duration = Duration::seconds(30); - let info_msg = format!("Idling for {} seconds", sleep_duration.num_seconds()); - info!(info_msg); - if Utc::now() - start > sleep_duration { - sleep_duration = Duration::seconds(60); - } - - if let Some(status_url) = config.status_post_url.clone() { - match reqwest::get(status_url).await { - Ok(_) => {} - Err(e) => { - let err_msg = format!("{e}"); - error!(err_msg); + self.wait(30, Wait::Buffer).await; + self.ping_status().await; + self.wait(30, Wait::Absolute).await; } + + lemmy.logout().await; } - }; - - while Utc::now() - start < sleep_duration { - sleep(Duration::milliseconds(100).to_std().unwrap()).await; - } -} - -async fn handle_series(series: &SeriesConfig, communities: &HashMap<String, CommunityId>, lemmy: &Lemmy, config: &Config, post_history: &mut SeriesHistory ) -> Result<(), ()> { - let jnc = jnovel::JFetcherOptions::new(series.slug.clone(), series.parted); - let post_list = match jnc.check_feed().await { - Ok(data) => data, - Err(_) => return Err(()), - }; - - if post_list.is_empty() && Utc::now().minute() % 10 == 0 { - let info_msg = "No Updates found"; - info!(info_msg); } - for post_info in post_list.clone().iter() { - let post_part_info = post_info.get_part_info(); - let post_lemmy_info = post_info.get_info(); - - if post_history.check_for_post( - series.slug.as_str(), - post_part_info.as_string().as_str(), - post_lemmy_info.title.as_str(), - ) { - continue; - } - - let post_series_config = match post_info { - JPostInfo::Chapter { .. } => &series.prepub_community, - JPostInfo::Volume { .. } => &series.volume_community, - }; - - let community_id = *communities - .get(post_series_config.name.as_str()) - .expect("Given community is invalid"); - - let post_body = match &post_series_config.post_body { - PostBody::None => None, - PostBody::Description => post_info.get_description(), - PostBody::Custom(text) => Some(text.clone()), - }; - - let post_data = CreatePost { - name: post_lemmy_info.title.clone(), - community_id, - url: Some(post_lemmy_info.url), - body: post_body, - honeypot: None, - nsfw: None, - language_id: Some(LanguageId(37)), // TODO get this id once every few hours per API request, the ordering of IDs suggests that the EN Id might change in the future - }; - - let info = format!( - "Posting '{}' to {}", - post_lemmy_info.title.as_str(), - post_series_config.name.as_str() - ); - info!(info); - let post_id = lemmy.post(post_data).await?; - - if post_series_config.pin_settings.pin_new_post_community - && config - .protected_communities - .contains(&post_series_config.name) - { - let info = format!( - "Pinning '{}' to {}", - post_lemmy_info.title, - post_series_config.name.as_str() - ); - info!(info); - let pinned_posts = lemmy.get_community_pinned(community_id).await?; - if !pinned_posts.is_empty() { - let community_pinned_post = &pinned_posts[0]; - lemmy - .unpin(community_pinned_post.post.id, PostFeatureType::Community) - .await?; - } - lemmy.pin(post_id, PostFeatureType::Community).await?; - } else if config - .protected_communities - .contains(&post_series_config.name) - { - let message = format!( - "Community '{}' for Series '{}' is protected. Is this intended?", - &post_series_config.name, series.slug - ); - warn!(message); - } - - if post_series_config.pin_settings.pin_new_post_local { - let info = format!("Pinning '{}' to Instance", post_lemmy_info.title); - info!(info); - let pinned_posts = lemmy.get_local_pinned().await?; - if !pinned_posts.is_empty() { - for pinned_post in pinned_posts { - if config - .protected_communities - .contains(&pinned_post.community.name) - { - continue; - } else { - let community_pinned_post = &pinned_post; - lemmy - .unpin(community_pinned_post.post.id, PostFeatureType::Local) - .await?; - break; - } + async fn ping_status(&self) { + let read_config = &self.shared_config.read().expect("Read Lock Failed").clone(); + if let Some(status_url) = &read_config.status_post_url { + match reqwest::get(status_url).await { + Ok(_) => {}, + Err(e) => { + let err_msg = format!("While pinging status URL: {e}"); + error!(err_msg); } } - lemmy.pin(post_id, PostFeatureType::Local).await?; } - - let mut series_history = post_history.get_series(series.slug.as_str()); - let mut part_history = series_history.get_part(post_part_info.as_string().as_str()); - - match post_info { - JPostInfo::Chapter { .. } => part_history.chapter = post_info.get_info().title, - JPostInfo::Volume { .. } => part_history.volume = post_info.get_info().title, - } - - series_history.set_part(post_part_info.as_string().as_str(), part_history); - post_history - .set_series(series.slug.as_str(), series_history); - post_history.save_history(); } - Ok(()) + + async fn wait(&self, seconds: i64, start_time: Wait) { + let duration: Duration = Duration::seconds(seconds); + let start_time: DateTime<Utc> = match start_time { + Wait::Absolute => Utc::now(), + Wait::Buffer => self.run_start_time, + }; + while Utc::now() - start_time < duration { + sleep(Duration::milliseconds(100).to_std().unwrap()).await + } + } } diff --git a/src/config.rs b/src/config.rs index 776d868..0bee169 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,42 @@ +use std::path::PathBuf; +use std::sync::{Arc, RwLock}; +use chrono::{Timelike, Utc}; use crate::config::PostBody::Description; use lemmy_api_common::sensitive::Sensitive; +use lemmy_db_schema::PostFeatureType; use serde_derive::{Deserialize, Serialize}; +use crate::lemmy::{Lemmy, PartInfo, PostType}; +use crate::post_history::{SeriesHistory}; +use systemd_journal_logger::connected_to_journal; +use crate::fetchers::{FetcherTrait, Fetcher}; +use crate::fetchers::jnovel::{JNovelFetcher}; + +macro_rules! info { + ($msg:tt) => { + match connected_to_journal() { + true => log::info!("[INFO] {}", $msg), + false => println!("[INFO] {}", $msg), + } + }; +} + +macro_rules! warn { + ($msg:tt) => { + match connected_to_journal() { + true => log::warn!("[WARN] {}", $msg), + false => println!("[WARN] {}", $msg), + } + }; +} + +macro_rules! error { + ($msg:tt) => { + match connected_to_journal() { + true => log::error!("[ERROR] {}", $msg), + false => eprintln!("[ERROR] {}", $msg), + } + }; +} #[derive(Serialize, Deserialize, Clone, Debug)] pub(crate) struct Config { @@ -40,6 +76,10 @@ impl Config { cfg } + pub(crate) fn get_path() -> PathBuf { + confy::get_configuration_file_path(env!("CARGO_PKG_NAME"), "config").expect("Application will not without confy") + } + pub(crate) fn get_username(&self) -> Sensitive<String> { Sensitive::new(self.username.clone()) } @@ -69,6 +109,183 @@ pub(crate) struct SeriesConfig { pub(crate) parted: bool, pub(crate) prepub_community: PostConfig, pub(crate) volume_community: PostConfig, + pub(crate) fetcher: Fetcher +} + +impl SeriesConfig { + pub(crate) async fn update(&self, history: &mut SeriesHistory, lemmy: &Lemmy, config: &Arc<RwLock<Config>>) { + let info_msg = format!("Checking {} for Updates", self.slug); + info!(info_msg); + + let mut fetcher: Fetcher = match &self.fetcher { + Fetcher::Jnc(_) => { + Fetcher::Jnc(JNovelFetcher::new()) + }, + /*default => { + let err_msg = format!("Fetcher {default} not implemented"); + error!(err_msg); + return; + }*/ + }; + + match fetcher { + Fetcher::Jnc(ref mut jnc) => { + jnc.set_series(self.slug.clone()); + jnc.set_part_option(self.parted); + } + } + + let post_list = match fetcher.check_feed().await { + Ok(data) => data, + Err(_) => { + let err_msg = format!("While checking feed for {}", self.slug); + error!(err_msg); + return; + } + }; + + if post_list.is_empty() && Utc::now().minute() % 10 == 0 { + let info_msg = "No Updates found"; + info!(info_msg); + } + + for post_info in post_list.iter() { + if history.check_for_post( + self.slug.as_str(), + post_info.get_part_info().unwrap_or(PartInfo::NoParts).as_string().as_str(), + post_info.get_info().title.as_str() + ) { + continue + } + + let post_data = post_info.get_post_data(self, lemmy); + + let info = format!( + "Posting '{}' to {}", + post_info.get_info().title.as_str(), + post_info.get_post_config(self).name.as_str() + ); + info!(info); + + let post_id = match lemmy.post(post_data).await { + Ok(data) => data, + Err(_) => { + error!("Error posting chapter"); + return; + } + }; + + let read_config = config.read().expect("Read Lock Failed").clone(); + + if post_info.get_post_config(self).pin_settings.pin_new_post_community + && !read_config + .protected_communities + .contains(&post_info.get_post_config(self).name) + { + let info = format!( + "Pinning '{}' to {}", + post_info.get_info().title, + post_info.get_post_config(self).name.as_str() + ); + info!(info); + let pinned_posts = match lemmy.get_community_pinned(lemmy.get_community_id(&post_info.get_post_config(self).name)).await { + Ok(data) => data, + Err(_) => { + error!("Pinning of Post to community failed"); + continue; + } + }; + if !pinned_posts.is_empty() { + let community_pinned_post = &pinned_posts[0]; + match lemmy + .unpin(community_pinned_post.post.id, PostFeatureType::Community) + .await { + Ok(_) => {} + Err(_) => { + error!("Error un-pinning post"); + return; + } + } + } + match lemmy.pin(post_id, PostFeatureType::Community).await { + Ok(_) => {} + Err(_) => { + error!("Error pinning post"); + return; + } + } + } else if read_config + .protected_communities + .contains(&post_info.get_post_config(self).name) + { + let message = format!( + "Community '{}' for Series '{}' is protected. Is this intended?", + &post_info.get_post_config(self).name, self.slug + ); + warn!(message); + } + + if post_info.get_post_config(self).pin_settings.pin_new_post_local { + let info = format!("Pinning '{}' to Instance", post_info.get_info().title); + info!(info); + let pinned_posts = match lemmy.get_local_pinned().await { + Ok(data) => {data} + Err(_) => { + error!("Error fetching pinned posts"); + return; + } + }; + + if !pinned_posts.is_empty() { + for pinned_post in pinned_posts { + if read_config + .protected_communities + .contains(&pinned_post.community.name) + { + continue; + } else { + let community_pinned_post = &pinned_post; + match lemmy + .unpin(community_pinned_post.post.id, PostFeatureType::Local) + .await { + Ok(_) => {} + Err(_) => { + error!("Error pinning post"); + return; + } + } + break; + } + } + } + match lemmy.pin(post_id, PostFeatureType::Local).await { + Ok(_) => {} + Err(_) => { + error!("Error pinning post"); + return; + } + }; + } + + let mut series_history = history.get_series(self.slug.as_str()); + let mut part_history = series_history.get_part(post_info.get_part_info().unwrap_or(PartInfo::NoParts).as_string().as_str()); + + match post_info.post_type { + Some(post_type) => { + match post_type { + PostType::Chapter => part_history.chapter = post_info.get_info().title, + PostType::Volume => part_history.volume = post_info.get_info().title, + } + } + None => part_history.chapter = post_info.get_info().title, + } + + series_history.set_part(post_info.get_part_info().unwrap_or(PartInfo::NoParts).as_string().as_str(), part_history); + history + .set_series(self.slug.as_str(), series_history); + history.save_history(); + } + } } #[derive(Debug, Serialize, Deserialize, Clone)] diff --git a/src/fetchers/jnovel.rs b/src/fetchers/jnovel.rs index a2fdf6d..7ce0a6a 100644 --- a/src/fetchers/jnovel.rs +++ b/src/fetchers/jnovel.rs @@ -1,16 +1,13 @@ -use crate::{HTTP_CLIENT, lemmy}; +use crate::{HTTP_CLIENT}; use chrono::{DateTime, Duration, Utc}; use serde_derive::{Deserialize, Serialize}; -use std::cmp::Ordering; use std::collections::HashMap; use std::ops::Sub; -use async_trait::async_trait; use url::Url; -use crate::fetchers::Fetcher; -use crate::fetchers::jnovel::JPostInfo::{Chapter, Volume}; -use crate::fetchers::jnovel::PartInfo::{NoParts, Part}; -use crate::lemmy::{PostInfo, PostInfoInner}; +use crate::fetchers::{FetcherTrait}; +use crate::lemmy::{PartInfo, PostInfo, PostInfoInner, PostType}; use systemd_journal_logger::connected_to_journal; +use crate::lemmy::PartInfo::{NoParts, Part}; macro_rules! error { ($msg:tt) => { @@ -91,191 +88,31 @@ pub(crate) struct ChapterDetail { pub(crate) cover: Option<Cover>, } -#[derive(Debug, Copy, Clone)] -pub(crate) enum PartInfo { - NoParts, - Part(u8), -} - -impl PartInfo { - pub(crate) fn as_u8(&self) -> u8 { - match self { - Part(number) => *number, - NoParts => 0, - } - } - - pub(crate) fn as_string(&self) -> String { - self.as_u8().to_string() - } -} - -impl PartialEq for PartInfo { - fn eq(&self, other: &Self) -> bool { - let self_numeric = self.as_u8(); - let other_numeric = other.as_u8(); - self_numeric == other_numeric - } -} - -impl PartialOrd for PartInfo { - fn partial_cmp(&self, other: &Self) -> Option<Ordering> { - if self.gt(other) { - Some(Ordering::Greater) - } else if self.eq(other) { - Some(Ordering::Equal) - } else { - Some(Ordering::Less) - } - } - - fn lt(&self, other: &Self) -> bool { - let self_numeric = self.as_u8(); - let other_numeric = other.as_u8(); - - self_numeric < other_numeric - } - - fn le(&self, other: &Self) -> bool { - !self.gt(other) - } - - fn gt(&self, other: &Self) -> bool { - let self_numeric = self.as_u8(); - let other_numeric = other.as_u8(); - - self_numeric > other_numeric - } - - fn ge(&self, other: &Self) -> bool { - !self.lt(other) - } -} - -#[derive(Debug, Clone)] -pub(crate) enum JPostInfo { - Chapter { - part: PartInfo, - lemmy_info: PostInfoInner, - }, - Volume { - part: PartInfo, - description: String, - lemmy_info: PostInfoInner, - }, -} - -impl JPostInfo { - pub(crate) fn get_part_info(&self) -> PartInfo { - match self { - Chapter { - part: part_info, .. - } => *part_info, - Volume { - part: part_info, .. - } => *part_info, - } - } -} - -impl PostInfo for JPostInfo { - fn get_info(&self) -> PostInfoInner { - match self { - Chapter { lemmy_info, .. } => lemmy_info.clone(), - Volume { lemmy_info, .. } => lemmy_info.clone(), - } - } - - fn get_description(&self) -> Option<String> { - match self { - Chapter { .. } => None, - Volume { description, .. } => Some(description.clone()), - } - } -} - -impl PartialEq for JPostInfo { - fn eq(&self, other: &Self) -> bool { - let self_part = match self { - Chapter { part, .. } => part, - Volume { part, .. } => part, - }; - - let other_part = match other { - Chapter { part, .. } => part, - Volume { part, .. } => part, - }; - - self_part.eq(other_part) - } -} - -impl PartialOrd for JPostInfo { - fn partial_cmp(&self, other: &Self) -> Option<Ordering> { - if self.gt(other) { - Some(Ordering::Greater) - } else if self.eq(other) { - Some(Ordering::Equal) - } else { - Some(Ordering::Less) - } - } - - fn lt(&self, other: &Self) -> bool { - let self_part = match self { - Chapter { part, .. } => part, - Volume { part, .. } => part, - }; - - let other_part = match other { - Chapter { part, .. } => part, - Volume { part, .. } => part, - }; - - self_part < other_part - } - - fn le(&self, other: &Self) -> bool { - !self.gt(other) - } - - fn gt(&self, other: &Self) -> bool { - let self_part = match self { - Chapter { part, .. } => part, - Volume { part, .. } => part, - }; - - let other_part = match other { - Chapter { part, .. } => part, - Volume { part, .. } => part, - }; - - self_part > other_part - } - - fn ge(&self, other: &Self) -> bool { - !self.lt(other) - } -} - -pub(crate) struct JFetcherOptions { +#[derive(Deserialize, Serialize, Debug, Clone)] +pub(crate) struct JNovelFetcher { series_slug: String, series_has_parts: bool } -impl JFetcherOptions { - pub(crate) fn new(series_slug: String, series_has_parts: bool) -> Self { - JFetcherOptions { - series_slug, - series_has_parts - } +impl JNovelFetcher { + pub(crate) fn set_series(&mut self, series: String) { + self.series_slug = series; + } + + pub(crate) fn set_part_option(&mut self, has_parts: bool) { + self.series_has_parts = has_parts; } } -#[async_trait] -impl Fetcher for JFetcherOptions { - type Return = JPostInfo; - async fn check_feed(&self) -> Result<Vec<Self::Return>, ()> { +impl FetcherTrait for JNovelFetcher { + fn new() -> Self { + JNovelFetcher { + series_slug: "".to_owned(), + series_has_parts: false + } + } + + async fn check_feed(&self) -> Result<Vec<PostInfo>, ()> { let response = match HTTP_CLIENT .get(api_url!() + "/series/" + self.series_slug.as_str() + "/volumes?format=json") .send() @@ -307,8 +144,8 @@ impl Fetcher for JFetcherOptions { volume_brief_data.volumes.reverse(); // Makes breaking out of the volume loop easier // If no parts just use 0 as Part indicator as no Series with Parts has a Part 0 - let mut volume_map: HashMap<u8, JPostInfo> = HashMap::new(); - let mut prepub_map: HashMap<u8, JPostInfo> = HashMap::new(); + let mut volume_map: HashMap<u8, PostInfo> = HashMap::new(); + let mut prepub_map: HashMap<u8, PostInfo> = HashMap::new(); for volume in volume_brief_data.volumes.iter() { let publishing_date = DateTime::parse_from_rfc3339(&volume.publishing).unwrap(); @@ -351,14 +188,15 @@ impl Fetcher for JFetcherOptions { self.series_slug.as_str(), volume.number ); - let post_details = lemmy::PostInfoInner { + let post_details = PostInfoInner { title: volume.title.clone(), url: Url::parse(&post_url).unwrap(), }; - let new_post_info = Volume { - part: new_part_info, - description: volume.short_description.clone(), + let new_post_info = PostInfo { + post_type: Some(PostType::Volume), + part: Some(new_part_info), + description: Some(volume.short_description.clone()), lemmy_info: post_details, }; @@ -376,9 +214,11 @@ impl Fetcher for JFetcherOptions { } if let Some(prepub_info) = get_latest_prepub(&volume.slug).await? { - let prepub_post_info = Chapter { - part: new_part_info, + let prepub_post_info = PostInfo { + post_type: Some(PostType::Chapter), + part: Some(new_part_info), lemmy_info: prepub_info, + description: None, }; prepub_map @@ -392,8 +232,8 @@ impl Fetcher for JFetcherOptions { } } - let mut result_vec: Vec<JPostInfo> = volume_map.values().cloned().collect(); - let mut prepub_vec: Vec<JPostInfo> = prepub_map.values().cloned().collect(); + let mut result_vec: Vec<PostInfo> = volume_map.values().cloned().collect(); + let mut prepub_vec: Vec<PostInfo> = prepub_map.values().cloned().collect(); result_vec.append(&mut prepub_vec); Ok(result_vec) @@ -401,7 +241,7 @@ impl Fetcher for JFetcherOptions { } -async fn get_latest_prepub(volume_slug: &str) -> Result<Option<lemmy::PostInfoInner>, ()> { +async fn get_latest_prepub(volume_slug: &str) -> Result<Option<PostInfoInner>, ()> { let response = match HTTP_CLIENT .get(api_url!() + "/volumes/" + volume_slug + "/parts?format=json") .send() @@ -432,7 +272,7 @@ async fn get_latest_prepub(volume_slug: &str) -> Result<Option<lemmy::PostInfoIn }; volume_prepub_parts_data.parts.reverse(); // Makes breaking out of the parts loop easier - let mut post_details: Option<lemmy::PostInfoInner> = None; + let mut post_details: Option<PostInfoInner> = None; for prepub_part in volume_prepub_parts_data.parts.iter() { let publishing_date = DateTime::parse_from_rfc3339(&prepub_part.launch).unwrap(); @@ -443,7 +283,7 @@ async fn get_latest_prepub(volume_slug: &str) -> Result<Option<lemmy::PostInfoIn } let post_url = format!("{}/read/{}", jnc_base_url!(), prepub_part.slug); - post_details = Some(lemmy::PostInfoInner { + post_details = Some(PostInfoInner { title: prepub_part.title.clone(), url: Url::parse(&post_url).unwrap(), }); diff --git a/src/fetchers/mod.rs b/src/fetchers/mod.rs index 126aeb2..990d7c1 100644 --- a/src/fetchers/mod.rs +++ b/src/fetchers/mod.rs @@ -1,9 +1,31 @@ -use async_trait::async_trait; +use serde_derive::{Deserialize, Serialize}; +use strum_macros::Display; +use crate::fetchers::Fetcher::Jnc; +use crate::fetchers::jnovel::JNovelFetcher; +use crate::lemmy::{PostInfo}; pub mod jnovel; -#[async_trait] -pub(crate) trait Fetcher { - type Return; - async fn check_feed(&self) -> Result<Vec<Self::Return>, ()>; +pub(crate) trait FetcherTrait { + fn new() -> Self where Self: Sized; + async fn check_feed(&self) -> Result<Vec<PostInfo>, ()>; +} + +impl Fetcher { + pub(crate) async fn check_feed(&self) -> Result<Vec<PostInfo>, ()> { + match self { + Jnc(fetcher) => fetcher.check_feed().await, + /*default => { + let err_msg = format!("Fetcher {default} is not implemented"); + error!(err_msg); + Err(()) + }*/ + } + } +} + +#[derive(Deserialize, Serialize, Debug, Clone, Display)] +pub(crate) enum Fetcher { + #[serde(rename = "jnc")] + Jnc(JNovelFetcher) } diff --git a/src/lemmy.rs b/src/lemmy.rs index 32f45ce..29b2408 100644 --- a/src/lemmy.rs +++ b/src/lemmy.rs @@ -1,14 +1,16 @@ -use crate::config::Config; +use std::cmp::Ordering; +use crate::config::{Config, PostBody, PostConfig, SeriesConfig}; use crate::{HTTP_CLIENT}; use lemmy_api_common::community::{ListCommunities, ListCommunitiesResponse}; use lemmy_api_common::lemmy_db_views::structs::PostView; use lemmy_api_common::person::{Login, LoginResponse}; use lemmy_api_common::post::{CreatePost, FeaturePost, GetPosts, GetPostsResponse}; use lemmy_api_common::sensitive::Sensitive; -use lemmy_db_schema::newtypes::{CommunityId, PostId}; +use lemmy_db_schema::newtypes::{CommunityId, LanguageId, PostId}; use lemmy_db_schema::{ListingType, PostFeatureType}; use reqwest::StatusCode; use std::collections::HashMap; +use std::sync::{RwLock}; use serde::{Deserialize, Serialize}; use url::Url; use systemd_journal_logger::connected_to_journal; @@ -25,6 +27,7 @@ macro_rules! error { pub(crate) struct Lemmy { jwt_token: Sensitive<String>, instance: String, + communities: HashMap<String, CommunityId>, } @@ -34,60 +37,221 @@ pub(crate) struct PostInfoInner { pub(crate) url: Url, } -pub(crate) trait PostInfo { - fn get_info(&self) -> PostInfoInner; - - fn get_description(&self) -> Option<String>; +#[derive(Debug, Copy, Clone)] +pub(crate) enum PartInfo { + NoParts, + Part(u8), } -pub(crate) async fn login(config: &Config) -> Result<Lemmy, ()> { - let login_params = Login { - username_or_email: config.get_username(), - password: config.get_password(), - totp_2fa_token: None, - }; - - let response = match HTTP_CLIENT - .post(config.instance.to_owned() + "/api/v3/user/login") - .json(&login_params) - .send() - .await - { - Ok(data) => data, - Err(e) => { - let err_msg = format!("{e}"); - error!(err_msg); - return Err(()); +impl PartInfo { + pub(crate) fn as_u8(&self) -> u8 { + match self { + PartInfo::Part(number) => *number, + PartInfo::NoParts => 0, } - }; + } - match response.status() { - StatusCode::OK => { - let data: LoginResponse = response - .json() - .await - .expect("Successful Login Request should return JSON"); - match data.jwt { - Some(token) => Ok(Lemmy { - jwt_token: token.clone(), - instance: config.instance.to_owned(), - }), - None => { - let err_msg = "Login did not return JWT token. Are the credentials valid?".to_owned(); - error!(err_msg); - Err(()) + pub(crate) fn as_string(&self) -> String { + self.as_u8().to_string() + } +} + +impl PartialEq for PartInfo { + fn eq(&self, other: &Self) -> bool { + let self_numeric = self.as_u8(); + let other_numeric = other.as_u8(); + self_numeric == other_numeric + } +} + +impl PartialOrd for PartInfo { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if self.gt(other) { + Some(Ordering::Greater) + } else if self.eq(other) { + Some(Ordering::Equal) + } else { + Some(Ordering::Less) + } + } + + fn lt(&self, other: &Self) -> bool { + let self_numeric = self.as_u8(); + let other_numeric = other.as_u8(); + + self_numeric < other_numeric + } + + fn le(&self, other: &Self) -> bool { + !self.gt(other) + } + + fn gt(&self, other: &Self) -> bool { + let self_numeric = self.as_u8(); + let other_numeric = other.as_u8(); + + self_numeric > other_numeric + } + + fn ge(&self, other: &Self) -> bool { + !self.lt(other) + } +} + +#[derive(Debug, Clone, Copy)] +pub(crate) enum PostType { + Chapter, + Volume +} + +#[derive(Debug, Clone)] +pub(crate) struct PostInfo { + pub(crate) part: Option<PartInfo>, + pub(crate) lemmy_info: PostInfoInner, + pub(crate) description: Option<String>, + pub(crate) post_type: Option<PostType> +} + +impl PostInfo { + pub(crate)fn get_info(&self) -> PostInfoInner { + self.lemmy_info.clone() + } + + pub(crate)fn get_description(&self) -> Option<String> { + self.description.clone() + } + + pub(crate) fn get_part_info(&self) -> Option<PartInfo> { + self.part + } + + pub(crate) fn get_post_config(&self, series: &SeriesConfig) -> PostConfig { + match self.post_type { + Some(post_type) => { + match post_type { + PostType::Chapter => series.prepub_community.clone(), + PostType::Volume => series.volume_community.clone(), } } + None => series.prepub_community.clone(), } - status => { - let err_msg = format!("Unexpected HTTP Status '{}' during Login", status); - error!(err_msg); - Err(()) + } + + pub(crate) fn get_post_data(&self, series: &SeriesConfig, lemmy: &Lemmy) -> CreatePost { + let post_config = self.get_post_config(series); + + let post_body = match &post_config.post_body { + PostBody::None => None, + PostBody::Description => self.get_description(), + PostBody::Custom(text) => Some(text.clone()), + }; + + let community_id: CommunityId = lemmy.get_community_id(&post_config.name); + + CreatePost { + name: self.get_info().title.clone(), + community_id, + url: Some(self.get_info().url), + body: post_body, + honeypot: None, + nsfw: None, + language_id: Some(LanguageId(37)), // TODO get this id once every few hours per API request, the ordering of IDs suggests that the EN Id might change in the future + } + } +} + +impl PartialEq for PostInfo { + fn eq(&self, other: &Self) -> bool { + self.part.eq(&other.part) + } +} + +impl PartialOrd for PostInfo { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if self.gt(other) { + Some(Ordering::Greater) + } else if self.eq(other) { + Some(Ordering::Equal) + } else { + Some(Ordering::Less) } } + + fn lt(&self, other: &Self) -> bool { + self.part < other.part + } + + fn le(&self, other: &Self) -> bool { + !self.gt(other) + } + + fn gt(&self, other: &Self) -> bool { + self.part > other.part + } + + fn ge(&self, other: &Self) -> bool { + !self.lt(other) + } } impl Lemmy { + pub(crate) fn get_community_id(&self, name: &str) -> CommunityId { + *self.communities.get(name).expect("Given community is invalid") + } + pub(crate) async fn new(config: &RwLock<Config>) -> Result<Self, ()> { + let read_config = config.read().expect("Read Lock Failed").clone(); + let login_params = Login { + username_or_email: read_config.get_username(), + password: read_config.get_password(), + totp_2fa_token: None, + }; + + let response = match HTTP_CLIENT + .post(read_config.instance.to_owned() + "/api/v3/user/login") + .json(&login_params) + .send() + .await + { + Ok(data) => data, + Err(e) => { + let err_msg = format!("{e}"); + error!(err_msg); + return Err(()); + } + }; + + match response.status() { + StatusCode::OK => { + let data: LoginResponse = response + .json() + .await + .expect("Successful Login Request should return JSON"); + match data.jwt { + Some(token) => Ok(Lemmy { + jwt_token: token.clone(), + instance: read_config.instance.to_owned(), + communities: HashMap::new(), + }), + None => { + let err_msg = "Login did not return JWT token. Are the credentials valid?".to_owned(); + error!(err_msg); + Err(()) + } + } + } + status => { + let err_msg = format!("Unexpected HTTP Status '{}' during Login", status); + error!(err_msg); + Err(()) + } + } + } + + pub(crate) async fn logout(&self) { + let _ = self.post_data_json("/api/v3/user/logout", &"").await; + } + + pub(crate) async fn post(&self, post: CreatePost) -> Result<PostId, ()> { let response: String = self.post_data_json("/api/v3/post", &post).await?; let json_data: PostView = self.parse_json_map(&response).await?; @@ -155,14 +319,26 @@ impl Lemmy { .collect()) } - pub(crate) async fn get_communities(&self) -> Result<HashMap<String, CommunityId>, ()> { + pub(crate) async fn get_communities(&mut self) { let list_params = ListCommunities { type_: Some(ListingType::Local), ..Default::default() }; - let response: String = self.get_data_query("/api/v3/community/list", &list_params).await?; - let json_data: ListCommunitiesResponse = self.parse_json(&response).await?; + let response: String = match self.get_data_query("/api/v3/community/list", &list_params).await { + Ok(data) => data, + Err(_) => { + error!("Unable to extract data from request"); + return; + } + }; + let json_data: ListCommunitiesResponse = match self.parse_json::<ListCommunitiesResponse>(&response).await { + Ok(data) => data, + Err(_) => { + error!("Unable to parse data from json"); + return; + }, + }; let mut communities: HashMap<String, CommunityId> = HashMap::new(); for community_view in json_data.communities { @@ -170,7 +346,7 @@ impl Lemmy { communities.insert(community.name, community.id); } - Ok(communities) + self.communities = communities; } async fn post_data_json<T: Serialize>(&self, route: &str, json: &T ) -> Result<String,()> { diff --git a/src/main.rs b/src/main.rs index e5242da..5eae9ae 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ use log::{LevelFilter}; use once_cell::sync::Lazy; use reqwest::Client; use systemd_journal_logger::{JournalLog}; +use crate::bot::Bot; mod bot; mod config; @@ -25,5 +26,6 @@ async fn main() { .install() .expect("Systemd-Logger crate error"); log::set_max_level(LevelFilter::Info); - bot::run().await; + let mut bot = Bot::new(); + bot.run().await; } From affe62b97380d0d126fba3b694593ae2ec556fc6 Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Tue, 7 May 2024 22:11:16 +0200 Subject: [PATCH 25/43] Release Candidate 3.0.0-rc.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f45e76..aa6f6ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,7 +43,7 @@ dependencies = [ [[package]] name = "aob-lemmy-bot" -version = "2.2.8" +version = "3.0.0-rc.1" dependencies = [ "chrono", "confy", diff --git a/Cargo.toml b/Cargo.toml index fe4b32d..1599c33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Neshura"] name = "aob-lemmy-bot" -version = "2.2.8" +version = "3.0.0-rc.1" edition = "2021" description = "Bot for automatically posting new chapters of 'Ascendance of a Bookworm' released by J-Novel Club" license = "GPL-3.0-or-later" From 4297860b9e2c883d4ca33f5fe2679503237c78bf Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Tue, 7 May 2024 22:29:48 +0200 Subject: [PATCH 26/43] Legacy fixes for async traits --- Cargo.lock | 1 + Cargo.toml | 1 + src/fetchers/jnovel.rs | 2 ++ src/fetchers/mod.rs | 2 ++ 4 files changed, 6 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index aa6f6ca..96888c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -45,6 +45,7 @@ dependencies = [ name = "aob-lemmy-bot" version = "3.0.0-rc.1" dependencies = [ + "async-trait", "chrono", "confy", "lemmy_api_common", diff --git a/Cargo.toml b/Cargo.toml index 1599c33..9b3d486 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,4 +31,5 @@ confy = "^0.6" toml = "^0.8" systemd-journal-logger = "^2.1.1" log = "^0.4" +async-trait = "^0.1" notify = "6.1.1" \ No newline at end of file diff --git a/src/fetchers/jnovel.rs b/src/fetchers/jnovel.rs index 7ce0a6a..6a7e437 100644 --- a/src/fetchers/jnovel.rs +++ b/src/fetchers/jnovel.rs @@ -3,6 +3,7 @@ use chrono::{DateTime, Duration, Utc}; use serde_derive::{Deserialize, Serialize}; use std::collections::HashMap; use std::ops::Sub; +use async_trait::async_trait; use url::Url; use crate::fetchers::{FetcherTrait}; use crate::lemmy::{PartInfo, PostInfo, PostInfoInner, PostType}; @@ -104,6 +105,7 @@ impl JNovelFetcher { } } +#[async_trait] impl FetcherTrait for JNovelFetcher { fn new() -> Self { JNovelFetcher { diff --git a/src/fetchers/mod.rs b/src/fetchers/mod.rs index 990d7c1..ce05d8a 100644 --- a/src/fetchers/mod.rs +++ b/src/fetchers/mod.rs @@ -1,3 +1,4 @@ +use async_trait::async_trait; use serde_derive::{Deserialize, Serialize}; use strum_macros::Display; use crate::fetchers::Fetcher::Jnc; @@ -6,6 +7,7 @@ use crate::lemmy::{PostInfo}; pub mod jnovel; +#[async_trait] pub(crate) trait FetcherTrait { fn new() -> Self where Self: Sized; async fn check_feed(&self) -> Result<Vec<PostInfo>, ()>; From 32ea83a7bbfe3fd311221fd1bafe50770788c13b Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Tue, 7 May 2024 22:30:02 +0200 Subject: [PATCH 27/43] Release Candidate 3.0.0-rc.2 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 96888c9..204e607 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,7 +43,7 @@ dependencies = [ [[package]] name = "aob-lemmy-bot" -version = "3.0.0-rc.1" +version = "3.0.0-rc.2" dependencies = [ "async-trait", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 9b3d486..8a1ad0e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Neshura"] name = "aob-lemmy-bot" -version = "3.0.0-rc.1" +version = "3.0.0-rc.2" edition = "2021" description = "Bot for automatically posting new chapters of 'Ascendance of a Bookworm' released by J-Novel Club" license = "GPL-3.0-or-later" From e02cd900edd5524fa3eb3040b6db6fee2d45d9b4 Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Tue, 7 May 2024 22:35:15 +0200 Subject: [PATCH 28/43] Release 3.0.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 204e607..c6ff7c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,7 +43,7 @@ dependencies = [ [[package]] name = "aob-lemmy-bot" -version = "3.0.0-rc.2" +version = "3.0.0" dependencies = [ "async-trait", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 8a1ad0e..d8836c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Neshura"] name = "aob-lemmy-bot" -version = "3.0.0-rc.2" +version = "3.0.0" edition = "2021" description = "Bot for automatically posting new chapters of 'Ascendance of a Bookworm' released by J-Novel Club" license = "GPL-3.0-or-later" From 6a8c1662f02e52fa7da3dada8c7bcb96dc5e9e58 Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Tue, 7 May 2024 22:50:12 +0200 Subject: [PATCH 29/43] Fix enum problems in config --- src/fetchers/jnovel.rs | 9 +++++++++ src/fetchers/mod.rs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/fetchers/jnovel.rs b/src/fetchers/jnovel.rs index 6a7e437..c13c626 100644 --- a/src/fetchers/jnovel.rs +++ b/src/fetchers/jnovel.rs @@ -95,6 +95,15 @@ pub(crate) struct JNovelFetcher { series_has_parts: bool } +impl Default for JNovelFetcher { + fn default() -> Self { + Self { + series_slug: "".to_owned(), + series_has_parts: false, + } + } +} + impl JNovelFetcher { pub(crate) fn set_series(&mut self, series: String) { self.series_slug = series; diff --git a/src/fetchers/mod.rs b/src/fetchers/mod.rs index ce05d8a..0f2eacc 100644 --- a/src/fetchers/mod.rs +++ b/src/fetchers/mod.rs @@ -29,5 +29,5 @@ impl Fetcher { #[derive(Deserialize, Serialize, Debug, Clone, Display)] pub(crate) enum Fetcher { #[serde(rename = "jnc")] - Jnc(JNovelFetcher) + Jnc(#[serde(skip)] JNovelFetcher) } From 5d708bdb822e49f4d37a61e419829bb3a420b0fb Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Tue, 7 May 2024 22:50:22 +0200 Subject: [PATCH 30/43] Release 3.0.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c6ff7c9..8774ff1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,7 +43,7 @@ dependencies = [ [[package]] name = "aob-lemmy-bot" -version = "3.0.0" +version = "3.0.1" dependencies = [ "async-trait", "chrono", diff --git a/Cargo.toml b/Cargo.toml index d8836c5..f9bf393 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Neshura"] name = "aob-lemmy-bot" -version = "3.0.0" +version = "3.0.1" edition = "2021" description = "Bot for automatically posting new chapters of 'Ascendance of a Bookworm' released by J-Novel Club" license = "GPL-3.0-or-later" From b6f5c38e4a2b65fb06e034e125333254ef162383 Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Tue, 7 May 2024 23:49:55 +0200 Subject: [PATCH 31/43] Overhaul Error handling (Option instead of Result<T, ()> + Logging changes --- src/bot.rs | 15 +++++ src/config.rs | 68 +++++++++------------ src/fetchers/jnovel.rs | 12 ++-- src/lemmy.rs | 135 ++++++++++++++++++++++++++--------------- src/main.rs | 12 +++- 5 files changed, 146 insertions(+), 96 deletions(-) diff --git a/src/bot.rs b/src/bot.rs index 4539351..6a2890f 100644 --- a/src/bot.rs +++ b/src/bot.rs @@ -7,6 +7,15 @@ use notify::{Event, EventKind, event::{AccessKind, AccessMode}, RecursiveMode, W use tokio::time::sleep; use systemd_journal_logger::connected_to_journal; +macro_rules! debug { + ($msg:tt) => { + match connected_to_journal() { + true => log::debug!("[DEBUG] {}", $msg), + false => println!("[DEBUG] {}", $msg), + } + }; +} + macro_rules! info { ($msg:tt) => { match connected_to_journal() { @@ -76,6 +85,8 @@ impl Bot { }; lemmy.get_communities().await; + + self.history = SeriesHistory::load_history(); let start: DateTime<Utc> = Utc::now(); while Utc::now() - start <= Duration::minutes(60) { @@ -84,10 +95,14 @@ impl Bot { let read_copy = self.shared_config.read().expect("Read Lock Failed").clone(); for series in read_copy.series { series.update(&mut self.history, &lemmy, &self.shared_config).await; + debug!("Done Updating Series"); self.wait(1, Wait::Absolute).await; } + debug!("Awaiting Timeout"); self.wait(30, Wait::Buffer).await; + debug!("Pinging Server"); self.ping_status().await; + debug!("Awaiting Timeout 2"); self.wait(30, Wait::Absolute).await; } diff --git a/src/config.rs b/src/config.rs index 0bee169..a1da5e4 100644 --- a/src/config.rs +++ b/src/config.rs @@ -11,6 +11,15 @@ use systemd_journal_logger::connected_to_journal; use crate::fetchers::{FetcherTrait, Fetcher}; use crate::fetchers::jnovel::{JNovelFetcher}; +macro_rules! debug { + ($msg:tt) => { + match connected_to_journal() { + true => log::debug!("[DEBUG] {}", $msg), + false => println!("[DEBUG] {}", $msg), + } + }; +} + macro_rules! info { ($msg:tt) => { match connected_to_journal() { @@ -168,8 +177,8 @@ impl SeriesConfig { info!(info); let post_id = match lemmy.post(post_data).await { - Ok(data) => data, - Err(_) => { + Some(data) => data, + None=> { error!("Error posting chapter"); return; } @@ -188,31 +197,18 @@ impl SeriesConfig { post_info.get_post_config(self).name.as_str() ); info!(info); - let pinned_posts = match lemmy.get_community_pinned(lemmy.get_community_id(&post_info.get_post_config(self).name)).await { - Ok(data) => data, - Err(_) => { - error!("Pinning of Post to community failed"); - continue; - } - }; + let pinned_posts = lemmy.get_community_pinned(lemmy.get_community_id(&post_info.get_post_config(self).name)).await.unwrap_or_else(|| { + error!("Pinning of Post to community failed"); + vec![] + }); if !pinned_posts.is_empty() { let community_pinned_post = &pinned_posts[0]; - match lemmy - .unpin(community_pinned_post.post.id, PostFeatureType::Community) - .await { - Ok(_) => {} - Err(_) => { - error!("Error un-pinning post"); - return; - } + if lemmy.unpin(community_pinned_post.post.id, PostFeatureType::Community).await.is_none() { + error!("Error un-pinning post"); } } - match lemmy.pin(post_id, PostFeatureType::Community).await { - Ok(_) => {} - Err(_) => { - error!("Error pinning post"); - return; - } + if lemmy.pin(post_id, PostFeatureType::Community).await.is_none() { + error!("Error pinning post"); } } else if read_config .protected_communities @@ -229,10 +225,10 @@ impl SeriesConfig { let info = format!("Pinning '{}' to Instance", post_info.get_info().title); info!(info); let pinned_posts = match lemmy.get_local_pinned().await { - Ok(data) => {data} - Err(_) => { + Some(data) => {data} + None => { error!("Error fetching pinned posts"); - return; + vec![] } }; @@ -245,25 +241,16 @@ impl SeriesConfig { continue; } else { let community_pinned_post = &pinned_post; - match lemmy - .unpin(community_pinned_post.post.id, PostFeatureType::Local) - .await { - Ok(_) => {} - Err(_) => { - error!("Error pinning post"); - return; - } + if lemmy.unpin(community_pinned_post.post.id, PostFeatureType::Local).await.is_none() { + error!("Error pinning post"); + continue; } break; } } } - match lemmy.pin(post_id, PostFeatureType::Local).await { - Ok(_) => {} - Err(_) => { - error!("Error pinning post"); - return; - } + if lemmy.pin(post_id, PostFeatureType::Local).await.is_none() { + error!("Error pinning post"); }; } @@ -283,6 +270,7 @@ impl SeriesConfig { series_history.set_part(post_info.get_part_info().unwrap_or(PartInfo::NoParts).as_string().as_str(), part_history); history .set_series(self.slug.as_str(), series_history); + debug!("Saving History"); history.save_history(); } } diff --git a/src/fetchers/jnovel.rs b/src/fetchers/jnovel.rs index c13c626..69f6e6a 100644 --- a/src/fetchers/jnovel.rs +++ b/src/fetchers/jnovel.rs @@ -224,7 +224,7 @@ impl FetcherTrait for JNovelFetcher { .or_insert(new_post_info); } - if let Some(prepub_info) = get_latest_prepub(&volume.slug).await? { + if let Some(prepub_info) = get_latest_prepub(&volume.slug).await { let prepub_post_info = PostInfo { post_type: Some(PostType::Chapter), part: Some(new_part_info), @@ -252,7 +252,7 @@ impl FetcherTrait for JNovelFetcher { } -async fn get_latest_prepub(volume_slug: &str) -> Result<Option<PostInfoInner>, ()> { +async fn get_latest_prepub(volume_slug: &str) -> Option<PostInfoInner> { let response = match HTTP_CLIENT .get(api_url!() + "/volumes/" + volume_slug + "/parts?format=json") .send() @@ -263,13 +263,13 @@ async fn get_latest_prepub(volume_slug: &str) -> Result<Option<PostInfoInner>, ( Err(e) => { let err_msg = format!("While getting latest PrePub: {e}"); error!(err_msg); - return Err(()); + return None; } }, Err(e) => { let err_msg = format!("{e}"); error!(err_msg); - return Err(()); + return None; } }; @@ -278,7 +278,7 @@ async fn get_latest_prepub(volume_slug: &str) -> Result<Option<PostInfoInner>, ( Err(e) => { let err_msg = format!("{e}"); error!(err_msg); - return Err(()); + return None; } }; volume_prepub_parts_data.parts.reverse(); // Makes breaking out of the parts loop easier @@ -300,5 +300,5 @@ async fn get_latest_prepub(volume_slug: &str) -> Result<Option<PostInfoInner>, ( }); } - Ok(post_details) + post_details } diff --git a/src/lemmy.rs b/src/lemmy.rs index 29b2408..67b8dd0 100644 --- a/src/lemmy.rs +++ b/src/lemmy.rs @@ -15,6 +15,15 @@ use serde::{Deserialize, Serialize}; use url::Url; use systemd_journal_logger::connected_to_journal; +macro_rules! debug { + ($msg:tt) => { + match connected_to_journal() { + true => log::debug!("[DEBUG] {}", $msg), + false => println!("[DEBUG] {}", $msg), + } + }; +} + macro_rules! error { ($msg:tt) => { match connected_to_journal() { @@ -124,7 +133,7 @@ impl PostInfo { pub(crate) fn get_part_info(&self) -> Option<PartInfo> { self.part } - + pub(crate) fn get_post_config(&self, series: &SeriesConfig) -> PostConfig { match self.post_type { Some(post_type) => { @@ -136,10 +145,10 @@ impl PostInfo { None => series.prepub_community.clone(), } } - + pub(crate) fn get_post_data(&self, series: &SeriesConfig, lemmy: &Lemmy) -> CreatePost { let post_config = self.get_post_config(series); - + let post_body = match &post_config.post_body { PostBody::None => None, PostBody::Description => self.get_description(), @@ -156,7 +165,7 @@ impl PostInfo { honeypot: None, nsfw: None, language_id: Some(LanguageId(37)), // TODO get this id once every few hours per API request, the ordering of IDs suggests that the EN Id might change in the future - } + } } } @@ -252,21 +261,33 @@ impl Lemmy { } - pub(crate) async fn post(&self, post: CreatePost) -> Result<PostId, ()> { - let response: String = self.post_data_json("/api/v3/post", &post).await?; - let json_data: PostView = self.parse_json_map(&response).await?; + pub(crate) async fn post(&self, post: CreatePost) -> Option<PostId> { + let response: String = match self.post_data_json("/api/v3/post", &post).await { + Some(data) => data, + None => return None, + }; + let json_data: PostView = match self.parse_json_map(&response).await { + Some(data) => data, + None => return None, + }; - Ok(json_data.post.id) + Some(json_data.post.id) } - async fn feature(&self, params: FeaturePost) -> Result<PostView, ()> { - let response: String = self.post_data_json("/api/v3/post/feature", ¶ms).await?; - let json_data: PostView = self.parse_json_map(&response).await?; + async fn feature(&self, params: FeaturePost) -> Option<PostView> { + let response: String = match self.post_data_json("/api/v3/post/feature", ¶ms).await { + Some(data) => data, + None => return None, + }; + let json_data: PostView = match self.parse_json_map(&response).await { + Some(data) => data, + None => return None, + }; - Ok(json_data) + Some(json_data) } - pub(crate) async fn unpin(&self, post_id: PostId, location: PostFeatureType) -> Result<PostView, ()> { + pub(crate) async fn unpin(&self, post_id: PostId, location: PostFeatureType) -> Option<PostView> { let pin_params = FeaturePost { post_id, featured: false, @@ -275,7 +296,7 @@ impl Lemmy { self.feature(pin_params).await } - pub(crate) async fn pin(&self, post_id: PostId, location: PostFeatureType) -> Result<PostView, ()> { + pub(crate) async fn pin(&self, post_id: PostId, location: PostFeatureType) -> Option<PostView> { let pin_params = FeaturePost { post_id, featured: true, @@ -284,17 +305,23 @@ impl Lemmy { self.feature(pin_params).await } - pub(crate) async fn get_community_pinned(&self, community: CommunityId) -> Result<Vec<PostView>, ()> { + pub(crate) async fn get_community_pinned(&self, community: CommunityId) -> Option<Vec<PostView>> { let list_params = GetPosts { community_id: Some(community), type_: Some(ListingType::Local), ..Default::default() }; - let response: String = self.get_data_query("/api/v3/post/list", &list_params).await?; - let json_data: GetPostsResponse = self.parse_json(&response).await?; + let response: String = match self.get_data_query("/api/v3/post/list", &list_params).await { + Some(data) => data, + None => return None, + }; + let json_data: GetPostsResponse = match self.parse_json(&response).await { + Some(data) => data, + None => return None, + }; - Ok(json_data + Some(json_data .posts .iter() .filter(|post| post.post.featured_community) @@ -302,16 +329,22 @@ impl Lemmy { .collect()) } - pub(crate) async fn get_local_pinned(&self) -> Result<Vec<PostView>, ()> { + pub(crate) async fn get_local_pinned(&self) -> Option<Vec<PostView>> { let list_params = GetPosts { type_: Some(ListingType::Local), ..Default::default() }; - let response: String = self.get_data_query("/api/v3/post/list", &list_params).await?; - let json_data: GetPostsResponse = self.parse_json(&response).await?; + let response: String = match self.get_data_query("/api/v3/post/list", &list_params).await { + Some(data) => data, + None => return None, + }; + let json_data: GetPostsResponse = match self.parse_json(&response).await { + Some(data) => data, + None => return None, + }; - Ok(json_data + Some(json_data .posts .iter() .filter(|post| post.post.featured_local) @@ -326,18 +359,12 @@ impl Lemmy { }; let response: String = match self.get_data_query("/api/v3/community/list", &list_params).await { - Ok(data) => data, - Err(_) => { - error!("Unable to extract data from request"); - return; - } + Some(data) => data, + None => return, }; let json_data: ListCommunitiesResponse = match self.parse_json::<ListCommunitiesResponse>(&response).await { - Ok(data) => data, - Err(_) => { - error!("Unable to parse data from json"); - return; - }, + Some(data) => data, + None => return, }; let mut communities: HashMap<String, CommunityId> = HashMap::new(); @@ -349,7 +376,7 @@ impl Lemmy { self.communities = communities; } - async fn post_data_json<T: Serialize>(&self, route: &str, json: &T ) -> Result<String,()> { + async fn post_data_json<T: Serialize>(&self, route: &str, json: &T ) -> Option<String> { let res = HTTP_CLIENT .post(format!("{}{route}", &self.instance)) .bearer_auth(&self.jwt_token.to_string()) @@ -359,7 +386,7 @@ impl Lemmy { self.extract_data(res).await } - async fn get_data_query<T: Serialize>(&self, route: &str, param: &T ) -> Result<String,()> { + async fn get_data_query<T: Serialize>(&self, route: &str, param: &T ) -> Option<String> { let res = HTTP_CLIENT .get(format!("{}{route}", &self.instance)) .bearer_auth(&self.jwt_token.to_string()) @@ -369,42 +396,52 @@ impl Lemmy { self.extract_data(res).await } - async fn extract_data(&self, response: Result<reqwest::Response, reqwest::Error>) -> Result<String,()> { + async fn extract_data(&self, response: Result<reqwest::Response, reqwest::Error>) -> Option<String> { match response { - Ok(data) => match data.text().await { - Ok(data) => Ok(data), - Err(e) => { - let err_msg = format!("{e}"); + Ok(data) => { + if data.status().is_success() { + match data.text().await { + Ok(data) => Some(data), + Err(e) => { + let err_msg = format!("{e}"); + error!(err_msg); + None + } + } + } + else { + let err_msg = format!("HTTP Request failed: {}", data.text().await.unwrap()); error!(err_msg); - Err(()) + None } }, Err(e) => { let err_msg = format!("{e}"); error!(err_msg); - Err(()) + None } } } - async fn parse_json<'a, T: Deserialize<'a>>(&self, response: &'a str) -> Result<T,()> { + async fn parse_json<'a, T: Deserialize<'a>>(&self, response: &'a str) -> Option<T> { match serde_json::from_str::<T>(response) { - Ok(data) => Ok(data), + Ok(data) => Some(data), Err(e) => { - let err_msg = format!("{e} while parsing JSON"); + let err_msg = format!("while parsing JSON: {e} "); error!(err_msg); - Err(()) + None } } } - async fn parse_json_map<'a, T: Deserialize<'a>>(&self, response: &'a str) -> Result<T,()> { + async fn parse_json_map<'a, T: Deserialize<'a>>(&self, response: &'a str) -> Option<T> { + debug!(response); match serde_json::from_str::<HashMap<&str, T>>(response) { - Ok(mut data) => Ok(data.remove("post_view").expect("Element should be present")), + Ok(mut data) => Some(data.remove("post_view").expect("Element should be present")), Err(e) => { - let err_msg = format!("{e} while parsing JSON HashMap"); + let err_msg = format!("while parsing JSON HashMap: {e}"); error!(err_msg); - Err(()) + None } } } diff --git a/src/main.rs b/src/main.rs index 5eae9ae..cc0e9cd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,7 +25,17 @@ async fn main() { .expect("Systemd-Logger crate error") .install() .expect("Systemd-Logger crate error"); - log::set_max_level(LevelFilter::Info); + match std::env::var("LOG_LEVEL") { + Ok(level) => { + match level.as_str() { + "debug" => log::set_max_level(LevelFilter::Debug), + "info" => log::set_max_level(LevelFilter::Info), + _ => log::set_max_level(LevelFilter::Info), + } + } + _ => log::set_max_level(LevelFilter::Info), + } + let mut bot = Bot::new(); bot.run().await; } From 1b585eab7ead01a3ff64a426071ae228d8111171 Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Tue, 7 May 2024 23:50:14 +0200 Subject: [PATCH 32/43] Release 3.0.2 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8774ff1..b77b6aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,7 +43,7 @@ dependencies = [ [[package]] name = "aob-lemmy-bot" -version = "3.0.1" +version = "3.0.2" dependencies = [ "async-trait", "chrono", diff --git a/Cargo.toml b/Cargo.toml index f9bf393..16e0bd6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Neshura"] name = "aob-lemmy-bot" -version = "3.0.1" +version = "3.0.2" edition = "2021" description = "Bot for automatically posting new chapters of 'Ascendance of a Bookworm' released by J-Novel Club" license = "GPL-3.0-or-later" From 94d8a4e6733bb5f84aa2e37598c32c5c07471789 Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Wed, 8 May 2024 16:34:32 +0200 Subject: [PATCH 33/43] Add Timeout to Status Ping HTTP Request --- src/bot.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bot.rs b/src/bot.rs index 6a2890f..ba0e8b9 100644 --- a/src/bot.rs +++ b/src/bot.rs @@ -1,4 +1,4 @@ -use crate::{config::{Config}}; +use crate::{config::{Config}, HTTP_CLIENT}; use crate::lemmy::{Lemmy}; use crate::post_history::{SeriesHistory}; use chrono::{DateTime, Duration, Utc}; @@ -113,7 +113,7 @@ impl Bot { async fn ping_status(&self) { let read_config = &self.shared_config.read().expect("Read Lock Failed").clone(); if let Some(status_url) = &read_config.status_post_url { - match reqwest::get(status_url).await { + match HTTP_CLIENT.get(status_url).send().await { Ok(_) => {}, Err(e) => { let err_msg = format!("While pinging status URL: {e}"); From 7dcc7bfee26205317114d9ab8a96721a93dd9b5a Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Wed, 8 May 2024 16:34:48 +0200 Subject: [PATCH 34/43] Release 3.0.3 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b77b6aa..3232c07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,7 +43,7 @@ dependencies = [ [[package]] name = "aob-lemmy-bot" -version = "3.0.2" +version = "3.0.3" dependencies = [ "async-trait", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 16e0bd6..e650afe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Neshura"] name = "aob-lemmy-bot" -version = "3.0.2" +version = "3.0.3" edition = "2021" description = "Bot for automatically posting new chapters of 'Ascendance of a Bookworm' released by J-Novel Club" license = "GPL-3.0-or-later" From 2ecfe88cb937118abe56dd4649469f7faf638690 Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 15 Jul 2024 22:15:19 +0200 Subject: [PATCH 35/43] Update to 0.19.5 and include optional thumbnail --- Cargo.lock | 446 ++++++++++++++++++++++++++++++++--------- Cargo.toml | 4 +- src/config.rs | 18 +- src/fetchers/jnovel.rs | 9 +- src/lemmy.rs | 10 +- 5 files changed, 378 insertions(+), 109 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3232c07..5e392fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,6 +41,15 @@ dependencies = [ "libc", ] +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +dependencies = [ + "backtrace", +] + [[package]] name = "aob-lemmy-bot" version = "3.0.3" @@ -57,7 +66,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "strum_macros 0.26.2", + "strum_macros", "systemd-journal-logger", "tokio", "toml", @@ -65,10 +74,21 @@ dependencies = [ ] [[package]] -name = "async-trait" -version = "0.1.77" +name = "async-lock" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-trait" +version = "0.1.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", @@ -96,12 +116,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base64" -version = "0.21.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" - [[package]] name = "base64" version = "0.22.1" @@ -149,9 +163,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", @@ -159,7 +173,16 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.48.5", + "windows-targets 0.52.0", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", ] [[package]] @@ -174,6 +197,12 @@ dependencies = [ "toml", ] +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + [[package]] name = "core-foundation" version = "0.9.4" @@ -199,6 +228,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.19" @@ -250,6 +288,17 @@ dependencies = [ "serde", ] +[[package]] +name = "derive-new" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d150dea618e920167e5973d70ae6ece4385b7164e0d799fe7c122dd0a5d912ad" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "directories" version = "5.0.1" @@ -316,6 +365,27 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener", + "pin-project-lite", +] + [[package]] name = "fastrand" version = "2.0.1" @@ -330,7 +400,7 @@ checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.4.1", "windows-sys 0.52.0", ] @@ -385,21 +455,21 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-io" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", @@ -408,21 +478,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-core", "futures-io", @@ -437,9 +507,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "js-sys", @@ -487,9 +557,9 @@ checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" @@ -729,10 +799,11 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lemmy_api_common" -version = "0.19.3" +version = "0.19.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17366fcde90b07f4e5a8fefa62378fe348424ba79c8e9fb3ddc63ef76d687493" +checksum = "0350aefa5e5b7bc90fe5a6f992dbac5a1960c776ff16f4bee18660f11b3b95fc" dependencies = [ + "anyhow", "chrono", "enum-map", "getrandom", @@ -740,25 +811,31 @@ dependencies = [ "lemmy_db_views", "lemmy_db_views_actor", "lemmy_db_views_moderator", + "lemmy_utils", + "moka", "regex", "serde", "serde_with", "url", + "urlencoding", ] [[package]] name = "lemmy_db_schema" -version = "0.19.3" +version = "0.19.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e2d9a0c6f8f3df4664f9479ceca138ee6217b89653bafb753a498cabc5f3ab5" +checksum = "4280976725dce988e4750e124a5600ead8d7fca0a07a7cf9e42da3ece946396c" dependencies = [ + "anyhow", "async-trait", "chrono", + "derive-new", "futures-util", + "moka", "serde", "serde_with", "strum", - "strum_macros 0.25.3", + "strum_macros", "tracing", "typed-builder", "url", @@ -767,10 +844,11 @@ dependencies = [ [[package]] name = "lemmy_db_views" -version = "0.19.3" +version = "0.19.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02659eb474ab54da6296d4edb5a974c0affa5cfcf8a2fa31bb52793dedef9d5a" +checksum = "d7107a8725ed7fd12eb0cb451dff52d969ca5ac445d1aabb77881cfe75715a45" dependencies = [ + "chrono", "lemmy_db_schema", "serde", "serde_with", @@ -778,23 +856,23 @@ dependencies = [ [[package]] name = "lemmy_db_views_actor" -version = "0.19.3" +version = "0.19.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5187730858dc808b5cf06aadbb1d1f8ca360d4ed3c375e5606e63be4c9e24e06" +checksum = "bb7eeb5e65373c37aff03793cf90f8096557af7eb5f41426be9d3bc64b782152" dependencies = [ "chrono", "lemmy_db_schema", "serde", "serde_with", "strum", - "strum_macros 0.25.3", + "strum_macros", ] [[package]] name = "lemmy_db_views_moderator" -version = "0.19.3" +version = "0.19.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18f6fab36e1dcadc043b81c5916044ee65219d837f5d221a908296f9c55f3872" +checksum = "52b9425bb6059979ebe5b4f2124ff5af898ac6e5fcf43053bd2485c504afe39e" dependencies = [ "lemmy_db_schema", "serde", @@ -802,10 +880,23 @@ dependencies = [ ] [[package]] -name = "libc" -version = "0.2.151" +name = "lemmy_utils" +version = "0.19.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" +checksum = "5afa108b6db73c057eb9aadaecd84269c138500519789c76106c671df684fb5a" +dependencies = [ + "cfg-if", + "rosetta-build", + "serde", + "strum", + "strum_macros", +] + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libredox" @@ -815,7 +906,7 @@ checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ "bitflags 2.4.1", "libc", - "redox_syscall", + "redox_syscall 0.4.1", ] [[package]] @@ -824,6 +915,16 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.20" @@ -866,6 +967,30 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "moka" +version = "0.12.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cf62eb4dd975d2dde76432fb1075c49e3ee2331cf36f1f8fd4b66550d32b6f" +dependencies = [ + "async-lock", + "async-trait", + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "event-listener", + "futures-util", + "once_cell", + "parking_lot", + "quanta", + "rustc_version", + "smallvec", + "tagptr", + "thiserror", + "triomphe", + "uuid", +] + [[package]] name = "native-tls" version = "0.2.11" @@ -903,6 +1028,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-traits" version = "0.2.17" @@ -987,6 +1118,35 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.3", + "smallvec", + "windows-targets 0.52.0", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1046,6 +1206,21 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quanta" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5" +dependencies = [ + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi", + "web-sys", + "winapi", +] + [[package]] name = "quote" version = "1.0.35" @@ -1055,6 +1230,15 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "raw-cpuid" +version = "11.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e29830cbb1290e404f24c73af91c5d8d631ce7e128691e9477556b540cd01ecd" +dependencies = [ + "bitflags 2.4.1", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -1064,6 +1248,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +dependencies = [ + "bitflags 2.4.1", +] + [[package]] name = "redox_users" version = "0.4.4" @@ -1077,9 +1270,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.2" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", @@ -1089,9 +1282,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", @@ -1110,7 +1303,7 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" dependencies = [ - "base64 0.22.1", + "base64", "bytes", "encoding_rs", "futures-channel", @@ -1147,12 +1340,35 @@ dependencies = [ "winreg", ] +[[package]] +name = "rosetta-build" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24191a1fed7ae7a5d89f816366f5c03ebce70a7a4d7158534afdf8dd719749fe" +dependencies = [ + "convert_case", + "lazy_static", + "proc-macro2", + "quote", + "regex", + "tinyjson", +] + [[package]] name = "rustc-demangle" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.28" @@ -1172,7 +1388,7 @@ version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" dependencies = [ - "base64 0.22.1", + "base64", "rustls-pki-types", ] @@ -1212,6 +1428,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "security-framework" version = "2.9.2" @@ -1236,19 +1458,25 @@ dependencies = [ ] [[package]] -name = "serde" -version = "1.0.193" +name = "semver" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "serde" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", @@ -1289,16 +1517,17 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.4.0" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23" +checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" dependencies = [ - "base64 0.21.5", + "base64", "chrono", "hex", "indexmap 1.9.3", "indexmap 2.1.0", "serde", + "serde_derive", "serde_json", "serde_with_macros", "time", @@ -1306,9 +1535,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.4.0" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788" +checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" dependencies = [ "darling", "proc-macro2", @@ -1349,28 +1578,15 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strum" -version = "0.25.0" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" [[package]] name = "strum_macros" -version = "0.25.3" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn", -] - -[[package]] -name = "strum_macros" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ "heck", "proc-macro2", @@ -1427,6 +1643,12 @@ dependencies = [ "rustix", ] +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + [[package]] name = "tempfile" version = "3.8.1" @@ -1435,7 +1657,7 @@ checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", + "redox_syscall 0.4.1", "rustix", "windows-sys 0.48.0", ] @@ -1462,12 +1684,13 @@ dependencies = [ [[package]] name = "time" -version = "0.3.30" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", + "num-conv", "powerfmt", "serde", "time-core", @@ -1482,13 +1705,20 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.15" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ + "num-conv", "time-core", ] +[[package]] +name = "tinyjson" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ab95735ea2c8fd51154d01e39cf13912a78071c2d89abc49a7ef102a7dd725a" + [[package]] name = "tinyvec" version = "1.6.0" @@ -1650,6 +1880,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "triomphe" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3" + [[package]] name = "try-lock" version = "0.2.5" @@ -1658,18 +1894,18 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typed-builder" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e47c0496149861b7c95198088cbf36645016b1a0734cf350c50e2a38e070f38a" +checksum = "77739c880e00693faef3d65ea3aad725f196da38b22fdc7ea6ded6e1ce4d3add" dependencies = [ "typed-builder-macro", ] [[package]] name = "typed-builder-macro" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982ee4197351b5c9782847ef5ec1fdcaf50503fb19d68f9771adae314e72b492" +checksum = "1f718dfaf347dcb5b983bfc87608144b0bad87970aebcbea5ce44d2a30c08e63" dependencies = [ "proc-macro2", "quote", @@ -1710,10 +1946,16 @@ dependencies = [ ] [[package]] -name = "uuid" -version = "1.6.1" +name = "urlencoding" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "uuid" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ "getrandom", "serde", @@ -1832,6 +2074,22 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + [[package]] name = "winapi-util" version = "0.1.8" @@ -1841,6 +2099,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-core" version = "0.51.1" diff --git a/Cargo.toml b/Cargo.toml index e650afe..e51df17 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,8 +17,8 @@ systemd-units = { enable = false } [dependencies] chrono = "^0.4" -lemmy_api_common = "0.19.3" -lemmy_db_schema = "0.19.3" +lemmy_api_common = "0.19.5" +lemmy_db_schema = "0.19.5" once_cell = "^1.19" reqwest = { version = "^0.12", features = ["blocking", "json"] } serde = "^1.0" diff --git a/src/config.rs b/src/config.rs index a1da5e4..34627b3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -2,8 +2,8 @@ use std::path::PathBuf; use std::sync::{Arc, RwLock}; use chrono::{Timelike, Utc}; use crate::config::PostBody::Description; -use lemmy_api_common::sensitive::Sensitive; use lemmy_db_schema::PostFeatureType; +use lemmy_db_schema::sensitive::SensitiveString; use serde_derive::{Deserialize, Serialize}; use crate::lemmy::{Lemmy, PartInfo, PostType}; use crate::post_history::{SeriesHistory}; @@ -50,8 +50,8 @@ macro_rules! error { #[derive(Serialize, Deserialize, Clone, Debug)] pub(crate) struct Config { pub(crate) instance: String, - username: String, - password: String, + username: SensitiveString, + password: SensitiveString, pub(crate) status_post_url: Option<String>, pub(crate) config_reload_seconds: u32, pub(crate) protected_communities: Vec<String>, @@ -89,12 +89,12 @@ impl Config { confy::get_configuration_file_path(env!("CARGO_PKG_NAME"), "config").expect("Application will not without confy") } - pub(crate) fn get_username(&self) -> Sensitive<String> { - Sensitive::new(self.username.clone()) + pub(crate) fn get_username(&self) -> SensitiveString { + self.username.clone() } - pub(crate) fn get_password(&self) -> Sensitive<String> { - Sensitive::new(self.password.clone()) + pub(crate) fn get_password(&self) -> SensitiveString { + self.password.clone() } } @@ -102,8 +102,8 @@ impl Default for Config { fn default() -> Self { Config { instance: "".to_owned(), - username: "".to_owned(), - password: "".to_owned(), + username: SensitiveString::from("".to_owned()), + password: SensitiveString::from("".to_owned()), status_post_url: None, config_reload_seconds: 21600, protected_communities: vec![], diff --git a/src/fetchers/jnovel.rs b/src/fetchers/jnovel.rs index 69f6e6a..493ed07 100644 --- a/src/fetchers/jnovel.rs +++ b/src/fetchers/jnovel.rs @@ -4,7 +4,6 @@ use serde_derive::{Deserialize, Serialize}; use std::collections::HashMap; use std::ops::Sub; use async_trait::async_trait; -use url::Url; use crate::fetchers::{FetcherTrait}; use crate::lemmy::{PartInfo, PostInfo, PostInfoInner, PostType}; use systemd_journal_logger::connected_to_journal; @@ -201,7 +200,8 @@ impl FetcherTrait for JNovelFetcher { ); let post_details = PostInfoInner { title: volume.title.clone(), - url: Url::parse(&post_url).unwrap(), + url: post_url.clone(), + thumbnail: Some(volume.cover.thumbnail.clone()) }; let new_post_info = PostInfo { @@ -293,10 +293,13 @@ async fn get_latest_prepub(volume_slug: &str) -> Option<PostInfoInner> { continue; } + let thumbnail = prepub_part.cover.as_ref().map(|cover| cover.thumbnail.clone()); + let post_url = format!("{}/read/{}", jnc_base_url!(), prepub_part.slug); post_details = Some(PostInfoInner { title: prepub_part.title.clone(), - url: Url::parse(&post_url).unwrap(), + url: post_url.clone(), + thumbnail }); } diff --git a/src/lemmy.rs b/src/lemmy.rs index 67b8dd0..2686778 100644 --- a/src/lemmy.rs +++ b/src/lemmy.rs @@ -5,14 +5,13 @@ use lemmy_api_common::community::{ListCommunities, ListCommunitiesResponse}; use lemmy_api_common::lemmy_db_views::structs::PostView; use lemmy_api_common::person::{Login, LoginResponse}; use lemmy_api_common::post::{CreatePost, FeaturePost, GetPosts, GetPostsResponse}; -use lemmy_api_common::sensitive::Sensitive; use lemmy_db_schema::newtypes::{CommunityId, LanguageId, PostId}; use lemmy_db_schema::{ListingType, PostFeatureType}; use reqwest::StatusCode; use std::collections::HashMap; use std::sync::{RwLock}; +use lemmy_db_schema::sensitive::SensitiveString; use serde::{Deserialize, Serialize}; -use url::Url; use systemd_journal_logger::connected_to_journal; macro_rules! debug { @@ -34,7 +33,7 @@ macro_rules! error { } pub(crate) struct Lemmy { - jwt_token: Sensitive<String>, + jwt_token: SensitiveString, instance: String, communities: HashMap<String, CommunityId>, } @@ -43,7 +42,8 @@ pub(crate) struct Lemmy { #[derive(Debug, Clone)] pub(crate) struct PostInfoInner { pub(crate) title: String, - pub(crate) url: Url, + pub(crate) url: String, + pub(crate) thumbnail: Option<String> } #[derive(Debug, Copy, Clone)] @@ -161,7 +161,9 @@ impl PostInfo { name: self.get_info().title.clone(), community_id, url: Some(self.get_info().url), + custom_thumbnail: self.get_info().thumbnail, body: post_body, + alt_text: None, honeypot: None, nsfw: None, language_id: Some(LanguageId(37)), // TODO get this id once every few hours per API request, the ordering of IDs suggests that the EN Id might change in the future From 2ae6468ad8026b3ad3dc0a874890ab203a8641ec Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Mon, 15 Jul 2024 22:15:49 +0200 Subject: [PATCH 36/43] Release 3.1.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5e392fd..e713680 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,7 +52,7 @@ dependencies = [ [[package]] name = "aob-lemmy-bot" -version = "3.0.3" +version = "3.1.0" dependencies = [ "async-trait", "chrono", diff --git a/Cargo.toml b/Cargo.toml index e51df17..fd82bf3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Neshura"] name = "aob-lemmy-bot" -version = "3.0.3" +version = "3.1.0" edition = "2021" description = "Bot for automatically posting new chapters of 'Ascendance of a Bookworm' released by J-Novel Club" license = "GPL-3.0-or-later" From 0fc71f0a7d7f4dbbbcc1d16b1d5cbae1e2db649a Mon Sep 17 00:00:00 2001 From: Neshura <neshura@noreply.forgejo.neshweb.net> Date: Tue, 6 Aug 2024 12:19:37 +0000 Subject: [PATCH 37/43] Bump forgejo-release to v2 --- .forgejo/workflows/build+release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/build+release.yml b/.forgejo/workflows/build+release.yml index 6b63dad..a21f697 100644 --- a/.forgejo/workflows/build+release.yml +++ b/.forgejo/workflows/build+release.yml @@ -137,7 +137,7 @@ jobs: run: rm release_blobs/build.env - name: Release New Version - uses: actions/forgejo-release@v1 + uses: actions/forgejo-release@v2 with: direction: upload url: https://forgejo.neshweb.net From d6f883f89011c0aaf4ceea52096591067a6f202b Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Tue, 22 Oct 2024 16:13:30 +0200 Subject: [PATCH 38/43] Bump API version --- src/fetchers/jnovel.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fetchers/jnovel.rs b/src/fetchers/jnovel.rs index 493ed07..c5a0a42 100644 --- a/src/fetchers/jnovel.rs +++ b/src/fetchers/jnovel.rs @@ -31,7 +31,7 @@ static PAST_DAYS_ELIGIBLE: u8 = 4; macro_rules! api_url { () => { - "https://labs.j-novel.club/app/v1".to_owned() + "https://labs.j-novel.club/app/v2".to_owned() }; } From 041590a55907c1aafdd2cda942feded9d6b69233 Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Tue, 22 Oct 2024 16:15:19 +0200 Subject: [PATCH 39/43] Release 3.2.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e713680..86dff79 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,7 +52,7 @@ dependencies = [ [[package]] name = "aob-lemmy-bot" -version = "3.1.0" +version = "3.2.0" dependencies = [ "async-trait", "chrono", diff --git a/Cargo.toml b/Cargo.toml index fd82bf3..d7fa472 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Neshura"] name = "aob-lemmy-bot" -version = "3.1.0" +version = "3.2.0" edition = "2021" description = "Bot for automatically posting new chapters of 'Ascendance of a Bookworm' released by J-Novel Club" license = "GPL-3.0-or-later" From 3b5e65b35067ca2b9e45600d7306602c718bb53b Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Tue, 25 Mar 2025 21:11:44 +0100 Subject: [PATCH 40/43] Release 3.2.1 - fix #27 --- Cargo.lock | 409 +++++++++++++++++++++++++++++++++++++++++++------- Cargo.toml | 6 +- src/config.rs | 14 +- src/lemmy.rs | 35 ++++- 4 files changed, 403 insertions(+), 61 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 86dff79..07245d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -52,7 +52,7 @@ dependencies = [ [[package]] name = "aob-lemmy-bot" -version = "3.2.0" +version = "3.2.1" dependencies = [ "async-trait", "chrono", @@ -140,6 +140,12 @@ version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.5.0" @@ -155,6 +161,17 @@ dependencies = [ "libc", ] +[[package]] +name = "cfb" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +dependencies = [ + "byteorder", + "fnv", + "uuid", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -176,6 +193,20 @@ dependencies = [ "windows-targets 0.52.0", ] +[[package]] +name = "clearurls" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e291c00af89ac0a5b400d9ba46a682e38015ae3cd8926dbbe85b3b864d550be3" +dependencies = [ + "linkify", + "percent-encoding", + "regex", + "serde", + "serde_json", + "url", +] + [[package]] name = "concurrent-queue" version = "2.5.0" @@ -290,9 +321,9 @@ dependencies = [ [[package]] name = "derive-new" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d150dea618e920167e5973d70ae6ece4385b7164e0d799fe7c122dd0a5d912ad" +checksum = "2cdc8d50f426189eef89dac62fabfa0abb27d5cc008f25bf4156a0203325becc" dependencies = [ "proc-macro2", "quote", @@ -320,6 +351,17 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "encoding_rs" version = "0.8.33" @@ -692,6 +734,124 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -700,12 +860,23 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] @@ -730,6 +901,15 @@ dependencies = [ "serde", ] +[[package]] +name = "infer" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc150e5ce2330295b8616ce0e3f53250e53af31759a9dbedad1621ba29151847" +dependencies = [ + "cfb", +] + [[package]] name = "inotify" version = "0.9.6" @@ -799,19 +979,21 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lemmy_api_common" -version = "0.19.5" +version = "0.19.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0350aefa5e5b7bc90fe5a6f992dbac5a1960c776ff16f4bee18660f11b3b95fc" +checksum = "06a7554d0a71b37c1f666125918a72fe92103a5f254668a988aaa31ed80d4b7b" dependencies = [ "anyhow", "chrono", "enum-map", "getrandom", + "infer", "lemmy_db_schema", "lemmy_db_views", "lemmy_db_views_actor", "lemmy_db_views_moderator", "lemmy_utils", + "mime_guess", "moka", "regex", "serde", @@ -822,9 +1004,9 @@ dependencies = [ [[package]] name = "lemmy_db_schema" -version = "0.19.5" +version = "0.19.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4280976725dce988e4750e124a5600ead8d7fca0a07a7cf9e42da3ece946396c" +checksum = "5454e0df45ec4831b7c6502d965cb9865ecbe2cb181a20c616ad8235444c06e8" dependencies = [ "anyhow", "async-trait", @@ -835,7 +1017,6 @@ dependencies = [ "serde", "serde_with", "strum", - "strum_macros", "tracing", "typed-builder", "url", @@ -844,9 +1025,9 @@ dependencies = [ [[package]] name = "lemmy_db_views" -version = "0.19.5" +version = "0.19.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7107a8725ed7fd12eb0cb451dff52d969ca5ac445d1aabb77881cfe75715a45" +checksum = "c4d348095887630617ef02b823887d422ae2e93dfff7a13a127e7524eec51d99" dependencies = [ "chrono", "lemmy_db_schema", @@ -856,23 +1037,22 @@ dependencies = [ [[package]] name = "lemmy_db_views_actor" -version = "0.19.5" +version = "0.19.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7eeb5e65373c37aff03793cf90f8096557af7eb5f41426be9d3bc64b782152" +checksum = "cd7a42bf16a72d6f313f59116538e1333e6ce5f2efbeb9b834ddb147b2cdf986" dependencies = [ "chrono", "lemmy_db_schema", "serde", "serde_with", "strum", - "strum_macros", ] [[package]] name = "lemmy_db_views_moderator" -version = "0.19.5" +version = "0.19.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52b9425bb6059979ebe5b4f2124ff5af898ac6e5fcf43053bd2485c504afe39e" +checksum = "4b6a1a841c4ccac1947f7edfbb52b3113d32f218a2eede769ec5dce4a039cd43" dependencies = [ "lemmy_db_schema", "serde", @@ -881,15 +1061,15 @@ dependencies = [ [[package]] name = "lemmy_utils" -version = "0.19.5" +version = "0.19.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5afa108b6db73c057eb9aadaecd84269c138500519789c76106c671df684fb5a" +checksum = "0ee28dc456fac8d5c7ae67b4f596a1e9e2a0a9a6e1c4f8a024bdfb34cf25dfa5" dependencies = [ "cfg-if", + "clearurls", "rosetta-build", "serde", "strum", - "strum_macros", ] [[package]] @@ -909,12 +1089,27 @@ dependencies = [ "redox_syscall 0.4.1", ] +[[package]] +name = "linkify" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dfa36d52c581e9ec783a7ce2a5e0143da6237be5811a0b3153fedfdbe9f780" +dependencies = [ + "memchr", +] + [[package]] name = "linux-raw-sys" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +[[package]] +name = "litemap" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" + [[package]] name = "lock_api" version = "0.4.12" @@ -946,6 +1141,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "miniz_oxide" version = "0.7.1" @@ -1485,11 +1690,12 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -1570,6 +1776,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "strsim" version = "0.10.0" @@ -1581,6 +1793,9 @@ name = "strum" version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] [[package]] name = "strum_macros" @@ -1612,6 +1827,17 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "system-configuration" version = "0.5.1" @@ -1720,20 +1946,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ab95735ea2c8fd51154d01e39cf13912a78071c2d89abc49a7ef102a7dd725a" [[package]] -name = "tinyvec" -version = "1.6.0" +name = "tinystr" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ - "tinyvec_macros", + "displaydoc", + "zerovec", ] -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "tokio" version = "1.37.0" @@ -1894,18 +2115,18 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typed-builder" -version = "0.18.2" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77739c880e00693faef3d65ea3aad725f196da38b22fdc7ea6ded6e1ce4d3add" +checksum = "a06fbd5b8de54c5f7c91f6fe4cebb949be2125d7758e630bb58b1d831dbce600" dependencies = [ "typed-builder-macro", ] [[package]] name = "typed-builder-macro" -version = "0.18.2" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f718dfaf347dcb5b983bfc87608144b0bad87970aebcbea5ce44d2a30c08e63" +checksum = "f9534daa9fd3ed0bd911d462a37f172228077e7abf18c18a5f67199d959205f8" dependencies = [ "proc-macro2", "quote", @@ -1913,10 +2134,10 @@ dependencies = [ ] [[package]] -name = "unicode-bidi" -version = "0.3.14" +name = "unicase" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-ident" @@ -1924,20 +2145,11 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - [[package]] name = "url" -version = "2.5.0" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", @@ -1951,6 +2163,18 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "uuid" version = "1.10.0" @@ -2264,3 +2488,82 @@ dependencies = [ "cfg-if", "windows-sys 0.48.0", ] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index d7fa472..43f3599 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Neshura"] name = "aob-lemmy-bot" -version = "3.2.0" +version = "3.2.1" edition = "2021" description = "Bot for automatically posting new chapters of 'Ascendance of a Bookworm' released by J-Novel Club" license = "GPL-3.0-or-later" @@ -17,8 +17,8 @@ systemd-units = { enable = false } [dependencies] chrono = "^0.4" -lemmy_api_common = "0.19.5" -lemmy_db_schema = "0.19.5" +lemmy_api_common = "0.19.9" +lemmy_db_schema = "0.19.9" once_cell = "^1.19" reqwest = { version = "^0.12", features = ["blocking", "json"] } serde = "^1.0" diff --git a/src/config.rs b/src/config.rs index 34627b3..d392db0 100644 --- a/src/config.rs +++ b/src/config.rs @@ -176,11 +176,17 @@ impl SeriesConfig { ); info!(info); - let post_id = match lemmy.post(post_data).await { + let post_id = match lemmy.post(post_data.clone()).await { Some(data) => data, - None=> { - error!("Error posting chapter"); - return; + None => { + error!("Error posting chapter, applying fix for Issue #27"); + match lemmy.check_community_for_post(post_data).await { + Some(data) => data, + None => { + error!("Unable to find Post via API"); + return; + } + } } }; diff --git a/src/lemmy.rs b/src/lemmy.rs index 2686778..6afe1e5 100644 --- a/src/lemmy.rs +++ b/src/lemmy.rs @@ -6,7 +6,7 @@ use lemmy_api_common::lemmy_db_views::structs::PostView; use lemmy_api_common::person::{Login, LoginResponse}; use lemmy_api_common::post::{CreatePost, FeaturePost, GetPosts, GetPostsResponse}; use lemmy_db_schema::newtypes::{CommunityId, LanguageId, PostId}; -use lemmy_db_schema::{ListingType, PostFeatureType}; +use lemmy_db_schema::{ListingType, PostFeatureType, SortType}; use reqwest::StatusCode; use std::collections::HashMap; use std::sync::{RwLock}; @@ -378,6 +378,39 @@ impl Lemmy { self.communities = communities; } + pub(crate) async fn check_community_for_post(&self, post: CreatePost) -> Option<PostId> { + let get_params: GetPosts = GetPosts { + type_: None, + sort: Some(SortType::New), + page: None, + limit: None, + community_id: Some(post.community_id), + community_name: None, + saved_only: None, + liked_only: None, + disliked_only: None, + show_hidden: None, + show_read: None, + show_nsfw: None, + page_cursor: None, + }; + + let response: String = match self.get_data_query("/api/v3/post/list", &get_params).await { + Some(data) => data, + None => return None, + }; + let json_data: GetPostsResponse = match self.parse_json(&response).await { + Some(data) => data, + None => return None, + }; + + if json_data.posts[0].post.name == post.name { + Some(json_data.posts[0].post.id) + } else { + None + } + } + async fn post_data_json<T: Serialize>(&self, route: &str, json: &T ) -> Option<String> { let res = HTTP_CLIENT .post(format!("{}{route}", &self.instance)) From da4220e02737d282df8f0ec9f4425be488580cad Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Tue, 22 Apr 2025 13:27:32 +0200 Subject: [PATCH 41/43] Iterate over all returned posts from API rather than only the first one since pins stay at the top --- src/lemmy.rs | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/lemmy.rs b/src/lemmy.rs index 6afe1e5..2af495b 100644 --- a/src/lemmy.rs +++ b/src/lemmy.rs @@ -23,6 +23,15 @@ macro_rules! debug { }; } +macro_rules! info { + ($msg:tt) => { + match connected_to_journal() { + true => log::info!("[INFO] {}", $msg), + false => println!("[INFO] {}", $msg), + } + }; +} + macro_rules! error { ($msg:tt) => { match connected_to_journal() { @@ -397,24 +406,32 @@ impl Lemmy { let response: String = match self.get_data_query("/api/v3/post/list", &get_params).await { Some(data) => data, - None => return None, + None => { + error!("Unable to query post list"); + return None + }, }; let json_data: GetPostsResponse = match self.parse_json(&response).await { Some(data) => data, - None => return None, + None => { + error!("Unable to parse post data"); + return None + }, }; - if json_data.posts[0].post.name == post.name { - Some(json_data.posts[0].post.id) - } else { - None + for api_post in json_data.posts { + if api_post.post.name == post.name { + return Some(api_post.post.id); + } } + info!("Unable to find post {}", post.name); + None } async fn post_data_json<T: Serialize>(&self, route: &str, json: &T ) -> Option<String> { let res = HTTP_CLIENT .post(format!("{}{route}", &self.instance)) - .bearer_auth(&self.jwt_token.to_string()) + .bearer_auth(self.jwt_token.to_string()) .json(&json) .send() .await; @@ -424,7 +441,7 @@ impl Lemmy { async fn get_data_query<T: Serialize>(&self, route: &str, param: &T ) -> Option<String> { let res = HTTP_CLIENT .get(format!("{}{route}", &self.instance)) - .bearer_auth(&self.jwt_token.to_string()) + .bearer_auth(self.jwt_token.to_string()) .query(¶m) .send() .await; From 3abfaf55c135a2b668e797f73eaf798766e4cc39 Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Tue, 22 Apr 2025 13:33:12 +0200 Subject: [PATCH 42/43] Syntax Fix --- src/lemmy.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lemmy.rs b/src/lemmy.rs index 2af495b..ccfb2d2 100644 --- a/src/lemmy.rs +++ b/src/lemmy.rs @@ -424,7 +424,8 @@ impl Lemmy { return Some(api_post.post.id); } } - info!("Unable to find post {}", post.name); + let msg = format!("Unable to find post {}", post.name); + info!(msg); None } From 13954f26aa8887e40f154c3b2a2e63f48dae6f7b Mon Sep 17 00:00:00 2001 From: Neshura <neshura@neshweb.net> Date: Tue, 22 Apr 2025 13:33:23 +0200 Subject: [PATCH 43/43] Release 3.2.2 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 07245d6..c26d591 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,7 +52,7 @@ dependencies = [ [[package]] name = "aob-lemmy-bot" -version = "3.2.1" +version = "3.2.2" dependencies = [ "async-trait", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 43f3599..382aa18 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Neshura"] name = "aob-lemmy-bot" -version = "3.2.1" +version = "3.2.2" edition = "2021" description = "Bot for automatically posting new chapters of 'Ascendance of a Bookworm' released by J-Novel Club" license = "GPL-3.0-or-later"