From bd29978b2a0d0d6def486fcdaa63bc8934d68045 Mon Sep 17 00:00:00 2001 From: salmonik Date: Tue, 5 May 2026 21:12:32 +0200 Subject: fix(daemon): robust auto-advance; ensure next track starts even if playback fails --- src/cli.rs | 186 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 src/cli.rs (limited to 'src/cli.rs') diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..13ef67c --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,186 @@ +use crate::config::Config; +use crate::database::Database; +use clap::{Parser, Subcommand}; +use std::path::PathBuf; + +#[derive(Parser)] +#[command(name = "rsp")] +#[command(about = "Rust music player daemon", long_about = None)] +pub struct Cli { + #[command(subcommand)] + pub command: Commands, +} + +#[derive(Subcommand)] +pub enum Commands { + /// Start the daemon + Start, + /// Stop the daemon + Stop, + /// Restart the daemon (kill existing and start new) + Restart, + /// Play a track, album, or artist + Play { + #[arg(value_name = "QUERY")] + query: Option, + }, + /// Pause playback + Pause, + /// Resume playback + Resume, + /// Stop playback + StopPlayback, + /// Skip to next track + Next, + /// Skip to previous track + Previous, + /// Set volume (0-100) + Volume { + #[arg(value_name = "LEVEL")] + level: Option, + }, + /// Shuffle mode + Shuffle { + #[arg(value_name = "MODE")] + mode: Option, + }, + /// Queue management + Queue { + #[arg(value_name = "POSITION")] + position: Option, + #[arg(value_name = "QUERY")] + query: Option, + }, + /// Show player status + Status, + /// Scan music paths to populate database + Scan { + #[arg(long)] + force: bool, + #[arg(long, value_name = "PATHS")] + paths: Option>, + }, + /// Settings management + Settings { + #[command(subcommand)] + command: SettingsCommands, + }, +} + +#[derive(Subcommand)] +pub enum SettingsCommands { + /// Get a setting value + Get { + #[arg(value_name = "KEY")] + key: String, + }, + /// Set a setting value + Set { + #[arg(value_name = "KEY")] + key: String, + #[arg(value_name = "VALUE")] + value: String, + }, + /// List all settings + List, + /// Unset a setting + Unset { + #[arg(value_name = "KEY")] + key: String, + }, +} + +impl Cli { + pub fn run(&self) -> Result<(), Box> { + match &self.command { + Commands::Start => { + crate::daemon::start_daemon()?; + } + Commands::Stop => { + crate::daemon::stop_daemon()?; + } + Commands::Restart => { + crate::daemon::restart_daemon()?; + } + Commands::Play { query } => { + if let Some(q) = query { + crate::daemon::send_command(format!("play {}", q))?; + } else { + crate::daemon::send_command("play".to_string())?; + } + } + Commands::Pause => { + crate::daemon::send_command("pause".to_string())?; + } + Commands::Resume => { + crate::daemon::send_command("resume".to_string())?; + } + Commands::StopPlayback => { + crate::daemon::send_command("stop".to_string())?; + } + Commands::Next => { + crate::daemon::send_command("next".to_string())?; + } + Commands::Previous => { + crate::daemon::send_command("previous".to_string())?; + } + Commands::Volume { level } => { + if let Some(l) = level { + crate::daemon::send_command(format!("volume {}", l))?; + } else { + crate::daemon::send_command("volume".to_string())?; + } + } + Commands::Shuffle { mode } => { + if let Some(m) = mode { + crate::daemon::send_command(format!("shuffle {}", m))?; + } else { + crate::daemon::send_command("shuffle".to_string())?; + } + } + Commands::Queue { position, query } => match (position, query) { + (None, None) => { + crate::daemon::send_command("queue".to_string())?; + } + (pos, Some(q)) => { + let pos = pos.as_deref().unwrap_or("last"); + crate::daemon::send_command(format!("queue {} {}", pos, q))?; + } + _ => {} + }, + Commands::Status => { + crate::daemon::send_command("status".to_string())?; + } + Commands::Scan { force, paths } => { + let config = Config::load()?; + let db = Database::open(&config)?; + if let Some(custom_paths) = paths { + db.scan_paths(custom_paths, *force)?; + } else { + db.scan_paths(&config.music_paths, *force)?; + } + println!("Scan complete"); + } + Commands::Settings { command } => { + let mut config = Config::load()?; + match command { + SettingsCommands::Get { key } => { + println!("{}", config.get(key)?); + } + SettingsCommands::Set { key, value } => { + config.set(key, value)?; + config.save()?; + } + SettingsCommands::List => { + config.list(); + } + SettingsCommands::Unset { key } => { + config.unset(key)?; + config.save()?; + } + } + } + } + Ok(()) + } +} -- cgit v1.2.3