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/file_system.rs | |
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/file_system.rs')
-rw-r--r-- | src/config/file_system.rs | 123 |
1 files changed, 123 insertions, 0 deletions
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() + }, + }, + }) + } +} |