aob-lemmy-bot/src/config.rs

299 lines
9.8 KiB
Rust
Raw Normal View History

2024-05-07 22:10:21 +02:00
use std::path::PathBuf;
use std::sync::{Arc, RwLock};
use chrono::{Timelike, Utc};
2023-12-30 01:27:11 +01:00
use crate::config::PostBody::Description;
use lemmy_api_common::sensitive::Sensitive;
2024-05-07 22:10:21 +02:00
use lemmy_db_schema::PostFeatureType;
use serde_derive::{Deserialize, Serialize};
2024-05-07 22:10:21 +02:00
use crate::lemmy::{Lemmy, PartInfo, PostType};
use crate::post_history::{SeriesHistory};
use systemd_journal_logger::connected_to_journal;
use crate::fetchers::{FetcherTrait, Fetcher};
use crate::fetchers::jnovel::{JNovelFetcher};
macro_rules! debug {
($msg:tt) => {
match connected_to_journal() {
true => log::debug!("[DEBUG] {}", $msg),
false => println!("[DEBUG] {}", $msg),
}
};
}
2024-05-07 22:10:21 +02:00
macro_rules! info {
($msg:tt) => {
match connected_to_journal() {
true => log::info!("[INFO] {}", $msg),
false => println!("[INFO] {}", $msg),
}
};
}
macro_rules! warn {
($msg:tt) => {
match connected_to_journal() {
true => log::warn!("[WARN] {}", $msg),
false => println!("[WARN] {}", $msg),
}
};
}
macro_rules! error {
($msg:tt) => {
match connected_to_journal() {
true => log::error!("[ERROR] {}", $msg),
false => eprintln!("[ERROR] {}", $msg),
}
};
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub(crate) struct Config {
pub(crate) instance: String,
username: String,
password: String,
pub(crate) status_post_url: Option<String>,
pub(crate) config_reload_seconds: u32,
2023-12-18 11:23:47 +01:00
pub(crate) protected_communities: Vec<String>,
pub(crate) series: Vec<SeriesConfig>,
}
impl Config {
2023-12-29 22:35:16 +01:00
pub(crate) fn load() -> Self {
let cfg: Self = match confy::load(env!("CARGO_PKG_NAME"), "config") {
2023-12-17 22:29:18 +01:00
Ok(data) => data,
Err(e) => panic!("config.toml not found: {e}"),
2023-12-17 22:29:18 +01:00
};
2023-12-17 01:42:41 +01:00
if cfg.instance.is_empty() {
panic!("bot instance not set!")
}
if cfg.username.is_empty() {
panic!("bot username not set!")
}
if cfg.password.is_empty() {
panic!("bot password not provided!")
}
cfg.series.iter().for_each(|series| {
if series.prepub_community.post_body == Description {
panic!("'Description' type Post Body only supported for Volumes!")
}
});
2023-12-29 22:35:16 +01:00
cfg
2023-06-22 22:08:10 +02:00
}
2024-05-07 22:10:21 +02:00
pub(crate) fn get_path() -> PathBuf {
confy::get_configuration_file_path(env!("CARGO_PKG_NAME"), "config").expect("Application will not without confy")
}
pub(crate) fn get_username(&self) -> Sensitive<String> {
Sensitive::new(self.username.clone())
}
pub(crate) fn get_password(&self) -> Sensitive<String> {
Sensitive::new(self.password.clone())
}
}
2023-12-17 01:42:41 +01:00
impl Default for Config {
fn default() -> Self {
Config {
instance: "".to_owned(),
username: "".to_owned(),
password: "".to_owned(),
2023-12-17 01:42:41 +01:00
status_post_url: None,
config_reload_seconds: 21600,
2023-12-18 11:23:47 +01:00
protected_communities: vec![],
2023-12-30 01:27:11 +01:00
series: vec![],
}
}
}
2023-12-17 01:42:41 +01:00
#[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,
2024-05-07 22:10:21 +02:00
pub(crate) fetcher: Fetcher
}
impl SeriesConfig {
pub(crate) async fn update(&self, history: &mut SeriesHistory, lemmy: &Lemmy, config: &Arc<RwLock<Config>>) {
let info_msg = format!("Checking {} for Updates", self.slug);
info!(info_msg);
let mut fetcher: Fetcher = match &self.fetcher {
Fetcher::Jnc(_) => {
Fetcher::Jnc(JNovelFetcher::new())
},
/*default => {
let err_msg = format!("Fetcher {default} not implemented");
error!(err_msg);
return;
}*/
};
match fetcher {
Fetcher::Jnc(ref mut jnc) => {
jnc.set_series(self.slug.clone());
jnc.set_part_option(self.parted);
}
}
let post_list = match fetcher.check_feed().await {
Ok(data) => data,
Err(_) => {
let err_msg = format!("While checking feed for {}", self.slug);
error!(err_msg);
return;
}
};
if post_list.is_empty() && Utc::now().minute() % 10 == 0 {
let info_msg = "No Updates found";
info!(info_msg);
}
for post_info in post_list.iter() {
if history.check_for_post(
self.slug.as_str(),
post_info.get_part_info().unwrap_or(PartInfo::NoParts).as_string().as_str(),
post_info.get_info().title.as_str()
) {
continue
}
let post_data = post_info.get_post_data(self, lemmy);
let info = format!(
"Posting '{}' to {}",
post_info.get_info().title.as_str(),
post_info.get_post_config(self).name.as_str()
);
info!(info);
let post_id = match lemmy.post(post_data).await {
Some(data) => data,
None=> {
2024-05-07 22:10:21 +02:00
error!("Error posting chapter");
return;
}
};
let read_config = config.read().expect("Read Lock Failed").clone();
if post_info.get_post_config(self).pin_settings.pin_new_post_community
&& !read_config
.protected_communities
.contains(&post_info.get_post_config(self).name)
{
let info = format!(
"Pinning '{}' to {}",
post_info.get_info().title,
post_info.get_post_config(self).name.as_str()
);
info!(info);
let pinned_posts = 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![]
});
2024-05-07 22:10:21 +02:00
if !pinned_posts.is_empty() {
let community_pinned_post = &pinned_posts[0];
if lemmy.unpin(community_pinned_post.post.id, PostFeatureType::Community).await.is_none() {
error!("Error un-pinning post");
2024-05-07 22:10:21 +02:00
}
}
if lemmy.pin(post_id, PostFeatureType::Community).await.is_none() {
error!("Error pinning post");
2024-05-07 22:10:21 +02:00
}
} else if read_config
.protected_communities
.contains(&post_info.get_post_config(self).name)
{
let message = format!(
"Community '{}' for Series '{}' is protected. Is this intended?",
&post_info.get_post_config(self).name, self.slug
);
warn!(message);
}
if post_info.get_post_config(self).pin_settings.pin_new_post_local {
let info = format!("Pinning '{}' to Instance", post_info.get_info().title);
info!(info);
let pinned_posts = match lemmy.get_local_pinned().await {
Some(data) => {data}
None => {
2024-05-07 22:10:21 +02:00
error!("Error fetching pinned posts");
vec![]
2024-05-07 22:10:21 +02:00
}
};
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).await.is_none() {
error!("Error pinning post");
continue;
2024-05-07 22:10:21 +02:00
}
break;
}
}
}
if lemmy.pin(post_id, PostFeatureType::Local).await.is_none() {
error!("Error pinning post");
2024-05-07 22:10:21 +02:00
};
}
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);
debug!("Saving History");
2024-05-07 22:10:21 +02:00
history.save_history();
}
}
2023-12-17 01:42:41 +01:00
}
2023-06-22 22:08:10 +02:00
2023-12-17 01:42:41 +01:00
#[derive(Debug, Serialize, Deserialize, Clone)]
pub(crate) struct PostConfig {
2023-12-17 20:17:00 +01:00
pub(crate) name: String,
pub(crate) pin_settings: PinConfig,
pub(crate) post_body: PostBody,
2023-12-17 01:42:41 +01:00
}
2023-06-22 22:08:10 +02:00
2023-12-17 01:42:41 +01:00
#[derive(Debug, Serialize, Deserialize, Clone)]
pub(crate) struct PinConfig {
pub(crate) pin_new_post_local: bool,
pub(crate) pin_new_post_community: bool,
2023-12-17 01:42:41 +01:00
}
2023-06-22 22:08:10 +02:00
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
2023-12-17 01:42:41 +01:00
#[serde(tag = "body_type", content = "body_content")]
pub(crate) enum PostBody {
None,
Description,
Custom(String),
2023-06-22 22:08:10 +02:00
}