use crate::config::Config; use crate::database::Database; use clap::{Parser, Subcommand}; use std::path::PathBuf; #[derive(Parser)] #[command(name = "rsp", infer_long_args = true)] #[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 StartDaemon, /// Stop the daemon StopDaemon, /// Restart the daemon (kill existing and start new) Restart, /// Play a track, album, or artist Play { /// Add after current track and skip to it #[arg(short = 'i', long = "now")] now: bool, /// Add to queue after current track (don't skip) #[arg(short = 'n', long = "next")] next: bool, #[arg(value_name = "QUERY")] query: Option, }, /// Pause playback Pause, /// Resume playback Resume, /// Toggle play/pause Toggle, /// Stop playback Stop, /// 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::StartDaemon => { crate::daemon::start_daemon()?; } Commands::StopDaemon => { crate::daemon::stop_daemon()?; } Commands::Restart => { crate::daemon::restart_daemon()?; } Commands::Play { now, next, query, .. } => { if let Some(q) = query { let pos = if *now { "now" } else if *next { "next" } else { "last" }; crate::daemon::send_command(format!("play {} {}", pos, q))?; } else { crate::daemon::send_command("play last".to_string())?; } } Commands::Pause => { crate::daemon::send_command("pause".to_string())?; } Commands::Resume => { crate::daemon::send_command("resume".to_string())?; } Commands::Toggle => { crate::daemon::send_command("toggle".to_string())?; } Commands::Stop => { 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(()) } }