feat: started to impl queue system

This commit is contained in:
moonleay 2024-03-09 00:25:12 +01:00
parent a16d8a6b60
commit a06299fb6f
Signed by: moonleay
GPG key ID: 82667543CCD715FB
9 changed files with 134 additions and 54 deletions

8
Cargo.lock generated
View file

@ -1338,12 +1338,6 @@ dependencies = [
"unicase", "unicase",
] ]
[[package]]
name = "queues"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1475abae4f8ad4998590fe3acfe20104f0a5d48fc420c817cd2c09c3f56151f0"
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.35" version = "1.0.35"
@ -1567,8 +1561,6 @@ dependencies = [
"chrono", "chrono",
"confy", "confy",
"futures", "futures",
"once_cell",
"queues",
"reqwest", "reqwest",
"serde", "serde",
"serde_json", "serde_json",

View file

@ -1,7 +1,7 @@
[package] [package]
name = "rustendo" name = "rustendo"
version = "0.1.0" version = "0.1.0"
authors = ["moonleay <contact@moonleay.net>"] authors = ["moonleay <contact@moonleay.net>", "migueldamota <miguel@damota.de>"]
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -21,5 +21,3 @@ tracing = "0.1.40"
tracing-subscriber = "0.3.18" tracing-subscriber = "0.3.18"
tracing-futures = "0.2.5" tracing-futures = "0.2.5"
futures = "0.3.1" futures = "0.3.1"
queues = "1"
once_cell = "1"

View file

@ -5,7 +5,7 @@ use crate::music::music_manager;
use crate::util::embed::Embed; use crate::util::embed::Embed;
pub async fn run(ctx: &Context, command: &CommandInteraction) -> CreateEmbed { pub async unsafe fn run(ctx: &Context, command: &CommandInteraction) -> CreateEmbed {
let username = command.user.name.as_str(); let username = command.user.name.as_str();
let options = &command.data.options; let options = &command.data.options;

View file

@ -3,7 +3,7 @@ use serenity::builder::{CreateCommand, CreateEmbed};
use crate::music::music_manager; use crate::music::music_manager;
use crate::util::embed::Embed; use crate::util::embed::Embed;
pub async fn run(ctx: &Context, command: &CommandInteraction) -> CreateEmbed { pub async unsafe fn run(ctx: &Context, command: &CommandInteraction) -> CreateEmbed {
let username = command.user.name.as_str(); let username = command.user.name.as_str();
let guild_id = match &command.guild_id { let guild_id = match &command.guild_id {

View file

@ -29,20 +29,22 @@ struct Handler;
#[async_trait] #[async_trait]
impl EventHandler for Handler { impl EventHandler for Handler {
async fn interaction_create(&self, ctx: Context, interaction: Interaction) { async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
if let Interaction::Command(command) = interaction { unsafe {
let _ = &command.defer(&ctx.http()).await.expect("Cannot defer"); if let Interaction::Command(command) = interaction {
let _ = &command.defer(&ctx.http()).await.expect("Cannot defer");
let content = Some(match command.data.name.as_str() { let content = Some(match command.data.name.as_str() {
"info" => commands::info::run(&ctx, &command).await, "info" => commands::info::run(&ctx, &command).await,
"play" => commands::play::run(&ctx, &command).await, "play" => commands::play::run(&ctx, &command).await,
"stop" => commands::stop::run(&ctx, &command).await, "stop" => commands::stop::run(&ctx, &command).await,
_ => respond_with_error(&ctx, &command).await, _ => respond_with_error(&ctx, &command).await,
}); });
if let Some(embed) = content { if let Some(embed) = content {
let followup = CreateInteractionResponseFollowup::new().embed(embed); let followup = CreateInteractionResponseFollowup::new().embed(embed);
if let Err(why) = command.create_followup(&ctx.http, followup).await { if let Err(why) = command.create_followup(&ctx.http, followup).await {
println!("Cannot followup to slash command: {why}") println!("Cannot followup to slash command: {why}")
}
} }
} }
} }

View file

@ -1,2 +1,3 @@
pub mod music_manager; pub mod music_manager;
pub mod music_events; pub mod music_events;
mod music_queue;

View file

@ -1,9 +1,8 @@
use std::sync::Arc; use std::sync::Arc;
use queues::IsQueue;
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};
use crate::music::music_manager; use crate::music::{music_manager, music_queue};
pub struct TrackEndNotifier { pub struct TrackEndNotifier {
pub guild_id: GuildId, pub guild_id: GuildId,
@ -18,8 +17,10 @@ impl EventHandler for TrackEndNotifier {
unsafe { // TODO: Does this need to be unsafe? unsafe { // TODO: Does this need to be unsafe?
if let EventContext::Track(track_list) = ctx { if let EventContext::Track(track_list) = ctx {
println!("The track ended!"); println!("The track ended!");
let queue = music_manager::get_queue(&self.guild_id); let music_queue = music_queue::get_queue(&self.guild_id);
if queue.size() == 0 { let q = &music_queue.queue;
if q.len() == 0 {
// 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,
Err(e) => { Err(e) => {
@ -34,6 +35,19 @@ impl EventHandler for TrackEndNotifier {
} }
return None; return None;
} }
let head = music_queue::get_head(&self.guild_id);
if head.is_none() {
println!("Cannot get head of queue");
return None;
}
let head = head.unwrap();
/*let started = match music_manager::play(&self.cmdctx, &self.guild_id, &head).await {
Ok(started) => started,
Err(e) => {
println!("Cannot play: {:?}", e);
return None;
}
}; */
} }
} }

View file

@ -1,28 +1,16 @@
use std::collections::{HashMap}; use std::sync::{Arc};
use std::sync::{Arc, Mutex};
use std::time::Duration; use std::time::Duration;
use once_cell::sync::Lazy;
use queues::Queue;
use serenity::all::{Context, CreateEmbed, GuildId, UserId}; use serenity::all::{Context, CreateEmbed, GuildId, UserId};
use songbird::{Event, TrackEvent}; use songbird::{Event, TrackEvent};
use songbird::error::JoinError; use songbird::error::JoinError;
use songbird::input::{Compose, YoutubeDl}; use songbird::input::{Compose, YoutubeDl};
use crate::HttpKey; use crate::HttpKey;
use crate::music::music_events; use crate::music::{music_events, music_queue};
use crate::util::embed::Embed; use crate::util::embed::Embed;
use crate::util::user_util; use crate::util::user_util;
use crate::util::user_util::get_vc_id; use crate::util::user_util::get_vc_id;
/// pub static mut MUSIC_QUEUE: HashMap<GuildId, Queue<String>> = HashMap::new(); pub async unsafe fn attempt_to_queue_song(ctx: &Context, guild_id: &GuildId, user_id: &UserId, username: &str, query: &str) -> CreateEmbed {
pub static mut MUSIC_QUEUE: Lazy<Mutex<HashMap<GuildId, Queue<String>>>> = Lazy::new(|| {
Mutex::new(HashMap::new())
}); // TODO: This does not work and this is not the way to do it. This is a placeholder for now.
pub unsafe fn get_queue(guild_id: &GuildId) -> &Queue<String> {
MUSIC_QUEUE.lock().unwrap().entry(*guild_id).or_insert_with(Queue::new)
}
pub async fn attempt_to_queue_song(ctx: &Context, guild_id: &GuildId, user_id: &UserId, username: &str, query: &str) -> CreateEmbed {
if !user_util::is_user_connected_to_vc(ctx, guild_id, user_id).await { if !user_util::is_user_connected_to_vc(ctx, guild_id, user_id).await {
return Embed::create(username, "You are not connected to a VC", "Connect to my VC to control the music."); return Embed::create(username, "You are not connected to a VC", "Connect to my VC to control the music.");
} }
@ -35,7 +23,7 @@ pub async fn attempt_to_queue_song(ctx: &Context, guild_id: &GuildId, user_id: &
}; };
let manager = &songbird::get(ctx) let manager = &songbird::get(ctx) // TODO match
.await .await
.expect("Cannot get Songbird.") .expect("Cannot get Songbird.")
.clone(); .clone();
@ -65,6 +53,16 @@ pub async fn attempt_to_queue_song(ctx: &Context, guild_id: &GuildId, user_id: &
} }
} }
let currently_playing = music_queue::get_now_playing(&guild_id);
music_queue::add_to_queue(&guild_id, query.to_string());
if currently_playing != "".to_string() {
// Add to queue
return Embed::create(username, "Added to queue", "The song was added to the queue.");
}
let query = music_queue::get_head(&guild_id).expect("Cannot get head of queue");
music_queue::set_now_playing(&guild_id, query.clone());
// Get query // Get query
let do_search = !query.starts_with("http"); let do_search = !query.starts_with("http");
let http_client = { let http_client = {
@ -83,13 +81,13 @@ pub async fn attempt_to_queue_song(ctx: &Context, guild_id: &GuildId, user_id: &
let handler_lock = match manager.get(*guild_id) { let handler_lock = match manager.get(*guild_id) {
Some(handler) => handler, Some(handler) => handler,
None => { None => {
return Embed::create(username, "Error", "Cannot get handler"); return Embed::create("", "Error", "Cannot get handler");
}, },
}; };
// Start playing // Start playing
let mut handler = handler_lock.lock().await; let mut handler = handler_lock.lock().await;
let track_handle = handler.play_input(src.clone().into()); // TODO: Add event handlers let _ = handler.play_input(src.clone().into()); // TODO: Add event handlers
handler.add_global_event( handler.add_global_event(
Event::Track(TrackEvent::End), Event::Track(TrackEvent::End),
music_events::TrackEndNotifier { music_events::TrackEndNotifier {
@ -113,8 +111,11 @@ pub async fn attempt_to_queue_song(ctx: &Context, guild_id: &GuildId, user_id: &
.thumbnail(thumbnail) .thumbnail(thumbnail)
} }
pub async unsafe fn play() {
pub async fn attempt_to_stop(ctx: &Context, guild_id: &GuildId, user_id: &UserId, username: &str) -> CreateEmbed { }
pub async unsafe fn attempt_to_stop(ctx: &Context, guild_id: &GuildId, user_id: &UserId, username: &str) -> CreateEmbed {
if !user_util::is_self_connected_to_vc(ctx, guild_id).await { if !user_util::is_self_connected_to_vc(ctx, guild_id).await {
// Bot is not connectd to vc; no need to dc // Bot is not connectd to vc; no need to dc
return Embed::create( return Embed::create(
@ -143,17 +144,24 @@ pub async fn attempt_to_stop(ctx: &Context, guild_id: &GuildId, user_id: &UserId
} }
}; };
if !stopped { return if !stopped {
return Embed::create(username, "Can't stop, what ain't running.", "I am not connected. I cant stop doing something, when I'm not doing it".to_string()); Embed::create(username, "Can't stop, what ain't running.", "I am not connected. I cant stop doing something, when I'm not doing it".to_string())
} else { } else {
return Embed::create( music_queue::delete_queue(guild_id); // Clear queue
Embed::create(
username, username,
"I stopped and left", "I stopped and left",
"Just like your girlfriend.", "Just like your girlfriend.",
); )
} }
} }
/// pub async unsafe fn play_song(ctx: &Context, guild_id: &GuildId, query: String) -> Result<bool, JoinError> {
/// }
// Make the bot leave the voice channel. Returns Ok(true) if bot was connected, returns Ok(false) if bot was not connected. Returns Err if something went wrong. // Make the bot leave the voice channel. Returns Ok(true) if bot was connected, returns Ok(false) if bot was not connected. Returns Err if something went wrong.
pub async fn stop(ctx: &Context, guild_id: &GuildId) -> Result<bool, JoinError> { pub async fn stop(ctx: &Context, guild_id: &GuildId) -> Result<bool, JoinError> {
let manager = songbird::get(ctx) let manager = songbird::get(ctx)

65
src/music/music_queue.rs Normal file
View file

@ -0,0 +1,65 @@
use serenity::all::GuildId;
pub struct MusicQueue { // God this sucks. This needs to be reprogrammed properly.
guild_id: GuildId,
pub queue: Vec<String>,
pub now_playing: String,
}
static mut MUSIC_QUEUE: Vec<MusicQueue> = Vec::new();
pub unsafe fn get_queue(guild_id: &GuildId) -> &MusicQueue {
let queue = MUSIC_QUEUE.iter().find(|q| q.guild_id == *guild_id);
match queue {
Some(queue) => queue,
None => {
let new_queue = MusicQueue {
guild_id: *guild_id,
queue: Vec::new(),
now_playing: "".to_string(),
};
MUSIC_QUEUE.push(new_queue);
MUSIC_QUEUE.iter().find(|q| q.guild_id == *guild_id).expect("Cannot get queue")
}
}
}
unsafe fn update_queue(guild_id: &GuildId, queue: Vec<String>, now_playing: String) {
let index = MUSIC_QUEUE.iter().position(|q| q.guild_id == *guild_id).expect("Cannot get index");
MUSIC_QUEUE[index] = MusicQueue{
guild_id: *guild_id,
queue,
now_playing,
};
}
pub unsafe fn delete_queue(guild_id: &GuildId) {
let index = MUSIC_QUEUE.iter().position(|q| q.guild_id == *guild_id).expect("Cannot get index");
MUSIC_QUEUE.remove(index);
}
pub unsafe fn add_to_queue(guild_id: &GuildId, input: String) {
let queue = get_queue(guild_id);
let mut new_queue = queue.queue.clone();
new_queue.push(input);
update_queue(guild_id, new_queue, queue.now_playing.clone());
}
pub unsafe fn get_head(guild_id: &GuildId) -> Option<String> {
let queue = get_queue(guild_id);
let mut q = queue.queue.clone();
let result = q.first().map(|s| s.clone());
q.remove(0);
update_queue(guild_id, q, queue.now_playing.clone());
result
}
pub unsafe fn set_now_playing(guild_id: &GuildId, now_playing: String) {
let queue = get_queue(guild_id);
update_queue(guild_id, queue.queue.clone(), now_playing);
}
pub unsafe fn get_now_playing(guild_id: &GuildId) -> String {
let queue = get_queue(guild_id);
queue.now_playing.clone()
}