use directories::{ProjectDirs, UserDirs}; use serde::{Deserialize, Serialize}; use std::fs; use expanduser::expanduser; #[derive(Serialize, Deserialize)] pub struct Config { pub music_roots: Vec, pub audio_exts: Vec, pub skip_window_secs: u64, pub temperature: f32, pub low_weight: f32, pub mid_weight: f32, pub high_weight: f32, pub max_weight: f32, } fn default_config_path() -> String { let name = "mood.json"; ProjectDirs::from("qualifier", "organisation", "mood") .and_then(|pd| pd.config_dir().join(name).to_str().map(|x| x.to_string())) .unwrap_or(format!("~/.config/mood/{name}")) } impl Config { pub fn try_load() -> Result { expanduser(default_config_path()) .map_err(|e| e.to_string()) .and_then(|p| fs::read_to_string(p).map_err(|e| e.to_string())) .and_then(|contents| serde_json::from_str(&contents).map_err(|e| e.to_string())) } pub fn try_save(&self) -> Result<(), String> { let path = expanduser(default_config_path()).map_err(|e| e.to_string())?; _ = path.parent().map(std::fs::create_dir_all); let serialised = serde_json::to_string_pretty(self) .map_err(|e| format!("Failed to serialize config: {}", e))?; fs::write(&path, serialised).map_err(|e| format!("Failed to write config file: {}", e))?; Ok(()) } } impl Default for Config { fn default() -> Config { Config { music_roots: vec![ UserDirs::new() .and_then(|u| { u.audio_dir() .and_then(|p| p.to_str().map(|x| x.to_string())) }) .unwrap_or("~/Music".to_string()), ], audio_exts: [".mp3", ".flac", ".wav", ".m4a", ".ogg", ".vorbis"] .into_iter() .map(String::from) .collect(), skip_window_secs: 60, temperature: 0.6, low_weight: 0.25, mid_weight: 0.5, high_weight: 0.75, max_weight: 1.0, } } }