From 1e48765ab39a679abcc4eac6927ad3bb58f7b438 Mon Sep 17 00:00:00 2001 From: salmonik Date: Thu, 4 Jun 2026 00:21:46 +0200 Subject: dirty, broken commit --- src/daemon.rs | 183 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 160 insertions(+), 23 deletions(-) (limited to 'src/daemon.rs') diff --git a/src/daemon.rs b/src/daemon.rs index c794495..d34305a 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -747,30 +747,40 @@ fn process_command( } else { match Config::load() { Ok(config) => match crate::database::Database::open(&config) { - Ok(db) => match db.search_tracks(query_str) { - Ok(tracks) if !tracks.is_empty() => { - let db_track = &tracks[0]; - let album_tracks = db - .get_album_tracks_after( - db_track.album_id, - db_track.track_number, - &db_track.path, - ) - .unwrap_or_default(); - let display = format!( - "{} - {}", - db_track.artist_name.as_deref().unwrap_or("unknown"), - db_track.title, - ); - let paths: Vec = - album_tracks.into_iter().map(|t| t.path).collect(); - (db_track.path.clone(), paths, display) - } - Ok(_) => { + Ok(db) => { + let tracks = match db.resolve_path(query_str) { + Ok(Some(t)) => t, + Ok(None) => match db.search_tracks(query_str) { + Ok(t) => t, + Err(e) => return format!("Database error: {}\n", e), + }, + Err(e) => return format!("Database error: {}\n", e), + }; + if tracks.is_empty() { return format!("No tracks found matching '{}'\n", query_str); } - Err(e) => return format!("Database error: {}\n", e), - }, + let db_track = &tracks[0]; + let album_paths: Vec = if tracks.len() > 1 { + // resolve_path returned full album — use remaining tracks + tracks[1..].iter().map(|t| t.path.clone()).collect() + } else { + db.get_album_tracks_after( + db_track.album_id, + db_track.track_number, + &db_track.path, + ) + .unwrap_or_default() + .into_iter() + .map(|t| t.path) + .collect() + }; + let display = format!( + "{} - {}", + db_track.artist_name.as_deref().unwrap_or("unknown"), + db_track.title, + ); + (db_track.path.clone(), album_paths, display) + } Err(e) => return format!("Database error: {}\n", e), }, Err(e) => return format!("Config error: {}\n", e), @@ -862,6 +872,8 @@ fn process_command( } else { path_str.to_string() }; + // Strip trailing slash so autocompleted Artist/Album/ resolves cleanly + let path_str = path_str.trim_end_matches('/').to_string(); if path_str.is_empty() { return "Usage: play [now|next|last] \n".to_string(); @@ -1052,7 +1064,132 @@ fn process_command( _ => format!("Error: No audio files found in '{}'\n", path_str), } } else { - format!("File not found: {}\n", path_str) + match Config::load() { + Ok(config) => match crate::database::Database::open(&config) { + Ok(db) => { + // Collect tracks: try hierarchical path first, fallback to search + let tracks = match db.resolve_path(&path_str) { + Ok(Some(t)) => t, + Ok(None) => { + let query = path_str + .rsplit_once('/') + .and_then(|(_, after)| { + (!after.is_empty()).then_some(after) + }) + .unwrap_or(&path_str); + match db.search_tracks(query) { + Ok(t) => t, + Err(e) => return format!("Database error: {}\n", e), + } + } + Err(e) => return format!("Database error: {}\n", e), + }; + + if tracks.is_empty() { + return format!("No tracks found matching '{}'\n", path_str); + } + + let is_album_play = tracks.len() > 1; + if let Ok(mut q) = queue.lock() { + let was_empty = q.is_empty(); + match position { + "now" => { + if let Ok(mut s) = scrobble_state.lock() { + try_scrobble_current(scrobbler, &mut s); + } + for t in tracks.iter().rev() { + q.insert_after_current(t.path.clone()); + } + if !was_empty { + let new_pos = q.position() + 1; + q.set_position(new_pos); + } + if let Some(track) = q.track_at(q.position()) { + audio.play(track.path.clone()); + send_now_playing(scrobbler, track); + if let Ok(mut s) = scrobble_state.lock() { + s.start(track.clone()); + } + let fmt = Config::load() + .ok() + .and_then(|c| c.display_format.clone()); + notification::notify_track(track, fmt.as_deref()); + } + if is_album_play { + format!( + "Playing now: {} tracks from {}\n", + tracks.len(), + path_str + ) + } else { + format!("Playing now: {}\n", path_str) + } + } + "next" => { + for t in tracks.iter().rev() { + q.insert_after_current(t.path.clone()); + } + if is_album_play { + format!( + "Queued next: {} tracks from {}\n", + tracks.len(), + path_str + ) + } else { + format!("Queued next: {}\n", path_str) + } + } + _ => { + let was_playing = audio.is_playing(); + for t in &tracks { + q.add_track(t.path.clone()); + } + if was_empty && !was_playing { + if is_album_play { + q.shuffle_initial(); + } + if let Some(track) = q.current() { + audio.play(track.path.clone()); + send_now_playing(scrobbler, track); + if let Ok(mut s) = scrobble_state.lock() { + s.start(track.clone()); + } + let fmt = Config::load() + .ok() + .and_then(|c| c.display_format.clone()); + notification::notify_track( + track, + fmt.as_deref(), + ); + } + if is_album_play { + format!( + "Playing: {} tracks from {}\n", + tracks.len(), + path_str + ) + } else { + format!("Playing: {}\n", path_str) + } + } else if is_album_play { + format!( + "Queued {} tracks from: {}\n", + tracks.len(), + path_str + ) + } else { + format!("Queued: {}\n", path_str) + } + } + } + } else { + "Error accessing queue\n".to_string() + } + } + Err(e) => format!("Database error: {}\n", e), + }, + Err(e) => format!("Config error: {}\n", e), + } } } } -- cgit v1.2.3