From 09c78a14cb7dc83c7711b6e58025d43272e9eaf7 Mon Sep 17 00:00:00 2001 From: salmonik Date: Wed, 27 May 2026 20:26:56 +0200 Subject: play [track] [-a/--album] option if supplied when a track is played, the rest of the album will be queued after the track --- src/database.rs | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) (limited to 'src/database.rs') diff --git a/src/database.rs b/src/database.rs index cd839b1..b80ad4a 100644 --- a/src/database.rs +++ b/src/database.rs @@ -199,6 +199,76 @@ impl Database { Ok(()) } + pub fn get_album_tracks_after( + &self, + album_id: i64, + after_track_number: Option, + exclude_path: &Path, + ) -> SqlResult> { + let exclude = exclude_path.to_string_lossy(); + let mut stmt = self.conn.prepare( + "SELECT t.id, t.album_id, t.title, t.path, t.duration, t.track_number, ar.name, a.title + FROM tracks t + JOIN albums a ON t.album_id = a.id + JOIN artists ar ON a.artist_id = ar.id + WHERE t.album_id = ?1 + AND t.path != ?3 + AND (?2 IS NULL OR t.track_number > ?2) + ORDER BY t.track_number", + )?; + + let rows = stmt.query_map( + rusqlite::params![album_id, after_track_number, exclude.as_ref()], + |row| { + Ok(Track { + id: row.get(0)?, + album_id: row.get(1)?, + title: row.get(2)?, + path: PathBuf::from(row.get::<_, String>(3)?), + duration: row.get(4)?, + track_number: row.get(5)?, + artist_name: Some(row.get(6)?), + album_title: Some(row.get(7)?), + }) + }, + )?; + + rows.collect() + } + + /// Find album tracks that come after the given file's position in its album. + /// Uses directory-based metadata extraction (matching how the DB stores data). + /// Returns empty vec if the file's album isn't in the DB. + pub fn find_album_tracks_after_path(&self, path: &Path) -> SqlResult> { + // Canonicalize so relative paths match absolute paths stored in the DB + let path = std::fs::canonicalize(path).unwrap_or_else(|_| path.to_path_buf()); + let (ref artist, ref album, _, _, _) = extract_metadata(&path); + + let album_id = match self.conn.query_row( + "SELECT al.id FROM albums al + JOIN artists ar ON al.artist_id = ar.id + WHERE ar.name = ? AND al.title = ?", + rusqlite::params![artist, album], + |row| row.get::<_, i64>(0), + ) { + Ok(id) => id, + Err(rusqlite::Error::QueryReturnedNoRows) => return Ok(Vec::new()), + Err(e) => return Err(e), + }; + + let path_str = path.to_string_lossy(); + let track_number: Option = self + .conn + .query_row( + "SELECT track_number FROM tracks WHERE path = ?", + rusqlite::params![path_str.as_ref()], + |row| row.get(0), + ) + .unwrap_or(None); + + self.get_album_tracks_after(album_id, track_number, &path) + } + pub fn search_tracks(&self, query: &str) -> SqlResult> { let mut stmt = self.conn.prepare( "SELECT t.id, t.album_id, t.title, t.path, t.duration, t.track_number, ar.name, a.title -- cgit v1.2.3