commit
53a8bb3127
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="SqlDialectMappings">
|
<component name="SqlDialectMappings">
|
||||||
<file url="file://$PROJECT_DIR$/create.sql" dialect="GenericSQL" />
|
<file url="file://$PROJECT_DIR$/migrations/create.sql" dialect="GenericSQL" />
|
||||||
<file url="PROJECT" dialect="MySQL" />
|
<file url="PROJECT" dialect="MySQL" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
448
Cargo.lock
generated
448
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "soundfx-rs"
|
name = "soundfx-rs"
|
||||||
version = "1.4.0"
|
version = "1.4.3"
|
||||||
authors = ["jellywx <judesouthworth@pm.me>"]
|
authors = ["jellywx <judesouthworth@pm.me>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
|
2
migrations/01-move-roles.sql
Normal file
2
migrations/01-move-roles.sql
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE servers ADD COLUMN allowed_role BIGINT;
|
||||||
|
ALTER TABLE servers DROP COLUMN name;
|
2
rustfmt.toml
Normal file
2
rustfmt.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
imports_granularity = "Crate"
|
||||||
|
group_imports = "StdExternalCrate"
|
@ -1,15 +1,13 @@
|
|||||||
use regex_command_attr::command;
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
|
use regex_command_attr::command;
|
||||||
use serenity::{client::Context, framework::standard::CommandResult};
|
use serenity::{client::Context, framework::standard::CommandResult};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
framework::{Args, CommandInvoke, CreateGenericResponse, RegexFramework},
|
framework::{Args, CommandInvoke, CommandKind, CreateGenericResponse, RegexFramework},
|
||||||
THEME_COLOR,
|
THEME_COLOR,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::framework::CommandKind;
|
|
||||||
use std::{collections::HashMap, sync::Arc};
|
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
#[group("Information")]
|
#[group("Information")]
|
||||||
#[description("Get information on the commands of the bot")]
|
#[description("Get information on the commands of the bot")]
|
||||||
@ -147,7 +145,7 @@ pub async fn help(
|
|||||||
CreateGenericResponse::new().embed(|e| {
|
CreateGenericResponse::new().embed(|e| {
|
||||||
e.title("Invalid Command")
|
e.title("Invalid Command")
|
||||||
.color(THEME_COLOR)
|
.color(THEME_COLOR)
|
||||||
.description("Type `/help command` to view help about a command below:")
|
.description("Type `/help command` to view more about a command below:")
|
||||||
.fields(groups_iter)
|
.fields(groups_iter)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
@ -173,7 +171,10 @@ pub async fn help(
|
|||||||
CreateGenericResponse::new().embed(|e| {
|
CreateGenericResponse::new().embed(|e| {
|
||||||
e.title("Help")
|
e.title("Help")
|
||||||
.color(THEME_COLOR)
|
.color(THEME_COLOR)
|
||||||
.description("Type `/help command` to view help about a command below:")
|
.description("**Welcome to SoundFX!**
|
||||||
|
To get started, upload a sound with `/upload`, or use `/search` and `/play` to look at some of the public sounds
|
||||||
|
|
||||||
|
Type `/help command` to view help about a command below:")
|
||||||
.fields(groups_iter)
|
.fields(groups_iter)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use regex_command_attr::command;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use regex_command_attr::command;
|
||||||
use serenity::{
|
use serenity::{
|
||||||
client::Context,
|
client::Context,
|
||||||
framework::standard::CommandResult,
|
framework::standard::CommandResult,
|
||||||
@ -12,8 +13,6 @@ use crate::{
|
|||||||
MySQL, MAX_SOUNDS, PATREON_GUILD, PATREON_ROLE,
|
MySQL, MAX_SOUNDS, PATREON_GUILD, PATREON_ROLE,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
#[command("upload")]
|
#[command("upload")]
|
||||||
#[group("Manage")]
|
#[group("Manage")]
|
||||||
#[description("Upload a new sound to the bot")]
|
#[description("Upload a new sound to the bot")]
|
||||||
@ -156,7 +155,7 @@ pub async fn upload_new_sound(
|
|||||||
invoke.respond(
|
invoke.respond(
|
||||||
ctx.http.clone(),
|
ctx.http.clone(),
|
||||||
CreateGenericResponse::new().content(format!(
|
CreateGenericResponse::new().content(format!(
|
||||||
"You have reached the maximum number of sounds ({}). Either delete some with `?delete` or join our Patreon for unlimited uploads at **https://patreon.com/jellywx**",
|
"You have reached the maximum number of sounds ({}). Either delete some with `/delete` or join our Patreon for unlimited uploads at **https://patreon.com/jellywx**",
|
||||||
*MAX_SOUNDS,
|
*MAX_SOUNDS,
|
||||||
))).await?;
|
))).await?;
|
||||||
}
|
}
|
||||||
@ -171,7 +170,7 @@ pub async fn upload_new_sound(
|
|||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
invoke.respond(ctx.http.clone(), CreateGenericResponse::new().content("Usage: `?upload <name>`. Please ensure the name provided is less than 20 characters in length")).await?;
|
invoke.respond(ctx.http.clone(), CreateGenericResponse::new().content("Usage: `/upload <name>`. Please ensure the name provided is less than 20 characters in length")).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
use regex_command_attr::command;
|
use std::{convert::TryFrom, time::Duration};
|
||||||
|
|
||||||
|
use regex_command_attr::command;
|
||||||
use serenity::{
|
use serenity::{
|
||||||
builder::CreateActionRow,
|
builder::CreateActionRow,
|
||||||
client::Context,
|
client::Context,
|
||||||
framework::standard::CommandResult,
|
framework::standard::CommandResult,
|
||||||
model::interactions::{message_component::ButtonStyle, InteractionResponseType},
|
model::interactions::{message_component::ButtonStyle, InteractionResponseType},
|
||||||
};
|
};
|
||||||
|
|
||||||
use songbird::{
|
use songbird::{
|
||||||
create_player, ffmpeg,
|
create_player, ffmpeg,
|
||||||
input::{cached::Memory, Input},
|
input::{cached::Memory, Input},
|
||||||
@ -22,8 +22,6 @@ use crate::{
|
|||||||
AudioIndex, MySQL,
|
AudioIndex, MySQL,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::{convert::TryFrom, time::Duration};
|
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
#[aliases("p")]
|
#[aliases("p")]
|
||||||
#[required_permissions(Managed)]
|
#[required_permissions(Managed)]
|
||||||
@ -110,13 +108,14 @@ pub async fn play_ambience(
|
|||||||
|
|
||||||
match channel_to_join {
|
match channel_to_join {
|
||||||
Some(user_channel) => {
|
Some(user_channel) => {
|
||||||
let search_name = args.named("name").unwrap().to_lowercase();
|
|
||||||
let audio_index = ctx.data.read().await.get::<AudioIndex>().cloned().unwrap();
|
let audio_index = ctx.data.read().await.get::<AudioIndex>().cloned().unwrap();
|
||||||
|
|
||||||
if let Some(filename) = audio_index.get(&search_name) {
|
if let Some(search_name) = args.named("name") {
|
||||||
|
if let Some(filename) = audio_index.get(search_name) {
|
||||||
let (track, track_handler) = create_player(
|
let (track, track_handler) = create_player(
|
||||||
Input::try_from(
|
Input::try_from(
|
||||||
Memory::new(ffmpeg(format!("audio/{}", filename)).await.unwrap()).unwrap(),
|
Memory::new(ffmpeg(format!("audio/{}", filename)).await.unwrap())
|
||||||
|
.unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
@ -168,6 +167,23 @@ __Available ambience sounds:__
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
invoke
|
||||||
|
.respond(
|
||||||
|
ctx.http.clone(),
|
||||||
|
CreateGenericResponse::new().embed(|e| {
|
||||||
|
e.title("Available Sounds").description(
|
||||||
|
audio_index
|
||||||
|
.keys()
|
||||||
|
.into_iter()
|
||||||
|
.map(|i| i.as_str())
|
||||||
|
.collect::<Vec<&str>>()
|
||||||
|
.join("\n"),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
None => {
|
None => {
|
||||||
@ -374,9 +390,11 @@ pub async fn soundboard(
|
|||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if let Some(sound) = search.first() {
|
if let Some(sound) = search.first() {
|
||||||
|
if !sounds.contains(sound) {
|
||||||
sounds.push(sound.clone());
|
sounds.push(sound.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
invoke
|
invoke
|
||||||
.followup(
|
.followup(
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use regex_command_attr::command;
|
use regex_command_attr::command;
|
||||||
|
|
||||||
use serenity::{client::Context, framework::standard::CommandResult};
|
use serenity::{client::Context, framework::standard::CommandResult};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -15,13 +14,7 @@ fn format_search_results(search_results: Vec<Sound>) -> CreateGenericResponse {
|
|||||||
let field_iter = search_results
|
let field_iter = search_results
|
||||||
.iter()
|
.iter()
|
||||||
.take(25)
|
.take(25)
|
||||||
.map(|item| {
|
.map(|item| (&item.name, format!("ID: {}", item.id), true))
|
||||||
(
|
|
||||||
&item.name,
|
|
||||||
format!("ID: {}\nPlays: {}", item.id, item.plays),
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.filter(|item| {
|
.filter(|item| {
|
||||||
current_character_count += item.0.len() + item.1.len();
|
current_character_count += item.0.len() + item.1.len();
|
||||||
|
|
||||||
@ -59,11 +52,11 @@ pub async fn list_sounds(
|
|||||||
let mut message_buffer;
|
let mut message_buffer;
|
||||||
|
|
||||||
if args.named("me").map(|i| i.to_owned()) == Some("me".to_string()) {
|
if args.named("me").map(|i| i.to_owned()) == Some("me".to_string()) {
|
||||||
sounds = Sound::get_user_sounds(invoke.author_id(), pool).await?;
|
sounds = Sound::user_sounds(invoke.author_id(), pool).await?;
|
||||||
|
|
||||||
message_buffer = "All your sounds: ".to_string();
|
message_buffer = "All your sounds: ".to_string();
|
||||||
} else {
|
} else {
|
||||||
sounds = Sound::get_guild_sounds(invoke.guild_id().unwrap(), pool).await?;
|
sounds = Sound::guild_sounds(invoke.guild_id().unwrap(), pool).await?;
|
||||||
|
|
||||||
message_buffer = "All sounds on this server: ".to_string();
|
message_buffer = "All sounds on this server: ".to_string();
|
||||||
}
|
}
|
||||||
@ -142,42 +135,6 @@ pub async fn search_sounds(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command("popular")]
|
|
||||||
#[group("Search")]
|
|
||||||
#[description("Show popular sounds")]
|
|
||||||
pub async fn show_popular_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");
|
|
||||||
|
|
||||||
let search_results = sqlx::query_as_unchecked!(
|
|
||||||
Sound,
|
|
||||||
"
|
|
||||||
SELECT name, id, plays, public, server_id, uploader_id
|
|
||||||
FROM sounds
|
|
||||||
WHERE public = 1
|
|
||||||
ORDER BY plays DESC
|
|
||||||
LIMIT 25
|
|
||||||
"
|
|
||||||
)
|
|
||||||
.fetch_all(&pool)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
invoke
|
|
||||||
.respond(ctx.http.clone(), format_search_results(search_results))
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[command("random")]
|
#[command("random")]
|
||||||
#[group("Search")]
|
#[group("Search")]
|
||||||
#[description("Show a page of random sounds")]
|
#[description("Show a page of random sounds")]
|
||||||
@ -197,7 +154,7 @@ pub async fn show_random_sounds(
|
|||||||
let search_results = sqlx::query_as_unchecked!(
|
let search_results = sqlx::query_as_unchecked!(
|
||||||
Sound,
|
Sound,
|
||||||
"
|
"
|
||||||
SELECT name, id, plays, public, server_id, uploader_id
|
SELECT name, id, public, server_id, uploader_id
|
||||||
FROM sounds
|
FROM sounds
|
||||||
WHERE public = 1
|
WHERE public = 1
|
||||||
ORDER BY rand()
|
ORDER BY rand()
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use regex_command_attr::command;
|
use regex_command_attr::command;
|
||||||
|
|
||||||
use serenity::{client::Context, framework::standard::CommandResult};
|
use serenity::{client::Context, framework::standard::CommandResult};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -145,23 +144,21 @@ pub async fn change_prefix(
|
|||||||
|
|
||||||
#[command("roles")]
|
#[command("roles")]
|
||||||
#[required_permissions(Restricted)]
|
#[required_permissions(Restricted)]
|
||||||
#[kind(Text)]
|
|
||||||
#[group("Settings")]
|
#[group("Settings")]
|
||||||
#[description("Change the roles allowed to use the bot")]
|
#[description("Change the role allowed to use the bot")]
|
||||||
#[arg(
|
#[arg(
|
||||||
name = "roles",
|
name = "role",
|
||||||
kind = "String",
|
kind = "Role",
|
||||||
description = "The role mentions to enlist",
|
description = "A role to allow to use the bot. Use @everyone to allow all server members",
|
||||||
required = true
|
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(
|
pub async fn set_allowed_roles(
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
invoke: &(dyn CommandInvoke + Sync + Send),
|
invoke: &(dyn CommandInvoke + Sync + Send),
|
||||||
args: Args,
|
args: Args,
|
||||||
) -> CommandResult {
|
) -> CommandResult {
|
||||||
let msg = invoke.msg().unwrap();
|
|
||||||
let guild_id = *msg.guild_id.unwrap().as_u64();
|
|
||||||
|
|
||||||
let pool = ctx
|
let pool = ctx
|
||||||
.data
|
.data
|
||||||
.read()
|
.read()
|
||||||
@ -170,73 +167,19 @@ pub async fn set_allowed_roles(
|
|||||||
.cloned()
|
.cloned()
|
||||||
.expect("Could not get SQLPool from data");
|
.expect("Could not get SQLPool from data");
|
||||||
|
|
||||||
if args.is_empty() {
|
let role_id = args.named("role").unwrap().parse::<u64>().unwrap();
|
||||||
let roles = sqlx::query!(
|
let guild_data = ctx.guild_data(invoke.guild_id().unwrap()).await.unwrap();
|
||||||
"
|
|
||||||
SELECT role
|
guild_data.write().await.allowed_role = Some(role_id);
|
||||||
FROM roles
|
guild_data.read().await.commit(pool).await?;
|
||||||
WHERE guild_id = ?
|
|
||||||
",
|
invoke
|
||||||
guild_id
|
.respond(
|
||||||
|
ctx.http.clone(),
|
||||||
|
CreateGenericResponse::new().content(format!("Allowed role set to <@&{}>", role_id)),
|
||||||
)
|
)
|
||||||
.fetch_all(&pool)
|
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let all_roles = roles
|
|
||||||
.iter()
|
|
||||||
.map(|i| format!("<@&{}>", i.role.to_string()))
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
.join(", ");
|
|
||||||
|
|
||||||
msg.channel_id.say(&ctx, format!("Usage: `?roles <role mentions or anything else to disable>`. Current roles: {}", all_roles)).await?;
|
|
||||||
} else {
|
|
||||||
sqlx::query!(
|
|
||||||
"
|
|
||||||
DELETE FROM roles
|
|
||||||
WHERE guild_id = ?
|
|
||||||
",
|
|
||||||
guild_id
|
|
||||||
)
|
|
||||||
.execute(&pool)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
if msg.mention_roles.len() > 0 {
|
|
||||||
for role in msg.mention_roles.iter().map(|r| *r.as_u64()) {
|
|
||||||
sqlx::query!(
|
|
||||||
"
|
|
||||||
INSERT INTO roles (guild_id, role)
|
|
||||||
VALUES
|
|
||||||
(?, ?)
|
|
||||||
",
|
|
||||||
guild_id,
|
|
||||||
role
|
|
||||||
)
|
|
||||||
.execute(&pool)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.channel_id
|
|
||||||
.say(&ctx, "Specified roles whitelisted")
|
|
||||||
.await?;
|
|
||||||
} else {
|
|
||||||
sqlx::query!(
|
|
||||||
"
|
|
||||||
INSERT INTO roles (guild_id, role)
|
|
||||||
VALUES
|
|
||||||
(?, ?)
|
|
||||||
",
|
|
||||||
guild_id,
|
|
||||||
guild_id
|
|
||||||
)
|
|
||||||
.execute(&pool)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
msg.channel_id
|
|
||||||
.say(&ctx, "Role whitelisting disabled")
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
use regex_command_attr::command;
|
use regex_command_attr::command;
|
||||||
|
|
||||||
use serenity::{client::Context, framework::standard::CommandResult};
|
use serenity::{client::Context, framework::standard::CommandResult};
|
||||||
|
use songbird;
|
||||||
|
|
||||||
use crate::framework::{Args, CommandInvoke, CreateGenericResponse};
|
use crate::framework::{Args, CommandInvoke, CreateGenericResponse};
|
||||||
|
|
||||||
use songbird;
|
|
||||||
|
|
||||||
#[command("stop")]
|
#[command("stop")]
|
||||||
#[required_permissions(Managed)]
|
#[required_permissions(Managed)]
|
||||||
#[group("Stop")]
|
#[group("Stop")]
|
||||||
|
@ -1,10 +1,4 @@
|
|||||||
use crate::{
|
use std::{collections::HashMap, env};
|
||||||
framework::RegexFramework,
|
|
||||||
guild_data::CtxGuildData,
|
|
||||||
join_channel, play_audio, play_from_query,
|
|
||||||
sound::{JoinSoundCtx, Sound},
|
|
||||||
MySQL, ReqwestClient,
|
|
||||||
};
|
|
||||||
|
|
||||||
use serenity::{
|
use serenity::{
|
||||||
async_trait,
|
async_trait,
|
||||||
@ -19,12 +13,15 @@ use serenity::{
|
|||||||
},
|
},
|
||||||
utils::shard_id,
|
utils::shard_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
use songbird::{Event, EventContext, EventHandler as SongbirdEventHandler};
|
use songbird::{Event, EventContext, EventHandler as SongbirdEventHandler};
|
||||||
|
|
||||||
use crate::framework::Args;
|
use crate::{
|
||||||
|
framework::{Args, RegexFramework},
|
||||||
use std::{collections::HashMap, env};
|
guild_data::CtxGuildData,
|
||||||
|
join_channel, play_audio, play_from_query,
|
||||||
|
sound::{JoinSoundCtx, Sound},
|
||||||
|
MySQL, ReqwestClient,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct RestartTrack;
|
pub struct RestartTrack;
|
||||||
|
|
||||||
@ -47,18 +44,6 @@ impl EventHandler for Handler {
|
|||||||
ctx.set_activity(Activity::watching("for /play")).await;
|
ctx.set_activity(Activity::watching("for /play")).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn cache_ready(&self, ctx: Context, _: Vec<GuildId>) {
|
|
||||||
let framework = ctx
|
|
||||||
.data
|
|
||||||
.read()
|
|
||||||
.await
|
|
||||||
.get::<RegexFramework>()
|
|
||||||
.cloned()
|
|
||||||
.expect("RegexFramework not found in context");
|
|
||||||
|
|
||||||
framework.build_slash(ctx).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn guild_create(&self, ctx: Context, guild: Guild, is_new: bool) {
|
async fn guild_create(&self, ctx: Context, guild: Guild, is_new: bool) {
|
||||||
if is_new {
|
if is_new {
|
||||||
if let Ok(token) = env::var("DISCORDBOTS_TOKEN") {
|
if let Ok(token) = env::var("DISCORDBOTS_TOKEN") {
|
||||||
@ -152,7 +137,7 @@ impl EventHandler for Handler {
|
|||||||
let mut sound = sqlx::query_as_unchecked!(
|
let mut sound = sqlx::query_as_unchecked!(
|
||||||
Sound,
|
Sound,
|
||||||
"
|
"
|
||||||
SELECT name, id, plays, public, server_id, uploader_id
|
SELECT name, id, public, server_id, uploader_id
|
||||||
FROM sounds
|
FROM sounds
|
||||||
WHERE id = ?
|
WHERE id = ?
|
||||||
",
|
",
|
||||||
|
240
src/framework.rs
240
src/framework.rs
@ -1,6 +1,16 @@
|
|||||||
|
use std::{
|
||||||
|
collections::{HashMap, HashSet},
|
||||||
|
env, fmt,
|
||||||
|
hash::{Hash, Hasher},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
|
use log::{debug, error, info, warn};
|
||||||
|
use regex::{Match, Regex, RegexBuilder};
|
||||||
|
use serde_json::Value;
|
||||||
use serenity::{
|
use serenity::{
|
||||||
async_trait,
|
async_trait,
|
||||||
builder::CreateEmbed,
|
builder::{CreateApplicationCommands, CreateComponents, CreateEmbed},
|
||||||
cache::Cache,
|
cache::Cache,
|
||||||
client::Context,
|
client::Context,
|
||||||
framework::{standard::CommandResult, Framework},
|
framework::{standard::CommandResult, Framework},
|
||||||
@ -9,7 +19,7 @@ use serenity::{
|
|||||||
model::{
|
model::{
|
||||||
channel::{Channel, GuildChannel, Message},
|
channel::{Channel, GuildChannel, Message},
|
||||||
guild::{Guild, Member},
|
guild::{Guild, Member},
|
||||||
id::{ChannelId, GuildId, UserId},
|
id::{ChannelId, GuildId, RoleId, UserId},
|
||||||
interactions::{
|
interactions::{
|
||||||
application_command::{
|
application_command::{
|
||||||
ApplicationCommand, ApplicationCommandInteraction, ApplicationCommandOptionType,
|
ApplicationCommand, ApplicationCommandInteraction, ApplicationCommandOptionType,
|
||||||
@ -21,20 +31,7 @@ use serenity::{
|
|||||||
Result as SerenityResult,
|
Result as SerenityResult,
|
||||||
};
|
};
|
||||||
|
|
||||||
use log::{debug, error, info, warn};
|
use crate::guild_data::CtxGuildData;
|
||||||
|
|
||||||
use regex::{Match, Regex, RegexBuilder};
|
|
||||||
|
|
||||||
use std::{
|
|
||||||
collections::{HashMap, HashSet},
|
|
||||||
env, fmt,
|
|
||||||
hash::{Hash, Hasher},
|
|
||||||
sync::Arc,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{guild_data::CtxGuildData, MySQL};
|
|
||||||
use serde_json::Value;
|
|
||||||
use serenity::builder::CreateComponents;
|
|
||||||
|
|
||||||
type CommandFn = for<'fut> fn(
|
type CommandFn = for<'fut> fn(
|
||||||
&'fut Context,
|
&'fut Context,
|
||||||
@ -74,10 +71,6 @@ impl Args {
|
|||||||
Self { args }
|
Self { args }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.args.is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn named<D: ToString>(&self, name: D) -> Option<&String> {
|
pub fn named<D: ToString>(&self, name: D) -> Option<&String> {
|
||||||
let name = name.to_string();
|
let name = name.to_string();
|
||||||
|
|
||||||
@ -397,42 +390,14 @@ impl Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.required_permissions == PermissionLevel::Managed {
|
if self.required_permissions == PermissionLevel::Managed {
|
||||||
let pool = ctx
|
match ctx.guild_data(guild.id).await {
|
||||||
.data
|
Ok(guild_data) => guild_data.read().await.allowed_role.map_or(true, |role| {
|
||||||
.read()
|
role == guild.id.0 || {
|
||||||
.await
|
let role_id = RoleId(role);
|
||||||
.get::<MySQL>()
|
|
||||||
.cloned()
|
|
||||||
.expect("Could not get SQLPool from data");
|
|
||||||
|
|
||||||
match sqlx::query!(
|
member.roles.contains(&role_id)
|
||||||
"
|
|
||||||
SELECT role
|
|
||||||
FROM roles
|
|
||||||
WHERE guild_id = ?
|
|
||||||
",
|
|
||||||
guild.id.as_u64()
|
|
||||||
)
|
|
||||||
.fetch_all(&pool)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(rows) => {
|
|
||||||
let role_ids = member
|
|
||||||
.roles
|
|
||||||
.iter()
|
|
||||||
.map(|r| *r.as_u64())
|
|
||||||
.collect::<Vec<u64>>();
|
|
||||||
|
|
||||||
for row in rows {
|
|
||||||
if role_ids.contains(&row.role) || &row.role == guild.id.as_u64() {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}),
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(sqlx::Error::RowNotFound) => false,
|
|
||||||
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("Unexpected error occurred querying roles: {:?}", e);
|
warn!("Unexpected error occurred querying roles: {:?}", e);
|
||||||
@ -540,132 +505,55 @@ impl RegexFramework {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn _populate_commands<'a>(
|
||||||
|
&self,
|
||||||
|
commands: &'a mut CreateApplicationCommands,
|
||||||
|
) -> &'a mut CreateApplicationCommands {
|
||||||
|
for command in &self.commands_ {
|
||||||
|
commands.create_application_command(|c| {
|
||||||
|
c.name(command.names[0]).description(command.desc);
|
||||||
|
|
||||||
|
for arg in command.args {
|
||||||
|
c.create_option(|o| {
|
||||||
|
o.name(arg.name)
|
||||||
|
.description(arg.description)
|
||||||
|
.kind(arg.kind)
|
||||||
|
.required(arg.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
c
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
commands
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn build_slash(&self, http: impl AsRef<Http>) {
|
pub async fn build_slash(&self, http: impl AsRef<Http>) {
|
||||||
info!("Building slash commands...");
|
info!("Building slash commands...");
|
||||||
|
|
||||||
let mut count = 0;
|
match env::var("TEST_GUILD")
|
||||||
|
.map(|i| i.parse::<u64>().ok())
|
||||||
if let Some(guild_id) = env::var("TEST_GUILD")
|
|
||||||
.map(|v| v.parse::<u64>().ok())
|
|
||||||
.ok()
|
.ok()
|
||||||
.flatten()
|
.flatten()
|
||||||
.map(|v| GuildId(v))
|
.map(|i| GuildId(i))
|
||||||
{
|
{
|
||||||
for command in self
|
None => {
|
||||||
.commands_
|
ApplicationCommand::set_global_application_commands(&http, |c| {
|
||||||
.iter()
|
self._populate_commands(c)
|
||||||
.filter(|c| c.kind != CommandKind::Text)
|
|
||||||
{
|
|
||||||
guild_id
|
|
||||||
.create_application_command(&http, |a| {
|
|
||||||
a.name(command.names[0]).description(command.desc);
|
|
||||||
|
|
||||||
for arg in command.args {
|
|
||||||
a.create_option(|o| {
|
|
||||||
o.name(arg.name)
|
|
||||||
.description(arg.description)
|
|
||||||
.kind(arg.kind)
|
|
||||||
.required(arg.required)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
a
|
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.expect(&format!(
|
.unwrap();
|
||||||
"Failed to create application command for {}",
|
|
||||||
command.names[0]
|
|
||||||
));
|
|
||||||
|
|
||||||
count += 1;
|
|
||||||
}
|
}
|
||||||
} else {
|
Some(debug_guild) => {
|
||||||
info!("Checking for existing commands...");
|
debug_guild
|
||||||
|
.set_application_commands(&http, |c| self._populate_commands(c))
|
||||||
let current_commands = ApplicationCommand::get_global_application_commands(&http)
|
|
||||||
.await
|
.await
|
||||||
.expect("Failed to fetch existing commands");
|
.unwrap();
|
||||||
|
|
||||||
debug!("Existing commands: {:?}", current_commands);
|
|
||||||
|
|
||||||
// delete commands not in use
|
|
||||||
for command in ¤t_commands {
|
|
||||||
if self
|
|
||||||
.commands_
|
|
||||||
.iter()
|
|
||||||
.find(|c| c.names[0] == command.name)
|
|
||||||
.is_none()
|
|
||||||
{
|
|
||||||
info!("Deleting command {}", command.name);
|
|
||||||
|
|
||||||
ApplicationCommand::delete_global_application_command(&http, command.id)
|
|
||||||
.await
|
|
||||||
.expect("Failed to delete an unused command");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for command in self
|
info!("Slash commands built!");
|
||||||
.commands_
|
|
||||||
.iter()
|
|
||||||
.filter(|c| c.kind != CommandKind::Text)
|
|
||||||
{
|
|
||||||
let already_created = if let Some(current_command) = current_commands
|
|
||||||
.iter()
|
|
||||||
.find(|curr| curr.name == command.names[0])
|
|
||||||
{
|
|
||||||
if current_command.description == command.desc
|
|
||||||
&& current_command.options.len() == command.args.len()
|
|
||||||
{
|
|
||||||
let mut has_different_arg = false;
|
|
||||||
|
|
||||||
for (arg, option) in
|
|
||||||
command.args.iter().zip(current_command.options.clone())
|
|
||||||
{
|
|
||||||
if arg.required != option.required
|
|
||||||
|| arg.name != option.name
|
|
||||||
|| arg.description != option.description
|
|
||||||
|| arg.kind != option.kind
|
|
||||||
{
|
|
||||||
has_different_arg = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
!has_different_arg
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
if !already_created {
|
|
||||||
ApplicationCommand::create_global_application_command(&http, |a| {
|
|
||||||
a.name(command.names[0]).description(command.desc);
|
|
||||||
|
|
||||||
for arg in command.args {
|
|
||||||
a.create_option(|o| {
|
|
||||||
o.name(arg.name)
|
|
||||||
.description(arg.description)
|
|
||||||
.kind(arg.kind)
|
|
||||||
.required(arg.required)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
a
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.expect(&format!(
|
|
||||||
"Failed to create application command for {}",
|
|
||||||
command.names[0]
|
|
||||||
));
|
|
||||||
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
info!("{} slash commands built! Ready to go", count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn execute(&self, ctx: Context, interaction: ApplicationCommandInteraction) {
|
pub async fn execute(&self, ctx: Context, interaction: ApplicationCommandInteraction) {
|
||||||
@ -709,6 +597,14 @@ impl RegexFramework {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info!(
|
||||||
|
"[Shard {}] [Guild {}] /{} {:?}",
|
||||||
|
ctx.shard_id,
|
||||||
|
interaction.guild_id.unwrap(),
|
||||||
|
interaction.data.name,
|
||||||
|
args
|
||||||
|
);
|
||||||
|
|
||||||
(command.fun)(&ctx, &interaction, Args { args })
|
(command.fun)(&ctx, &interaction, Args { args })
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -716,7 +612,7 @@ impl RegexFramework {
|
|||||||
let _ = interaction
|
let _ = interaction
|
||||||
.respond(
|
.respond(
|
||||||
ctx.http.clone(),
|
ctx.http.clone(),
|
||||||
CreateGenericResponse::new().content("You must either be an Admin or have a role specified in `?roles` to do this command")
|
CreateGenericResponse::new().content("You must either be an Admin or have a role specified by `/roles` to do this command")
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
} else if command.required_permissions == PermissionLevel::Restricted {
|
} else if command.required_permissions == PermissionLevel::Restricted {
|
||||||
@ -794,6 +690,14 @@ impl Framework for RegexFramework {
|
|||||||
let member = guild.member(&ctx, &msg.author).await.unwrap();
|
let member = guild.member(&ctx, &msg.author).await.unwrap();
|
||||||
|
|
||||||
if command.check_permissions(&ctx, &guild, &member).await {
|
if command.check_permissions(&ctx, &guild, &member).await {
|
||||||
|
let _ = msg.channel_id.say(
|
||||||
|
&ctx,
|
||||||
|
format!(
|
||||||
|
"You **must** begin to switch to slash commands. All commands are available via slash commands now. If slash commands don't display in your server, please use this link: https://discord.com/api/oauth2/authorize?client_id={}&permissions=3165184&scope=applications.commands%20bot",
|
||||||
|
ctx.cache.current_user().id
|
||||||
|
)
|
||||||
|
).await;
|
||||||
|
|
||||||
(command.fun)(&ctx, &msg, Args::from(&args, command.args))
|
(command.fun)(&ctx, &msg, Args::from(&args, command.args))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
use crate::{GuildDataCache, MySQL};
|
use std::sync::Arc;
|
||||||
|
|
||||||
use serenity::{async_trait, model::id::GuildId, prelude::Context};
|
use serenity::{async_trait, model::id::GuildId, prelude::Context};
|
||||||
use sqlx::mysql::MySqlPool;
|
use sqlx::mysql::MySqlPool;
|
||||||
use std::sync::Arc;
|
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
|
use crate::{GuildDataCache, MySQL};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct GuildData {
|
pub struct GuildData {
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
pub prefix: String,
|
pub prefix: String,
|
||||||
pub volume: u8,
|
pub volume: u8,
|
||||||
pub allow_greets: bool,
|
pub allow_greets: bool,
|
||||||
|
pub allowed_role: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@ -41,7 +44,7 @@ impl CtxGuildData for Context {
|
|||||||
} else {
|
} else {
|
||||||
let pool = self.data.read().await.get::<MySQL>().cloned().unwrap();
|
let pool = self.data.read().await.get::<MySQL>().cloned().unwrap();
|
||||||
|
|
||||||
match GuildData::get_from_id(guild_id, pool).await {
|
match GuildData::from_id(guild_id, pool).await {
|
||||||
Ok(d) => {
|
Ok(d) => {
|
||||||
let lock = Arc::new(RwLock::new(d));
|
let lock = Arc::new(RwLock::new(d));
|
||||||
|
|
||||||
@ -59,7 +62,7 @@ impl CtxGuildData for Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl GuildData {
|
impl GuildData {
|
||||||
pub async fn get_from_id<G: Into<GuildId>>(
|
pub async fn from_id<G: Into<GuildId>>(
|
||||||
guild_id: G,
|
guild_id: G,
|
||||||
db_pool: MySqlPool,
|
db_pool: MySqlPool,
|
||||||
) -> Result<GuildData, sqlx::Error> {
|
) -> Result<GuildData, sqlx::Error> {
|
||||||
@ -68,7 +71,7 @@ impl GuildData {
|
|||||||
let guild_data = sqlx::query_as_unchecked!(
|
let guild_data = sqlx::query_as_unchecked!(
|
||||||
GuildData,
|
GuildData,
|
||||||
"
|
"
|
||||||
SELECT id, prefix, volume, allow_greets
|
SELECT id, prefix, volume, allow_greets, allowed_role
|
||||||
FROM servers
|
FROM servers
|
||||||
WHERE id = ?
|
WHERE id = ?
|
||||||
",
|
",
|
||||||
@ -102,22 +105,12 @@ INSERT INTO servers (id)
|
|||||||
.execute(&db_pool)
|
.execute(&db_pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
sqlx::query!(
|
|
||||||
"
|
|
||||||
INSERT IGNORE INTO roles (guild_id, role)
|
|
||||||
VALUES (?, ?)
|
|
||||||
",
|
|
||||||
guild_id.as_u64(),
|
|
||||||
guild_id.as_u64()
|
|
||||||
)
|
|
||||||
.execute(&db_pool)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(GuildData {
|
Ok(GuildData {
|
||||||
id: guild_id.as_u64().to_owned(),
|
id: guild_id.as_u64().to_owned(),
|
||||||
prefix: String::from("?"),
|
prefix: String::from("?"),
|
||||||
volume: 100,
|
volume: 100,
|
||||||
allow_greets: true,
|
allow_greets: true,
|
||||||
|
allowed_role: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,13 +124,15 @@ UPDATE servers
|
|||||||
SET
|
SET
|
||||||
prefix = ?,
|
prefix = ?,
|
||||||
volume = ?,
|
volume = ?,
|
||||||
allow_greets = ?
|
allow_greets = ?,
|
||||||
|
allowed_role = ?
|
||||||
WHERE
|
WHERE
|
||||||
id = ?
|
id = ?
|
||||||
",
|
",
|
||||||
self.prefix,
|
self.prefix,
|
||||||
self.volume,
|
self.volume,
|
||||||
self.allow_greets,
|
self.allow_greets,
|
||||||
|
self.allowed_role,
|
||||||
self.id
|
self.id
|
||||||
)
|
)
|
||||||
.execute(&db_pool)
|
.execute(&db_pool)
|
||||||
|
32
src/main.rs
32
src/main.rs
@ -8,15 +8,11 @@ mod framework;
|
|||||||
mod guild_data;
|
mod guild_data;
|
||||||
mod sound;
|
mod sound;
|
||||||
|
|
||||||
use crate::{
|
use std::{collections::HashMap, env, sync::Arc};
|
||||||
event_handlers::Handler,
|
|
||||||
framework::{Args, RegexFramework},
|
|
||||||
guild_data::{CtxGuildData, GuildData},
|
|
||||||
sound::Sound,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
use dashmap::DashMap;
|
||||||
|
use dotenv::dotenv;
|
||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
use serenity::{
|
use serenity::{
|
||||||
client::{bridge::gateway::GatewayIntents, Client, Context},
|
client::{bridge::gateway::GatewayIntents, Client, Context},
|
||||||
http::Http,
|
http::Http,
|
||||||
@ -27,19 +23,17 @@ use serenity::{
|
|||||||
},
|
},
|
||||||
prelude::{Mutex, TypeMapKey},
|
prelude::{Mutex, TypeMapKey},
|
||||||
};
|
};
|
||||||
|
|
||||||
use songbird::{create_player, error::JoinResult, tracks::TrackHandle, Call, SerenityInit};
|
use songbird::{create_player, error::JoinResult, tracks::TrackHandle, Call, SerenityInit};
|
||||||
|
|
||||||
use sqlx::mysql::MySqlPool;
|
use sqlx::mysql::MySqlPool;
|
||||||
|
|
||||||
use dotenv::dotenv;
|
|
||||||
|
|
||||||
use dashmap::DashMap;
|
|
||||||
|
|
||||||
use std::{collections::HashMap, env, sync::Arc};
|
|
||||||
|
|
||||||
use tokio::sync::{MutexGuard, RwLock};
|
use tokio::sync::{MutexGuard, RwLock};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
event_handlers::Handler,
|
||||||
|
framework::{Args, RegexFramework},
|
||||||
|
guild_data::{CtxGuildData, GuildData},
|
||||||
|
sound::Sound,
|
||||||
|
};
|
||||||
|
|
||||||
struct MySQL;
|
struct MySQL;
|
||||||
|
|
||||||
impl TypeMapKey for MySQL {
|
impl TypeMapKey for MySQL {
|
||||||
@ -98,9 +92,6 @@ async fn play_audio(
|
|||||||
|
|
||||||
call_handler.play(track);
|
call_handler.play(track);
|
||||||
|
|
||||||
sound.plays += 1;
|
|
||||||
sound.commit(mysql_pool).await?;
|
|
||||||
|
|
||||||
Ok(track_handler)
|
Ok(track_handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +259,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
// search commands
|
// search commands
|
||||||
.add_command(&cmds::search::LIST_SOUNDS_COMMAND)
|
.add_command(&cmds::search::LIST_SOUNDS_COMMAND)
|
||||||
.add_command(&cmds::search::SEARCH_SOUNDS_COMMAND)
|
.add_command(&cmds::search::SEARCH_SOUNDS_COMMAND)
|
||||||
.add_command(&cmds::search::SHOW_POPULAR_SOUNDS_COMMAND)
|
|
||||||
.add_command(&cmds::search::SHOW_RANDOM_SOUNDS_COMMAND);
|
.add_command(&cmds::search::SHOW_RANDOM_SOUNDS_COMMAND);
|
||||||
|
|
||||||
if audio_index.is_some() {
|
if audio_index.is_some() {
|
||||||
@ -314,6 +304,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
framework_arc.build_slash(&client.cache_and_http.http).await;
|
||||||
|
|
||||||
if let Ok((Some(lower), Some(upper))) = env::var("SHARD_RANGE").map(|sr| {
|
if let Ok((Some(lower), Some(upper))) = env::var("SHARD_RANGE").map(|sr| {
|
||||||
let mut split = sr
|
let mut split = sr
|
||||||
.split(',')
|
.split(',')
|
||||||
|
40
src/sound.rs
40
src/sound.rs
@ -1,15 +1,12 @@
|
|||||||
use super::error::ErrorTypes;
|
|
||||||
|
|
||||||
use sqlx::mysql::MySqlPool;
|
|
||||||
|
|
||||||
use tokio::{fs::File, io::AsyncWriteExt, process::Command};
|
|
||||||
|
|
||||||
use songbird::input::restartable::Restartable;
|
|
||||||
|
|
||||||
use std::{env, path::Path};
|
use std::{env, path::Path};
|
||||||
|
|
||||||
use crate::{JoinSoundCache, MySQL};
|
|
||||||
use serenity::{async_trait, model::id::UserId, prelude::Context};
|
use serenity::{async_trait, model::id::UserId, prelude::Context};
|
||||||
|
use songbird::input::restartable::Restartable;
|
||||||
|
use sqlx::mysql::MySqlPool;
|
||||||
|
use tokio::{fs::File, io::AsyncWriteExt, process::Command};
|
||||||
|
|
||||||
|
use super::error::ErrorTypes;
|
||||||
|
use crate::{JoinSoundCache, MySQL};
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait JoinSoundCtx {
|
pub trait JoinSoundCtx {
|
||||||
@ -83,7 +80,6 @@ SELECT join_sound_id
|
|||||||
|
|
||||||
let pool = self.data.read().await.get::<MySQL>().cloned().unwrap();
|
let pool = self.data.read().await.get::<MySQL>().cloned().unwrap();
|
||||||
|
|
||||||
if join_sound_cache.get(&user_id).is_none() {
|
|
||||||
let _ = sqlx::query!(
|
let _ = sqlx::query!(
|
||||||
"
|
"
|
||||||
INSERT IGNORE INTO users (user)
|
INSERT IGNORE INTO users (user)
|
||||||
@ -93,7 +89,6 @@ INSERT IGNORE INTO users (user)
|
|||||||
)
|
)
|
||||||
.execute(&pool)
|
.execute(&pool)
|
||||||
.await;
|
.await;
|
||||||
}
|
|
||||||
|
|
||||||
let _ = sqlx::query!(
|
let _ = sqlx::query!(
|
||||||
"
|
"
|
||||||
@ -115,12 +110,17 @@ WHERE
|
|||||||
pub struct Sound {
|
pub struct Sound {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub id: u32,
|
pub id: u32,
|
||||||
pub plays: u32,
|
|
||||||
pub public: bool,
|
pub public: bool,
|
||||||
pub server_id: u64,
|
pub server_id: u64,
|
||||||
pub uploader_id: Option<u64>,
|
pub uploader_id: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Sound {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.id == other.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Sound {
|
impl Sound {
|
||||||
pub async fn search_for_sound<G: Into<u64>, U: Into<u64>>(
|
pub async fn search_for_sound<G: Into<u64>, U: Into<u64>>(
|
||||||
query: &str,
|
query: &str,
|
||||||
@ -150,7 +150,7 @@ impl Sound {
|
|||||||
let sound = sqlx::query_as_unchecked!(
|
let sound = sqlx::query_as_unchecked!(
|
||||||
Self,
|
Self,
|
||||||
"
|
"
|
||||||
SELECT name, id, plays, public, server_id, uploader_id
|
SELECT name, id, public, server_id, uploader_id
|
||||||
FROM sounds
|
FROM sounds
|
||||||
WHERE id = ? AND (
|
WHERE id = ? AND (
|
||||||
public = 1 OR
|
public = 1 OR
|
||||||
@ -174,7 +174,7 @@ SELECT name, id, plays, public, server_id, uploader_id
|
|||||||
sound = sqlx::query_as_unchecked!(
|
sound = sqlx::query_as_unchecked!(
|
||||||
Self,
|
Self,
|
||||||
"
|
"
|
||||||
SELECT name, id, plays, public, server_id, uploader_id
|
SELECT name, id, public, server_id, uploader_id
|
||||||
FROM sounds
|
FROM sounds
|
||||||
WHERE name = ? AND (
|
WHERE name = ? AND (
|
||||||
public = 1 OR
|
public = 1 OR
|
||||||
@ -195,7 +195,7 @@ SELECT name, id, plays, public, server_id, uploader_id
|
|||||||
sound = sqlx::query_as_unchecked!(
|
sound = sqlx::query_as_unchecked!(
|
||||||
Self,
|
Self,
|
||||||
"
|
"
|
||||||
SELECT name, id, plays, public, server_id, uploader_id
|
SELECT name, id, public, server_id, uploader_id
|
||||||
FROM sounds
|
FROM sounds
|
||||||
WHERE name LIKE CONCAT('%', ?, '%') AND (
|
WHERE name LIKE CONCAT('%', ?, '%') AND (
|
||||||
public = 1 OR
|
public = 1 OR
|
||||||
@ -310,12 +310,10 @@ SELECT COUNT(1) as count
|
|||||||
"
|
"
|
||||||
UPDATE sounds
|
UPDATE sounds
|
||||||
SET
|
SET
|
||||||
plays = ?,
|
|
||||||
public = ?
|
public = ?
|
||||||
WHERE
|
WHERE
|
||||||
id = ?
|
id = ?
|
||||||
",
|
",
|
||||||
self.plays,
|
|
||||||
self.public,
|
self.public,
|
||||||
self.id
|
self.id
|
||||||
)
|
)
|
||||||
@ -407,14 +405,14 @@ INSERT INTO sounds (name, server_id, uploader_id, public, src)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_user_sounds<U: Into<u64>>(
|
pub async fn user_sounds<U: Into<u64>>(
|
||||||
user_id: U,
|
user_id: U,
|
||||||
db_pool: MySqlPool,
|
db_pool: MySqlPool,
|
||||||
) -> Result<Vec<Sound>, Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<Vec<Sound>, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let sounds = sqlx::query_as_unchecked!(
|
let sounds = sqlx::query_as_unchecked!(
|
||||||
Sound,
|
Sound,
|
||||||
"
|
"
|
||||||
SELECT name, id, plays, public, server_id, uploader_id
|
SELECT name, id, public, server_id, uploader_id
|
||||||
FROM sounds
|
FROM sounds
|
||||||
WHERE uploader_id = ?
|
WHERE uploader_id = ?
|
||||||
",
|
",
|
||||||
@ -426,14 +424,14 @@ SELECT name, id, plays, public, server_id, uploader_id
|
|||||||
Ok(sounds)
|
Ok(sounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_guild_sounds<G: Into<u64>>(
|
pub async fn guild_sounds<G: Into<u64>>(
|
||||||
guild_id: G,
|
guild_id: G,
|
||||||
db_pool: MySqlPool,
|
db_pool: MySqlPool,
|
||||||
) -> Result<Vec<Sound>, Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<Vec<Sound>, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let sounds = sqlx::query_as_unchecked!(
|
let sounds = sqlx::query_as_unchecked!(
|
||||||
Sound,
|
Sound,
|
||||||
"
|
"
|
||||||
SELECT name, id, plays, public, server_id, uploader_id
|
SELECT name, id, public, server_id, uploader_id
|
||||||
FROM sounds
|
FROM sounds
|
||||||
WHERE server_id = ?
|
WHERE server_id = ?
|
||||||
",
|
",
|
||||||
|
Loading…
Reference in New Issue
Block a user