fix: music queue improvements

This commit is contained in:
Miguel da Mota 2024-03-10 19:36:28 +01:00
parent 29392dc72d
commit 1879b4ee0f
3 changed files with 75 additions and 57 deletions

View file

@ -3,7 +3,7 @@ mod music;
mod util; mod util;
use serenity::all::{ use serenity::all::{
CommandInteraction, CreateInteractionResponseFollowup, GuildId, OnlineStatus, VoiceState, CommandInteraction, CreateInteractionResponseFollowup, OnlineStatus, VoiceState,
}; };
use serenity::async_trait; use serenity::async_trait;
use serenity::builder::CreateEmbed; use serenity::builder::CreateEmbed;
@ -30,34 +30,6 @@ impl TypeMapKey for HttpKey {
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
use crate::music::music_queue::MusicQueue;
use std::collections::HashMap;
lazy_static! {
static ref HASHMAP: Mutex<HashMap<GuildId, MusicQueue>> = Mutex::new(HashMap::new());
}
pub async fn get_queue(guild_id: &GuildId) -> MusicQueue {
let mut queues = HASHMAP.lock().await;
match queues.get(&guild_id) {
Some(music_queue) => music_queue.clone(),
None => {
let q = MusicQueue {
guild_id: *guild_id,
queue: Vec::new(),
now_playing: None,
};
queues.insert(*guild_id, q.clone());
q
}
}
}
pub async fn set_queue(guild_id: &GuildId, queue: MusicQueue) {
HASHMAP.lock().await.insert(*guild_id, queue);
}
struct Handler; struct Handler;
#[async_trait] #[async_trait]

View file

@ -1,4 +1,5 @@
use crate::music::{music_manager, music_queue}; use crate::music::{music_manager, music_queue};
use serenity::all::{ChannelId, GuildId, Http}; use serenity::all::{ChannelId, GuildId, Http};
use serenity::async_trait; use serenity::async_trait;
use songbird::{Event, EventContext, EventHandler}; use songbird::{Event, EventContext, EventHandler};
@ -17,9 +18,8 @@ impl EventHandler for TrackEndNotifier {
// TODO: Does this need to be unsafe? // TODO: Does this need to be unsafe?
if let EventContext::Track(..) = ctx { if let EventContext::Track(..) = ctx {
println!("The track ended!"); println!("The track ended!");
let music_queue = crate::get_queue(&self.guild_id).await;
let q = &music_queue.queue; if music_queue::is_empty(&self.guild_id).await {
if q.is_empty() {
// No more songs in queue, exit the vc // No more songs in queue, exit the vc
let stopped = match music_manager::stop(&self.cmdctx, &self.guild_id).await { let stopped = match music_manager::stop(&self.cmdctx, &self.guild_id).await {
Ok(stopped) => stopped, Ok(stopped) => stopped,
@ -35,12 +35,15 @@ impl EventHandler for TrackEndNotifier {
} }
return None; return None;
} }
let head = music_queue::get_head(&self.guild_id).await;
if head.is_none() { let head = match music_queue::get_head(&self.guild_id).await {
println!("Cannot get head of queue"); Some(head) => head,
return None; None => {
} println!("Cannot get head of queue");
let head = head.unwrap(); return None;
}
};
music_manager::play_song(&self.cmdctx, &self.guild_id, &head).await; music_manager::play_song(&self.cmdctx, &self.guild_id, &head).await;
} }

View file

@ -1,7 +1,41 @@
use serenity::all::GuildId; use serenity::all::GuildId;
use songbird::input::YoutubeDl; use songbird::input::YoutubeDl;
use tokio::sync::{Mutex, MutexGuard};
#[derive(Debug, Clone)] use std::collections::HashMap;
use std::sync::Arc;
type MusicQueueItem = Arc<Mutex<MusicQueue>>;
lazy_static! {
static ref HASHMAP: Mutex<HashMap<GuildId, MusicQueueItem>> = Mutex::new(HashMap::new());
}
async fn get_music_queue(guild_id: &GuildId) -> MusicQueueItem {
let mut queues = HASHMAP.lock().await;
queues
.entry(*guild_id)
.or_insert(Arc::new(Mutex::new(MusicQueue {
guild_id: *guild_id,
queue: Vec::new(),
now_playing: None,
})))
.clone()
}
pub async fn with_music_queue<F, T>(guild_id: &GuildId, f: F) -> T
where
F: FnOnce(&mut MusicQueue) -> T,
T: Send,
{
let queue = get_music_queue(guild_id).await;
let mut queue = queue.lock().await;
f(&mut *queue)
}
#[derive(Debug)]
pub struct MusicQueue { pub struct MusicQueue {
// God this sucks. This needs to be reprogrammed properly. // God this sucks. This needs to be reprogrammed properly.
pub guild_id: GuildId, pub guild_id: GuildId,
@ -10,35 +44,44 @@ pub struct MusicQueue {
} }
pub async fn delete_queue(guild_id: &GuildId) { pub async fn delete_queue(guild_id: &GuildId) {
let mut queue = crate::get_queue(guild_id).await; with_music_queue(guild_id, |queue| {
queue.now_playing = None; queue.now_playing = None;
queue.queue = Vec::new(); queue.queue.clear();
crate::set_queue(guild_id, queue).await; })
.await;
} }
pub async fn add_to_queue(guild_id: &GuildId, input: YoutubeDl) { pub async fn add_to_queue(guild_id: &GuildId, input: YoutubeDl) {
let mut queue = crate::get_queue(guild_id).await; with_music_queue(guild_id, |queue| {
queue.queue.push(input); queue.queue.push(input);
crate::set_queue(guild_id, queue).await; })
.await;
} }
pub async fn get_head(guild_id: &GuildId) -> Option<YoutubeDl> { pub async fn get_head(guild_id: &GuildId) -> Option<YoutubeDl> {
let mut music_queue = crate::get_queue(guild_id).await; with_music_queue(guild_id, |queue| {
if music_queue.queue.is_empty() { if queue.queue.is_empty() {
return None; None
} } else {
let result = music_queue.queue.remove(0); Some(queue.queue.remove(0))
crate::set_queue(guild_id, music_queue).await; }
Some(result) })
.await
} }
pub async fn set_now_playing(guild_id: &GuildId, now_playing: Option<YoutubeDl>) { pub async fn set_now_playing(guild_id: &GuildId, now_playing: Option<YoutubeDl>) {
let mut queue = crate::get_queue(guild_id).await; let queue = get_music_queue(guild_id).await;
let mut queue = queue.lock().await;
queue.now_playing = now_playing; queue.now_playing = now_playing;
crate::set_queue(guild_id, queue).await;
} }
pub async fn get_now_playing(guild_id: &GuildId) -> Option<YoutubeDl> { pub async fn get_now_playing(guild_id: &GuildId) -> Option<YoutubeDl> {
let queue = crate::get_queue(guild_id).await; let queue = get_queue(guild_id).await;
queue.now_playing
queue.now_playing.to_owned()
}
pub async fn is_empty(guild_id: &GuildId) -> bool {
with_music_queue(guild_id, |queue| queue.queue.is_empty()).await
} }