aboutsummaryrefslogtreecommitdiffstats
path: root/src/database.rs
diff options
context:
space:
mode:
authorsalmonik <raisersoft@proton.me>2026-05-27 20:26:56 +0200
committersalmonik <raisersoft@proton.me>2026-05-27 20:26:56 +0200
commit09c78a14cb7dc83c7711b6e58025d43272e9eaf7 (patch)
treee5eec691695c3beff320a2a2a9c2d60c2524ec55 /src/database.rs
parentadd licensing (diff)
downloadrsplayer-09c78a14cb7dc83c7711b6e58025d43272e9eaf7.tar.gz
rsplayer-09c78a14cb7dc83c7711b6e58025d43272e9eaf7.zip
play [track] [-a/--album] option
if supplied when a track is played, the rest of the album will be queued after the track
Diffstat (limited to '')
-rw-r--r--src/database.rs70
1 files changed, 70 insertions, 0 deletions
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 {
199 Ok(()) 199 Ok(())
200 } 200 }
201 201
202 pub fn get_album_tracks_after(
203 &self,
204 album_id: i64,
205 after_track_number: Option<i32>,
206 exclude_path: &Path,
207 ) -> SqlResult<Vec<Track>> {
208 let exclude = exclude_path.to_string_lossy();
209 let mut stmt = self.conn.prepare(
210 "SELECT t.id, t.album_id, t.title, t.path, t.duration, t.track_number, ar.name, a.title
211 FROM tracks t
212 JOIN albums a ON t.album_id = a.id
213 JOIN artists ar ON a.artist_id = ar.id
214 WHERE t.album_id = ?1
215 AND t.path != ?3
216 AND (?2 IS NULL OR t.track_number > ?2)
217 ORDER BY t.track_number",
218 )?;
219
220 let rows = stmt.query_map(
221 rusqlite::params![album_id, after_track_number, exclude.as_ref()],
222 |row| {
223 Ok(Track {
224 id: row.get(0)?,
225 album_id: row.get(1)?,
226 title: row.get(2)?,
227 path: PathBuf::from(row.get::<_, String>(3)?),
228 duration: row.get(4)?,
229 track_number: row.get(5)?,
230 artist_name: Some(row.get(6)?),
231 album_title: Some(row.get(7)?),
232 })
233 },
234 )?;
235
236 rows.collect()
237 }
238
239 /// Find album tracks that come after the given file's position in its album.
240 /// Uses directory-based metadata extraction (matching how the DB stores data).
241 /// Returns empty vec if the file's album isn't in the DB.
242 pub fn find_album_tracks_after_path(&self, path: &Path) -> SqlResult<Vec<Track>> {
243 // Canonicalize so relative paths match absolute paths stored in the DB
244 let path = std::fs::canonicalize(path).unwrap_or_else(|_| path.to_path_buf());
245 let (ref artist, ref album, _, _, _) = extract_metadata(&path);
246
247 let album_id = match self.conn.query_row(
248 "SELECT al.id FROM albums al
249 JOIN artists ar ON al.artist_id = ar.id
250 WHERE ar.name = ? AND al.title = ?",
251 rusqlite::params![artist, album],
252 |row| row.get::<_, i64>(0),
253 ) {
254 Ok(id) => id,
255 Err(rusqlite::Error::QueryReturnedNoRows) => return Ok(Vec::new()),
256 Err(e) => return Err(e),
257 };
258
259 let path_str = path.to_string_lossy();
260 let track_number: Option<i32> = self
261 .conn
262 .query_row(
263 "SELECT track_number FROM tracks WHERE path = ?",
264 rusqlite::params![path_str.as_ref()],
265 |row| row.get(0),
266 )
267 .unwrap_or(None);
268
269 self.get_album_tracks_after(album_id, track_number, &path)
270 }
271
202 pub fn search_tracks(&self, query: &str) -> SqlResult<Vec<Track>> { 272 pub fn search_tracks(&self, query: &str) -> SqlResult<Vec<Track>> {
203 let mut stmt = self.conn.prepare( 273 let mut stmt = self.conn.prepare(
204 "SELECT t.id, t.album_id, t.title, t.path, t.duration, t.track_number, ar.name, a.title 274 "SELECT t.id, t.album_id, t.title, t.path, t.duration, t.track_number, ar.name, a.title