mirror of
				https://github.com/johrpan/musicus.git
				synced 2025-10-26 11:47:25 +01:00 
			
		
		
		
	Keep playing random tracks after the playlist ends
This commit is contained in:
		
							parent
							
								
									42d1d047e3
								
							
						
					
					
						commit
						487fd0a048
					
				
					 3 changed files with 35 additions and 7 deletions
				
			
		|  | @ -1,5 +1,6 @@ | ||||||
| use crate::{Backend, BackendState, Player, Result}; | use crate::{Backend, BackendState, Player, Result}; | ||||||
| use gio::prelude::*; | use gio::prelude::*; | ||||||
|  | use glib::clone; | ||||||
| use log::warn; | use log::warn; | ||||||
| use musicus_database::Database; | use musicus_database::Database; | ||||||
| use std::path::PathBuf; | use std::path::PathBuf; | ||||||
|  | @ -41,10 +42,16 @@ impl Backend { | ||||||
|         let mut db_path = path.clone(); |         let mut db_path = path.clone(); | ||||||
|         db_path.push("musicus.db"); |         db_path.push("musicus.db"); | ||||||
| 
 | 
 | ||||||
|         let database = Database::new(db_path.to_str().unwrap())?; |         let database = Rc::new(Database::new(db_path.to_str().unwrap())?); | ||||||
|         self.database.replace(Some(Rc::new(database))); |         self.database.replace(Some(Rc::clone(&database))); | ||||||
| 
 | 
 | ||||||
|         let player = Player::new(path); |         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.player.replace(Some(player)); | ||||||
| 
 | 
 | ||||||
|         self.set_state(BackendState::Ready); |         self.set_state(BackendState::Ready); | ||||||
|  |  | ||||||
|  | @ -17,6 +17,7 @@ pub struct Player { | ||||||
|     current_track: Cell<Option<usize>>, |     current_track: Cell<Option<usize>>, | ||||||
|     playing: Cell<bool>, |     playing: Cell<bool>, | ||||||
|     duration: Cell<u64>, |     duration: Cell<u64>, | ||||||
|  |     generate_next_track_cb: RefCell<Option<Box<dyn Fn() -> Track>>>, | ||||||
|     playlist_cbs: RefCell<Vec<Box<dyn Fn(Vec<Track>)>>>, |     playlist_cbs: RefCell<Vec<Box<dyn Fn(Vec<Track>)>>>, | ||||||
|     track_cbs: RefCell<Vec<Box<dyn Fn(usize)>>>, |     track_cbs: RefCell<Vec<Box<dyn Fn(usize)>>>, | ||||||
|     duration_cbs: RefCell<Vec<Box<dyn Fn(u64)>>>, |     duration_cbs: RefCell<Vec<Box<dyn Fn(u64)>>>, | ||||||
|  | @ -44,6 +45,7 @@ impl Player { | ||||||
|             current_track: Cell::new(None), |             current_track: Cell::new(None), | ||||||
|             playing: Cell::new(false), |             playing: Cell::new(false), | ||||||
|             duration: Cell::new(0), |             duration: Cell::new(0), | ||||||
|  |             generate_next_track_cb: RefCell::new(None), | ||||||
|             playlist_cbs: RefCell::new(Vec::new()), |             playlist_cbs: RefCell::new(Vec::new()), | ||||||
|             track_cbs: RefCell::new(Vec::new()), |             track_cbs: RefCell::new(Vec::new()), | ||||||
|             duration_cbs: RefCell::new(Vec::new()), |             duration_cbs: RefCell::new(Vec::new()), | ||||||
|  | @ -144,6 +146,10 @@ impl Player { | ||||||
|         result |         result | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     pub fn set_generate_next_track_cb<F: Fn() -> Track + 'static>(&self, cb: F) { | ||||||
|  |         self.generate_next_track_cb.replace(Some(Box::new(cb))); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     pub fn add_playlist_cb<F: Fn(Vec<Track>) + 'static>(&self, cb: F) { |     pub fn add_playlist_cb<F: Fn(Vec<Track>) + 'static>(&self, cb: F) { | ||||||
|         self.playlist_cbs.borrow_mut().push(Box::new(cb)); |         self.playlist_cbs.borrow_mut().push(Box::new(cb)); | ||||||
|     } |     } | ||||||
|  | @ -270,7 +276,9 @@ impl Player { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn has_next(&self) -> bool { |     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(); |             let playlist = self.playlist.borrow(); | ||||||
|             current_track + 1 < playlist.len() |             current_track + 1 < playlist.len() | ||||||
|         } else { |         } else { | ||||||
|  | @ -285,9 +293,11 @@ impl Player { | ||||||
|             )) |             )) | ||||||
|         })?; |         })?; | ||||||
| 
 | 
 | ||||||
|         let playlist = self.playlist.borrow(); |         if current_track + 1 < self.playlist.borrow().len() { | ||||||
| 
 |             current_track += 1; | ||||||
|         if current_track + 1 < playlist.len() { |         } else if let Some(cb) = &*self.generate_next_track_cb.borrow() { | ||||||
|  |             let new_track = cb(); | ||||||
|  |             self.add_item(new_track)?; | ||||||
|             current_track += 1; |             current_track += 1; | ||||||
|         } else { |         } else { | ||||||
|             return Err(Error::Other(String::from("No existing next track."))); |             return Err(Error::Other(String::from("No existing next track."))); | ||||||
|  |  | ||||||
|  | @ -49,7 +49,7 @@ struct MediumRow { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Table data for a [`Track`].
 | /// Table data for a [`Track`].
 | ||||||
| #[derive(Insertable, Queryable, Debug, Clone)] | #[derive(Insertable, Queryable, QueryableByName, Debug, Clone)] | ||||||
| #[table_name = "tracks"] | #[table_name = "tracks"] | ||||||
| struct TrackRow { | struct TrackRow { | ||||||
|     pub id: String, |     pub id: String, | ||||||
|  | @ -224,6 +224,17 @@ impl Database { | ||||||
|         Ok(tracks) |         Ok(tracks) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// Get a random track from the database.
 | ||||||
|  |     pub fn random_track(&self) -> Result<Track> { | ||||||
|  |         let row = diesel::sql_query("SELECT * FROM tracks ORDER BY RANDOM() LIMIT 1") | ||||||
|  |             .load::<TrackRow>(&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.
 |     /// Retrieve all available information on a medium from related tables.
 | ||||||
|     fn get_medium_data(&self, row: MediumRow) -> Result<Medium> { |     fn get_medium_data(&self, row: MediumRow) -> Result<Medium> { | ||||||
|         let track_rows = tracks::table |         let track_rows = tracks::table | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue