From 487fd0a04830ab207074208def2d6d712006035b Mon Sep 17 00:00:00 2001 From: Elias Projahn Date: Tue, 8 Feb 2022 17:44:21 +0100 Subject: [PATCH] Keep playing random tracks after the playlist ends --- backend/src/library.rs | 11 +++++++++-- backend/src/player.rs | 18 ++++++++++++++---- database/src/medium.rs | 13 ++++++++++++- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/backend/src/library.rs b/backend/src/library.rs index 56d404a..9bfc1a3 100644 --- a/backend/src/library.rs +++ b/backend/src/library.rs @@ -1,5 +1,6 @@ use crate::{Backend, BackendState, Player, Result}; use gio::prelude::*; +use glib::clone; use log::warn; use musicus_database::Database; use std::path::PathBuf; @@ -41,10 +42,16 @@ impl Backend { let mut db_path = path.clone(); db_path.push("musicus.db"); - let database = Database::new(db_path.to_str().unwrap())?; - self.database.replace(Some(Rc::new(database))); + let database = Rc::new(Database::new(db_path.to_str().unwrap())?); + self.database.replace(Some(Rc::clone(&database))); let player = Player::new(path); + + // Keep adding random tracks in case the playlist ends. + player.set_generate_next_track_cb(clone!(@weak database => @default-panic, move || { + database.random_track().unwrap() + })); + self.player.replace(Some(player)); self.set_state(BackendState::Ready); diff --git a/backend/src/player.rs b/backend/src/player.rs index f471423..a77d822 100644 --- a/backend/src/player.rs +++ b/backend/src/player.rs @@ -17,6 +17,7 @@ pub struct Player { current_track: Cell>, playing: Cell, duration: Cell, + generate_next_track_cb: RefCell Track>>>, playlist_cbs: RefCell)>>>, track_cbs: RefCell>>, duration_cbs: RefCell>>, @@ -44,6 +45,7 @@ impl Player { current_track: Cell::new(None), playing: Cell::new(false), duration: Cell::new(0), + generate_next_track_cb: RefCell::new(None), playlist_cbs: RefCell::new(Vec::new()), track_cbs: RefCell::new(Vec::new()), duration_cbs: RefCell::new(Vec::new()), @@ -144,6 +146,10 @@ impl Player { result } + pub fn set_generate_next_track_cb Track + 'static>(&self, cb: F) { + self.generate_next_track_cb.replace(Some(Box::new(cb))); + } + pub fn add_playlist_cb) + 'static>(&self, cb: F) { self.playlist_cbs.borrow_mut().push(Box::new(cb)); } @@ -270,7 +276,9 @@ impl Player { } pub fn has_next(&self) -> bool { - if let Some(current_track) = self.current_track.get() { + if self.generate_next_track_cb.borrow().is_some() { + true + } else if let Some(current_track) = self.current_track.get() { let playlist = self.playlist.borrow(); current_track + 1 < playlist.len() } else { @@ -285,9 +293,11 @@ impl Player { )) })?; - let playlist = self.playlist.borrow(); - - if current_track + 1 < playlist.len() { + if current_track + 1 < self.playlist.borrow().len() { + current_track += 1; + } else if let Some(cb) = &*self.generate_next_track_cb.borrow() { + let new_track = cb(); + self.add_item(new_track)?; current_track += 1; } else { return Err(Error::Other(String::from("No existing next track."))); diff --git a/database/src/medium.rs b/database/src/medium.rs index 6d5b2b5..1a1a406 100644 --- a/database/src/medium.rs +++ b/database/src/medium.rs @@ -49,7 +49,7 @@ struct MediumRow { } /// Table data for a [`Track`]. -#[derive(Insertable, Queryable, Debug, Clone)] +#[derive(Insertable, Queryable, QueryableByName, Debug, Clone)] #[table_name = "tracks"] struct TrackRow { pub id: String, @@ -224,6 +224,17 @@ impl Database { Ok(tracks) } + /// Get a random track from the database. + pub fn random_track(&self) -> Result { + let row = diesel::sql_query("SELECT * FROM tracks ORDER BY RANDOM() LIMIT 1") + .load::(&self.connection)? + .into_iter() + .next() + .ok_or(Error::Other("Failed to generate random track"))?; + + self.get_track_from_row(row) + } + /// Retrieve all available information on a medium from related tables. fn get_medium_data(&self, row: MediumRow) -> Result { let track_rows = tracks::table