Implement moving to the next track
This commit is contained in:
		
							parent
							
								
									07618676db
								
							
						
					
					
						commit
						2fd2079330
					
				
					 1 changed files with 89 additions and 13 deletions
				
			
		
							
								
								
									
										102
									
								
								src/queue.rs
									
										
									
									
									
								
							
							
						
						
									
										102
									
								
								src/queue.rs
									
										
									
									
									
								
							|  | @ -1,10 +1,15 @@ | ||||||
| //! Implements a queue for the bot to play songs in order
 | //! Implements a queue for the bot to play songs in order
 | ||||||
| 
 | 
 | ||||||
|  | use std::sync::Arc; | ||||||
|  | 
 | ||||||
| use anyhow::Result; | use anyhow::Result; | ||||||
|  | use parking_lot::Mutex; | ||||||
|  | use poise::async_trait; | ||||||
| use songbird::{ | use songbird::{ | ||||||
|  |     events::EventData, | ||||||
|     input::Input, |     input::Input, | ||||||
|     tracks::{self, TrackHandle}, |     tracks::{self, TrackHandle}, | ||||||
|     Driver, |     Driver, Event, EventContext, EventHandler, TrackEvent, | ||||||
| }; | }; | ||||||
| use thiserror::Error; | use thiserror::Error; | ||||||
| 
 | 
 | ||||||
