soundboard cmd

This commit is contained in:
jellywx 2021-06-25 14:51:52 +01:00
parent f0590328b0
commit b4b8d16bcc
3 changed files with 154 additions and 92 deletions

View File

@ -1,7 +1,7 @@
use crate::{
framework::RegexFramework,
guild_data::CtxGuildData,
join_channel, play_audio,
join_channel, play_audio, play_cmd,
sound::{JoinSoundCtx, Sound},
MySQL, ReqwestClient,
};
@ -22,6 +22,9 @@ use serenity::{
use songbird::{Event, EventContext, EventHandler as SongbirdEventHandler};
use crate::framework::{Args, CommandInvoke};
use serenity::model::interactions::{InteractionData, InteractionType};
use serenity::model::prelude::InteractionResponseType;
use std::{collections::HashMap, env};
pub struct RestartTrack;
@ -180,14 +183,49 @@ SELECT name, id, plays, public, server_id, uploader_id
}
async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
let framework = ctx
.data
.read()
.await
.get::<RegexFramework>()
.cloned()
.expect("RegexFramework not found in context");
if interaction.guild_id.is_none() {
return;
}
framework.execute(ctx, interaction).await;
match interaction.kind {
InteractionType::ApplicationCommand => {
let framework = ctx
.data
.read()
.await
.get::<RegexFramework>()
.cloned()
.expect("RegexFramework not found in context");
framework.execute(ctx, interaction).await;
}
InteractionType::MessageComponent => {
if let (Some(InteractionData::MessageComponent(data)), Some(member)) =
(interaction.clone().data, interaction.clone().member)
{
let mut args = Args {
args: Default::default(),
};
args.args.insert("query".to_string(), data.custom_id);
play_cmd(
&ctx,
interaction.guild(ctx.cache.clone()).await.unwrap(),
member.user.id,
args,
false,
)
.await;
interaction
.create_interaction_response(ctx, |r| {
r.kind(InteractionResponseType::DeferredUpdateMessage)
})
.await
.unwrap();
}
}
_ => {}
}
}
}

View File

