diff options
Diffstat (limited to 'src/daemon.rs')
| -rw-r--r-- | src/daemon.rs | 66 |
1 files changed, 50 insertions, 16 deletions
diff --git a/src/daemon.rs b/src/daemon.rs index b79e67a..acc7729 100644 --- a/src/daemon.rs +++ b/src/daemon.rs | |||
| @@ -12,7 +12,7 @@ use std::time::Duration; | |||
| 12 | 12 | ||
| 13 | pub fn start_daemon() -> Result<(), Box<dyn std::error::Error>> { | 13 | pub fn start_daemon() -> Result<(), Box<dyn std::error::Error>> { |
| 14 | let config = Config::load()?; | 14 | let config = Config::load()?; |
| 15 | let socket_path = config.get_socket_path(); | 15 | let socket_path = Config::get_socket_path(); |
| 16 | let pid_path = get_pid_path(&config); | 16 | let pid_path = get_pid_path(&config); |
| 17 | 17 | ||
| 18 | // Check if daemon is already running | 18 | // Check if daemon is already running |
| @@ -55,7 +55,6 @@ pub fn start_daemon() -> Result<(), Box<dyn std::error::Error>> { | |||
| 55 | let queue = Arc::new(Mutex::new(Queue::new())); | 55 | let queue = Arc::new(Mutex::new(Queue::new())); |
| 56 | 56 | ||
| 57 | // Load and apply saved settings | 57 | // Load and apply saved settings |
| 58 | let config = Config::load().unwrap_or_default(); | ||
| 59 | if let Some(vol) = config.volume { | 58 | if let Some(vol) = config.volume { |
| 60 | audio_engine.set_volume(vol as f32 / 100.0); | 59 | audio_engine.set_volume(vol as f32 / 100.0); |
| 61 | } | 60 | } |
| @@ -69,6 +68,9 @@ pub fn start_daemon() -> Result<(), Box<dyn std::error::Error>> { | |||
| 69 | } | 68 | } |
| 70 | } | 69 | } |
| 71 | 70 | ||
| 71 | // Save full config | ||
| 72 | config.save()?; | ||
| 73 | |||
| 72 | // Accept connections until shutdown | 74 | // Accept connections until shutdown |
| 73 | listener.set_nonblocking(true)?; | 75 | listener.set_nonblocking(true)?; |
| 74 | // Helper: poll until a specific track actually starts playing or timeout | 76 | // Helper: poll until a specific track actually starts playing or timeout |
| @@ -106,7 +108,8 @@ pub fn start_daemon() -> Result<(), Box<dyn std::error::Error>> { | |||
| 106 | audio_engine.play(next_track.clone()); | 108 | audio_engine.play(next_track.clone()); |
| 107 | if wait_for_start(&audio_engine, &next_track, 500) { | 109 | if wait_for_start(&audio_engine, &next_track, 500) { |
| 108 | started = true; | 110 | started = true; |
| 109 | notification::notify_track(&Track::from_path(next_track)); | 111 | let fmt = Config::load().ok().and_then(|c| c.display_format.clone()); |
| 112 | notification::notify_track(&Track::from_path(next_track), fmt.as_deref()); | ||
| 110 | break; | 113 | break; |
| 111 | } | 114 | } |
| 112 | } else { | 115 | } else { |
| @@ -182,7 +185,7 @@ pub fn stop_daemon() -> Result<(), Box<dyn std::error::Error>> { | |||
| 182 | } | 185 | } |
| 183 | 186 | ||
| 184 | // Clean up files | 187 | // Clean up files |
| 185 | let socket_path = config.get_socket_path(); | 188 | let socket_path = Config::get_socket_path(); |
| 186 | std::fs::remove_file(&socket_path).ok(); | 189 | std::fs::remove_file(&socket_path).ok(); |
| 187 | std::fs::remove_file(&pid_path).ok(); | 190 | std::fs::remove_file(&pid_path).ok(); |
| 188 | 191 | ||
| @@ -203,7 +206,7 @@ pub fn restart_daemon() -> Result<(), Box<dyn std::error::Error>> { | |||
| 203 | // Start new daemon in background | 206 | // Start new daemon in background |
| 204 | let current_exe = std::env::current_exe()?; | 207 | let current_exe = std::env::current_exe()?; |
| 205 | std::process::Command::new(current_exe) | 208 | std::process::Command::new(current_exe) |
| 206 | .arg("start") | 209 | .arg("start-daemon") |
| 207 | .spawn()?; | 210 | .spawn()?; |
| 208 | 211 | ||
| 209 | println!("Daemon restarted"); | 212 | println!("Daemon restarted"); |
| @@ -216,8 +219,7 @@ pub fn send_command(cmd: String) -> Result<(), Box<dyn std::error::Error>> { | |||
| 216 | } | 219 | } |
| 217 | 220 | ||
| 218 | fn send_command_raw(cmd: String) -> Result<(), Box<dyn std::error::Error>> { | 221 | fn send_command_raw(cmd: String) -> Result<(), Box<dyn std::error::Error>> { |
| 219 | let config = Config::load()?; | 222 | let socket_path = Config::get_socket_path(); |
| 220 | let socket_path = config.get_socket_path(); | ||
| 221 | 223 | ||
| 222 | let mut stream = UnixStream::connect(socket_path)?; | 224 | let mut stream = UnixStream::connect(socket_path)?; |
| 223 | stream.write_all(cmd.as_bytes())?; | 225 | stream.write_all(cmd.as_bytes())?; |
| @@ -254,7 +256,11 @@ fn process_command( | |||
| 254 | if audio.is_playing() { | 256 | if audio.is_playing() { |
| 255 | if let Some(track_path) = audio.current_track() { | 257 | if let Some(track_path) = audio.current_track() { |
| 256 | let track = Track::from_path(track_path); | 258 | let track = Track::from_path(track_path); |
| 257 | let track_str = track.display_string(0, 1); | 259 | let fmt = Config::load().ok().and_then(|c| c.display_format.clone()); |
| 260 | let track_str = match fmt.as_deref() { | ||
| 261 | Some(f) => track.format(f), | ||
| 262 | None => track.display_string(0, 1), | ||
| 263 | }; | ||
| 258 | format!("Playing\nTrack: {}\n", track_str) | 264 | format!("Playing\nTrack: {}\n", track_str) |
| 259 | } else { | 265 | } else { |
| 260 | "Playing\n".to_string() | 266 | "Playing\n".to_string() |
| @@ -296,7 +302,11 @@ fn process_command( | |||
| 296 | if let Ok(mut q) = queue.lock() { | 302 | if let Ok(mut q) = queue.lock() { |
| 297 | if let Some(next_track) = q.next() { | 303 | if let Some(next_track) = q.next() { |
| 298 | audio.play(next_track.clone()); | 304 | audio.play(next_track.clone()); |
| 299 | notification::notify_track(&Track::from_path(next_track)); | 305 | let fmt = Config::load().ok().and_then(|c| c.display_format.clone()); |
| 306 | notification::notify_track( | ||
| 307 | &Track::from_path(next_track.clone()), | ||
| 308 | fmt.as_deref(), | ||
| 309 | ); | ||
| 300 | "Playing next track\n".to_string() | 310 | "Playing next track\n".to_string() |
| 301 | } else { | 311 | } else { |
| 302 | audio.stop(); | 312 | audio.stop(); |
| @@ -311,7 +321,11 @@ fn process_command( | |||
| 311 | if let Ok(mut q) = queue.lock() { | 321 | if let Ok(mut q) = queue.lock() { |
| 312 | if let Some(prev_track) = q.previous() { | 322 | if let Some(prev_track) = q.previous() { |
| 313 | audio.play(prev_track.clone()); | 323 | audio.play(prev_track.clone()); |
| 314 | notification::notify_track(&Track::from_path(prev_track)); | 324 | let fmt = Config::load().ok().and_then(|c| c.display_format.clone()); |
| 325 | notification::notify_track( | ||
| 326 | &Track::from_path(prev_track.clone()), | ||
| 327 | fmt.as_deref(), | ||
| 328 | ); | ||
| 315 | "Playing previous track\n".to_string() | 329 | "Playing previous track\n".to_string() |
| 316 | } else { | 330 | } else { |
| 317 | "No previous track\n".to_string() | 331 | "No previous track\n".to_string() |
| @@ -371,7 +385,13 @@ fn process_command( | |||
| 371 | } else { | 385 | } else { |
| 372 | ("last", rest) | 386 | ("last", rest) |
| 373 | }; | 387 | }; |
| 374 | let path_str = path_str.to_string(); | 388 | let path_str = if path_str.starts_with("~/") { |
| 389 | std::env::var("HOME") | ||
| 390 | .map(|h| path_str.replacen("~", &h, 1)) | ||
| 391 | .unwrap_or_else(|_| path_str.to_string()) | ||
| 392 | } else { | ||
| 393 | path_str.to_string() | ||
| 394 | }; | ||
| 375 | 395 | ||
| 376 | if path_str.is_empty() { | 396 | if path_str.is_empty() { |
| 377 | return "Usage: play [now|next|last] <path>\n".to_string(); | 397 | return "Usage: play [now|next|last] <path>\n".to_string(); |
| @@ -390,7 +410,9 @@ fn process_command( | |||
| 390 | } | 410 | } |
| 391 | if let Some(track) = q.track_at(q.position()) { | 411 | if let Some(track) = q.track_at(q.position()) { |
| 392 | audio.play(track.path.clone()); | 412 | audio.play(track.path.clone()); |
| 393 | notification::notify_track(track); | 413 | let fmt = |
| 414 | Config::load().ok().and_then(|c| c.display_format.clone()); | ||
| 415 | notification::notify_track(track, fmt.as_deref()); | ||
| 394 | } | 416 | } |
| 395 | format!("Playing now: {}\n", path_str) | 417 | format!("Playing now: {}\n", path_str) |
| 396 | } | 418 | } |
| @@ -405,7 +427,9 @@ fn process_command( | |||
| 405 | if was_empty && !was_playing { | 427 | if was_empty && !was_playing { |
| 406 | let track = Track::from_path(path.clone()); | 428 | let track = Track::from_path(path.clone()); |
| 407 | audio.play(path); | 429 | audio.play(path); |
| 408 | notification::notify_track(&track); | 430 | let fmt = |
| 431 | Config::load().ok().and_then(|c| c.display_format.clone()); | ||
| 432 | notification::notify_track(&track, fmt.as_deref()); | ||
| 409 | format!("Playing: {}\n", path_str) | 433 | format!("Playing: {}\n", path_str) |
| 410 | } else { | 434 | } else { |
| 411 | format!("Queued: {}\n", path_str) | 435 | format!("Queued: {}\n", path_str) |
| @@ -431,7 +455,10 @@ fn process_command( | |||
| 431 | } | 455 | } |
| 432 | if let Some(track) = q.track_at(q.position()) { | 456 | if let Some(track) = q.track_at(q.position()) { |
| 433 | audio.play(track.path.clone()); | 457 | audio.play(track.path.clone()); |
| 434 | notification::notify_track(track); | 458 | let fmt = Config::load() |
| 459 | .ok() | ||
| 460 | .and_then(|c| c.display_format.clone()); | ||
| 461 | notification::notify_track(track, fmt.as_deref()); | ||
| 435 | } | 462 | } |
| 436 | format!( | 463 | format!( |
| 437 | "Playing now: {} tracks from {}\n", | 464 | "Playing now: {} tracks from {}\n", |
| @@ -459,7 +486,10 @@ fn process_command( | |||
| 459 | && let Some(track) = q.current() | 486 | && let Some(track) = q.current() |
| 460 | { | 487 | { |
| 461 | audio.play(track.path.clone()); | 488 | audio.play(track.path.clone()); |
| 462 | notification::notify_track(track); | 489 | let fmt = Config::load() |
| 490 | .ok() | ||
| 491 | .and_then(|c| c.display_format.clone()); | ||
| 492 | notification::notify_track(track, fmt.as_deref()); | ||
| 463 | } | 493 | } |
| 464 | format!("Queued {} tracks from: {}\n", files.len(), path_str) | 494 | format!("Queued {} tracks from: {}\n", files.len(), path_str) |
| 465 | } | 495 | } |
| @@ -512,9 +542,13 @@ fn process_command( | |||
| 512 | q.shuffled_indices().to_vec() | 542 | q.shuffled_indices().to_vec() |
| 513 | }; | 543 | }; |
| 514 | let is_playing = audio.is_playing(); | 544 | let is_playing = audio.is_playing(); |
| 545 | let fmt = Config::load().ok().and_then(|c| c.display_format.clone()); | ||
| 515 | for (display_idx, &track_idx) in indices.iter().enumerate() { | 546 | for (display_idx, &track_idx) in indices.iter().enumerate() { |
| 516 | if let Some(track) = q.track_at(track_idx) { | 547 | if let Some(track) = q.track_at(track_idx) { |
| 517 | let track_str = track.display_string(display_idx, q.len()); | 548 | let track_str = match fmt.as_deref() { |
| 549 | Some(f) => track.format(f), | ||
| 550 | None => track.display_string(display_idx, q.len()), | ||
| 551 | }; | ||
| 518 | if track_idx == playing_track_idx && is_playing { | 552 | if track_idx == playing_track_idx && is_playing { |
| 519 | output.push_str(&format!("> {} (playing)\n", track_str)); | 553 | output.push_str(&format!("> {} (playing)\n", track_str)); |
| 520 | } else { | 554 | } else { |
