248 lines
8.8 KiB
Rust
248 lines
8.8 KiB
Rust
use std::path::PathBuf;
|
|
use std::sync::{Arc, RwLock};
|
|
use chrono::{Timelike, Utc};
|
|
use crate::settings::PostBody::Description;
|
|
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};
|
|
use crate::fetchers::{FetcherTrait, Fetcher};
|
|
use crate::fetchers::jnovel::{JNovelFetcher};
|
|
use crate::logging::Logging;
|
|
use crate::settings::PostBody;
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
pub(crate) struct SingleBotConfig {
|
|
pub(crate) instance: String,
|
|
username: SensitiveString,
|
|
password: SensitiveString,
|
|
pub(crate) status_post_url: Option<String>,
|
|
pub(crate) protected_communities: Vec<String>,
|
|
pub(crate) series: Vec<SeriesConfig>,
|
|
}
|
|
|
|
impl SingleBotConfig {
|
|
pub(crate) fn load(&self) -> Self {
|
|
if self.instance.is_empty() {
|
|
panic!("bot instance not set!")
|
|
}
|
|
|
|
if self.username.is_empty() {
|
|
panic!("bot username not set!")
|
|
}
|
|
|
|
if self.password.is_empty() {
|
|
panic!("bot password not provided!")
|
|
}
|
|
|
|
self.series.iter().for_each(|series| {
|
|
if series.prepub_community.post_body == Description {
|
|
panic!("'Description' type Post Body only supported for Volumes!")
|
|
}
|
|
});
|
|
self.clone()
|
|
}
|
|
|
|
pub(crate) fn get_path() -> PathBuf {
|
|
confy::get_configuration_file_path(env!("CARGO_PKG_NAME"), "config").expect("Application will not without confy")
|
|
}
|
|
|
|
pub(crate) fn get_username(&self) -> SensitiveString {
|
|
self.username.clone()
|
|
}
|
|
|
|
pub(crate) fn get_password(&self) -> SensitiveString {
|
|
self.password.clone()
|
|
}
|
|
}
|
|
|
|
impl Default for SingleBotConfig {
|
|
fn default() -> Self {
|
|
SingleBotConfig {
|
|
instance: "".to_owned(),
|
|
username: SensitiveString::from("".to_owned()),
|
|
password: SensitiveString::from("".to_owned()),
|
|
status_post_url: None,
|
|
protected_communities: vec![],
|
|
series: vec![],
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
pub(crate) struct SeriesConfig {
|
|
pub(crate) slug: String,
|
|
pub(crate) parted: bool,
|
|
pub(crate) prepub_community: PostConfig,
|
|
pub(crate) volume_community: PostConfig,
|
|
pub(crate) fetcher: Fetcher
|
|
}
|
|
|
|
impl SeriesConfig {
|
|
pub(crate) fn update(&self, history: &mut SeriesHistory, lemmy: &Lemmy, config: &Arc<RwLock<SingleBotConfig>>) {
|
|
let info_msg = format!("Checking {} for Updates", self.slug);
|
|
Logging::info(info_msg.as_str());
|
|
|
|
let mut fetcher: Fetcher = match &self.fetcher {
|
|
Fetcher::Jnc(_) => {
|
|
Fetcher::Jnc(JNovelFetcher::new())
|
|
},
|
|
/*default => {
|
|
let err_msg = format!("Fetcher {default} not implemented");
|
|
error!(err_msg);
|
|
return;
|
|
}*/
|
|
};
|
|
|
|
match fetcher {
|
|
Fetcher::Jnc(ref mut jnc) => {
|
|
jnc.set_series(self.slug.clone());
|
|
jnc.set_part_option(self.parted);
|
|
}
|
|
}
|
|
|
|
let post_list = match fetcher.check_feed() {
|
|
Ok(data) => data,
|
|
Err(_) => {
|
|
let err_msg = format!("While checking feed for {}", self.slug);
|
|
Logging::error(err_msg.as_str());
|
|
return;
|
|
}
|
|
};
|
|
|
|
if post_list.is_empty() && Utc::now().minute() % 10 == 0 {
|
|
let info_msg = "No Updates found";
|
|
Logging::info(info_msg);
|
|
}
|
|
|
|
for post_info in post_list.iter() {
|
|
if history.check_for_post(
|
|
self.slug.as_str(),
|
|
post_info.get_part_info().unwrap_or(PartInfo::NoParts).as_string().as_str(),
|
|
post_info.get_info().title.as_str()
|
|
) {
|
|
continue
|
|
}
|
|
|
|
let post_data = post_info.get_post_data(self, lemmy);
|
|
|
|
let info = format!(
|
|
"Posting '{}' to {}",
|
|
post_info.get_info().title.as_str(),
|
|
post_info.get_post_config(self).name.as_str()
|
|
);
|
|
Logging::info(info.as_str());
|
|
|
|
let post_id = match lemmy.post(post_data) {
|
|
Some(data) => data,
|
|
None=> {
|
|
Logging::error("Error posting chapter");
|
|
return;
|
|
}
|
|
};
|
|
|
|
let read_config = config.read().expect("Read Lock Failed").clone();
|
|
|
|
if post_info.get_post_config(self).pin_settings.pin_new_post_community
|
|
&& !read_config
|
|
.protected_communities
|
|
.contains(&post_info.get_post_config(self).name)
|
|
{
|
|
let info = format!(
|
|
"Pinning '{}' to {}",
|
|
post_info.get_info().title,
|
|
post_info.get_post_config(self).name.as_str()
|
|
);
|
|
Logging::info(info.as_str());
|
|
let pinned_posts = lemmy.get_community_pinned(lemmy.get_community_id(&post_info.get_post_config(self).name)).unwrap_or_else(|| {
|
|
Logging::error("Pinning of Post to community failed");
|
|
vec![]
|
|
});
|
|
if !pinned_posts.is_empty() {
|
|
let community_pinned_post = &pinned_posts[0];
|
|
if lemmy.unpin(community_pinned_post.post.id, PostFeatureType::Community).is_none() {
|
|
Logging::error("Error un-pinning post");
|
|
}
|
|
}
|
|
if lemmy.pin(post_id, PostFeatureType::Community).is_none() {
|
|
Logging::error("Error pinning post");
|
|
}
|
|
} else if read_config
|
|
.protected_communities
|
|
.contains(&post_info.get_post_config(self).name)
|
|
{
|
|
let message = format!(
|
|
"Community '{}' for Series '{}' is protected. Is this intended?",
|
|
&post_info.get_post_config(self).name, self.slug
|
|
);
|
|
Logging::warn(message.as_str());
|
|
}
|
|
|
|
if post_info.get_post_config(self).pin_settings.pin_new_post_local {
|
|
let info = format!("Pinning '{}' to Instance", post_info.get_info().title);
|
|
Logging::info(info.as_str());
|
|
let pinned_posts = match lemmy.get_local_pinned() {
|
|
Some(data) => {data}
|
|
None => {
|
|
Logging::error("Error fetching pinned posts");
|
|
vec![]
|
|
}
|
|
};
|
|
|
|
if !pinned_posts.is_empty() {
|
|
for pinned_post in pinned_posts {
|
|
if read_config
|
|
.protected_communities
|
|
.contains(&pinned_post.community.name)
|
|
{
|
|
continue;
|
|
} else {
|
|
let community_pinned_post = &pinned_post;
|
|
if lemmy.unpin(community_pinned_post.post.id, PostFeatureType::Local).is_none() {
|
|
Logging::error("Error pinning post");
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if lemmy.pin(post_id, PostFeatureType::Local).is_none() {
|
|
Logging::error("Error pinning post");
|
|
};
|
|
}
|
|
|
|
let mut series_history = history.get_series(self.slug.as_str());
|
|
let mut part_history = series_history.get_part(post_info.get_part_info().unwrap_or(PartInfo::NoParts).as_string().as_str());
|
|
|
|
match post_info.post_type {
|
|
Some(post_type) => {
|
|
match post_type {
|
|
PostType::Chapter => part_history.chapter = post_info.get_info().title,
|
|
PostType::Volume => part_history.volume = post_info.get_info().title,
|
|
}
|
|
}
|
|
None => part_history.chapter = post_info.get_info().title,
|
|
}
|
|
|
|
series_history.set_part(post_info.get_part_info().unwrap_or(PartInfo::NoParts).as_string().as_str(), part_history);
|
|
history
|
|
.set_series(self.slug.as_str(), series_history);
|
|
Logging::debug("Saving History");
|
|
history.save_history();
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
pub(crate) struct PostConfig {
|
|
pub(crate) name: String,
|
|
pub(crate) pin_settings: PinConfig,
|
|
pub(crate) post_body: PostBody,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
pub(crate) struct PinConfig {
|
|
pub(crate) pin_new_post_local: bool,
|
|
pub(crate) pin_new_post_community: bool,
|
|
}
|