restructured a lot. everything updated to poise.
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
use crate::{Context, Error, THEME_COLOR};
|
||||
use crate::{consts::THEME_COLOR, Context, Error};
|
||||
|
||||
/// Get additional information about the bot
|
||||
#[poise::command(slash_command, category = "Information")]
|
||||
|
@ -1,8 +1,14 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use poise::serenity::model::id::{GuildId, RoleId};
|
||||
use tokio::fs::File;
|
||||
|
||||
use crate::{sound::Sound, Context, Error, MAX_SOUNDS, PATREON_GUILD, PATREON_ROLE};
|
||||
use crate::{
|
||||
cmds::autocomplete_sound,
|
||||
consts::{MAX_SOUNDS, PATREON_GUILD, PATREON_ROLE},
|
||||
models::sound::{Sound, SoundCtx},
|
||||
Context, Error,
|
||||
};
|
||||
|
||||
/// Upload a new sound to the bot
|
||||
#[poise::command(slash_command, rename = "upload", category = "Manage")]
|
||||
@ -123,14 +129,16 @@ pub async fn upload_new_sound(
|
||||
#[poise::command(slash_command, rename = "delete", category = "Manage")]
|
||||
pub async fn delete_sound(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Name or ID of sound to delete"] name: String,
|
||||
#[description = "Name or ID of sound to delete"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
name: String,
|
||||
) -> Result<(), Error> {
|
||||
let pool = ctx.data().database.clone();
|
||||
|
||||
let uid = ctx.author().id.0;
|
||||
let gid = ctx.guild_id().unwrap().0;
|
||||
|
||||
let sound_vec = Sound::search_for_sound(&name, gid, uid, pool.clone(), true).await?;
|
||||
let sound_vec = ctx.data().search_for_sound(&name, gid, uid, true).await?;
|
||||
let sound_result = sound_vec.first();
|
||||
|
||||
match sound_result {
|
||||
@ -174,14 +182,16 @@ pub async fn delete_sound(
|
||||
#[poise::command(slash_command, rename = "public", category = "Manage")]
|
||||
pub async fn change_public(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Name or ID of sound to change privacy setting of"] name: String,
|
||||
#[description = "Name or ID of sound to change privacy setting of"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
name: String,
|
||||
) -> Result<(), Error> {
|
||||
let pool = ctx.data().database.clone();
|
||||
|
||||
let uid = ctx.author().id.0;
|
||||
let gid = ctx.guild_id().unwrap().0;
|
||||
|
||||
let mut sound_vec = Sound::search_for_sound(&name, gid, uid, pool.clone(), true).await?;
|
||||
let mut sound_vec = ctx.data().search_for_sound(&name, gid, uid, true).await?;
|
||||
let sound_result = sound_vec.first_mut();
|
||||
|
||||
match sound_result {
|
||||
@ -210,3 +220,39 @@ pub async fn change_public(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Download a sound file from the bot
|
||||
#[poise::command(slash_command, rename = "download", category = "Manage")]
|
||||
pub async fn download_file(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Name or ID of sound to download"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
name: String,
|
||||
) -> Result<(), Error> {
|
||||
ctx.defer().await?;
|
||||
|
||||
let sound = ctx
|
||||
.data()
|
||||
.search_for_sound(&name, ctx.guild_id().unwrap(), ctx.author().id, true)
|
||||
.await?;
|
||||
|
||||
match sound.first() {
|
||||
Some(sound) => {
|
||||
let source = sound
|
||||
.store_sound_source(ctx.data().database.clone())
|
||||
.await?;
|
||||
|
||||
let file = File::open(&source).await?;
|
||||
let name = format!("{}-{}.opus", sound.id, sound.name);
|
||||
|
||||
ctx.send(|m| m.attachment((&file, name.as_str()).into()))
|
||||
.await?;
|
||||
}
|
||||
|
||||
None => {
|
||||
ctx.say("No sound found by specified name/ID").await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,6 +1,24 @@
|
||||
use crate::{models::sound::SoundCtx, Context};
|
||||
|
||||
pub mod info;
|
||||
pub mod manage;
|
||||
pub mod play;
|
||||
// pub mod search;
|
||||
// pub mod settings;
|
||||
// pub mod stop;
|
||||
pub mod search;
|
||||
pub mod settings;
|
||||
pub mod stop;
|
||||
|
||||
pub async fn autocomplete_sound(
|
||||
ctx: Context<'_>,
|
||||
partial: String,
|
||||
) -> Vec<poise::AutocompleteChoice<String>> {
|
||||
ctx.data()
|
||||
.autocomplete_user_sounds(&partial, ctx.author().id, ctx.guild_id().unwrap())
|
||||
.await
|
||||
.unwrap_or(vec![])
|
||||
.iter()
|
||||
.map(|s| poise::AutocompleteChoice {
|
||||
name: s.name.clone(),
|
||||
value: s.id.to_string(),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
156
src/cmds/play.rs
156
src/cmds/play.rs
@ -2,32 +2,58 @@ use poise::serenity::{
|
||||
builder::CreateActionRow, model::interactions::message_component::ButtonStyle,
|
||||
};
|
||||
|
||||
use crate::{play_from_query, sound::Sound, Context, Error};
|
||||
use crate::{
|
||||
cmds::autocomplete_sound, models::sound::SoundCtx, utils::play_from_query, Context, Error,
|
||||
};
|
||||
|
||||
/// Play a sound in your current voice channel
|
||||
#[poise::command(slash_command)]
|
||||
pub async fn play(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Name or ID of sound to play"] name: String,
|
||||
#[description = "Name or ID of sound to play"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
name: String,
|
||||
) -> Result<(), Error> {
|
||||
let guild = ctx.guild().unwrap();
|
||||
|
||||
ctx.say(play_from_query(&ctx, guild, ctx.author().id, &name, false).await)
|
||||
.await?;
|
||||
ctx.say(
|
||||
play_from_query(
|
||||
&ctx.discord(),
|
||||
&ctx.data(),
|
||||
guild,
|
||||
ctx.author().id,
|
||||
&name,
|
||||
false,
|
||||
)
|
||||
.await,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Loop a sound in your current voice channel
|
||||
#[poise::command(slash_command)]
|
||||
#[poise::command(slash_command, rename = "loop")]
|
||||
pub async fn loop_play(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Name or ID of sound to loop"] name: String,
|
||||
#[description = "Name or ID of sound to loop"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
name: String,
|
||||
) -> Result<(), Error> {
|
||||
let guild = ctx.guild().unwrap();
|
||||
|
||||
ctx.say(play_from_query(&ctx, guild, ctx.author().id, &name, true).await)
|
||||
.await?;
|
||||
ctx.say(
|
||||
play_from_query(
|
||||
&ctx.discord(),
|
||||
&ctx.data(),
|
||||
guild,
|
||||
ctx.author().id,
|
||||
&name,
|
||||
true,
|
||||
)
|
||||
.await,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -36,36 +62,84 @@ pub async fn loop_play(
|
||||
#[poise::command(slash_command, rename = "soundboard", category = "Play")]
|
||||
pub async fn soundboard(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Name or ID of sound for button 1"] sound_1: String,
|
||||
#[description = "Name or ID of sound for button 2"] sound_2: Option<String>,
|
||||
#[description = "Name or ID of sound for button 3"] sound_3: Option<String>,
|
||||
#[description = "Name or ID of sound for button 4"] sound_4: Option<String>,
|
||||
#[description = "Name or ID of sound for button 5"] sound_5: Option<String>,
|
||||
#[description = "Name or ID of sound for button 6"] sound_6: Option<String>,
|
||||
#[description = "Name or ID of sound for button 7"] sound_7: Option<String>,
|
||||
#[description = "Name or ID of sound for button 8"] sound_8: Option<String>,
|
||||
#[description = "Name or ID of sound for button 9"] sound_9: Option<String>,
|
||||
#[description = "Name or ID of sound for button 10"] sound_10: Option<String>,
|
||||
#[description = "Name or ID of sound for button 11"] sound_11: Option<String>,
|
||||
#[description = "Name or ID of sound for button 12"] sound_12: Option<String>,
|
||||
#[description = "Name or ID of sound for button 13"] sound_13: Option<String>,
|
||||
#[description = "Name or ID of sound for button 14"] sound_14: Option<String>,
|
||||
#[description = "Name or ID of sound for button 15"] sound_15: Option<String>,
|
||||
#[description = "Name or ID of sound for button 16"] sound_16: Option<String>,
|
||||
#[description = "Name or ID of sound for button 17"] sound_17: Option<String>,
|
||||
#[description = "Name or ID of sound for button 18"] sound_18: Option<String>,
|
||||
#[description = "Name or ID of sound for button 19"] sound_19: Option<String>,
|
||||
#[description = "Name or ID of sound for button 20"] sound_20: Option<String>,
|
||||
#[description = "Name or ID of sound for button 21"] sound_21: Option<String>,
|
||||
#[description = "Name or ID of sound for button 22"] sound_22: Option<String>,
|
||||
#[description = "Name or ID of sound for button 23"] sound_23: Option<String>,
|
||||
#[description = "Name or ID of sound for button 24"] sound_24: Option<String>,
|
||||
#[description = "Name or ID of sound for button 25"] sound_25: Option<String>,
|
||||
#[description = "Name or ID of sound for button 1"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_1: String,
|
||||
#[description = "Name or ID of sound for button 2"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_2: Option<String>,
|
||||
#[description = "Name or ID of sound for button 3"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_3: Option<String>,
|
||||
#[description = "Name or ID of sound for button 4"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_4: Option<String>,
|
||||
#[description = "Name or ID of sound for button 5"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_5: Option<String>,
|
||||
#[description = "Name or ID of sound for button 6"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_6: Option<String>,
|
||||
#[description = "Name or ID of sound for button 7"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_7: Option<String>,
|
||||
#[description = "Name or ID of sound for button 8"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_8: Option<String>,
|
||||
#[description = "Name or ID of sound for button 9"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_9: Option<String>,
|
||||
#[description = "Name or ID of sound for button 10"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_10: Option<String>,
|
||||
#[description = "Name or ID of sound for button 11"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_11: Option<String>,
|
||||
#[description = "Name or ID of sound for button 12"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_12: Option<String>,
|
||||
#[description = "Name or ID of sound for button 13"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_13: Option<String>,
|
||||
#[description = "Name or ID of sound for button 14"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_14: Option<String>,
|
||||
#[description = "Name or ID of sound for button 15"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_15: Option<String>,
|
||||
#[description = "Name or ID of sound for button 16"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_16: Option<String>,
|
||||
#[description = "Name or ID of sound for button 17"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_17: Option<String>,
|
||||
#[description = "Name or ID of sound for button 18"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_18: Option<String>,
|
||||
#[description = "Name or ID of sound for button 19"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_19: Option<String>,
|
||||
#[description = "Name or ID of sound for button 20"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_20: Option<String>,
|
||||
#[description = "Name or ID of sound for button 21"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_21: Option<String>,
|
||||
#[description = "Name or ID of sound for button 22"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_22: Option<String>,
|
||||
#[description = "Name or ID of sound for button 23"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_23: Option<String>,
|
||||
#[description = "Name or ID of sound for button 24"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_24: Option<String>,
|
||||
#[description = "Name or ID of sound for button 25"]
|
||||
#[autocomplete = "autocomplete_sound"]
|
||||
sound_25: Option<String>,
|
||||
) -> Result<(), Error> {
|
||||
ctx.defer().await?;
|
||||
|
||||
let pool = ctx.data().database.clone();
|
||||
|
||||
let query_terms = [
|
||||
Some(sound_1),
|
||||
sound_2,
|
||||
@ -97,14 +171,10 @@ pub async fn soundboard(
|
||||
let mut sounds = vec![];
|
||||
|
||||
for sound in query_terms.iter().flatten() {
|
||||
let search = Sound::search_for_sound(
|
||||
&sound,
|
||||
ctx.guild_id().unwrap(),
|
||||
ctx.author().id,
|
||||
pool.clone(),
|
||||
true,
|
||||
)
|
||||
.await?;
|
||||
let search = ctx
|
||||
.data()
|
||||
.search_for_sound(&sound, ctx.guild_id().unwrap(), ctx.author().id, true)
|
||||
.await?;
|
||||
|
||||
if let Some(sound) = search.first() {
|
||||
if !sounds.contains(sound) {
|
||||
|
@ -1,6 +1,13 @@
|
||||
use crate::sound::Sound;
|
||||
use poise::{serenity::constants::MESSAGE_CODE_LIMIT, CreateReply};
|
||||
|
||||
use crate::{
|
||||
models::sound::{Sound, SoundCtx},
|
||||
Context, Error,
|
||||
};
|
||||
|
||||
fn format_search_results<'a>(search_results: Vec<Sound>) -> CreateReply<'a> {
|
||||
let mut builder = CreateReply::default();
|
||||
|
||||
fn format_search_results(search_results: Vec<Sound>) -> CreateGenericResponse {
|
||||
let mut current_character_count = 0;
|
||||
let title = "Public sounds matching filter:";
|
||||
|
||||
@ -11,49 +18,25 @@ fn format_search_results(search_results: Vec<Sound>) -> CreateGenericResponse {
|
||||
.filter(|item| {
|
||||
current_character_count += item.0.len() + item.1.len();
|
||||
|
||||
current_character_count <= serenity::constants::MESSAGE_CODE_LIMIT - title.len()
|
||||
current_character_count <= MESSAGE_CODE_LIMIT - title.len()
|
||||
});
|
||||
|
||||
CreateGenericResponse::new().embed(|e| e.title(title).fields(field_iter))
|
||||
builder.embed(|e| e.title(title).fields(field_iter));
|
||||
|
||||
builder
|
||||
}
|
||||
|
||||
#[command("list")]
|
||||
#[group("Search")]
|
||||
#[description("Show the sounds uploaded by you or to your server")]
|
||||
#[arg(
|
||||
name = "me",
|
||||
description = "Whether to list your sounds or server sounds (default: server)",
|
||||
kind = "Boolean",
|
||||
required = false
|
||||
)]
|
||||
#[example("`/list` - list sounds uploaded to the server you're in")]
|
||||
#[example("`/list [me: True]` - list sounds you have uploaded across all servers")]
|
||||
pub async fn list_sounds(
|
||||
ctx: &Context,
|
||||
invoke: &(dyn CommandInvoke + Sync + Send),
|
||||
args: Args,
|
||||
) -> CommandResult {
|
||||
let pool = ctx
|
||||
.data
|
||||
.read()
|
||||
.await
|
||||
.get::<MySQL>()
|
||||
.cloned()
|
||||
.expect("Could not get SQLPool from data");
|
||||
|
||||
/// Show the sounds uploaded to this server
|
||||
#[poise::command(slash_command, rename = "list")]
|
||||
pub async fn list_sounds(ctx: Context<'_>) -> Result<(), Error> {
|
||||
let sounds;
|
||||
let mut message_buffer;
|
||||
|
||||
if args.named("me").map(|i| i.to_owned()) == Some("me".to_string()) {
|
||||
sounds = Sound::user_sounds(invoke.author_id(), pool).await?;
|
||||
sounds = ctx.data().guild_sounds(ctx.guild_id().unwrap()).await?;
|
||||
|
||||
message_buffer = "All your sounds: ".to_string();
|
||||
} else {
|
||||
sounds = Sound::guild_sounds(invoke.guild_id().unwrap(), pool).await?;
|
||||
|
||||
message_buffer = "All sounds on this server: ".to_string();
|
||||
}
|
||||
message_buffer = "Sounds on this server: ".to_string();
|
||||
|
||||
// todo change this to iterator
|
||||
for sound in sounds {
|
||||
message_buffer.push_str(
|
||||
format!(
|
||||
@ -65,85 +48,77 @@ pub async fn list_sounds(
|
||||
);
|
||||
|
||||
if message_buffer.len() > 2000 {
|
||||
invoke
|
||||
.respond(
|
||||
ctx.http.clone(),
|
||||
CreateGenericResponse::new().content(message_buffer),
|
||||
)
|
||||
.await?;
|
||||
ctx.say(message_buffer).await?;
|
||||
|
||||
message_buffer = "".to_string();
|
||||
}
|
||||
}
|
||||
|
||||
if message_buffer.len() > 0 {
|
||||
invoke
|
||||
.respond(
|
||||
ctx.http.clone(),
|
||||
CreateGenericResponse::new().content(message_buffer),
|
||||
)
|
||||
.await?;
|
||||
ctx.say(message_buffer).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[command("search")]
|
||||
#[group("Search")]
|
||||
#[description("Search for sounds")]
|
||||
#[arg(
|
||||
name = "query",
|
||||
kind = "String",
|
||||
description = "Sound name to search for",
|
||||
required = true
|
||||
)]
|
||||
pub async fn search_sounds(
|
||||
ctx: &Context,
|
||||
invoke: &(dyn CommandInvoke + Sync + Send),
|
||||
args: Args,
|
||||
) -> CommandResult {
|
||||
let pool = ctx
|
||||
.data
|
||||
.read()
|
||||
.await
|
||||
.get::<MySQL>()
|
||||
.cloned()
|
||||
.expect("Could not get SQLPool from data");
|
||||
/// Show all sounds you have uploaded
|
||||
#[poise::command(slash_command, rename = "me")]
|
||||
pub async fn list_user_sounds(ctx: Context<'_>) -> Result<(), Error> {
|
||||
let sounds;
|
||||
let mut message_buffer;
|
||||
|
||||
let query = args.named("query").unwrap();
|
||||
sounds = ctx.data().user_sounds(ctx.author().id).await?;
|
||||
|
||||
let search_results = Sound::search_for_sound(
|
||||
query,
|
||||
invoke.guild_id().unwrap(),
|
||||
invoke.author_id(),
|
||||
pool,
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
message_buffer = "Sounds on this server: ".to_string();
|
||||
|
||||
invoke
|
||||
.respond(ctx.http.clone(), format_search_results(search_results))
|
||||
.await?;
|
||||
// todo change this to iterator
|
||||
for sound in sounds {
|
||||
message_buffer.push_str(
|
||||
format!(
|
||||
"**{}** ({}), ",
|
||||
sound.name,
|
||||
if sound.public { "🔓" } else { "🔒" }
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
|
||||
if message_buffer.len() > 2000 {
|
||||
ctx.say(message_buffer).await?;
|
||||
|
||||
message_buffer = "".to_string();
|
||||
}
|
||||
}
|
||||
|
||||
if message_buffer.len() > 0 {
|
||||
ctx.say(message_buffer).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[command("random")]
|
||||
#[group("Search")]
|
||||
#[description("Show a page of random sounds")]
|
||||
pub async fn show_random_sounds(
|
||||
ctx: &Context,
|
||||
invoke: &(dyn CommandInvoke + Sync + Send),
|
||||
_args: Args,
|
||||
) -> CommandResult {
|
||||
let pool = ctx
|
||||
.data
|
||||
.read()
|
||||
.await
|
||||
.get::<MySQL>()
|
||||
.cloned()
|
||||
.expect("Could not get SQLPool from data");
|
||||
/// Search for sounds
|
||||
#[poise::command(slash_command, rename = "search", category = "Search")]
|
||||
pub async fn search_sounds(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Sound name to search for"] query: String,
|
||||
) -> Result<(), Error> {
|
||||
let search_results = ctx
|
||||
.data()
|
||||
.search_for_sound(&query, ctx.guild_id().unwrap(), ctx.author().id, false)
|
||||
.await?;
|
||||
|
||||
ctx.send(|m| {
|
||||
*m = format_search_results(search_results);
|
||||
m
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Show a page of random sounds
|
||||
#[poise::command(slash_command, rename = "random")]
|
||||
pub async fn show_random_sounds(ctx: Context<'_>) -> Result<(), Error> {
|
||||
let search_results = sqlx::query_as_unchecked!(
|
||||
Sound,
|
||||
"
|
||||
@ -154,13 +129,14 @@ SELECT name, id, public, server_id, uploader_id
|
||||
LIMIT 25
|
||||
"
|
||||
)
|
||||
.fetch_all(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
.fetch_all(&ctx.data().database)
|
||||
.await?;
|
||||
|
||||
invoke
|
||||
.respond(ctx.http.clone(), format_search_results(search_results))
|
||||
.await?;
|
||||
ctx.send(|m| {
|
||||
*m = format_search_results(search_results);
|
||||
m
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,307 +1,126 @@
|
||||
use regex_command_attr::command;
|
||||
use serenity::{client::Context, framework::standard::CommandResult};
|
||||
|
||||
use crate::{
|
||||
framework::{Args, CommandInvoke, CreateGenericResponse},
|
||||
guild_data::CtxGuildData,
|
||||
sound::{JoinSoundCtx, Sound},
|
||||
MySQL,
|
||||
models::{guild_data::CtxGuildData, join_sound::JoinSoundCtx, sound::SoundCtx},
|
||||
Context, Error,
|
||||
};
|
||||
|
||||
#[command("volume")]
|
||||
#[aliases("vol")]
|
||||
#[required_permissions(Managed)]
|
||||
#[group("Settings")]
|
||||
#[description("Change the bot's volume in this server")]
|
||||
#[arg(
|
||||
name = "volume",
|
||||
description = "New volume for the bot to use",
|
||||
kind = "Integer",
|
||||
required = false
|
||||
)]
|
||||
#[example("`/volume` - check the volume on the current server")]
|
||||
#[example("`/volume 100` - reset the volume on the current server")]
|
||||
#[example("`/volume 10` - set the volume on the current server to 10%")]
|
||||
/// Change the bot's volume in this server
|
||||
#[poise::command(slash_command, rename = "volume")]
|
||||
pub async fn change_volume(
|
||||
ctx: &Context,
|
||||
invoke: &(dyn CommandInvoke + Sync + Send),
|
||||
args: Args,
|
||||
) -> CommandResult {
|
||||
let pool = ctx
|
||||
.data
|
||||
.read()
|
||||
.await
|
||||
.get::<MySQL>()
|
||||
.cloned()
|
||||
.expect("Could not get SQLPool from data");
|
||||
|
||||
let guild_data_opt = ctx.guild_data(invoke.guild_id().unwrap()).await;
|
||||
ctx: Context<'_>,
|
||||
#[description = "New volume as a percentage"] volume: Option<usize>,
|
||||
) -> Result<(), Error> {
|
||||
let guild_data_opt = ctx.guild_data(ctx.guild_id().unwrap()).await;
|
||||
let guild_data = guild_data_opt.unwrap();
|
||||
|
||||
if let Some(volume) = args.named("volume").map(|i| i.parse::<u8>().ok()).flatten() {
|
||||
guild_data.write().await.volume = volume;
|
||||
if let Some(volume) = volume {
|
||||
guild_data.write().await.volume = volume as u8;
|
||||
|
||||
guild_data.read().await.commit(pool).await?;
|
||||
|
||||
invoke
|
||||
.respond(
|
||||
ctx.http.clone(),
|
||||
CreateGenericResponse::new().content(format!("Volume changed to {}%", volume)),
|
||||
)
|
||||
guild_data
|
||||
.read()
|
||||
.await
|
||||
.commit(ctx.data().database.clone())
|
||||
.await?;
|
||||
|
||||
ctx.say(format!("Volume changed to {}%", volume)).await?;
|
||||
} else {
|
||||
let read = guild_data.read().await;
|
||||
|
||||
invoke
|
||||
.respond(
|
||||
ctx.http.clone(),
|
||||
CreateGenericResponse::new().content(format!(
|
||||
"Current server volume: {vol}%. Change the volume with `/volume <new volume>`",
|
||||
vol = read.volume
|
||||
)),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[command("prefix")]
|
||||
#[required_permissions(Restricted)]
|
||||
#[kind(Text)]
|
||||
#[group("Settings")]
|
||||
#[description("Change the prefix of the bot for using non-slash commands")]
|
||||
#[arg(
|
||||
name = "prefix",
|
||||
kind = "String",
|
||||
description = "The new prefix to use for the bot",
|
||||
required = true
|
||||
)]
|
||||
pub async fn change_prefix(
|
||||
ctx: &Context,
|
||||
invoke: &(dyn CommandInvoke + Sync + Send),
|
||||
args: Args,
|
||||
) -> CommandResult {
|
||||
let pool = ctx
|
||||
.data
|
||||
.read()
|
||||
.await
|
||||
.get::<MySQL>()
|
||||
.cloned()
|
||||
.expect("Could not get SQLPool from data");
|
||||
|
||||
let guild_data;
|
||||
|
||||
{
|
||||
let guild_data_opt = ctx.guild_data(invoke.guild_id().unwrap()).await;
|
||||
|
||||
guild_data = guild_data_opt.unwrap();
|
||||
}
|
||||
|
||||
if let Some(prefix) = args.named("prefix") {
|
||||
if prefix.len() <= 5 && !prefix.is_empty() {
|
||||
let reply = format!("Prefix changed to `{}`", prefix);
|
||||
|
||||
{
|
||||
guild_data.write().await.prefix = prefix.to_string();
|
||||
}
|
||||
|
||||
{
|
||||
let read = guild_data.read().await;
|
||||
|
||||
read.commit(pool).await?;
|
||||
}
|
||||
|
||||
invoke
|
||||
.respond(
|
||||
ctx.http.clone(),
|
||||
CreateGenericResponse::new().content(reply),
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
invoke
|
||||
.respond(
|
||||
ctx.http.clone(),
|
||||
CreateGenericResponse::new()
|
||||
.content("Prefix must be less than 5 characters long"),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
} else {
|
||||
invoke
|
||||
.respond(
|
||||
ctx.http.clone(),
|
||||
CreateGenericResponse::new().content(format!(
|
||||
"Usage: `{prefix}prefix <new prefix>`",
|
||||
prefix = guild_data.read().await.prefix
|
||||
)),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[command("roles")]
|
||||
#[required_permissions(Restricted)]
|
||||
#[group("Settings")]
|
||||
#[description("Change the role allowed to use the bot")]
|
||||
#[arg(
|
||||
name = "role",
|
||||
kind = "Role",
|
||||
description = "A role to allow to use the bot. Use @everyone to allow all server members",
|
||||
required = true
|
||||
)]
|
||||
#[example("`/roles @everyone` - allow all server members to use the bot")]
|
||||
#[example("`/roles @DJ` - allow only server members with the 'DJ' role to use the bot")]
|
||||
pub async fn set_allowed_roles(
|
||||
ctx: &Context,
|
||||
invoke: &(dyn CommandInvoke + Sync + Send),
|
||||
args: Args,
|
||||
) -> CommandResult {
|
||||
let pool = ctx
|
||||
.data
|
||||
.read()
|
||||
.await
|
||||
.get::<MySQL>()
|
||||
.cloned()
|
||||
.expect("Could not get SQLPool from data");
|
||||
|
||||
let role_id = args.named("role").unwrap().parse::<u64>().unwrap();
|
||||
let guild_data = ctx.guild_data(invoke.guild_id().unwrap()).await.unwrap();
|
||||
|
||||
guild_data.write().await.allowed_role = Some(role_id);
|
||||
guild_data.read().await.commit(pool).await?;
|
||||
|
||||
invoke
|
||||
.respond(
|
||||
ctx.http.clone(),
|
||||
CreateGenericResponse::new().content(format!("Allowed role set to <@&{}>", role_id)),
|
||||
)
|
||||
ctx.say(format!(
|
||||
"Current server volume: {vol}%. Change the volume with `/volume <new volume>`",
|
||||
vol = read.volume
|
||||
))
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[command("greet")]
|
||||
#[group("Settings")]
|
||||
#[description("Set a join sound")]
|
||||
#[arg(
|
||||
name = "query",
|
||||
kind = "String",
|
||||
description = "Name or ID of sound to set as your greet sound",
|
||||
required = false
|
||||
)]
|
||||
#[example("`/greet` - remove your join sound")]
|
||||
#[example("`/greet 1523` - set your join sound to sound with ID 1523")]
|
||||
/// Manage greet sounds on this server
|
||||
#[poise::command(slash_command, rename = "greet")]
|
||||
pub async fn greet_sound(_ctx: Context<'_>) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set a join sound
|
||||
#[poise::command(slash_command, rename = "set")]
|
||||
pub async fn set_greet_sound(
|
||||
ctx: &Context,
|
||||
invoke: &(dyn CommandInvoke + Sync + Send),
|
||||
args: Args,
|
||||
) -> CommandResult {
|
||||
let pool = ctx
|
||||
.data
|
||||
.read()
|
||||
.await
|
||||
.get::<MySQL>()
|
||||
.cloned()
|
||||
.expect("Could not get SQLPool from data");
|
||||
|
||||
let query = args
|
||||
.named("query")
|
||||
.map(|s| s.to_owned())
|
||||
.unwrap_or(String::new());
|
||||
let user_id = invoke.author_id();
|
||||
|
||||
if query.len() == 0 {
|
||||
ctx.update_join_sound(user_id, None).await;
|
||||
|
||||
invoke
|
||||
.respond(
|
||||
ctx.http.clone(),
|
||||
CreateGenericResponse::new().content("Your greet sound has been unset."),
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
let sound_vec = Sound::search_for_sound(
|
||||
&query,
|
||||
invoke.guild_id().unwrap(),
|
||||
user_id,
|
||||
pool.clone(),
|
||||
true,
|
||||
)
|
||||
ctx: Context<'_>,
|
||||
#[description = "Name or ID of sound to set as your join sound"] name: String,
|
||||
) -> Result<(), Error> {
|
||||
let sound_vec = ctx
|
||||
.data()
|
||||
.search_for_sound(&name, ctx.guild_id().unwrap(), ctx.author().id, true)
|
||||
.await?;
|
||||
|
||||
match sound_vec.first() {
|
||||
Some(sound) => {
|
||||
ctx.update_join_sound(user_id, Some(sound.id)).await;
|
||||
match sound_vec.first() {
|
||||
Some(sound) => {
|
||||
ctx.data()
|
||||
.update_join_sound(ctx.author().id, Some(sound.id))
|
||||
.await;
|
||||
|
||||
invoke
|
||||
.respond(
|
||||
ctx.http.clone(),
|
||||
CreateGenericResponse::new().content(format!(
|
||||
"Greet sound has been set to {} (ID {})",
|
||||
sound.name, sound.id
|
||||
)),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
ctx.say(format!(
|
||||
"Greet sound has been set to {} (ID {})",
|
||||
sound.name, sound.id
|
||||
))
|
||||
.await?;
|
||||
}
|
||||
|
||||
None => {
|
||||
invoke
|
||||
.respond(
|
||||
ctx.http.clone(),
|
||||
CreateGenericResponse::new()
|
||||
.content("Could not find a sound by that name."),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
None => {
|
||||
ctx.say("Could not find a sound by that name.").await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[command("allow_greet")]
|
||||
#[group("Settings")]
|
||||
#[description("Configure whether users should be able to use join sounds")]
|
||||
#[required_permissions(Restricted)]
|
||||
#[example("`/allow_greet` - disable greet sounds in the server")]
|
||||
#[example("`/allow_greet` - re-enable greet sounds in the server")]
|
||||
pub async fn allow_greet_sounds(
|
||||
ctx: &Context,
|
||||
invoke: &(dyn CommandInvoke + Sync + Send),
|
||||
_args: Args,
|
||||
) -> CommandResult {
|
||||
let pool = ctx
|
||||
.data
|
||||
.read()
|
||||
.await
|
||||
.get::<MySQL>()
|
||||
.cloned()
|
||||
.expect("Could not acquire SQL pool from data");
|
||||
/// Set a join sound
|
||||
#[poise::command(slash_command, rename = "unset")]
|
||||
pub async fn unset_greet_sound(ctx: Context<'_>) -> Result<(), Error> {
|
||||
ctx.data().update_join_sound(ctx.author().id, None).await;
|
||||
|
||||
let guild_data_opt = ctx.guild_data(invoke.guild_id().unwrap()).await;
|
||||
ctx.say("Greet sound has been unset").await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Disable greet sounds on this server
|
||||
#[poise::command(slash_command, rename = "disable")]
|
||||
pub async fn disable_greet_sound(ctx: Context<'_>) -> Result<(), Error> {
|
||||
let guild_data_opt = ctx.guild_data(ctx.guild_id().unwrap()).await;
|
||||
|
||||
if let Ok(guild_data) = guild_data_opt {
|
||||
let current = guild_data.read().await.allow_greets;
|
||||
guild_data.write().await.allow_greets = false;
|
||||
|
||||
{
|
||||
guild_data.write().await.allow_greets = !current;
|
||||
}
|
||||
|
||||
guild_data.read().await.commit(pool).await?;
|
||||
|
||||
invoke
|
||||
.respond(
|
||||
ctx.http.clone(),
|
||||
CreateGenericResponse::new().content(format!(
|
||||
"Greet sounds have been {}abled in this server",
|
||||
if !current { "en" } else { "dis" }
|
||||
)),
|
||||
)
|
||||
guild_data
|
||||
.read()
|
||||
.await
|
||||
.commit(ctx.data().database.clone())
|
||||
.await?;
|
||||
}
|
||||
|
||||
ctx.say("Greet sounds have been disabled in this server")
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Enable greet sounds on this server
|
||||
#[poise::command(slash_command, rename = "enable")]
|
||||
pub async fn enable_greet_sound(ctx: Context<'_>) -> Result<(), Error> {
|
||||
let guild_data_opt = ctx.guild_data(ctx.guild_id().unwrap()).await;
|
||||
|
||||
if let Ok(guild_data) = guild_data_opt {
|
||||
guild_data.write().await.allow_greets = true;
|
||||
|
||||
guild_data
|
||||
.read()
|
||||
.await
|
||||
.commit(ctx.data().database.clone())
|
||||
.await?;
|
||||
}
|
||||
|
||||
ctx.say("Greet sounds have been enable in this server")
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,22 +1,12 @@
|
||||
use regex_command_attr::command;
|
||||
use serenity::{client::Context, framework::standard::CommandResult};
|
||||
use songbird;
|
||||
|
||||
use crate::framework::{Args, CommandInvoke, CreateGenericResponse};
|
||||
use crate::{Context, Error};
|
||||
|
||||
#[command("stop")]
|
||||
#[required_permissions(Managed)]
|
||||
#[group("Stop")]
|
||||
#[description("Stop the bot from playing")]
|
||||
pub async fn stop_playing(
|
||||
ctx: &Context,
|
||||
invoke: &(dyn CommandInvoke + Sync + Send),
|
||||
_args: Args,
|
||||
) -> CommandResult {
|
||||
let guild_id = invoke.guild_id().unwrap();
|
||||
|
||||
let songbird = songbird::get(ctx).await.unwrap();
|
||||
let call_opt = songbird.get(guild_id);
|
||||
/// Stop the bot from playing
|
||||
#[poise::command(slash_command, rename = "stop")]
|
||||
pub async fn stop_playing(ctx: Context<'_>) -> Result<(), Error> {
|
||||
let songbird = songbird::get(ctx.discord()).await.unwrap();
|
||||
let call_opt = songbird.get(ctx.guild_id().unwrap());
|
||||
|
||||
if let Some(call) = call_opt {
|
||||
let mut lock = call.lock().await;
|
||||
@ -24,31 +14,18 @@ pub async fn stop_playing(
|
||||
lock.stop();
|
||||
}
|
||||
|
||||
invoke
|
||||
.respond(ctx.http.clone(), CreateGenericResponse::new().content("👍"))
|
||||
.await?;
|
||||
ctx.say("👍").await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[command]
|
||||
#[aliases("dc")]
|
||||
#[required_permissions(Managed)]
|
||||
#[group("Stop")]
|
||||
#[description("Disconnect the bot")]
|
||||
pub async fn disconnect(
|
||||
ctx: &Context,
|
||||
invoke: &(dyn CommandInvoke + Sync + Send),
|
||||
_args: Args,
|
||||
) -> CommandResult {
|
||||
let guild_id = invoke.guild_id().unwrap();
|
||||
/// Disconnect the bot
|
||||
#[poise::command(slash_command)]
|
||||
pub async fn disconnect(ctx: Context<'_>) -> Result<(), Error> {
|
||||
let songbird = songbird::get(ctx.discord()).await.unwrap();
|
||||
let _ = songbird.leave(ctx.guild_id().unwrap()).await;
|
||||
|
||||
let songbird = songbird::get(ctx).await.unwrap();
|
||||
let _ = songbird.leave(guild_id).await;
|
||||
|
||||
invoke
|
||||
.respond(ctx.http.clone(), CreateGenericResponse::new().content("👍"))
|
||||
.await?;
|
||||
ctx.say("👍").await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
Reference in New Issue
Block a user