diff --git a/src/queue.rs b/src/queue.rs index 06953f7..9062b6a 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -1,6 +1,6 @@ //! Implements a queue for the bot to play songs in order -use std::sync::Arc; +use std::{collections::VecDeque, sync::Arc}; use anyhow::Result; use parking_lot::Mutex; @@ -8,7 +8,7 @@ use poise::async_trait; use songbird::{ events::EventData, input::Input, - tracks::{self, TrackHandle}, + tracks::{self, Track, TrackHandle}, Driver, Event, EventContext, EventHandler, TrackEvent, }; use thiserror::Error; @@ -19,11 +19,31 @@ pub enum QueueError { EmptyQueue, } +/// Inner queue data behind a Mutex to allow the event handler to access it +struct QueueCore { + tracks: VecDeque, +} + /// Event handler for the queue struct QueueHandler { remote_lock: Arc>, } +impl QueueHandler { + /// Event to remove the track from the queue when it ends + pub fn register_track_end_event(track: &mut Track, remote_lock: Arc>) { + let position = track.position(); + track + .events + .as_mut() + .expect("Why is this even an Option?") + .add_event( + EventData::new(Event::Track(TrackEvent::End), QueueHandler { remote_lock }), + position, + ); + } +} + #[async_trait] impl EventHandler for QueueHandler { async fn act(&self, ctx: &EventContext<'_>) -> Option { @@ -37,20 +57,20 @@ impl EventHandler for QueueHandler { // 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() { + if inner.tracks.front()?.uuid() != ts.first()?.1.uuid() { return None; } } _ => return None, } - let _old = inner.tracks.remove(0); + let _old = inner.tracks.pop_front(); // Keep going until we find one track which works, or we run out. - while let Some(new) = inner.tracks.first() { + while let Some(new) = inner.tracks.front() { if new.play().is_err() { // Discard files which cannot be used for whatever reason. - inner.tracks.remove(0); + inner.tracks.pop_front(); } else { break; } @@ -60,11 +80,6 @@ impl EventHandler for QueueHandler { } } -/// Inner queue data behind a Mutex to allow the event handler to access it -struct QueueCore { - tracks: Vec, -} - /// A queue of tracks to play pub struct Queue { inner: Arc>, @@ -74,14 +89,16 @@ impl Queue { #[must_use] pub fn new() -> Self { Self { - inner: Arc::new(Mutex::new(QueueCore { tracks: Vec::new() })), + inner: Arc::new(Mutex::new(QueueCore { + tracks: VecDeque::new(), + })), } } /// Resumes the current track pub fn resume(&mut self) -> Result<()> { let inner = self.inner.lock(); - let Some(track) = inner.tracks.first() else { + let Some(track) = inner.tracks.front() else { return Err(QueueError::EmptyQueue.into()); }; track.play()?; @@ -91,18 +108,18 @@ impl Queue { /// Stops the current track and removes it from the queue pub fn stop(&mut self) -> Result<()> { let mut inner = self.inner.lock(); - let Some(track) = inner.tracks.first() else { + let Some(track) = inner.tracks.front() else { return Err(QueueError::EmptyQueue.into()); }; track.stop()?; - inner.tracks.remove(0); + inner.tracks.pop_front(); Ok(()) } /// Pauses the current track pub fn pause(&mut self) -> Result<()> { let inner = self.inner.lock(); - let Some(track) = inner.tracks.first() else { + let Some(track) = inner.tracks.front() else { return Err(QueueError::EmptyQueue.into()); }; track.pause()?; @@ -114,22 +131,8 @@ impl Queue { let mut inner = self.inner.lock(); let (mut track, handle) = tracks::create_player(source); track.pause(); - 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()); + QueueHandler::register_track_end_event(&mut track, self.inner.clone()); + inner.tracks.push_back(handle.clone()); handler.play(track); handle } @@ -152,8 +155,9 @@ impl Queue { let mut inner = self.inner.lock(); let (mut track, handle) = tracks::create_player(source); track.pause(); + QueueHandler::register_track_end_event(&mut track, self.inner.clone()); if inner.tracks.is_empty() { - inner.tracks.push(handle.clone()); + inner.tracks.push_back(handle.clone()); } else { inner.tracks.insert(1, handle.clone()); }