From febeeefb018869d3dc87e736c32c5775fbf94fb1 Mon Sep 17 00:00:00 2001 From: jude Date: Sun, 13 Feb 2022 16:12:42 +0000 Subject: [PATCH] queue play command --- Cargo.toml | 2 +- src/cmds/play.rs | 163 ++++++++++++++++++++++++++++++++++++++++++ src/cmds/stop.rs | 2 +- src/event_handlers.rs | 5 +- src/main.rs | 1 + src/utils.rs | 19 ++++- 6 files changed, 187 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 015bd0c..a9fae0e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ authors = ["jellywx "] edition = "2018" [dependencies] -songbird = { git = "https://github.com/serenity-rs/songbird", branch = "next" } +songbird = { git = "https://github.com/serenity-rs/songbird", branch = "next", features = ["builtin-queue"] } poise = { git = "https://github.com/kangalioo/poise", branch = "master", features = ["collector"] } sqlx = { version = "0.5", default-features = false, features = ["runtime-tokio-rustls", "macros", "mysql", "bigdecimal"] } dotenv = "0.15" diff --git a/src/cmds/play.rs b/src/cmds/play.rs index 2a7a00f..c3dcb37 100644 --- a/src/cmds/play.rs +++ b/src/cmds/play.rs @@ -2,6 +2,8 @@ use poise::serenity::{ builder::CreateActionRow, model::interactions::message_component::ButtonStyle, }; +use crate::models::guild_data::CtxGuildData; +use crate::utils::{join_channel, queue_audio}; use crate::{ cmds::autocomplete_sound, models::sound::SoundCtx, utils::play_from_query, Context, Error, }; @@ -32,6 +34,167 @@ pub async fn play( Ok(()) } +/// Play up to 25 sounds on queue +#[poise::command(slash_command, rename = "queue")] +pub async fn queue_play( + ctx: Context<'_>, + #[description = "Name or ID for queue position 1"] + #[autocomplete = "autocomplete_sound"] + sound_1: String, + #[description = "Name or ID for queue position 2"] + #[autocomplete = "autocomplete_sound"] + sound_2: String, + #[description = "Name or ID for queue position 3"] + #[autocomplete = "autocomplete_sound"] + sound_3: Option, + #[description = "Name or ID for queue position 4"] + #[autocomplete = "autocomplete_sound"] + sound_4: Option, + #[description = "Name or ID for queue position 5"] + #[autocomplete = "autocomplete_sound"] + sound_5: Option, + #[description = "Name or ID for queue position 6"] + #[autocomplete = "autocomplete_sound"] + sound_6: Option, + #[description = "Name or ID for queue position 7"] + #[autocomplete = "autocomplete_sound"] + sound_7: Option, + #[description = "Name or ID for queue position 8"] + #[autocomplete = "autocomplete_sound"] + sound_8: Option, + #[description = "Name or ID for queue position 9"] + #[autocomplete = "autocomplete_sound"] + sound_9: Option, + #[description = "Name or ID for queue position 10"] + #[autocomplete = "autocomplete_sound"] + sound_10: Option, + #[description = "Name or ID for queue position 11"] + #[autocomplete = "autocomplete_sound"] + sound_11: Option, + #[description = "Name or ID for queue position 12"] + #[autocomplete = "autocomplete_sound"] + sound_12: Option, + #[description = "Name or ID for queue position 13"] + #[autocomplete = "autocomplete_sound"] + sound_13: Option, + #[description = "Name or ID for queue position 14"] + #[autocomplete = "autocomplete_sound"] + sound_14: Option, + #[description = "Name or ID for queue position 15"] + #[autocomplete = "autocomplete_sound"] + sound_15: Option, + #[description = "Name or ID for queue position 16"] + #[autocomplete = "autocomplete_sound"] + sound_16: Option, + #[description = "Name or ID for queue position 17"] + #[autocomplete = "autocomplete_sound"] + sound_17: Option, + #[description = "Name or ID for queue position 18"] + #[autocomplete = "autocomplete_sound"] + sound_18: Option, + #[description = "Name or ID for queue position 19"] + #[autocomplete = "autocomplete_sound"] + sound_19: Option, + #[description = "Name or ID for queue position 20"] + #[autocomplete = "autocomplete_sound"] + sound_20: Option, + #[description = "Name or ID for queue position 21"] + #[autocomplete = "autocomplete_sound"] + sound_21: Option, + #[description = "Name or ID for queue position 22"] + #[autocomplete = "autocomplete_sound"] + sound_22: Option, + #[description = "Name or ID for queue position 23"] + #[autocomplete = "autocomplete_sound"] + sound_23: Option, + #[description = "Name or ID for queue position 24"] + #[autocomplete = "autocomplete_sound"] + sound_24: Option, + #[description = "Name or ID for queue position 25"] + #[autocomplete = "autocomplete_sound"] + sound_25: Option, +) -> Result<(), Error> { + let _ = ctx.defer().await; + + let guild = ctx.guild().unwrap(); + + let channel_to_join = guild + .voice_states + .get(&ctx.author().id) + .and_then(|voice_state| voice_state.channel_id); + + match channel_to_join { + Some(user_channel) => { + let (call_handler, _) = join_channel(ctx.discord(), guild.clone(), user_channel).await; + + let guild_data = ctx + .data() + .guild_data(ctx.guild_id().unwrap()) + .await + .unwrap(); + + let mut lock = call_handler.lock().await; + + let query_terms = [ + Some(sound_1), + Some(sound_2), + sound_3, + sound_4, + sound_5, + sound_6, + sound_7, + sound_8, + sound_9, + sound_10, + sound_11, + sound_12, + sound_13, + sound_14, + sound_15, + sound_16, + sound_17, + sound_18, + sound_19, + sound_20, + sound_21, + sound_22, + sound_23, + sound_24, + sound_25, + ]; + + let mut sounds = vec![]; + + for sound in query_terms.iter().flatten() { + let search = ctx + .data() + .search_for_sound(&sound, ctx.guild_id().unwrap(), ctx.author().id, true) + .await?; + + if let Some(sound) = search.first() { + sounds.push(sound.clone()); + } + } + + queue_audio( + &sounds, + guild_data.read().await.volume, + &mut lock, + &ctx.data().database, + ) + .await + .unwrap(); + + ctx.say(format!("Queued {} sounds!", sounds.len())).await?; + } + None => { + ctx.say("You are not in a voice chat!").await?; + } + } + + Ok(()) +} + /// Loop a sound in your current voice channel #[poise::command(slash_command, rename = "loop")] pub async fn loop_play( diff --git a/src/cmds/stop.rs b/src/cmds/stop.rs index 9a26a5b..8c1f266 100644 --- a/src/cmds/stop.rs +++ b/src/cmds/stop.rs @@ -2,7 +2,7 @@ use songbird; use crate::{Context, Error}; -/// Stop the bot from playing +/// Stop the bot from playing and clear the play queue #[poise::command(slash_command, rename = "stop")] pub async fn stop_playing(ctx: Context<'_>) -> Result<(), Error> { let songbird = songbird::get(ctx.discord()).await.unwrap(); diff --git a/src/event_handlers.rs b/src/event_handlers.rs index d19bed3..6242b5f 100644 --- a/src/event_handlers.rs +++ b/src/event_handlers.rs @@ -102,14 +102,15 @@ SELECT name, id, public, server_id, uploader_id let (handler, _) = join_channel(&ctx, guild, user_channel).await; - let _ = play_audio( + play_audio( &mut sound, volume, &mut handler.lock().await, &data.database, false, ) - .await; + .await + .unwrap(); } } } diff --git a/src/main.rs b/src/main.rs index b6d1c41..eef1100 100644 --- a/src/main.rs +++ b/src/main.rs @@ -86,6 +86,7 @@ async fn main() -> Result<(), Box> { cmds::manage::download_file(), cmds::manage::delete_sound(), cmds::play::play(), + cmds::play::queue_play(), cmds::play::loop_play(), cmds::play::soundboard(), poise::Command { diff --git a/src/utils.rs b/src/utils.rs index 2fbcaf9..9593619 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -18,7 +18,7 @@ use crate::{ }; pub async fn play_audio( - sound: &mut Sound, + sound: &Sound, volume: u8, call_handler: &mut MutexGuard<'_, Call>, db_pool: impl Executor<'_, Database = Database>, @@ -39,6 +39,23 @@ pub async fn play_audio( Ok(track_handler) } +pub async fn queue_audio( + sounds: &[Sound], + volume: u8, + call_handler: &mut MutexGuard<'_, Call>, + db_pool: impl Executor<'_, Database = Database> + Copy, +) -> Result<(), Box> { + for sound in sounds { + let (a, b) = create_player(sound.playable(db_pool).await?.into()); + + let _ = b.set_volume(volume as f32 / 100.0); + + call_handler.enqueue(a); + } + + Ok(()) +} + pub async fn join_channel( ctx: &poise::serenity_prelude::Context, guild: Guild,