diff options
author | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2024-08-23 13:11:09 +0200 |
---|---|---|
committer | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2024-08-23 13:14:13 +0200 |
commit | 94c656ad40a7aae570e5a5fb61ad32632acc6d46 (patch) | |
tree | 269614af20caf10d76643c302e0115bd36fd2378 /src/config | |
parent | refactor(yt_dlp): Also move the `crates` subdirectory (diff) | |
download | yt-94c656ad40a7aae570e5a5fb61ad32632acc6d46.tar.gz yt-94c656ad40a7aae570e5a5fb61ad32632acc6d46.zip |
feat(treewide): Use a configuration file
This allows use to avoid duplication of default values in the codebase and obviously also facilitates changing these without having to re-compile.
Diffstat (limited to 'src/config')
-rw-r--r-- | src/config/default.rs | 100 | ||||
-rw-r--r-- | src/config/file_system.rs | 123 | ||||
-rw-r--r-- | src/config/mod.rs | 52 |
3 files changed, 275 insertions, 0 deletions
diff --git a/src/config/default.rs b/src/config/default.rs new file mode 100644 index 0000000..131c289 --- /dev/null +++ b/src/config/default.rs @@ -0,0 +1,100 @@ +// yt - A fully featured command line YouTube client +// +// Copyright (C) 2024 Benedikt Peetz <benedikt.peetz@b-peetz.de> +// SPDX-License-Identifier: GPL-3.0-or-later +// +// This file is part of Yt. +// +// You should have received a copy of the License along with this program. +// If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>. + +use std::path::PathBuf; + +use anyhow::{Context, Result}; + +fn get_runtime_path(name: &'static str) -> Result<PathBuf> { + let xdg_dirs = xdg::BaseDirectories::with_prefix(PREFIX)?; + xdg_dirs + .place_runtime_file(name) + .with_context(|| format!("Failed to place runtime file: '{}'", name)) +} +fn get_data_path(name: &'static str) -> Result<PathBuf> { + let xdg_dirs = xdg::BaseDirectories::with_prefix(PREFIX)?; + xdg_dirs + .place_data_file(name) + .with_context(|| format!("Failed to place data file: '{}'", name)) +} +fn get_config_path(name: &'static str) -> Result<PathBuf> { + let xdg_dirs = xdg::BaseDirectories::with_prefix(PREFIX)?; + xdg_dirs + .place_config_file(name) + .with_context(|| format!("Failed to place config file: '{}'", name)) +} + +pub(super) fn create_path(path: PathBuf) -> Result<PathBuf> { + if !path.exists() { + std::fs::create_dir_all(&path) + .with_context(|| format!("Failed to create the '{}' directory", path.display()))? + } + + Ok(path) +} + +pub const PREFIX: &str = "yt"; + +pub mod select { + pub fn playback_speed() -> f64 { + 2.7 + } + pub fn subtitle_langs() -> &'static str { + "" + } +} + +pub mod watch { + pub fn local_comments_length() -> i64 { + 1000 + } +} + +pub mod update { + pub fn max_backlog() -> i64 { + 20 + } +} + +pub mod paths { + use std::{env::temp_dir, path::PathBuf}; + + use anyhow::Result; + + use super::{create_path, get_config_path, get_data_path, get_runtime_path, PREFIX}; + + // We download to the temp dir to avoid taxing the disk + pub fn download_dir() -> Result<PathBuf> { + let temp_dir = temp_dir(); + + create_path(temp_dir.join(PREFIX)) + } + pub fn mpv_config_path() -> Result<PathBuf> { + get_config_path("mpv.conf") + } + pub fn mpv_input_path() -> Result<PathBuf> { + get_config_path("mpv.input.conf") + } + pub fn database_path() -> Result<PathBuf> { + get_data_path("videos.sqlite") + } + pub fn config_path() -> Result<PathBuf> { + get_config_path("config.toml") + } + pub fn last_selection_path() -> Result<PathBuf> { + get_runtime_path("selected.yts") + } +} + +pub mod download { + pub fn max_cache_size() -> &'static str { + "3 GiB" + } +} diff --git a/src/config/file_system.rs b/src/config/file_system.rs new file mode 100644 index 0000000..8528130 --- /dev/null +++ b/src/config/file_system.rs @@ -0,0 +1,123 @@ +// yt - A fully featured command line YouTube client +// +// Copyright (C) 2024 Benedikt Peetz <benedikt.peetz@b-peetz.de> +// SPDX-License-Identifier: GPL-3.0-or-later +// +// This file is part of Yt. +// +// You should have received a copy of the License along with this program. +// If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>. + +use crate::config::{DownloadConfig, PathsConfig, SelectConfig, WatchConfig}; + +use super::{ + default::{create_path, download, paths, select, update, watch}, + Config, UpdateConfig, +}; + +use std::{fs::read_to_string, path::PathBuf}; + +use anyhow::{Context, Result}; +use toml::Table; +use bytes::Bytes; + +macro_rules! get { + ($default:path, $config:expr, $get_fn:ident, $key_one:expr, $($keys:expr),*) => { + try_get!{@default $default, $config, $get_fn, $key_one, $($keys),*} + .with_context(|| format!("Failed to parse '{}' as a '{}'", stringify!($key_one), stringify!($get_fn)))? + }; + (@path_if_none $config:expr, $option_default:expr, $default:path, $key_one:expr, $($keys:expr),*) => { + { + let maybe_download_dir = + try_get! {@option $config, as_str, $key_one, $($keys),*}; + + let down_dir = if let Some(dir) = maybe_download_dir { + PathBuf::from(dir) + } else { + if let Some(path) = $option_default { + path + } else { + $default() + .with_context(|| format!("Failed to get default path for: '{}.{}'", stringify!($key_one), stringify!($($keys),*)))? + } + }; + create_path(down_dir)? + } + }; + (@path $config:expr, $default:path, $key_one:expr, $($keys:expr),*) => { + get! {@path_if_none $config, None, $default, $key_one, $($keys),*} + }; +} +macro_rules! try_get { + (@option $config:expr, $get_fn:ident, $key_one:expr, $($keys:expr),*) => { + $config.get($key_one).map(|val| { + try_get! {@option val, $get_fn, $($keys),*} + }).flatten().flatten() + }; + (@option $config:expr, $get_fn:ident, $key_one:expr) => { + $config.get($key_one).map(|val| val.$get_fn()) + }; + + (@default $default:path, $config:expr, $get_fn:ident, $key_one:expr, $($keys:expr),*) => { + if let Some(a) = $config.get($key_one) { + try_get! {@default $default, a, $get_fn, $($keys),*} + } else { + Some($default()) + } + }; + (@default $default:path, $config:expr, $get_fn:ident, $key_one:expr) => { + if let Some(a) = $config.get($key_one) { + a.$get_fn() + } else { + Some($default()) + } + }; +} + +impl Config { + pub fn from_config_file( + db_path: Option<PathBuf>, + config_path: Option<PathBuf>, + ) -> Result<Self> { + let config_file_path = config_path + .map(|val| Ok(val)) + .unwrap_or_else(|| -> Result<_> { paths::config_path() })?; + + let config: Table = read_to_string(config_file_path)? + .parse() + .context("Failed to parse the config file as toml")?; + + Ok(Self { + select: SelectConfig { + playback_speed: get! {select::playback_speed, config, as_float, "select", "playback_speed"}, + subtitle_langs: + get! {select::subtitle_langs, config, as_str, "select", "subtitle_langs"} + .to_owned(), + }, + watch: WatchConfig { + local_comments_length: get! {watch::local_comments_length, config, as_integer, "watch", "local_comments_length"} + as usize, + }, + update: UpdateConfig { + max_backlog: get! {update::max_backlog, config, as_integer, "update", "max_backlog"} + as u32, + }, + paths: PathsConfig { + download_dir: get! {@path config, paths::download_dir, "paths", "download_dir"}, + mpv_config_path: get! {@path config, paths::mpv_config_path, "paths", "mpv_config_path"}, + mpv_input_path: get! {@path config, paths::mpv_input_path, "paths", "mpv_input_path"}, + database_path: get! {@path_if_none config, db_path, paths::database_path, "paths", "database_path"}, + last_selection_path: get! {@path config, paths::last_selection_path, "paths", "last_selection_path"}, + }, + download: DownloadConfig { + max_cache_size: { + let bytes_str = get! {download::max_cache_size, config, as_str, "download", "max_cache_path"}; + let number: Bytes = bytes_str + .parse() + .context("Failed to parse max_cache_size")?; + number.as_u64() + }, + }, + }) + } +} diff --git a/src/config/mod.rs b/src/config/mod.rs new file mode 100644 index 0000000..8ee7cc7 --- /dev/null +++ b/src/config/mod.rs @@ -0,0 +1,52 @@ +// yt - A fully featured command line YouTube client +// +// Copyright (C) 2024 Benedikt Peetz <benedikt.peetz@b-peetz.de> +// SPDX-License-Identifier: GPL-3.0-or-later +// +// This file is part of Yt. +// +// You should have received a copy of the License along with this program. +// If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>. + +use std::path::PathBuf; + +pub mod default; +pub mod file_system; + +pub struct Config { + pub select: SelectConfig, + pub watch: WatchConfig, + pub paths: PathsConfig, + pub download: DownloadConfig, + pub update: UpdateConfig, +} +pub struct UpdateConfig { + pub max_backlog: u32, +} +pub struct DownloadConfig { + pub max_cache_size: u64, +} +pub struct SelectConfig { + pub playback_speed: f64, + pub subtitle_langs: String, +} +pub struct WatchConfig { + pub local_comments_length: usize, +} +pub struct PathsConfig { + pub download_dir: PathBuf, + pub mpv_config_path: PathBuf, + pub mpv_input_path: PathBuf, + pub database_path: PathBuf, + pub last_selection_path: PathBuf, +} + +// pub fn status_path() -> anyhow::Result<PathBuf> { +// const STATUS_PATH: &str = "running.info.json"; +// get_runtime_path(STATUS_PATH) +// } + +// pub fn subscriptions() -> anyhow::Result<PathBuf> { +// const SUBSCRIPTIONS: &str = "subscriptions.json"; +// get_data_path(SUBSCRIPTIONS) +// } |