use crate::actions::bitmagnet::BitmagnetConfig; use crate::actions::transmission::TransmissionConfig; use crate::args::Args; use crate::notifications::ntfy::NtfyConfig; use color_eyre::eyre::{eyre, Result, WrapErr}; use directories::ProjectDirs; use figment::providers::Env; use figment::{ providers::{Format, Toml}, Figment, }; use figment_file_provider_adapter::FileAdapter; use log::debug; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::path::{Path, PathBuf}; /// Configuration for a Reddit source #[derive(Debug, Serialize, Deserialize)] pub struct SourceConfig { pub username: String, pub title_filter: Option, pub imdb_id: Option, #[serde(default)] pub tags: Vec, } /// Main application configuration #[derive(Debug, Serialize, Deserialize)] pub struct Config { #[serde(default)] pub bitmagnet: Option, #[serde(default)] pub transmission: Option, #[serde(default)] pub ntfy: Option, #[serde(default)] pub sources: HashMap, } /// Loads the configuration from the specified file or default location pub fn load_config(args: &Args) -> Result { let mut conf_extractor = Figment::new(); let config_file_path: Option = match &args.config { Some(path) => Some(Path::new(path).to_path_buf()), None => ProjectDirs::from("fr", "enoent", "reddit-magnet") .map(|p| p.config_dir().join("config.toml")), }; match config_file_path { Some(path) => { if path.exists() { debug!("Reading configuration from {:?}", path); conf_extractor = conf_extractor.merge(FileAdapter::wrap(Toml::file_exact(path))); } else { debug!("Configuration file doesn't exist at {:?}", path); } } None => { debug!("No configuration file specified, using default configuration"); } } let conf: Config = conf_extractor .merge(FileAdapter::wrap(Env::prefixed("REDDIT_MAGNET_"))) .extract() .wrap_err_with(|| "Invalid configuration or insufficient command line arguments")?; if conf.sources.is_empty() { return Err(eyre!("No sources found in configuration. Please add at least one source to your configuration file.")); } Ok(conf) } /// Gets the database path from the command line arguments or default location pub fn get_db_path(args: &Args) -> Result { match &args.db { Some(path) => Ok(PathBuf::from(path)), None => ProjectDirs::from("fr", "enoent", "reddit-magnet") .map(|p| p.data_dir().join("reddit-magnet.db")) .ok_or_else(|| eyre!("Could not determine data directory")), } }