use std::{process::Command, process::exit}; mod albums; mod cli; mod config; mod learner; mod state; mod trajectory; use crate::cli::{Action, parse}; use crate::config::Config; use crate::state::State; fn mpc_load_and_play(path: &str) { _ = Command::new("mpc").arg("clear").output(); _ = Command::new("mpc").args(["add", path]).output(); _ = Command::new("mpc").arg("play").output(); } fn notify(text: &str) { if let Err(e) = Command::new("notify-send") .args(["-t", "5000", "-a", "mood", text]) .status() { eprintln!("Failed to show notification: {e}"); } } fn load_state_no_default() -> State { State::try_load().unwrap_or_else(|e| { eprintln!("Failed to load state: {e}, nothing to dump."); exit(1); }) } fn main() { let action = parse(); if action.is_none() { return; } let action = action.unwrap(); match action { Action::DumpLearner => { let state = load_state_no_default(); println!( "{}", state.dump_learner().unwrap_or_else(|e| { eprintln!("Failed to serialize state (dump-learner): {e}"); exit(1); }) ); } Action::DumpTrajectory => { let state = load_state_no_default(); println!( "{}", state.dump_trajectory().unwrap_or_else(|e| { eprintln!("Failed to serialize state (dump-trajectory): {e}"); exit(1); }) ); } Action::NewState => { let default = State::default(); if let Err(e) = default.try_save() { eprintln!("Failed to write new state: {e}"); exit(1); } println!("New state written."); } Action::NewConfig => { let default = Config::default(); if let Err(e) = default.try_save() { eprintln!("Failed to write new config: {e}"); exit(1); } println!("New config written."); } Action::Run => { let config = match Config::try_load() { Ok(c) => c, Err(e) => { eprintln!("Failed to load config: {e}, writing defaults."); let default = Config::default(); if let Err(se) = default.try_save() { panic!("Failed to save default config: {se}"); } default } }; let mut state = match State::try_load() { Ok(s) => s, Err(e) => { eprintln!("Failed to load state: {e}"); State::default() } }; if let Some((next_album, prob)) = state.next(&config) { let text = format!("Now playing: {next_album} ({:.2}%)", prob * 100.0); println!("{text}"); mpc_load_and_play(&next_album); notify(&text); } else { println!("No next album available."); } if let Err(e) = state.try_save() { panic!("Failed to save state: {e}"); } } } }