@ -10,14 +10,14 @@ use serenity::{
channel::{Channel, GuildChannel, Message},
guild::{Guild, Member},
id::{ChannelId, GuildId, UserId},
interactions::{ApplicationCommand, Interaction, InteractionData, InteractionType},
interactions::{ApplicationCommand, Interaction, InteractionData},
prelude::{ApplicationCommandOptionType, InteractionResponseType},
},
prelude::TypeMapKey,
Result as SerenityResult,
};
use log::{error, info, warn};
use log::{debug, error, info, warn};
use regex::{Match, Regex, RegexBuilder};
@ -30,6 +30,7 @@ use std::{
use crate::{guild_data::CtxGuildData, MySQL};
use serde_json::Value;
use serenity::builder::CreateComponents;
type CommandFn = for<'fut> fn(
&'fut Context,
@ -38,7 +39,7 @@ type CommandFn = for<'fut> fn(
) -> BoxFuture<'fut, CommandResult>;
pub struct Args {
args: HashMap<String, String>,
pub args: HashMap<String, String>,
}
impl Args {
@ -87,6 +88,7 @@ impl Args {
pub struct CreateGenericResponse {
content: String,
embed: Option<CreateEmbed>,
components: Option<CreateComponents>,
}
impl CreateGenericResponse {
@ -94,6 +96,7 @@ impl CreateGenericResponse {
Self {
content: "".to_string(),
embed: None,
components: None,
}
}
@ -112,6 +115,19 @@ impl CreateGenericResponse {
self
}
pub fn components<F: FnOnce(&mut CreateComponents) -> &mut CreateComponents>(
mut self,
f: F,
) -> Self {
let mut components = CreateComponents::default();
f(&mut components);
self.components = Some(components);
self
}
}
#[async_trait]
@ -178,6 +194,10 @@ impl CommandInvoke for Message {
m.set_embed(embed.clone());
}
if let Some(components) = generic_response.components {
m.set_components(components.clone());
}
m
})
.await
@ -197,6 +217,10 @@ impl CommandInvoke for Message {
m.set_embed(embed.clone());
}
if let Some(components) = generic_response.components {
m.set_components(components.clone());
}
m
})
.await
@ -252,6 +276,10 @@ impl CommandInvoke for Interaction {
d.add_embed(embed.clone());
}
if let Some(components) = generic_response.components {
d.set_components(components.clone());
}
d
})
})
@ -271,6 +299,10 @@ impl CommandInvoke for Interaction {
d.add_embed(embed.clone());
}
if let Some(components) = generic_response.components {
d.set_components(components.clone());
}
d
})
.await
@ -453,8 +485,6 @@ impl RegexFramework {
}
pub fn add_command(mut self, command: &'static Command) -> Self {
info!("{:?}", command);
self.commands_.insert(command);
for name in command.names {
@ -475,7 +505,7 @@ impl RegexFramework {
command_names = command_names_vec.join("|");
}
info!("Command names: {}", command_names);
debug!("Command names: {}", command_names);
{
let match_string = r#"^(?:(?:<@ID>\s*)|(?:<@!ID>\s*)|(?P<prefix>\S{1,5}?))(?P<cmd>COMMANDS)(?:$|\s+(?P<args>.*))$"#
@ -534,7 +564,7 @@ impl RegexFramework {
.await
.expect("Failed to fetch existing commands");
info!("Existing commands: {:?}", current_commands);
debug!("Existing commands: {:?}", current_commands);
// delete commands not in use
for command in &current_commands {
@ -613,64 +643,61 @@ impl RegexFramework {
}
pub async fn execute(&self, ctx: Context, interaction: Interaction) {
if interaction.kind == InteractionType::ApplicationCommand && interaction.guild_id.is_some()
{
if let Some(InteractionData::ApplicationCommand(data)) = interaction.data.clone() {
let command = {
let name = data.name;
if let Some(InteractionData::ApplicationCommand(data)) = interaction.data.clone() {
let command = {
let name = data.name;
self.commands
.get(&name)
.expect(&format!("Received invalid command: {}", name))
};
self.commands
.get(&name)
.expect(&format!("Received invalid command: {}", name))
};
if command
.check_permissions(
&ctx,
&interaction.guild(ctx.cache.clone()).await.unwrap(),
&interaction.member(&ctx).await.unwrap(),
)
.await
{
let mut args = HashMap::new();
if command
.check_permissions(
&ctx,
&interaction.guild(ctx.cache.clone()).await.unwrap(),
&interaction.member(&ctx).await.unwrap(),
)
.await
{
let mut args = HashMap::new();
for arg in data.options.iter().filter(|o| o.value.is_some()) {
args.insert(
arg.name.clone(),
match arg.value.clone().unwrap() {
Value::Bool(b) => {
if b {
arg.name.clone()
} else {
String::new()
}
for arg in data.options.iter().filter(|o| o.value.is_some()) {
args.insert(
arg.name.clone(),
match arg.value.clone().unwrap() {
Value::Bool(b) => {
if b {
arg.name.clone()
} else {
String::new()
}
Value::Number(n) => n.to_string(),
Value::String(s) => s,
_ => String::new(),
},
);
}
(command.fun)(&ctx, &interaction, Args { args })
.await
.unwrap();
} else if command.required_permissions == PermissionLevel::Managed {
let _ = interaction
.respond(
ctx.http.clone(),
CreateGenericResponse::new().content("You must either be an Admin or have a role specified in `?roles` to do this command")
)
.await;
} else if command.required_permissions == PermissionLevel::Restricted {
let _ = interaction
.respond(
ctx.http.clone(),
CreateGenericResponse::new()
.content("You must be an Admin to do this command"),
)
.await;
}
Value::Number(n) => n.to_string(),
Value::String(s) => s,
_ => String::new(),
},
);
}
(command.fun)(&ctx, &interaction, Args { args })
.await
.unwrap();
} else if command.required_permissions == PermissionLevel::Managed {
let _ = interaction
.respond(
ctx.http.clone(),
CreateGenericResponse::new().content("You must either be an Admin or have a role specified in `?roles` to do this command")
)
.await;
} else if command.required_permissions == PermissionLevel::Restricted {
let _ = interaction
.respond(
ctx.http.clone(),
CreateGenericResponse::new()
.content("You must be an Admin to do this command"),
)
.await;
}
}
}

View File

@ -48,7 +48,6 @@ use dashmap::DashMap;
use std::{collections::HashMap, convert::TryFrom, env, sync::Arc, time::Duration};
use serenity::model::prelude::InteractionResponseType;
use tokio::sync::{MutexGuard, RwLock};
struct MySQL;
@ -1154,30 +1153,28 @@ async fn soundboard(
let sounds = Sound::get_guild_sounds(invoke.guild_id().unwrap(), pool).await?;
if let Some(interaction) = invoke.interaction() {
interaction
.create_interaction_response(&ctx, |r| r.kind(InteractionResponseType::Pong))
.await?;
}
invoke
.channel_id()
.send_message(&ctx, |m| {
m.components(|c| {
for row in sounds.as_slice().chunks(5) {
let mut action_row: CreateActionRow = Default::default();
for sound in row {
action_row.create_button(|b| {
b.style(ButtonStyle::Primary)
.label(&sound.name)
.custom_id(sound.id)
});
}
}
.respond(
ctx.http.clone(),
CreateGenericResponse::new()
.content("Select a sound from below:")
.components(|c| {
for row in sounds.as_slice().chunks(5) {
let mut action_row: CreateActionRow = Default::default();
for sound in row {
action_row.create_button(|b| {
b.style(ButtonStyle::Primary)
.label(&sound.name)
.custom_id(sound.id)
});
}
c
})
})
c.add_action_row(action_row);
}
c
}),
)
.await?;
Ok(())