Wip commit
This commit is contained in:
parent
cd5651c7f6
commit
e369b42131
1787
Cargo.lock
generated
1787
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
11
Cargo.toml
11
Cargo.toml
@ -7,17 +7,17 @@ authors = ["jellywx <judesouthworth@pm.me>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
songbird = { version = "0.3", features = ["builtin-queue"] }
|
songbird = { version = "0.4", features = ["builtin-queue"] }
|
||||||
poise = "0.5.5"
|
poise = "0.6.1-rc1"
|
||||||
sqlx = { version = "0.5", default-features = false, features = ["runtime-tokio-rustls", "macros", "mysql", "bigdecimal", "migrate"] }
|
sqlx = { version = "0.5", default-features = false, features = ["runtime-tokio-rustls", "macros", "mysql", "bigdecimal", "migrate"] }
|
||||||
tokio = { version = "1", features = ["fs", "process", "io-util"] }
|
tokio = { version = "1", features = ["fs", "process", "io-util"] }
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
reqwest = "0.11"
|
reqwest = "0.11"
|
||||||
env_logger = "0.10"
|
env_logger = "0.10"
|
||||||
regex = "1.4"
|
regex = "1.10"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
dashmap = "5.3"
|
dashmap = "5.5"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
dotenv = "0.15.0"
|
dotenv = "0.15.0"
|
||||||
prometheus = { version = "0.13.3", optional = true }
|
prometheus = { version = "0.13.3", optional = true }
|
||||||
@ -26,9 +26,6 @@ axum = { version = "0.6.20", optional = true }
|
|||||||
[features]
|
[features]
|
||||||
metrics = ["dep:prometheus", "dep:axum"]
|
metrics = ["dep:prometheus", "dep:axum"]
|
||||||
|
|
||||||
[patch."https://github.com/serenity-rs/serenity"]
|
|
||||||
serenity = { version = "0.11.6" }
|
|
||||||
|
|
||||||
[package.metadata.deb]
|
[package.metadata.deb]
|
||||||
features = ["metrics"]
|
features = ["metrics"]
|
||||||
depends = "$auto, ffmpeg"
|
depends = "$auto, ffmpeg"
|
||||||
|
@ -1,19 +1,23 @@
|
|||||||
|
use poise::{
|
||||||
|
serenity_prelude::{CreateEmbed, CreateEmbedFooter},
|
||||||
|
CreateReply,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{consts::THEME_COLOR, Context, Error};
|
use crate::{consts::THEME_COLOR, Context, Error};
|
||||||
|
|
||||||
/// View bot commands
|
/// View bot commands
|
||||||
#[poise::command(slash_command)]
|
#[poise::command(slash_command)]
|
||||||
pub async fn help(ctx: Context<'_>) -> Result<(), Error> {
|
pub async fn help(ctx: Context<'_>) -> Result<(), Error> {
|
||||||
ctx.send(|m| {
|
ctx.send(
|
||||||
m.ephemeral(true).embed(|e| {
|
CreateReply::default().ephemeral(true).embed(
|
||||||
e.title("Help")
|
CreateEmbed::new()
|
||||||
|
.title("Help")
|
||||||
.color(THEME_COLOR)
|
.color(THEME_COLOR)
|
||||||
.footer(|f| {
|
.footer(CreateEmbedFooter::new(concat!(
|
||||||
f.text(concat!(
|
|
||||||
env!("CARGO_PKG_NAME"),
|
env!("CARGO_PKG_NAME"),
|
||||||
" ver ",
|
" ver ",
|
||||||
env!("CARGO_PKG_VERSION")
|
env!("CARGO_PKG_VERSION")
|
||||||
))
|
)))
|
||||||
})
|
|
||||||
.description(
|
.description(
|
||||||
"__Info Commands__
|
"__Info Commands__
|
||||||
`/help` `/info`
|
`/help` `/info`
|
||||||
@ -49,9 +53,9 @@ __Setting Commands__
|
|||||||
|
|
||||||
__Advanced Commands__
|
__Advanced Commands__
|
||||||
`/soundboard` - Create a soundboard",
|
`/soundboard` - Create a soundboard",
|
||||||
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
})
|
|
||||||
})
|
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -62,12 +66,16 @@ __Advanced Commands__
|
|||||||
pub async fn info(ctx: Context<'_>) -> Result<(), Error> {
|
pub async fn info(ctx: Context<'_>) -> Result<(), Error> {
|
||||||
let current_user = ctx.serenity_context().cache.current_user();
|
let current_user = ctx.serenity_context().cache.current_user();
|
||||||
|
|
||||||
ctx.send(|m| m.ephemeral(true)
|
ctx.send(
|
||||||
.embed(|e| e
|
CreateReply::default().ephemeral(true).embed(
|
||||||
|
CreateEmbed::new()
|
||||||
.title("Info")
|
.title("Info")
|
||||||
.color(THEME_COLOR)
|
.color(THEME_COLOR)
|
||||||
.footer(|f| f
|
.footer(CreateEmbedFooter::new(concat!(
|
||||||
.text(concat!(env!("CARGO_PKG_NAME"), " ver ", env!("CARGO_PKG_VERSION"))))
|
env!("CARGO_PKG_NAME"),
|
||||||
|
" ver ",
|
||||||
|
env!("CARGO_PKG_VERSION")
|
||||||
|
)))
|
||||||
.description(format!("Invite me: https://discord.com/api/oauth2/authorize?client_id={}&permissions=3165184&scope=applications.commands%20bot
|
.description(format!("Invite me: https://discord.com/api/oauth2/authorize?client_id={}&permissions=3165184&scope=applications.commands%20bot
|
||||||
|
|
||||||
**Welcome to SoundFX!**
|
**Welcome to SoundFX!**
|
||||||
@ -76,7 +84,9 @@ Find me on https://discord.jellywx.com/ and on https://github.com/JellyWX :)
|
|||||||
|
|
||||||
**An online dashboard is available!** Visit https://soundfx.jellywx.com/dashboard
|
**An online dashboard is available!** Visit https://soundfx.jellywx.com/dashboard
|
||||||
There is a maximum sound limit per user. This can be removed by subscribing at **https://patreon.com/jellywx**",
|
There is a maximum sound limit per user. This can be removed by subscribing at **https://patreon.com/jellywx**",
|
||||||
current_user.id.as_u64())))).await?;
|
current_user.id.get())))
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
use poise::serenity_prelude::{Attachment, GuildId, RoleId};
|
use poise::{
|
||||||
|
serenity_prelude::{Attachment, CreateAttachment, GuildId, RoleId},
|
||||||
|
CreateReply,
|
||||||
|
};
|
||||||
use tokio::fs::File;
|
use tokio::fs::File;
|
||||||
|
|
||||||
#[cfg(feature = "metrics")]
|
#[cfg(feature = "metrics")]
|
||||||
@ -63,11 +66,12 @@ pub async fn upload_new_sound(
|
|||||||
|
|
||||||
// need to check if user is Patreon or not
|
// need to check if user is Patreon or not
|
||||||
if count >= *MAX_SOUNDS {
|
if count >= *MAX_SOUNDS {
|
||||||
let patreon_guild_member =
|
let patreon_guild_member = GuildId::from(*PATREON_GUILD)
|
||||||
GuildId(*PATREON_GUILD).member(ctx, ctx.author().id).await;
|
.member(ctx, ctx.author().id)
|
||||||
|
.await;
|
||||||
|
|
||||||
if let Ok(member) = patreon_guild_member {
|
if let Ok(member) = patreon_guild_member {
|
||||||
permit_upload = member.roles.contains(&RoleId(*PATREON_ROLE));
|
permit_upload = member.roles.contains(&RoleId::from(*PATREON_ROLE));
|
||||||
} else {
|
} else {
|
||||||
permit_upload = false;
|
permit_upload = false;
|
||||||
}
|
}
|
||||||
@ -120,8 +124,8 @@ pub async fn delete_sound(
|
|||||||
|
|
||||||
let pool = ctx.data().database.clone();
|
let pool = ctx.data().database.clone();
|
||||||
|
|
||||||
let uid = ctx.author().id.0;
|
let uid = ctx.author().id.get();
|
||||||
let gid = ctx.guild_id().unwrap().0;
|
let gid = ctx.guild_id().unwrap().get();
|
||||||
|
|
||||||
let sound_vec = ctx.data().search_for_sound(&name, gid, uid, true).await?;
|
let sound_vec = ctx.data().search_for_sound(&name, gid, uid, true).await?;
|
||||||
let sound_result = sound_vec.first();
|
let sound_result = sound_vec.first();
|
||||||
@ -173,8 +177,8 @@ pub async fn change_public(
|
|||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let pool = ctx.data().database.clone();
|
let pool = ctx.data().database.clone();
|
||||||
|
|
||||||
let uid = ctx.author().id.0;
|
let uid = ctx.author().id.get();
|
||||||
let gid = ctx.guild_id().unwrap().0;
|
let gid = ctx.guild_id().unwrap().get();
|
||||||
|
|
||||||
let mut sound_vec = ctx.data().search_for_sound(&name, gid, uid, true).await?;
|
let mut sound_vec = ctx.data().search_for_sound(&name, gid, uid, true).await?;
|
||||||
let sound_result = sound_vec.first_mut();
|
let sound_result = sound_vec.first_mut();
|
||||||
@ -228,7 +232,10 @@ pub async fn download_file(
|
|||||||
let file = File::open(&source).await?;
|
let file = File::open(&source).await?;
|
||||||
let name = format!("{}-{}.opus", sound.id, sound.name);
|
let name = format!("{}-{}.opus", sound.id, sound.name);
|
||||||
|
|
||||||
ctx.send(|m| m.attachment((&file, name.as_str()).into()))
|
ctx.send(
|
||||||
|
CreateReply::default()
|
||||||
|
.attachment(CreateAttachment::file(&file, name.as_str()).await?),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use poise::serenity_prelude::AutocompleteChoice;
|
||||||
|
|
||||||
use crate::{models::sound::SoundCtx, Context};
|
use crate::{models::sound::SoundCtx, Context};
|
||||||
|
|
||||||
pub mod favorite;
|
pub mod favorite;
|
||||||
@ -8,34 +10,22 @@ pub mod search;
|
|||||||
pub mod settings;
|
pub mod settings;
|
||||||
pub mod stop;
|
pub mod stop;
|
||||||
|
|
||||||
pub async fn autocomplete_sound(
|
pub async fn autocomplete_sound(ctx: Context<'_>, partial: &str) -> Vec<AutocompleteChoice> {
|
||||||
ctx: Context<'_>,
|
|
||||||
partial: &str,
|
|
||||||
) -> Vec<poise::AutocompleteChoice<String>> {
|
|
||||||
ctx.data()
|
ctx.data()
|
||||||
.autocomplete_user_sounds(&partial, ctx.author().id, ctx.guild_id().unwrap())
|
.autocomplete_user_sounds(&partial, ctx.author().id, ctx.guild_id().unwrap())
|
||||||
.await
|
.await
|
||||||
.unwrap_or(vec![])
|
.unwrap_or(vec![])
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| poise::AutocompleteChoice {
|
.map(|s| AutocompleteChoice::new(s.name.clone(), s.id.to_string()))
|
||||||
name: s.name.clone(),
|
|
||||||
value: s.id.to_string(),
|
|
||||||
})
|
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn autocomplete_favorite(
|
pub async fn autocomplete_favorite(ctx: Context<'_>, partial: &str) -> Vec<AutocompleteChoice> {
|
||||||
ctx: Context<'_>,
|
|
||||||
partial: &str,
|
|
||||||
) -> Vec<poise::AutocompleteChoice<String>> {
|
|
||||||
ctx.data()
|
ctx.data()
|
||||||
.autocomplete_favorite_sounds(&partial, ctx.author().id)
|
.autocomplete_favorite_sounds(&partial, ctx.author().id)
|
||||||
.await
|
.await
|
||||||
.unwrap_or(vec![])
|
.unwrap_or(vec![])
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| poise::AutocompleteChoice {
|
.map(|s| AutocompleteChoice::new(s.name.clone(), s.id.to_string()))
|
||||||
name: s.name.clone(),
|
|
||||||
value: s.id.to_string(),
|
|
||||||
})
|
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
use poise::serenity_prelude::{
|
use poise::{
|
||||||
builder::CreateActionRow, model::application::component::ButtonStyle, GuildChannel,
|
serenity_prelude::{
|
||||||
ReactionType,
|
builder::CreateActionRow, ButtonStyle, CreateButton, GuildChannel, ReactionType,
|
||||||
|
},
|
||||||
|
CreateReply,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "metrics")]
|
#[cfg(feature = "metrics")]
|
||||||
@ -74,8 +76,7 @@ pub async fn play_random(
|
|||||||
|
|
||||||
match channel_to_join {
|
match channel_to_join {
|
||||||
Some(channel) => {
|
Some(channel) => {
|
||||||
let (call_handler, _) =
|
let call = join_channel(ctx.serenity_context(), &guild.clone(), channel).await?;
|
||||||
join_channel(ctx.serenity_context(), guild.clone(), channel).await;
|
|
||||||
|
|
||||||
let sounds = ctx.data().guild_sounds(guild.id, None).await?;
|
let sounds = ctx.data().guild_sounds(guild.id, None).await?;
|
||||||
if sounds.len() == 0 {
|
if sounds.len() == 0 {
|
||||||
@ -92,7 +93,7 @@ pub async fn play_random(
|
|||||||
match sounds.get(ts.subsec_micros() as usize % sounds.len()) {
|
match sounds.get(ts.subsec_micros() as usize % sounds.len()) {
|
||||||
Some(sound) => {
|
Some(sound) => {
|
||||||
let guild_data = ctx.data().guild_data(guild.id).await.unwrap();
|
let guild_data = ctx.data().guild_data(guild.id).await.unwrap();
|
||||||
let mut lock = call_handler.lock().await;
|
let mut lock = call.lock().await;
|
||||||
|
|
||||||
play_audio(
|
play_audio(
|
||||||
sound,
|
sound,
|
||||||
@ -218,8 +219,7 @@ pub async fn queue_play(
|
|||||||
|
|
||||||
match channel_to_join {
|
match channel_to_join {
|
||||||
Some(user_channel) => {
|
Some(user_channel) => {
|
||||||
let (call_handler, _) =
|
let call = join_channel(ctx.serenity_context(), guild, user_channel).await?;
|
||||||
join_channel(ctx.serenity_context(), guild.clone(), user_channel).await;
|
|
||||||
|
|
||||||
let guild_data = ctx
|
let guild_data = ctx
|
||||||
.data()
|
.data()
|
||||||
@ -227,8 +227,6 @@ pub async fn queue_play(
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut lock = call_handler.lock().await;
|
|
||||||
|
|
||||||
let query_terms = [
|
let query_terms = [
|
||||||
Some(sound_1),
|
Some(sound_1),
|
||||||
Some(sound_2),
|
Some(sound_2),
|
||||||
@ -270,6 +268,9 @@ pub async fn queue_play(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut lock = call.lock().await;
|
||||||
|
|
||||||
queue_audio(
|
queue_audio(
|
||||||
&sounds,
|
&sounds,
|
||||||
guild_data.read().await.volume,
|
guild_data.read().await.volume,
|
||||||
@ -278,6 +279,7 @@ pub async fn queue_play(
|
|||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
ctx.say(format!("Queued {} sounds!", sounds.len())).await?;
|
ctx.say(format!("Queued {} sounds!", sounds.len())).await?;
|
||||||
}
|
}
|
||||||
@ -434,50 +436,49 @@ pub async fn soundboard(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.send(|m| {
|
let components = {
|
||||||
m.content("**Play a sound:**").components(|c| {
|
let mut c = vec![];
|
||||||
for row in sounds.as_slice().chunks(5) {
|
for row in sounds.as_slice().chunks(5) {
|
||||||
let mut action_row: CreateActionRow = Default::default();
|
let mut action_row = vec![];
|
||||||
for sound in row {
|
for sound in row {
|
||||||
action_row.create_button(|b| {
|
action_row.push(
|
||||||
b.style(ButtonStyle::Primary)
|
CreateButton::new(sound.id.to_string())
|
||||||
.label(&sound.name)
|
.style(ButtonStyle::Primary)
|
||||||
.custom_id(sound.id)
|
.label(&sound.name),
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
c.add_action_row(action_row);
|
c.push(CreateActionRow::Buttons(action_row));
|
||||||
}
|
}
|
||||||
|
|
||||||
c.create_action_row(|r| {
|
c.push(CreateActionRow::Buttons(vec![
|
||||||
r.create_button(|b| {
|
CreateButton::new("#stop")
|
||||||
b.label("Stop")
|
.label("Stop")
|
||||||
.emoji(ReactionType::Unicode("⏹".to_string()))
|
.emoji(ReactionType::Unicode("⏹".to_string()))
|
||||||
.style(ButtonStyle::Danger)
|
.style(ButtonStyle::Danger),
|
||||||
.custom_id("#stop")
|
CreateButton::new("#mode")
|
||||||
})
|
.label("Mode:")
|
||||||
.create_button(|b| {
|
|
||||||
b.label("Mode:")
|
|
||||||
.style(ButtonStyle::Secondary)
|
.style(ButtonStyle::Secondary)
|
||||||
.disabled(true)
|
.disabled(true),
|
||||||
.custom_id("#mode")
|
CreateButton::new("#instant")
|
||||||
})
|
.label("Instant")
|
||||||
.create_button(|b| {
|
|
||||||
b.label("Instant")
|
|
||||||
.emoji(ReactionType::Unicode("▶".to_string()))
|
.emoji(ReactionType::Unicode("▶".to_string()))
|
||||||
.style(ButtonStyle::Secondary)
|
.style(ButtonStyle::Secondary)
|
||||||
.disabled(true)
|
.disabled(true),
|
||||||
.custom_id("#instant")
|
CreateButton::new("#loop")
|
||||||
})
|
.label("Loop")
|
||||||
.create_button(|b| {
|
|
||||||
b.label("Loop")
|
|
||||||
.emoji(ReactionType::Unicode("🔁".to_string()))
|
.emoji(ReactionType::Unicode("🔁".to_string()))
|
||||||
.style(ButtonStyle::Secondary)
|
.style(ButtonStyle::Secondary),
|
||||||
.custom_id("#loop")
|
]));
|
||||||
})
|
|
||||||
})
|
c
|
||||||
})
|
};
|
||||||
})
|
|
||||||
|
ctx.send(
|
||||||
|
CreateReply::default()
|
||||||
|
.content("**Play a sound:**")
|
||||||
|
.components(components),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
use poise::{
|
use poise::{
|
||||||
serenity_prelude,
|
serenity_prelude,
|
||||||
serenity_prelude::{
|
serenity_prelude::{
|
||||||
application::component::ButtonStyle,
|
constants::MESSAGE_CODE_LIMIT, ButtonStyle, ComponentInteraction, CreateActionRow,
|
||||||
constants::MESSAGE_CODE_LIMIT,
|
CreateButton, CreateEmbed, EditInteractionResponse, GuildId, UserId,
|
||||||
interaction::{message_component::MessageComponentInteraction, InteractionResponseType},
|
|
||||||
CreateActionRow, CreateEmbed, GuildId, UserId,
|
|
||||||
},
|
},
|
||||||
CreateReply,
|
CreateReply,
|
||||||
};
|
};
|
||||||
@ -16,7 +14,7 @@ use crate::{
|
|||||||
Context, Data, Error,
|
Context, Data, Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn format_search_results<'a>(search_results: Vec<Sound>) -> CreateReply<'a> {
|
fn format_search_results(search_results: Vec<Sound>) -> CreateReply {
|
||||||
let mut builder = CreateReply::default();
|
let mut builder = CreateReply::default();
|
||||||
|
|
||||||
let mut current_character_count = 0;
|
let mut current_character_count = 0;
|
||||||
@ -32,7 +30,7 @@ fn format_search_results<'a>(search_results: Vec<Sound>) -> CreateReply<'a> {
|
|||||||
current_character_count <= MESSAGE_CODE_LIMIT - title.len()
|
current_character_count <= MESSAGE_CODE_LIMIT - title.len()
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.embed(|e| e.title(title).fields(field_iter));
|
builder.embed(CreateEmbed::default().title(title).fields(field_iter));
|
||||||
|
|
||||||
builder
|
builder
|
||||||
}
|
}
|
||||||
@ -124,10 +122,8 @@ impl SoundPager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create_action_row(&self, max_page: u64) -> CreateActionRow {
|
fn create_action_row(&self, max_page: u64) -> CreateActionRow {
|
||||||
let mut row = CreateActionRow::default();
|
let mut row = CreateActionRow::Buttons(vec![
|
||||||
|
CreateButton::new(
|
||||||
row.create_button(|b| {
|
|
||||||
b.custom_id(
|
|
||||||
serde_json::to_string(&SoundPager {
|
serde_json::to_string(&SoundPager {
|
||||||
nonce: 0,
|
nonce: 0,
|
||||||
page: 0,
|
page: 0,
|
||||||
@ -137,10 +133,8 @@ impl SoundPager {
|
|||||||
)
|
)
|
||||||
.style(ButtonStyle::Primary)
|
.style(ButtonStyle::Primary)
|
||||||
.label("⏪")
|
.label("⏪")
|
||||||
.disabled(self.page == 0)
|
.disabled(self.page == 0),
|
||||||
})
|
CreateButton::new(
|
||||||
.create_button(|b| {
|
|
||||||
b.custom_id(
|
|
||||||
serde_json::to_string(&SoundPager {
|
serde_json::to_string(&SoundPager {
|
||||||
nonce: 1,
|
nonce: 1,
|
||||||
page: self.page.saturating_sub(1),
|
page: self.page.saturating_sub(1),
|
||||||
@ -150,16 +144,12 @@ impl SoundPager {
|
|||||||
)
|
)
|
||||||
.style(ButtonStyle::Secondary)
|
.style(ButtonStyle::Secondary)
|
||||||
.label("◀️")
|
.label("◀️")
|
||||||
.disabled(self.page == 0)
|
.disabled(self.page == 0),
|
||||||
})
|
CreateButton::new("pid")
|
||||||
.create_button(|b| {
|
|
||||||
b.custom_id("pid")
|
|
||||||
.style(ButtonStyle::Success)
|
.style(ButtonStyle::Success)
|
||||||
.label(format!("Page {}", self.page + 1))
|
.label(format!("Page {}", self.page + 1))
|
||||||
.disabled(true)
|
.disabled(true),
|
||||||
})
|
CreateButton::new(
|
||||||
.create_button(|b| {
|
|
||||||
b.custom_id(
|
|
||||||
serde_json::to_string(&SoundPager {
|
serde_json::to_string(&SoundPager {
|
||||||
nonce: 2,
|
nonce: 2,
|
||||||
page: self.page.saturating_add(1),
|
page: self.page.saturating_add(1),
|
||||||
@ -169,10 +159,8 @@ impl SoundPager {
|
|||||||
)
|
)
|
||||||
.style(ButtonStyle::Secondary)
|
.style(ButtonStyle::Secondary)
|
||||||
.label("▶️")
|
.label("▶️")
|
||||||
.disabled(self.page == max_page)
|
.disabled(self.page == max_page),
|
||||||
})
|
CreateButton::new(
|
||||||
.create_button(|b| {
|
|
||||||
b.custom_id(
|
|
||||||
serde_json::to_string(&SoundPager {
|
serde_json::to_string(&SoundPager {
|
||||||
nonce: 3,
|
nonce: 3,
|
||||||
page: max_page,
|
page: max_page,
|
||||||
@ -182,16 +170,14 @@ impl SoundPager {
|
|||||||
)
|
)
|
||||||
.style(ButtonStyle::Primary)
|
.style(ButtonStyle::Primary)
|
||||||
.label("⏩")
|
.label("⏩")
|
||||||
.disabled(self.page == max_page)
|
.disabled(self.page == max_page),
|
||||||
});
|
]);
|
||||||
|
|
||||||
row
|
row
|
||||||
}
|
}
|
||||||
|
|
||||||
fn embed(&self, sounds: &[Sound], count: u64) -> CreateEmbed {
|
fn embed(&self, sounds: &[Sound], count: u64) -> CreateEmbed {
|
||||||
let mut embed = CreateEmbed::default();
|
CreateEmbed::default()
|
||||||
|
|
||||||
embed
|
|
||||||
.color(THEME_COLOR)
|
.color(THEME_COLOR)
|
||||||
.title(self.context.title())
|
.title(self.context.title())
|
||||||
.description(format!("**{}** sounds:", count))
|
.description(format!("**{}** sounds:", count))
|
||||||
@ -205,15 +191,13 @@ impl SoundPager {
|
|||||||
),
|
),
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
}));
|
}))
|
||||||
|
|
||||||
embed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_interaction(
|
pub async fn handle_interaction(
|
||||||
ctx: &serenity_prelude::Context,
|
ctx: &serenity_prelude::Context,
|
||||||
data: &Data,
|
data: &Data,
|
||||||
interaction: &MessageComponentInteraction,
|
interaction: &ComponentInteraction,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let user_id = interaction.user.id;
|
let user_id = interaction.user.id;
|
||||||
let guild_id = interaction.guild_id.unwrap();
|
let guild_id = interaction.guild_id.unwrap();
|
||||||
@ -227,14 +211,12 @@ impl SoundPager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
interaction
|
interaction
|
||||||
.create_interaction_response(&ctx, |r| {
|
.edit_response(
|
||||||
r.kind(InteractionResponseType::UpdateMessage)
|
&ctx,
|
||||||
.interaction_response_data(|d| {
|
EditInteractionResponse::default()
|
||||||
d.ephemeral(true)
|
|
||||||
.add_embed(pager.embed(&sounds, count))
|
.add_embed(pager.embed(&sounds, count))
|
||||||
.components(|c| c.add_action_row(pager.create_action_row(count / 25)))
|
.components(vec![pager.create_action_row(count / 25)]),
|
||||||
})
|
)
|
||||||
})
|
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -254,14 +236,12 @@ impl SoundPager {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ctx.send(|r| {
|
ctx.send(
|
||||||
r.ephemeral(true)
|
CreateReply::default()
|
||||||
.embed(|e| {
|
.ephemeral(true)
|
||||||
*e = self.embed(&sounds, count);
|
.embed(self.embed(&sounds, count))
|
||||||
e
|
.components(vec![self.create_action_row(count / 25)]),
|
||||||
})
|
)
|
||||||
.components(|c| c.add_action_row(self.create_action_row(count / 25)))
|
|
||||||
})
|
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -284,11 +264,7 @@ pub async fn search_sounds(
|
|||||||
.search_for_sound(&query, ctx.guild_id().unwrap(), ctx.author().id, false)
|
.search_for_sound(&query, ctx.guild_id().unwrap(), ctx.author().id, false)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
ctx.send(|m| {
|
ctx.send(format_search_results(search_results)).await?;
|
||||||
*m = format_search_results(search_results);
|
|
||||||
m
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
use poise::serenity_prelude::{GuildId, User};
|
use poise::{
|
||||||
|
serenity_prelude::{GuildId, User},
|
||||||
|
CreateReply,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cmds::autocomplete_sound,
|
cmds::autocomplete_sound,
|
||||||
@ -60,14 +63,14 @@ pub async fn set_guild_greet_sound(
|
|||||||
#[description = "User to set join sound for"] user: User,
|
#[description = "User to set join sound for"] user: User,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if user.id != ctx.author().id {
|
if user.id != ctx.author().id {
|
||||||
let guild = ctx.guild().unwrap();
|
let permissions = ctx.author_member().await.unwrap().permissions(&ctx.cache());
|
||||||
let permissions = guild.member_permissions(&ctx, ctx.author().id).await;
|
|
||||||
|
|
||||||
if permissions.map_or(true, |p| !p.manage_guild()) {
|
if permissions.map_or(true, |p| !p.manage_guild()) {
|
||||||
ctx.send(|b| {
|
ctx.send(
|
||||||
b.ephemeral(true)
|
CreateReply::default()
|
||||||
.content("Only admins can change other user's greet sounds.")
|
.ephemeral(true)
|
||||||
})
|
.content("Only admins can change other user's greet sounds."),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -107,14 +110,14 @@ pub async fn unset_guild_greet_sound(
|
|||||||
#[description = "User to set join sound for"] user: User,
|
#[description = "User to set join sound for"] user: User,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if user.id != ctx.author().id {
|
if user.id != ctx.author().id {
|
||||||
let guild = ctx.guild().unwrap();
|
let permissions = ctx.author_member().await.unwrap().permissions(&ctx.cache());
|
||||||
let permissions = guild.member_permissions(&ctx, ctx.author().id).await;
|
|
||||||
|
|
||||||
if permissions.map_or(true, |p| !p.manage_guild()) {
|
if permissions.map_or(true, |p| !p.manage_guild()) {
|
||||||
ctx.send(|b| {
|
ctx.send(
|
||||||
b.ephemeral(true)
|
CreateReply::default()
|
||||||
.content("Only admins can change other user's greet sounds.")
|
.ephemeral(true)
|
||||||
})
|
.content("Only admins can change other user's greet sounds."),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -155,20 +158,19 @@ pub async fn set_user_greet_sound(
|
|||||||
.update_join_sound(ctx.author().id, None::<GuildId>, Some(sound.id))
|
.update_join_sound(ctx.author().id, None::<GuildId>, Some(sound.id))
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
ctx.send(|b| {
|
ctx.send(CreateReply::default().ephemeral(true).content(format!(
|
||||||
b.ephemeral(true).content(format!(
|
|
||||||
"Greet sound has been set to {} (ID {})",
|
"Greet sound has been set to {} (ID {})",
|
||||||
sound.name, sound.id
|
sound.name, sound.id
|
||||||
))
|
)))
|
||||||
})
|
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
None => {
|
None => {
|
||||||
ctx.send(|b| {
|
ctx.send(
|
||||||
b.ephemeral(true)
|
CreateReply::default()
|
||||||
.content("Could not find a sound by that name.")
|
.ephemeral(true)
|
||||||
})
|
.content("Could not find a sound by that name."),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -183,7 +185,11 @@ pub async fn unset_user_greet_sound(ctx: Context<'_>) -> Result<(), Error> {
|
|||||||
.update_join_sound(ctx.author().id, None::<GuildId>, None)
|
.update_join_sound(ctx.author().id, None::<GuildId>, None)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
ctx.send(|b| b.ephemeral(true).content("Greet sound has been unset"))
|
ctx.send(
|
||||||
|
CreateReply::default()
|
||||||
|
.ephemeral(true)
|
||||||
|
.content("Greet sound has been unset"),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
use poise::serenity_prelude::{
|
use poise::serenity_prelude::{
|
||||||
model::{
|
model::channel::Channel, ActionRowComponent, Activity, Context, CreateActionRow, FullEvent,
|
||||||
application::interaction::{Interaction, InteractionResponseType},
|
Interaction,
|
||||||
channel::Channel,
|
|
||||||
},
|
|
||||||
ActionRowComponent, Activity, Context, CreateActionRow, CreateComponents,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "metrics")]
|
#[cfg(feature = "metrics")]
|
||||||
@ -19,16 +16,18 @@ use crate::{
|
|||||||
Data, Error,
|
Data, Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub async fn listener(ctx: &Context, event: &poise::Event<'_>, data: &Data) -> Result<(), Error> {
|
pub async fn listener(ctx: &Context, event: &FullEvent, data: &Data) -> Result<(), Error> {
|
||||||
match event {
|
match event {
|
||||||
poise::Event::Ready { .. } => {
|
FullEvent::Ready { .. } => {
|
||||||
ctx.set_activity(Activity::watching("for /play")).await;
|
ctx.set_activity(Activity::watching("for /play")).await;
|
||||||
}
|
}
|
||||||
poise::Event::VoiceStateUpdate { old, new, .. } => {
|
FullEvent::VoiceStateUpdate { old, new, .. } => {
|
||||||
if let Some(past_state) = old {
|
if let Some(past_state) = old {
|
||||||
if let (Some(guild_id), None) = (past_state.guild_id, new.channel_id) {
|
if let (Some(guild_id), None) = (past_state.guild_id, new.channel_id) {
|
||||||
if let Some(channel_id) = past_state.channel_id {
|
if let Some(channel_id) = past_state.channel_id {
|
||||||
if let Some(Channel::Guild(channel)) = channel_id.to_channel_cached(&ctx) {
|
if let Some(Channel::Guild(channel)) =
|
||||||
|
channel_id.to_channel_cached(&ctx.cache)
|
||||||
|
{
|
||||||
if channel.members(&ctx).await.map(|m| m.len()).unwrap_or(0) <= 1 {
|
if channel.members(&ctx).await.map(|m| m.len()).unwrap_or(0) <= 1 {
|
||||||
let songbird = songbird::get(ctx).await.unwrap();
|
let songbird = songbird::get(ctx).await.unwrap();
|
||||||
|
|
||||||
@ -93,7 +92,7 @@ pub async fn listener(ctx: &Context, event: &poise::Event<'_>, data: &Data) -> R
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
poise::Event::InteractionCreate { interaction } => match interaction {
|
FullEvent::InteractionCreate { interaction } => match interaction {
|
||||||
Interaction::MessageComponent(component) => {
|
Interaction::MessageComponent(component) => {
|
||||||
if let Some(guild_id) = component.guild_id {
|
if let Some(guild_id) = component.guild_id {
|
||||||
if let Ok(()) = SoundPager::handle_interaction(ctx, &data, component).await {
|
if let Ok(()) = SoundPager::handle_interaction(ctx, &data, component).await {
|
||||||
@ -123,7 +122,7 @@ pub async fn listener(ctx: &Context, event: &poise::Event<'_>, data: &Data) -> R
|
|||||||
.create_interaction_response(ctx, |r| {
|
.create_interaction_response(ctx, |r| {
|
||||||
r.kind(InteractionResponseType::UpdateMessage)
|
r.kind(InteractionResponseType::UpdateMessage)
|
||||||
.interaction_response_data(|d| {
|
.interaction_response_data(|d| {
|
||||||
let mut c: CreateComponents = Default::default();
|
let mut c = vec![];
|
||||||
|
|
||||||
for action_row in &component.message.components {
|
for action_row in &component.message.components {
|
||||||
let mut a: CreateActionRow = Default::default();
|
let mut a: CreateActionRow = Default::default();
|
||||||
@ -176,7 +175,7 @@ pub async fn listener(ctx: &Context, event: &poise::Event<'_>, data: &Data) -> R
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.add_action_row(a);
|
c.push(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
d.set_components(c)
|
d.set_components(c)
|
||||||
|
42
src/main.rs
42
src/main.rs
@ -14,13 +14,13 @@ use std::{env, path::Path, sync::Arc};
|
|||||||
|
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use poise::serenity_prelude::{
|
use poise::serenity_prelude::{
|
||||||
builder::CreateApplicationCommands,
|
|
||||||
model::{
|
model::{
|
||||||
gateway::GatewayIntents,
|
gateway::GatewayIntents,
|
||||||
id::{GuildId, UserId},
|
id::{GuildId, UserId},
|
||||||
},
|
},
|
||||||
|
ClientBuilder,
|
||||||
};
|
};
|
||||||
use songbird::SerenityInit;
|
use serde_json::Value;
|
||||||
use sqlx::{MySql, Pool};
|
use sqlx::{MySql, Pool};
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
@ -40,29 +40,20 @@ type Context<'a> = poise::Context<'a, Data, Error>;
|
|||||||
pub async fn register_application_commands(
|
pub async fn register_application_commands(
|
||||||
ctx: &poise::serenity_prelude::Context,
|
ctx: &poise::serenity_prelude::Context,
|
||||||
framework: &poise::Framework<Data, Error>,
|
framework: &poise::Framework<Data, Error>,
|
||||||
guild_id: Option<GuildId>,
|
|
||||||
) -> Result<(), poise::serenity_prelude::Error> {
|
) -> Result<(), poise::serenity_prelude::Error> {
|
||||||
let mut commands_builder = CreateApplicationCommands::default();
|
let mut commands_builder = vec![];
|
||||||
let commands = &framework.options().commands;
|
let commands = &framework.options().commands;
|
||||||
for command in commands {
|
for command in commands {
|
||||||
if let Some(slash_command) = command.create_as_slash_command() {
|
if let Some(slash_command) = command.create_as_slash_command() {
|
||||||
commands_builder.add_application_command(slash_command);
|
commands_builder.push(slash_command.into());
|
||||||
}
|
}
|
||||||
if let Some(context_menu_command) = command.create_as_context_menu_command() {
|
if let Some(context_menu_command) = command.create_as_context_menu_command() {
|
||||||
commands_builder.add_application_command(context_menu_command);
|
commands_builder.push(context_menu_command.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let commands_builder = poise::serenity_prelude::json::Value::Array(commands_builder.0);
|
let commands_builder = Value::Array(commands_builder);
|
||||||
|
|
||||||
if let Some(guild_id) = guild_id {
|
ctx.http.create_global_commands(&commands_builder).await?;
|
||||||
ctx.http
|
|
||||||
.create_guild_application_commands(guild_id.0, &commands_builder)
|
|
||||||
.await?;
|
|
||||||
} else {
|
|
||||||
ctx.http
|
|
||||||
.create_global_application_commands(&commands_builder)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -149,13 +140,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
tokio::spawn(async { metrics::serve().await });
|
tokio::spawn(async { metrics::serve().await });
|
||||||
}
|
}
|
||||||
|
|
||||||
poise::Framework::builder()
|
let framework = poise::Framework::builder()
|
||||||
.token(discord_token)
|
|
||||||
.setup(move |ctx, _bot, framework| {
|
.setup(move |ctx, _bot, framework| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
register_application_commands(ctx, framework, None)
|
register_application_commands(ctx, framework).await.unwrap();
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
Ok(Data {
|
Ok(Data {
|
||||||
database,
|
database,
|
||||||
@ -165,10 +153,16 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
.options(options)
|
.options(options)
|
||||||
.client_settings(move |client_builder| client_builder.register_songbird())
|
.build();
|
||||||
.intents(GatewayIntents::GUILD_VOICE_STATES | GatewayIntents::GUILDS)
|
|
||||||
.run_autosharded()
|
let mut client = ClientBuilder::new(
|
||||||
|
&discord_token,
|
||||||
|
GatewayIntents::GUILD_VOICE_STATES | GatewayIntents::GUILDS,
|
||||||
|
)
|
||||||
|
.framework(framework)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
client.start_autosharded().await.unwrap();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -78,12 +78,10 @@ impl GuildData {
|
|||||||
|
|
||||||
let guild_data = sqlx::query_as_unchecked!(
|
let guild_data = sqlx::query_as_unchecked!(
|
||||||
GuildData,
|
GuildData,
|
||||||
"
|
"SELECT id, prefix, volume, allow_greets, allowed_role
|
||||||
SELECT id, prefix, volume, allow_greets, allowed_role
|
|
||||||
FROM servers
|
FROM servers
|
||||||
WHERE id = ?
|
WHERE id = ?",
|
||||||
",
|
guild_id.get()
|
||||||
guild_id.as_u64()
|
|
||||||
)
|
)
|
||||||
.fetch_one(db_pool)
|
.fetch_one(db_pool)
|
||||||
.await;
|
.await;
|
||||||
@ -104,17 +102,15 @@ SELECT id, prefix, volume, allow_greets, allowed_role
|
|||||||
let guild_id = guild_id.into();
|
let guild_id = guild_id.into();
|
||||||
|
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"
|
"INSERT INTO servers (id)
|
||||||
INSERT INTO servers (id)
|
VALUES (?)",
|
||||||
VALUES (?)
|
guild_id.get()
|
||||||
",
|
|
||||||
guild_id.as_u64()
|
|
||||||
)
|
)
|
||||||
.execute(db_pool)
|
.execute(db_pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(GuildData {
|
Ok(GuildData {
|
||||||
id: guild_id.as_u64().to_owned(),
|
id: guild_id.get(),
|
||||||
prefix: String::from("?"),
|
prefix: String::from("?"),
|
||||||
volume: 100,
|
volume: 100,
|
||||||
allow_greets: AllowGreet::Enabled,
|
allow_greets: AllowGreet::Enabled,
|
||||||
|
@ -47,14 +47,13 @@ impl JoinSoundCtx for Data {
|
|||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
JoinSound,
|
JoinSound,
|
||||||
"
|
"
|
||||||
SELECT join_sound_id
|
SELECT join_sound_id
|
||||||
FROM join_sounds
|
FROM join_sounds
|
||||||
WHERE user = ?
|
WHERE user = ?
|
||||||
AND guild = ?
|
AND guild = ?
|
||||||
ORDER BY guild IS NULL
|
ORDER BY guild IS NULL",
|
||||||
",
|
user_id.get(),
|
||||||
user_id.as_u64(),
|
guild_id.map(|g| g.get())
|
||||||
guild_id.map(|g| g.0)
|
|
||||||
)
|
)
|
||||||
.fetch_one(&self.database)
|
.fetch_one(&self.database)
|
||||||
.await
|
.await
|
||||||
@ -62,14 +61,13 @@ SELECT join_sound_id
|
|||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
JoinSound,
|
JoinSound,
|
||||||
"
|
"
|
||||||
SELECT join_sound_id
|
SELECT join_sound_id
|
||||||
FROM join_sounds
|
FROM join_sounds
|
||||||
WHERE user = ?
|
WHERE user = ?
|
||||||
AND (guild IS NULL OR guild = ?)
|
AND (guild IS NULL OR guild = ?)
|
||||||
ORDER BY guild IS NULL
|
ORDER BY guild IS NULL",
|
||||||
",
|
user_id.get(),
|
||||||
user_id.as_u64(),
|
guild_id.map(|g| g.get())
|
||||||
guild_id.map(|g| g.0)
|
|
||||||
)
|
)
|
||||||
.fetch_one(&self.database)
|
.fetch_one(&self.database)
|
||||||
.await
|
.await
|
||||||
@ -111,17 +109,17 @@ SELECT join_sound_id
|
|||||||
Some(join_id) => {
|
Some(join_id) => {
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"DELETE FROM join_sounds WHERE user = ? AND guild <=> ?",
|
"DELETE FROM join_sounds WHERE user = ? AND guild <=> ?",
|
||||||
user_id.0,
|
user_id.get(),
|
||||||
guild_id.map(|g| g.0)
|
guild_id.map(|g| g.get())
|
||||||
)
|
)
|
||||||
.execute(&mut transaction)
|
.execute(&mut transaction)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"INSERT INTO join_sounds (user, join_sound_id, guild) VALUES (?, ?, ?)",
|
"INSERT INTO join_sounds (user, join_sound_id, guild) VALUES (?, ?, ?)",
|
||||||
user_id.0,
|
user_id.get(),
|
||||||
join_id,
|
join_id,
|
||||||
guild_id.map(|g| g.0)
|
guild_id.map(|g| g.get())
|
||||||
)
|
)
|
||||||
.execute(&mut transaction)
|
.execute(&mut transaction)
|
||||||
.await?;
|
.await?;
|
||||||
@ -130,8 +128,8 @@ SELECT join_sound_id
|
|||||||
None => {
|
None => {
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"DELETE FROM join_sounds WHERE user = ? AND guild <=> ?",
|
"DELETE FROM join_sounds WHERE user = ? AND guild <=> ?",
|
||||||
user_id.0,
|
user_id.get(),
|
||||||
guild_id.map(|g| g.0)
|
guild_id.map(|g| g.get())
|
||||||
)
|
)
|
||||||
.execute(&mut transaction)
|
.execute(&mut transaction)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::{env, path::Path};
|
use std::{env, path::Path};
|
||||||
|
|
||||||
use poise::serenity_prelude::async_trait;
|
use poise::serenity_prelude::async_trait;
|
||||||
use songbird::input::restartable::Restartable;
|
use songbird::input::Input;
|
||||||
use sqlx::Executor;
|
use sqlx::Executor;
|
||||||
use tokio::{fs::File, io::AsyncWriteExt, process::Command};
|
use tokio::{fs::File, io::AsyncWriteExt, process::Command};
|
||||||
|
|
||||||
@ -441,12 +441,10 @@ impl Sound {
|
|||||||
pub async fn playable(
|
pub async fn playable(
|
||||||
&self,
|
&self,
|
||||||
db_pool: impl Executor<'_, Database = Database>,
|
db_pool: impl Executor<'_, Database = Database>,
|
||||||
) -> Result<Restartable, Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<Input, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let path_name = self.store_sound_source(db_pool).await?;
|
let path_name = self.store_sound_source(db_pool).await?;
|
||||||
|
|
||||||
Ok(Restartable::ffmpeg(path_name, false)
|
Ok(Input::from(path_name))
|
||||||
.await
|
|
||||||
.expect("FFMPEG ERROR!"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn count_user_sounds<U: Into<u64>>(
|
pub async fn count_user_sounds<U: Into<u64>>(
|
||||||
|
75
src/utils.rs
75
src/utils.rs
@ -1,11 +1,13 @@
|
|||||||
use std::sync::Arc;
|
use std::{ops::Deref, sync::Arc};
|
||||||
|
|
||||||
use poise::serenity_prelude::model::{
|
use poise::serenity_prelude::{
|
||||||
channel::Channel,
|
model::{
|
||||||
guild::Guild,
|
guild::Guild,
|
||||||
id::{ChannelId, UserId},
|
id::{ChannelId, UserId},
|
||||||
|
},
|
||||||
|
EditVoiceState,
|
||||||
};
|
};
|
||||||
use songbird::{create_player, error::JoinResult, tracks::TrackHandle, Call};
|
use songbird::{tracks::TrackHandle, Call};
|
||||||
use sqlx::Executor;
|
use sqlx::Executor;
|
||||||
use tokio::sync::{Mutex, MutexGuard};
|
use tokio::sync::{Mutex, MutexGuard};
|
||||||
|
|
||||||
@ -24,19 +26,18 @@ pub async fn play_audio(
|
|||||||
db_pool: impl Executor<'_, Database = Database>,
|
db_pool: impl Executor<'_, Database = Database>,
|
||||||
r#loop: bool,
|
r#loop: bool,
|
||||||
) -> Result<TrackHandle, Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<TrackHandle, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let (track, track_handler) = create_player(sound.playable(db_pool).await?.into());
|
let track = sound.playable(db_pool).await?;
|
||||||
|
let handle = call_handler.play_input(track);
|
||||||
|
|
||||||
let _ = track_handler.set_volume(volume as f32 / 100.0);
|
handle.set_volume(volume as f32 / 100.0)?;
|
||||||
|
|
||||||
if r#loop {
|
if r#loop {
|
||||||
let _ = track_handler.enable_loop();
|
handle.enable_loop()?;
|
||||||
} else {
|
} else {
|
||||||
let _ = track_handler.disable_loop();
|
handle.disable_loop()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
call_handler.play(track);
|
Ok(handle)
|
||||||
|
|
||||||
Ok(track_handler)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn queue_audio(
|
pub async fn queue_audio(
|
||||||
@ -46,11 +47,10 @@ pub async fn queue_audio(
|
|||||||
db_pool: impl Executor<'_, Database = Database> + Copy,
|
db_pool: impl Executor<'_, Database = Database> + Copy,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
for sound in sounds {
|
for sound in sounds {
|
||||||
let (a, b) = create_player(sound.playable(db_pool).await?.into());
|
let track = sound.playable(db_pool).await?;
|
||||||
|
let handle = call_handler.enqueue_input(track).await;
|
||||||
|
|
||||||
let _ = b.set_volume(volume as f32 / 100.0);
|
handle.set_volume(volume as f32 / 100.0)?;
|
||||||
|
|
||||||
call_handler.enqueue(a);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -58,60 +58,62 @@ pub async fn queue_audio(
|
|||||||
|
|
||||||
pub async fn join_channel(
|
pub async fn join_channel(
|
||||||
ctx: &poise::serenity_prelude::Context,
|
ctx: &poise::serenity_prelude::Context,
|
||||||
guild: Guild,
|
guild: impl Deref<Target = Guild>,
|
||||||
channel_id: ChannelId,
|
channel_id: ChannelId,
|
||||||
) -> (Arc<Mutex<Call>>, JoinResult<()>) {
|
) -> Result<Arc<Mutex<Call>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let songbird = songbird::get(ctx).await.unwrap();
|
let songbird = songbird::get(ctx).await.unwrap();
|
||||||
let current_user = ctx.cache.current_user_id();
|
let current_user = ctx.cache.current_user().id;
|
||||||
|
|
||||||
let current_voice_state = guild
|
let current_voice_state = guild
|
||||||
|
.deref()
|
||||||
.voice_states
|
.voice_states
|
||||||
.get(¤t_user)
|
.get(¤t_user)
|
||||||
.and_then(|voice_state| voice_state.channel_id);
|
.and_then(|voice_state| voice_state.channel_id);
|
||||||
|
|
||||||
let (call, res) = if current_voice_state == Some(channel_id) {
|
let call = if current_voice_state == Some(channel_id) {
|
||||||
let call_opt = songbird.get(guild.id);
|
let call_opt = songbird.get(guild.deref().id);
|
||||||
|
|
||||||
if let Some(call) = call_opt {
|
if let Some(call) = call_opt {
|
||||||
(call, Ok(()))
|
Ok(call)
|
||||||
} else {
|
} else {
|
||||||
let (call, res) = songbird.join(guild.id, channel_id).await;
|
songbird.join(guild.deref().id, channel_id).await
|
||||||
|
|
||||||
(call, res)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let (call, res) = songbird.join(guild.id, channel_id).await;
|
songbird.join(guild.deref().id, channel_id).await
|
||||||
|
}?;
|
||||||
(call, res)
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
{
|
||||||
// set call to deafen
|
// set call to deafen
|
||||||
let _ = call.lock().await.deafen(true).await;
|
let _ = call.lock().await.deafen(true).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(Channel::Guild(channel)) = channel_id.to_channel_cached(&ctx) {
|
if let Some(channel) = channel_id.to_channel_cached(&ctx.cache).as_deref() {
|
||||||
let _ = channel
|
channel
|
||||||
.edit_voice_state(&ctx, ctx.cache.current_user(), |v| v.suppress(false))
|
.edit_voice_state(
|
||||||
.await;
|
&ctx,
|
||||||
|
ctx.cache.current_user().id,
|
||||||
|
EditVoiceState::new().suppress(true),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
(call, res)
|
Ok(call)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn play_from_query(
|
pub async fn play_from_query(
|
||||||
ctx: &poise::serenity_prelude::Context,
|
ctx: &poise::serenity_prelude::Context,
|
||||||
data: &Data,
|
data: &Data,
|
||||||
guild: Guild,
|
guild: impl Deref<Target = Guild>,
|
||||||
user_id: UserId,
|
user_id: UserId,
|
||||||
channel: Option<ChannelId>,
|
channel: Option<ChannelId>,
|
||||||
query: &str,
|
query: &str,
|
||||||
r#loop: bool,
|
r#loop: bool,
|
||||||
) -> String {
|
) -> String {
|
||||||
let guild_id = guild.id;
|
let guild_id = guild.deref().id;
|
||||||
|
|
||||||
let channel_to_join = channel.or_else(|| {
|
let channel_to_join = channel.or_else(|| {
|
||||||
guild
|
guild
|
||||||
|
.deref()
|
||||||
.voice_states
|
.voice_states
|
||||||
.get(&user_id)
|
.get(&user_id)
|
||||||
.and_then(|voice_state| voice_state.channel_id)
|
.and_then(|voice_state| voice_state.channel_id)
|
||||||
@ -129,8 +131,7 @@ pub async fn play_from_query(
|
|||||||
match sound_res {
|
match sound_res {
|
||||||
Some(sound) => {
|
Some(sound) => {
|
||||||
{
|
{
|
||||||
let (call_handler, _) =
|
let call_handler = join_channel(ctx, guild, user_channel).await.unwrap();
|
||||||
join_channel(ctx, guild.clone(), user_channel).await;
|
|
||||||
|
|
||||||
let guild_data = data.guild_data(guild_id).await.unwrap();
|
let guild_data = data.guild_data(guild_id).await.unwrap();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user