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 01/22] 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 02/22] 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 03/22] 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 04/22] 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 05/22] 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 06/22] 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", &params).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", &params).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 07/22] 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 08/22] 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 09/22] 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 10/22] 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 11/22] 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 12/22] 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 13/22] 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 14/22] 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 15/22] 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 16/22] 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(&param)
             .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 17/22] 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 18/22] 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"

From 10111ff61295e634eb9158c87bf545e5c24942db Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Sat, 14 Jun 2025 20:21:23 +0200
Subject: [PATCH 19/22] Change API Version from Lemmy v3 to Piefed Alpha

---
 src/lemmy.rs | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/lemmy.rs b/src/lemmy.rs
index ccfb2d2..9dc45ec 100644
--- a/src/lemmy.rs
+++ b/src/lemmy.rs
@@ -227,7 +227,7 @@ impl Lemmy {
         };
 
         let response = match HTTP_CLIENT
-            .post(read_config.instance.to_owned() + "/api/v3/user/login")
+            .post(read_config.instance.to_owned() + "/api/alpha/user/login")
             .json(&login_params)
             .send()
             .await
@@ -268,12 +268,12 @@ impl Lemmy {
     }
 
     pub(crate) async fn logout(&self) {
-        let _ = self.post_data_json("/api/v3/user/logout", &"").await;
+        let _ = self.post_data_json("/api/alpha/user/logout", &"").await;
     }
 
 
     pub(crate) async fn post(&self, post: CreatePost) -> Option<PostId> {
-        let response: String = match self.post_data_json("/api/v3/post", &post).await {
+        let response: String = match self.post_data_json("/api/alpha/post", &post).await {
             Some(data) => data,
             None => return None,
         };
@@ -286,7 +286,7 @@ impl Lemmy {
     }
 
     async fn feature(&self, params: FeaturePost) -> Option<PostView> {
-        let response: String = match self.post_data_json("/api/v3/post/feature", &params).await {
+        let response: String = match self.post_data_json("/api/alpha/post/feature", &params).await {
             Some(data) => data,
             None => return None,
         };
@@ -323,7 +323,7 @@ impl Lemmy {
             ..Default::default()
         };
 
-        let response: String = match self.get_data_query("/api/v3/post/list", &list_params).await {
+        let response: String = match self.get_data_query("/api/alpha/post/list", &list_params).await {
             Some(data) => data,
             None => return None,
         };
@@ -346,7 +346,7 @@ impl Lemmy {
             ..Default::default()
         };
 
-        let response: String = match self.get_data_query("/api/v3/post/list", &list_params).await {
+        let response: String = match self.get_data_query("/api/alpha/post/list", &list_params).await {
             Some(data) => data,
             None => return None,
         };
@@ -369,7 +369,7 @@ impl Lemmy {
             ..Default::default()
         };
 
-        let response: String = match self.get_data_query("/api/v3/community/list", &list_params).await {
+        let response: String = match self.get_data_query("/api/alpha/community/list", &list_params).await {
             Some(data) => data,
             None => return,
         };
@@ -404,7 +404,7 @@ impl Lemmy {
             page_cursor: None,
         };
 
-        let response: String = match self.get_data_query("/api/v3/post/list", &get_params).await {
+        let response: String = match self.get_data_query("/api/alpha/post/list", &get_params).await {
             Some(data) => data,
             None => {
                 error!("Unable to query post list");

From 204d4137791a10acaece0c44f5baef6d33f54969 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Sat, 14 Jun 2025 20:21:36 +0200
Subject: [PATCH 20/22] Release 3.3.0

---
 Cargo.lock | 2 +-
 Cargo.toml | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index c26d591..1872127 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -52,7 +52,7 @@ dependencies = [
 
 [[package]]
 name = "aob-lemmy-bot"
-version = "3.2.2"
+version = "3.3.0"
 dependencies = [
  "async-trait",
  "chrono",
diff --git a/Cargo.toml b/Cargo.toml
index 382aa18..c5a18da 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 authors = ["Neshura"]
 name = "aob-lemmy-bot"
-version = "3.2.2"
+version = "3.3.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 42aff098bdcfa93722ff561da02610cadd4c9d27 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Sat, 14 Jun 2025 20:52:05 +0200
Subject: [PATCH 21/22] Login Delay

---
 src/bot.rs | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/bot.rs b/src/bot.rs
index ba0e8b9..3e0bde8 100644
--- a/src/bot.rs
+++ b/src/bot.rs
@@ -81,7 +81,10 @@ impl Bot {
         loop {
             let mut lemmy = match Lemmy::new(&self.shared_config).await {
                 Ok(data) => data,
-                Err(_) => continue,
+                Err(_) => {
+                    sleep(Duration::seconds(10).to_std().unwrap()).await;
+                    continue;
+                },
             };
 
             lemmy.get_communities().await;

From f3bb504cfd359347f4d00ea5a243eff2d0715d90 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Sat, 14 Jun 2025 20:52:15 +0200
Subject: [PATCH 22/22] Release 3.3.1

---
 Cargo.lock | 2 +-
 Cargo.toml | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 1872127..734bb74 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -52,7 +52,7 @@ dependencies = [
 
 [[package]]
 name = "aob-lemmy-bot"
-version = "3.3.0"
+version = "3.3.1"
 dependencies = [
  "async-trait",
  "chrono",
diff --git a/Cargo.toml b/Cargo.toml
index c5a18da..e97bea1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 authors = ["Neshura"]
 name = "aob-lemmy-bot"
-version = "3.3.0"
+version = "3.3.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"