updated everything
This commit is contained in:
parent
f534d0f788
commit
7466c3d75b
1293
Cargo.lock
generated
1293
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
13
Cargo.toml
13
Cargo.toml
@ -1,13 +1,14 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "soundfx-rs"
|
name = "soundfx-rs"
|
||||||
version = "1.0.1-rc.6"
|
version = "1.1.0"
|
||||||
authors = ["jude-lafitteIII <judewrs@gmail.com>"]
|
authors = ["jellywx <judesouthworth@pm.me>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serenity = { git = "https://github.com/jellywx/serenity", branch = "jellywx-member_permissions", features = ["voice", "collector"] }
|
serenity = { version = "0.10", features = ["voice", "collector"] }
|
||||||
sqlx = { version = "0.3.5", default-features = false, features = ["runtime-tokio", "macros", "mysql", "bigdecimal"] }
|
sqlx = { git = "https://github.com/ant32/sqlx.git", branch = "tokio-1.0", default-features = false, features = ["runtime-tokio-rustls", "macros", "mysql", "bigdecimal"] }
|
||||||
dotenv = "0.15"
|
dotenv = "0.15"
|
||||||
tokio = { version = "0.2", features = ["fs", "process", "io-util"] }
|
tokio = { version = "1.0", features = ["fs", "process", "io-util"] }
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
reqwest = "0.10"
|
reqwest = "0.11"
|
||||||
|
songbird = "0.1"
|
||||||
|
146
src/main.rs
146
src/main.rs
@ -11,13 +11,10 @@ use guilddata::GuildData;
|
|||||||
use sound::Sound;
|
use sound::Sound;
|
||||||
|
|
||||||
use serenity::{
|
use serenity::{
|
||||||
client::{
|
client::{bridge::gateway::GatewayIntents, Client, Context},
|
||||||
bridge::{gateway::GatewayIntents, voice::ClientVoiceManager},
|
|
||||||
Client, Context,
|
|
||||||
},
|
|
||||||
framework::standard::{
|
framework::standard::{
|
||||||
macros::{check, command, group, hook},
|
macros::{check, command, group, hook},
|
||||||
Args, CheckResult, CommandError, CommandResult, DispatchError, Reason, StandardFramework,
|
Args, CommandError, CommandResult, DispatchError, Reason, StandardFramework,
|
||||||
},
|
},
|
||||||
http::Http,
|
http::Http,
|
||||||
model::{
|
model::{
|
||||||
@ -26,16 +23,20 @@ use serenity::{
|
|||||||
id::{GuildId, RoleId},
|
id::{GuildId, RoleId},
|
||||||
voice::VoiceState,
|
voice::VoiceState,
|
||||||
},
|
},
|
||||||
prelude::{Mutex as SerenityMutex, *},
|
prelude::*,
|
||||||
utils::shard_id,
|
utils::shard_id,
|
||||||
voice::Handler as VoiceHandler,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use songbird::{Call, SerenityInit};
|
||||||
|
|
||||||
|
type CheckResult = Result<(), Reason>;
|
||||||
|
|
||||||
use sqlx::mysql::MySqlPool;
|
use sqlx::mysql::MySqlPool;
|
||||||
|
|
||||||
use dotenv::dotenv;
|
use dotenv::dotenv;
|
||||||
|
|
||||||
use std::{collections::HashMap, env, sync::Arc, time::Duration};
|
use std::{collections::HashMap, env, sync::Arc, time::Duration};
|
||||||
|
use tokio::sync::MutexGuard;
|
||||||
|
|
||||||
struct MySQL;
|
struct MySQL;
|
||||||
|
|
||||||
@ -43,12 +44,6 @@ impl TypeMapKey for MySQL {
|
|||||||
type Value = MySqlPool;
|
type Value = MySqlPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VoiceManager;
|
|
||||||
|
|
||||||
impl TypeMapKey for VoiceManager {
|
|
||||||
type Value = Arc<SerenityMutex<ClientVoiceManager>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ReqwestClient;
|
struct ReqwestClient;
|
||||||
|
|
||||||
impl TypeMapKey for ReqwestClient {
|
impl TypeMapKey for ReqwestClient {
|
||||||
@ -109,20 +104,20 @@ async fn self_perm_check(ctx: &Context, msg: &Message, _args: &mut Args) -> Chec
|
|||||||
|
|
||||||
if let Ok(permissions) = permissions_r {
|
if let Ok(permissions) = permissions_r {
|
||||||
if permissions.send_messages() && permissions.embed_links() {
|
if permissions.send_messages() && permissions.embed_links() {
|
||||||
CheckResult::Success
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
CheckResult::Failure(Reason::Log(
|
Err(Reason::Log(
|
||||||
"Bot does not have enough permissions".to_string(),
|
"Bot does not have enough permissions".to_string(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
CheckResult::Failure(Reason::Log("No perms found".to_string()))
|
Err(Reason::Log("No perms found".to_string()))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
CheckResult::Failure(Reason::Log("No DM commands".to_string()))
|
Err(Reason::Log("No DM commands".to_string()))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
CheckResult::Failure(Reason::Log("Channel not available".to_string()))
|
Err(Reason::Log("Channel not available".to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,33 +168,33 @@ SELECT COUNT(1) as count
|
|||||||
match role_res {
|
match role_res {
|
||||||
Ok(role_count) => {
|
Ok(role_count) => {
|
||||||
if role_count.count > 0 {
|
if role_count.count > 0 {
|
||||||
CheckResult::Success
|
Ok(())
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
CheckResult::Failure(Reason::User("User has not got a sufficient role. Use `?roles` to set up role restrictions".to_string()))
|
Err(Reason::User("User has not got a sufficient role. Use `?roles` to set up role restrictions".to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
CheckResult::Failure(Reason::User("User has not got a sufficient role. Use `?roles` to set up role restrictions".to_string()))
|
Err(Reason::User("User has not got a sufficient role. Use `?roles` to set up role restrictions".to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(_) => CheckResult::Failure(Reason::User(
|
Err(_) => Err(Reason::User(
|
||||||
"Unexpected error looking up user roles".to_string(),
|
"Unexpected error looking up user roles".to_string(),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
None => CheckResult::Failure(Reason::User(
|
None => Err(Reason::User(
|
||||||
"Unexpected error looking up guild".to_string(),
|
"Unexpected error looking up guild".to_string(),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if perform_permission_check(ctx, &msg).await.is_success() {
|
if perform_permission_check(ctx, &msg).await.is_ok() {
|
||||||
CheckResult::Success
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
check_for_roles(&ctx, &msg).await
|
check_for_roles(&ctx, &msg).await
|
||||||
}
|
}
|
||||||
@ -219,14 +214,14 @@ async fn perform_permission_check(ctx: &Context, msg: &&Message) -> CheckResult
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.manage_guild()
|
.manage_guild()
|
||||||
{
|
{
|
||||||
CheckResult::Success
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
CheckResult::Failure(Reason::User(String::from(
|
Err(Reason::User(String::from(
|
||||||
"User needs `Manage Guild` permission",
|
"User needs `Manage Guild` permission",
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
CheckResult::Failure(Reason::User(String::from("Guild not cached")))
|
Err(Reason::User(String::from("Guild not cached")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,17 +290,9 @@ impl EventHandler for Handler {
|
|||||||
if let Some(Channel::Guild(channel)) = channel_id.to_channel_cached(&ctx).await
|
if let Some(Channel::Guild(channel)) = channel_id.to_channel_cached(&ctx).await
|
||||||
{
|
{
|
||||||
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 voice_manager_lock = ctx
|
let voice_manager = songbird::get(&ctx).await.unwrap();
|
||||||
.data
|
|
||||||
.read()
|
|
||||||
.await
|
|
||||||
.get::<VoiceManager>()
|
|
||||||
.cloned()
|
|
||||||
.expect("Could not get VoiceManager from data");
|
|
||||||
|
|
||||||
let mut voice_manager = voice_manager_lock.lock().await;
|
let _ = voice_manager.leave(guild_id).await;
|
||||||
|
|
||||||
voice_manager.leave(guild_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -351,20 +338,13 @@ SELECT name, id, plays, public, server_id, uploader_id
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let voice_manager_lock = ctx
|
let voice_manager = songbird::get(&ctx).await.unwrap();
|
||||||
.data
|
|
||||||
.read()
|
|
||||||
.await
|
|
||||||
.get::<VoiceManager>()
|
|
||||||
.cloned()
|
|
||||||
.expect("Could not get VoiceManager from data");
|
|
||||||
|
|
||||||
let mut voice_manager = voice_manager_lock.lock().await;
|
let (handler, _) = voice_manager.join(guild_id, user_channel).await;
|
||||||
|
|
||||||
if let Some(handler) = voice_manager.join(guild_id, user_channel) {
|
let _ =
|
||||||
let _audio =
|
play_audio(&mut sound, guild_data, &mut handler.lock().await, pool)
|
||||||
play_audio(&mut sound, guild_data, handler, pool).await;
|
.await;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -376,16 +356,12 @@ SELECT name, id, plays, public, server_id, uploader_id
|
|||||||
async fn play_audio(
|
async fn play_audio(
|
||||||
sound: &mut Sound,
|
sound: &mut Sound,
|
||||||
guild: GuildData,
|
guild: GuildData,
|
||||||
handler: &mut VoiceHandler,
|
handler: &mut MutexGuard<'_, Call>,
|
||||||
mysql_pool: MySqlPool,
|
mysql_pool: MySqlPool,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let audio = handler.play_only(sound.store_sound_source(mysql_pool.clone()).await?);
|
let audio = handler.play_source(sound.store_sound_source(mysql_pool.clone()).await?);
|
||||||
|
|
||||||
{
|
let _ = audio.set_volume(guild.volume as f32 / 100.0);
|
||||||
let mut locked = audio.lock().await;
|
|
||||||
|
|
||||||
locked.volume(guild.volume as f32 / 100.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
sound.plays += 1;
|
sound.plays += 1;
|
||||||
sound.commit(mysql_pool).await?;
|
sound.commit(mysql_pool).await?;
|
||||||
@ -484,12 +460,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
)
|
)
|
||||||
.framework(framework)
|
.framework(framework)
|
||||||
.event_handler(Handler)
|
.event_handler(Handler)
|
||||||
|
.register_songbird()
|
||||||
.await
|
.await
|
||||||
.expect("Error occurred creating client");
|
.expect("Error occurred creating client");
|
||||||
|
|
||||||
{
|
{
|
||||||
let mysql_pool =
|
let mysql_pool =
|
||||||
MySqlPool::new(&env::var("DATABASE_URL").expect("No database URL provided"))
|
MySqlPool::connect(&env::var("DATABASE_URL").expect("No database URL provided"))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -497,8 +474,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
|
|
||||||
data.insert::<MySQL>(mysql_pool);
|
data.insert::<MySQL>(mysql_pool);
|
||||||
|
|
||||||
data.insert::<VoiceManager>(Arc::clone(&client.voice_manager));
|
|
||||||
|
|
||||||
data.insert::<ReqwestClient>(Arc::new(reqwest::Client::new()));
|
data.insert::<ReqwestClient>(Arc::new(reqwest::Client::new()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -550,35 +525,20 @@ async fn play(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
|||||||
|
|
||||||
match sound_res {
|
match sound_res {
|
||||||
Some(sound) => {
|
Some(sound) => {
|
||||||
let voice_manager_lock = ctx
|
let voice_manager = songbird::get(ctx).await.unwrap();
|
||||||
.data
|
|
||||||
.read()
|
|
||||||
.await
|
|
||||||
.get::<VoiceManager>()
|
|
||||||
.cloned()
|
|
||||||
.expect("Could not get VoiceManager from data");
|
|
||||||
|
|
||||||
let mut voice_manager = voice_manager_lock.lock().await;
|
let (call_handler, _) = voice_manager.join(guild_id, user_channel).await;
|
||||||
|
|
||||||
match voice_manager.join(guild_id, user_channel) {
|
let guild_data = GuildData::get_from_id(guild, pool.clone()).await.unwrap();
|
||||||
Some(handler) => {
|
|
||||||
let guild_data =
|
|
||||||
GuildData::get_from_id(guild, pool.clone()).await.unwrap();
|
|
||||||
|
|
||||||
play_audio(sound, guild_data, handler, pool).await?;
|
play_audio(sound, guild_data, &mut call_handler.lock().await, pool).await?;
|
||||||
|
|
||||||
msg.channel_id
|
msg.channel_id
|
||||||
.say(
|
.say(
|
||||||
&ctx,
|
&ctx,
|
||||||
format!("Playing sound {} with ID {}", sound.name, sound.id),
|
format!("Playing sound {} with ID {}", sound.name, sound.id),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
|
||||||
|
|
||||||
None => {
|
|
||||||
msg.channel_id.say(&ctx, "Failed to join channel").await?;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
None => {
|
None => {
|
||||||
@ -1300,21 +1260,9 @@ WHERE
|
|||||||
|
|
||||||
#[command("stop")]
|
#[command("stop")]
|
||||||
async fn stop_playing(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
|
async fn stop_playing(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
|
||||||
let voice_manager_lock = ctx
|
let voice_manager = songbird::get(ctx).await.unwrap();
|
||||||
.data
|
|
||||||
.read()
|
|
||||||
.await
|
|
||||||
.get::<VoiceManager>()
|
|
||||||
.cloned()
|
|
||||||
.expect("Could not get VoiceManager from data");
|
|
||||||
|
|
||||||
let mut voice_manager = voice_manager_lock.lock().await;
|
let _ = voice_manager.leave(msg.guild_id.unwrap()).await;
|
||||||
|
|
||||||
let manager_opt = voice_manager.get_mut(msg.guild_id.unwrap());
|
|
||||||
|
|
||||||
if let Some(manager) = manager_opt {
|
|
||||||
manager.leave();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
16
src/sound.rs
16
src/sound.rs
@ -2,10 +2,10 @@ use super::error::ErrorTypes;
|
|||||||
|
|
||||||
use sqlx::mysql::MySqlPool;
|
use sqlx::mysql::MySqlPool;
|
||||||
|
|
||||||
use serenity::voice::{ffmpeg, AudioSource};
|
use tokio::{fs::File, io::AsyncWriteExt, process::Command};
|
||||||
|
|
||||||
use tokio::{fs::File, process::Command};
|
|
||||||
|
|
||||||
|
use songbird::ffmpeg;
|
||||||
|
use songbird::input::Input;
|
||||||
use std::{env, path::Path};
|
use std::{env, path::Path};
|
||||||
|
|
||||||
pub struct Sound {
|
pub struct Sound {
|
||||||
@ -136,21 +136,19 @@ SELECT src
|
|||||||
pub async fn store_sound_source(
|
pub async fn store_sound_source(
|
||||||
&self,
|
&self,
|
||||||
db_pool: MySqlPool,
|
db_pool: MySqlPool,
|
||||||
) -> Result<Box<dyn AudioSource>, Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<Input, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let caching_location = env::var("CACHING_LOCATION").unwrap_or(String::from("/tmp"));
|
let caching_location = env::var("CACHING_LOCATION").unwrap_or(String::from("/tmp"));
|
||||||
|
|
||||||
let path_name = format!("{}/sound-{}", caching_location, self.id);
|
let path_name = format!("{}/sound-{}", caching_location, self.id);
|
||||||
let path = Path::new(&path_name);
|
let path = Path::new(&path_name);
|
||||||
|
|
||||||
if !path.exists() {
|
if !path.exists() {
|
||||||
use tokio::prelude::*;
|
|
||||||
|
|
||||||
let mut file = File::create(&path).await?;
|
let mut file = File::create(&path).await?;
|
||||||
|
|
||||||
file.write_all(&self.get_self_src(db_pool).await).await?;
|
file.write_all(&self.get_self_src(db_pool).await).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ffmpeg(path_name).await?)
|
Ok(ffmpeg(path_name).await.expect("FFMPEG ERROR!"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn count_user_sounds(
|
pub async fn count_user_sounds(
|
||||||
@ -264,7 +262,7 @@ DELETE
|
|||||||
server_id: u64,
|
server_id: u64,
|
||||||
user_id: u64,
|
user_id: u64,
|
||||||
db_pool: MySqlPool,
|
db_pool: MySqlPool,
|
||||||
) -> Result<u64, Box<dyn std::error::Error + Send + Sync + Send>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync + Send>> {
|
||||||
async fn process_src(src_url: &str) -> Option<Vec<u8>> {
|
async fn process_src(src_url: &str) -> Option<Vec<u8>> {
|
||||||
let output = Command::new("ffmpeg")
|
let output = Command::new("ffmpeg")
|
||||||
.kill_on_drop(true)
|
.kill_on_drop(true)
|
||||||
@ -312,7 +310,7 @@ INSERT INTO sounds (name, server_id, uploader_id, public, src)
|
|||||||
.execute(&db_pool)
|
.execute(&db_pool)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(u) => Ok(u),
|
Ok(_) => Ok(()),
|
||||||
|
|
||||||
Err(e) => Err(Box::new(e)),
|
Err(e) => Err(Box::new(e)),
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user