soundboard cmd
This commit is contained in:
parent
f0590328b0
commit
b4b8d16bcc
@ -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();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
147
src/framework.rs
147
src/framework.rs
@ -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 ¤t_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
43
src/main.rs
43
src/main.rs
@ -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(())
|
||||
|
Loading…
Reference in New Issue
Block a user