From 2fd2079330582fd30aeb074f0ff0ba4caa395119 Mon Sep 17 00:00:00 2001 From: Alex Page Date: Wed, 8 Mar 2023 18:35:30 -0500 Subject: [PATCH] Implement moving to the next track --- src/queue.rs | 102 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 89 insertions(+), 13 deletions(-) diff --git a/src/queue.rs b/src/queue.rs index 36dd1c1..06953f7 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -1,10 +1,15 @@ //! Implements a queue for the bot to play songs in order +use std::sync::Arc; + use anyhow::Result; +use parking_lot::Mutex; +use poise::async_trait; use songbird::{ + events::EventData, input::Input, tracks::{self, TrackHandle}, - Driver, + Driver, Event, EventContext, EventHandler, TrackEvent, }; use thiserror::Error; @@ -14,19 +19,69 @@ pub enum QueueError { EmptyQueue, } +/// Event handler for the queue +struct QueueHandler { + remote_lock: Arc>, +} + +#[async_trait] +impl EventHandler for QueueHandler { + async fn act(&self, ctx: &EventContext<'_>) -> Option { + 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, +} + +/// A queue of tracks to play pub struct Queue { - queue: Vec, + inner: Arc>, } impl Queue { #[must_use] pub fn new() -> Self { - Self { queue: Vec::new() } + Self { + inner: Arc::new(Mutex::new(QueueCore { tracks: Vec::new() })), + } } /// Resumes the current track 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()); }; track.play()?; @@ -35,17 +90,19 @@ impl Queue { /// Stops the current track and removes it from the queue 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()); }; track.stop()?; - self.queue.remove(0); + inner.tracks.remove(0); Ok(()) } /// Pauses the current track 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()); }; track.pause()?; @@ -54,9 +111,25 @@ impl Queue { /// Adds a track to the end of the queue 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); 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); handle } @@ -76,12 +149,13 @@ impl Queue { /// Adds a track to play next 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); track.pause(); - if self.queue.is_empty() { - self.queue.push(handle.clone()); + if inner.tracks.is_empty() { + inner.tracks.push(handle.clone()); } else { - self.queue.insert(1, handle.clone()); + inner.tracks.insert(1, handle.clone()); } handler.play(track); handle @@ -89,7 +163,8 @@ impl Queue { /// Clears the queue 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(); } } @@ -97,6 +172,7 @@ impl Queue { /// Returns whether the queue is empty #[must_use] pub fn is_empty(&self) -> bool { - self.queue.is_empty() + let inner = self.inner.lock(); + inner.tracks.is_empty() } }