|  | @ -14,19 +19,69 @@ pub enum QueueError { | ||||||
|     EmptyQueue, |     EmptyQueue, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Event handler for the queue
 | ||||||
|  | struct QueueHandler { | ||||||
|  |     remote_lock: Arc<Mutex<QueueCore>>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[async_trait] | ||||||
|  | impl EventHandler for QueueHandler { | ||||||
|  |     async fn act(&self, ctx: &EventContext<'_>) -> Option<Event> { | ||||||
|  |         let mut inner = self.remote_lock.lock(); | ||||||
|  | 
 | ||||||
|  |         // Due to possibility that users might remove, reorder,
 | ||||||
|  |         // or dequeue+stop tracks, we need to verify that the FIRST
 | ||||||
|  |         // track is the one who has ended.
 | ||||||
|  |         match ctx { | ||||||
|  |             EventContext::Track(ts) => { | ||||||
|  |                 // This slice should have exactly one entry.
 | ||||||
|  |                 // If the ended track has same id as the queue head, then
 | ||||||
|  |                 // we can progress the queue.
 | ||||||
|  |                 if inner.tracks.first()?.uuid() != ts.first()?.1.uuid() { | ||||||
|  |                     return None; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             _ => return None, | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let _old = inner.tracks.remove(0); | ||||||
|  | 
 | ||||||
|  |         // Keep going until we find one track which works, or we run out.
 | ||||||
|  |         while let Some(new) = inner.tracks.first() { | ||||||
|  |             if new.play().is_err() { | ||||||
|  |                 // Discard files which cannot be used for whatever reason.
 | ||||||
|  |                 inner.tracks.remove(0); | ||||||
|  |             } else { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         None | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Inner queue data behind a Mutex to allow the event handler to access it
 | ||||||
|  | struct QueueCore { | ||||||
|  |     tracks: Vec<TrackHandle>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// A queue of tracks to play
 | ||||||
| pub struct Queue { | pub struct Queue { | ||||||
|     queue: Vec<TrackHandle>, |     inner: Arc<Mutex<QueueCore>>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Queue { | impl Queue { | ||||||
|     #[must_use] |     #[must_use] | ||||||
|     pub fn new() -> Self { |     pub fn new() -> Self { | ||||||
|         Self { queue: Vec::new() } |         Self { | ||||||
|  |             inner: Arc::new(Mutex::new(QueueCore { tracks: Vec::new() })), | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Resumes the current track
 |     /// Resumes the current track
 | ||||||
|     pub fn resume(&mut self) -> Result<()> { |     pub fn resume(&mut self) -> Result<()> { | ||||||
|         let Some(track) = self.queue.first() else { |         let inner = self.inner.lock(); | ||||||
|  |         let Some(track) = inner.tracks.first() else { | ||||||
|             return Err(QueueError::EmptyQueue.into()); |             return Err(QueueError::EmptyQueue.into()); | ||||||
|         }; |         }; | ||||||
|         track.play()?; |         track.play()?; | ||||||
|  | @ -35,17 +90,19 @@ impl Queue { | ||||||
| 
 | 
 | ||||||
|     /// Stops the current track and removes it from the queue
 |     /// Stops the current track and removes it from the queue
 | ||||||
|     pub fn stop(&mut self) -> Result<()> { |     pub fn stop(&mut self) -> Result<()> { | ||||||
|         let Some(track) = self.queue.first() else { |         let mut inner = self.inner.lock(); | ||||||
|  |         let Some(track) = inner.tracks.first() else { | ||||||
|             return Err(QueueError::EmptyQueue.into()); |             return Err(QueueError::EmptyQueue.into()); | ||||||
|         }; |         }; | ||||||
|         track.stop()?; |         track.stop()?; | ||||||
|         self.queue.remove(0); |         inner.tracks.remove(0); | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Pauses the current track
 |     /// Pauses the current track
 | ||||||
|     pub fn pause(&mut self) -> Result<()> { |     pub fn pause(&mut self) -> Result<()> { | ||||||
|         let Some(track) = self.queue.first() else { |         let inner = self.inner.lock(); | ||||||
|  |         let Some(track) = inner.tracks.first() else { | ||||||
|             return Err(QueueError::EmptyQueue.into()); |             return Err(QueueError::EmptyQueue.into()); | ||||||
|         }; |         }; | ||||||
|         track.pause()?; |         track.pause()?; | ||||||
|  | @ -54,9 +111,25 @@ impl Queue { | ||||||
| 
 | 
 | ||||||
|     /// Adds a track to the end of the queue
 |     /// Adds a track to the end of the queue
 | ||||||
|     pub fn add_to_end(&mut self, source: Input, handler: &mut Driver) -> TrackHandle { |     pub fn add_to_end(&mut self, source: Input, handler: &mut Driver) -> TrackHandle { | ||||||
|  |         let mut inner = self.inner.lock(); | ||||||
|         let (mut track, handle) = tracks::create_player(source); |         let (mut track, handle) = tracks::create_player(source); | ||||||
|         track.pause(); |         track.pause(); | ||||||
|         self.queue.push(handle.clone()); |         let position = track.position(); | ||||||
|  |         // Event to remove the track from the queue when it ends
 | ||||||
|  |         track | ||||||
|  |             .events | ||||||
|  |             .as_mut() | ||||||
|  |             .expect("Why is this even an Option?") | ||||||
|  |             .add_event( | ||||||
|  |                 EventData::new( | ||||||
|  |                     Event::Track(TrackEvent::End), | ||||||
|  |                     QueueHandler { | ||||||
|  |                         remote_lock: self.inner.clone(), | ||||||
|  |                     }, | ||||||
|  |                 ), | ||||||
|  |                 position, | ||||||
|  |             ); | ||||||
|  |         inner.tracks.push(handle.clone()); | ||||||
|         handler.play(track); |         handler.play(track); | ||||||
|         handle |         handle | ||||||
|     } |     } | ||||||
|  | @ -76,12 +149,13 @@ impl Queue { | ||||||
| 
 | 
 | ||||||
|     /// Adds a track to play next
 |     /// Adds a track to play next
 | ||||||
|     pub fn add_next(&mut self, source: Input, handler: &mut Driver) -> TrackHandle { |     pub fn add_next(&mut self, source: Input, handler: &mut Driver) -> TrackHandle { | ||||||
|  |         let mut inner = self.inner.lock(); | ||||||
|         let (mut track, handle) = tracks::create_player(source); |         let (mut track, handle) = tracks::create_player(source); | ||||||
|         track.pause(); |         track.pause(); | ||||||
|         if self.queue.is_empty() { |         if inner.tracks.is_empty() { | ||||||
|             self.queue.push(handle.clone()); |             inner.tracks.push(handle.clone()); | ||||||
|         } else { |         } else { | ||||||
|             self.queue.insert(1, handle.clone()); |             inner.tracks.insert(1, handle.clone()); | ||||||
|         } |         } | ||||||
|         handler.play(track); |         handler.play(track); | ||||||
|         handle |         handle | ||||||
|  | @ -89,7 +163,8 @@ impl Queue { | ||||||
| 
 | 
 | ||||||
|     /// Clears the queue
 |     /// Clears the queue
 | ||||||
|     pub fn clear(&mut self) { |     pub fn clear(&mut self) { | ||||||
|         for track in self.queue.drain(..) { |         let mut inner = self.inner.lock(); | ||||||
|  |         for track in inner.tracks.drain(..) { | ||||||
|             let _ = track.stop(); |             let _ = track.stop(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -97,6 +172,7 @@ impl Queue { | ||||||
|     /// Returns whether the queue is empty
 |     /// Returns whether the queue is empty
 | ||||||
|     #[must_use] |     #[must_use] | ||||||
|     pub fn is_empty(&self) -> bool { |     pub fn is_empty(&self) -> bool { | ||||||
|         self.queue.is_empty() |         let inner = self.inner.lock(); | ||||||
|  |         inner.tracks.is_empty() | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue