407 lines
10 KiB
Rust
407 lines
10 KiB
Rust
use std::{convert::TryFrom, time::Duration};
|
|
|
|
use regex_command_attr::command;
|
|
use serenity::{
|
|
builder::CreateActionRow,
|
|
client::Context,
|
|
framework::standard::CommandResult,
|
|
model::interactions::{message_component::ButtonStyle, InteractionResponseType},
|
|
};
|
|
use songbird::{
|
|
create_player, ffmpeg,
|
|
input::{cached::Memory, Input},
|
|
Event,
|
|
};
|
|
|
|
use crate::{
|
|
event_handlers::RestartTrack,
|
|
framework::{Args, CommandInvoke, CreateGenericResponse},
|
|
guild_data::CtxGuildData,
|
|
join_channel, play_from_query,
|
|
sound::Sound,
|
|
AudioIndex, MySQL,
|
|
};
|
|
|
|
#[command]
|
|
#[aliases("p")]
|
|
#[required_permissions(Managed)]
|
|
#[group("Play")]
|
|
#[description("Play a sound in your current voice channel")]
|
|
#[arg(
|
|
name = "query",
|
|
description = "Play sound with the specified name or ID",
|
|
kind = "String",
|
|
required = true
|
|
)]
|
|
#[example("`/play ubercharge` - play sound with name \"ubercharge\" ")]
|
|
#[example("`/play 13002` - play sound with ID 13002")]
|
|
pub async fn play(
|
|
ctx: &Context,
|
|
invoke: &(dyn CommandInvoke + Sync + Send),
|
|
args: Args,
|
|
) -> CommandResult {
|
|
let guild = invoke.guild(ctx.cache.clone()).unwrap();
|
|
|
|
invoke
|
|
.respond(
|
|
ctx.http.clone(),
|
|
CreateGenericResponse::new()
|
|
.content(play_from_query(ctx, guild, invoke.author_id(), args, false).await),
|
|
)
|
|
.await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[command("loop")]
|
|
#[required_permissions(Managed)]
|
|
#[group("Play")]
|
|
#[description("Play a sound on loop in your current voice channel")]
|
|
#[arg(
|
|
name = "query",
|
|
description = "Play sound with the specified name or ID",
|
|
kind = "String",
|
|
required = true
|
|
)]
|
|
#[example("`/loop rain` - loop sound with name \"rain\" ")]
|
|
#[example("`/loop 13002` - play sound with ID 13002")]
|
|
pub async fn loop_play(
|
|
ctx: &Context,
|
|
invoke: &(dyn CommandInvoke + Sync + Send),
|
|
args: Args,
|
|
) -> CommandResult {
|
|
let guild = invoke.guild(ctx.cache.clone()).unwrap();
|
|
|
|
invoke
|
|
.respond(
|
|
ctx.http.clone(),
|
|
CreateGenericResponse::new()
|
|
.content(play_from_query(ctx, guild, invoke.author_id(), args, true).await),
|
|
)
|
|
.await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[command("ambience")]
|
|
#[required_permissions(Managed)]
|
|
#[group("Play")]
|
|
#[description("Play ambient sound in your current voice channel")]
|
|
#[arg(
|
|
name = "name",
|
|
description = "Play sound with the specified name",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[example("`/ambience rain on tent` - play the ambient sound \"rain on tent\" ")]
|
|
pub async fn play_ambience(
|
|
ctx: &Context,
|
|
invoke: &(dyn CommandInvoke + Sync + Send),
|
|
args: Args,
|
|
) -> CommandResult {
|
|
let guild = invoke.guild(ctx.cache.clone()).unwrap();
|
|
|
|
let channel_to_join = guild
|
|
.voice_states
|
|
.get(&invoke.author_id())
|
|
.and_then(|voice_state| voice_state.channel_id);
|
|
|
|
match channel_to_join {
|
|
Some(user_channel) => {
|
|
let search_name = args.named("name").unwrap().to_lowercase();
|
|
let audio_index = ctx.data.read().await.get::<AudioIndex>().cloned().unwrap();
|
|
|
|
if let Some(filename) = audio_index.get(&search_name) {
|
|
let (track, track_handler) = create_player(
|
|
Input::try_from(
|
|
Memory::new(ffmpeg(format!("audio/{}", filename)).await.unwrap()).unwrap(),
|
|
)
|
|
.unwrap(),
|
|
);
|
|
|
|
let (call_handler, _) = join_channel(ctx, guild.clone(), user_channel).await;
|
|
let guild_data = ctx.guild_data(guild).await.unwrap();
|
|
|
|
{
|
|
let mut lock = call_handler.lock().await;
|
|
|
|
lock.play(track);
|
|
}
|
|
|
|
let _ = track_handler.set_volume(guild_data.read().await.volume as f32 / 100.0);
|
|
let _ = track_handler.add_event(
|
|
Event::Periodic(
|
|
track_handler.metadata().duration.unwrap() - Duration::from_millis(200),
|
|
None,
|
|
),
|
|
RestartTrack {},
|
|
);
|
|
|
|
invoke
|
|
.respond(
|
|
ctx.http.clone(),
|
|
CreateGenericResponse::new()
|
|
.content(format!("Playing ambience **{}**", search_name)),
|
|
)
|
|
.await?;
|
|
} else {
|
|
invoke
|
|
.respond(
|
|
ctx.http.clone(),
|
|
CreateGenericResponse::new().embed(|e| {
|
|
e.title("Not Found").description(format!(
|
|
"Could not find ambience sound by name **{}**
|
|
|
|
__Available ambience sounds:__
|
|
{}",
|
|
search_name,
|
|
audio_index
|
|
.keys()
|
|
.into_iter()
|
|
.map(|i| i.as_str())
|
|
.collect::<Vec<&str>>()
|
|
.join("\n")
|
|
))
|
|
}),
|
|
)
|
|
.await?;
|
|
}
|
|
}
|
|
|
|
None => {
|
|
invoke
|
|
.respond(
|
|
ctx.http.clone(),
|
|
CreateGenericResponse::new().content("You are not in a voice chat!"),
|
|
)
|
|
.await?;
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[command("soundboard")]
|
|
#[required_permissions(Managed)]
|
|
#[group("Play")]
|
|
#[kind(Slash)]
|
|
#[description("Get a menu of sounds with buttons to play them")]
|
|
#[arg(
|
|
name = "1",
|
|
description = "Query for sound button 1",
|
|
kind = "String",
|
|
required = true
|
|
)]
|
|
#[arg(
|
|
name = "2",
|
|
description = "Query for sound button 2",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[arg(
|
|
name = "3",
|
|
description = "Query for sound button 3",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[arg(
|
|
name = "4",
|
|
description = "Query for sound button 4",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[arg(
|
|
name = "5",
|
|
description = "Query for sound button 5",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[arg(
|
|
name = "6",
|
|
description = "Query for sound button 6",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[arg(
|
|
name = "7",
|
|
description = "Query for sound button 7",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[arg(
|
|
name = "8",
|
|
description = "Query for sound button 8",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[arg(
|
|
name = "9",
|
|
description = "Query for sound button 9",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[arg(
|
|
name = "10",
|
|
description = "Query for sound button 10",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[arg(
|
|
name = "11",
|
|
description = "Query for sound button 11",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[arg(
|
|
name = "12",
|
|
description = "Query for sound button 12",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[arg(
|
|
name = "13",
|
|
description = "Query for sound button 13",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[arg(
|
|
name = "14",
|
|
description = "Query for sound button 14",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[arg(
|
|
name = "15",
|
|
description = "Query for sound button 15",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[arg(
|
|
name = "16",
|
|
description = "Query for sound button 16",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[arg(
|
|
name = "17",
|
|
description = "Query for sound button 17",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[arg(
|
|
name = "18",
|
|
description = "Query for sound button 18",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[arg(
|
|
name = "19",
|
|
description = "Query for sound button 19",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[arg(
|
|
name = "20",
|
|
description = "Query for sound button 20",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[arg(
|
|
name = "21",
|
|
description = "Query for sound button 21",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[arg(
|
|
name = "22",
|
|
description = "Query for sound button 22",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[arg(
|
|
name = "23",
|
|
description = "Query for sound button 23",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[arg(
|
|
name = "24",
|
|
description = "Query for sound button 24",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[arg(
|
|
name = "25",
|
|
description = "Query for sound button 25",
|
|
kind = "String",
|
|
required = false
|
|
)]
|
|
#[example("`/soundboard ubercharge` - create a soundboard with a button for the \"ubercharge\" sound effect")]
|
|
#[example("`/soundboard 57000 24119 2 1002 13202` - create a soundboard with 5 buttons, for sounds with the IDs presented")]
|
|
pub async fn soundboard(
|
|
ctx: &Context,
|
|
invoke: &(dyn CommandInvoke + Sync + Send),
|
|
args: Args,
|
|
) -> CommandResult {
|
|
if let Some(interaction) = invoke.interaction() {
|
|
let _ = interaction
|
|
.create_interaction_response(&ctx, |r| {
|
|
r.kind(InteractionResponseType::DeferredChannelMessageWithSource)
|
|
})
|
|
.await;
|
|
}
|
|
|
|
let pool = ctx
|
|
.data
|
|
.read()
|
|
.await
|
|
.get::<MySQL>()
|
|
.cloned()
|
|
.expect("Could not get SQLPool from data");
|
|
|
|
let mut sounds = vec![];
|
|
|
|
for n in 1..25 {
|
|
let search = Sound::search_for_sound(
|
|
args.named(&n.to_string()).unwrap_or(&"".to_string()),
|
|
invoke.guild_id().unwrap(),
|
|
invoke.author_id(),
|
|
pool.clone(),
|
|
true,
|
|
)
|
|
.await?;
|
|
|
|
if let Some(sound) = search.first() {
|
|
if !sounds.contains(sound) {
|
|
sounds.push(sound.clone());
|
|
}
|
|
}
|
|
}
|
|
|
|
invoke
|
|
.followup(
|
|
ctx.http.clone(),
|
|
CreateGenericResponse::new()
|
|
.content("**Play a sound:**")
|
|
.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.add_action_row(action_row);
|
|
}
|
|
|
|
c
|
|
}),
|
|
)
|
|
.await?;
|
|
|
|
Ok(())
|
|
}
|