use directories::{ProjectDirs, UserDirs}; use std::io::{BufRead, BufReader, Write}; use std::path::PathBuf; use crate::Errors; fn project_dir() -> Result { ProjectDirs::from("info", "Fuzen", "Melody").ok_or(Errors::FailedToGetAppDirectory) } #[derive(Debug)] pub struct Settings { pub volume: f32, pub music: PathBuf, pub prioritize_cwd: bool, pub ignore_unknown_album: bool, pub ignore_unknown_title: bool, pub ignore_unknown_artist: bool, pub ignore_all_unknowns: bool, } impl Settings { pub fn new() -> Result { let project_dir = project_dir()?; let mut config_file = project_dir.config_dir().to_owned(); let _ = ::std::fs::create_dir_all(&config_file).is_ok(); // Result doesn't matter config_file.push("Config.melody"); println!("Config is located at: {:#?}", config_file); let settings = if !config_file.exists() { Self::create_default(config_file)? } else { let file = ::std::fs::File::open(config_file).map_err(|_| Errors::FailedToGetConfig)?; Self::parse_lines(BufReader::new(file).lines())? }; Ok(Self::env_override(settings)) } fn parse_lines( lines: std::io::Lines>, ) -> Result { let mut settings = Settings::default(); let mut music: Option = None; for line in lines { if let Ok(line) = line { if line.starts_with("volume=") { if let Some(v) = line.get(7..) { if let Ok(v) = v.parse() { settings.volume = v; } } } else if line.starts_with("music=") { if let Some(v) = line.get(6..) { let p = PathBuf::from(v); if p.exists() { music = Some(p) } } } else if line.starts_with("prioritize_cwd=") { if let Some(v) = line.get(15..) { if let Ok(v) = v.parse() { settings.prioritize_cwd = v; } } } else if line.starts_with("ignore_unknown_album=") { if let Some(v) = line.get(21..) { if let Ok(v) = v.parse() { settings.ignore_unknown_album = v; } } } else if line.starts_with("ignore_unknown_title=") { if let Some(v) = line.get(21..) { if let Ok(v) = v.parse() { settings.ignore_unknown_artist = v; } } } else if line.starts_with("ignore_unknown_artist=") { if let Some(v) = line.get(22..) { if let Ok(v) = v.parse() { settings.ignore_unknown_artist = v; } } } else if line.starts_with("ignore_all_unknowns=") { if let Some(v) = line.get(20..) { if let Ok(v) = v.parse() { settings.ignore_all_unknowns = v; } } } } } let music = match music { Some(m) => m, None => { let user_dir = UserDirs::new().ok_or(Errors::FailedToGetUserDir)?; user_dir .audio_dir() .ok_or(Errors::FailedToGetAudioDir)? .to_owned() } }; settings.music = music; Ok(settings) } fn env_override(mut settings: Settings) -> Settings { if let Ok(v) = ::std::env::var("MELODY_VOLUME") { if let Ok(v) = v.parse() { settings.volume = v; } } if let Ok(v) = ::std::env::var("MELODY_MUSIC") { let p = PathBuf::from(v); if p.exists() { settings.music = p; } } if let Ok(v) = ::std::env::var("MELODY_PRIORITIZE_CWD") { if let Ok(v) = v.parse() { settings.prioritize_cwd = v; } } if let Ok(v) = ::std::env::var("MELODY_IGNORE_ALL_UNKNOWNS") { if let Ok(v) = v.parse() { settings.ignore_all_unknowns = v; } } if let Ok(v) = ::std::env::var("MELODY_IGNORE_UNKNOWN_TITLE") { if let Ok(v) = v.parse() { settings.ignore_unknown_title = v; } } if let Ok(v) = ::std::env::var("MELODY_IGNORE_UNKNOWN_ALBUM") { if let Ok(v) = v.parse() { settings.ignore_unknown_album = v; } } if let Ok(v) = ::std::env::var("MELODY_IGNORE_UNKNOWN_ARTIST") { if let Ok(v) = v.parse() { settings.ignore_unknown_artist = v; } } settings } fn create_default(config_file: PathBuf) -> Result { let user_dir = UserDirs::new().ok_or(Errors::FailedToGetUserDir)?; let audio_dir = user_dir .audio_dir() .ok_or(Errors::FailedToGetAudioDir)? .to_owned(); let mut f = ::std::fs::File::create(config_file).map_err(|_| Errors::FailedToGetConfig)?; let file_txt = [ "volume=0.25", &format!( "music={}", audio_dir.to_str().ok_or(Errors::FailedToGetAudioDir)? ), "prioritize_cwd=false", "ignore_unknown_title=false", "ignore_unknown_artist=false", "ignore_unknown_album=false", "ignore_all_unknowns=false", ] .join("\n"); f.write_all(file_txt.as_bytes()) .map_err(|_| Errors::FailedToGetConfig)?; Ok(Settings { volume: 0.25, music: audio_dir, prioritize_cwd: false, ignore_unknown_album: false, ignore_unknown_title: false, ignore_unknown_artist: false, ignore_all_unknowns: false, }) } } /// Used to streamline the config parsing impl Default for Settings { fn default() -> Self { Settings { volume: 0.25, music: PathBuf::default(), prioritize_cwd: false, ignore_unknown_album: false, ignore_unknown_title: false, ignore_unknown_artist: false, ignore_all_unknowns: false, } } }