diff --git a/.gitignore b/.gitignore index f680304..5de384b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ /target /data -config.json \ No newline at end of file +config.json + +.idea/ diff --git a/src/commands/play.rs b/src/commands/play.rs index 874c8e9..9d536ea 100644 --- a/src/commands/play.rs +++ b/src/commands/play.rs @@ -3,22 +3,24 @@ use serenity::all::{CommandDataOption, CommandDataOptionValue, CommandInteractio use serenity::builder::{CreateCommand, CreateCommandOption, CreateEmbed, CreateEmbedAuthor, CreateEmbedFooter}; use serenity::model::application::CommandOptionType; +use crate::util::user_util; + pub async fn run(ctx: &Context, command: &CommandInteraction) -> CreateEmbed { let username = command.user.name.as_str(); let current_time = Local::now().format("%Y-%m-%d @ %H:%M:%S"); let options = &command.data.options; let query = if let Some(CommandDataOption { - value: CommandDataOptionValue::String(query), .. - }) = &options.first() + value: CommandDataOptionValue::String(query), .. + }) = &options.first() { query } else { return CreateEmbed::new() - .author(CreateEmbedAuthor::new("Rustendo")) - .title("Error 400") - .description("There is no query provied.") - .footer(CreateEmbedFooter::new(format!(">{} | {}", current_time, username))) + .author(CreateEmbedAuthor::new("Rustendo")) + .title("Error 400") + .description("There is no query provied.") + .footer(CreateEmbedFooter::new(format!(">{} | {}", current_time, username))) }; let guild_id = match &command.guild_id { @@ -26,14 +28,14 @@ pub async fn run(ctx: &Context, command: &CommandInteraction) -> CreateEmbed { None => { return CreateEmbed::new() .author(CreateEmbedAuthor::new("Rustendo")) - .title("guildid not found") + .title("GuildId not found") .description("Could not find guild id.") .footer(CreateEmbedFooter::new(format!("> {} | {}", current_time, username))); } }; - + let (guild_id, channel_id) = { - let guild = &ctx.cache.guild(guild_id).unwrap(); + let guild = &ctx.cache.guild(guild_id).unwrap(); // TODO: This unwrap throws errors. // This may be unsafe, idk not sure yet let channel_id = guild .voice_states @@ -52,26 +54,40 @@ pub async fn run(ctx: &Context, command: &CommandInteraction) -> CreateEmbed { .footer(CreateEmbedFooter::new(format!("> {} | {}", current_time, username))); }, }; - + let manager = &songbird::get(ctx) .await - .expect("") + .expect("Cannot get Songbird.") .clone(); - manager.join(guild_id, connect_to).await.expect("Cannot connect>..."); + if !user_util::is_self_connected_to_vc(&ctx, &guild_id) { + // self is connected to vc, check if user is in same vc + let self_channel = user_util::get_self_vc_id(&ctx, &guild_id); + // Check if user is in the same VC as the bot + if self_channel != connect_to { + return CreateEmbed::new() + .author(CreateEmbedAuthor::new("Rustendo")) + .title("You are not in my VC.") + .description("Connect to my VC to control the music.") + .footer(CreateEmbedFooter::new(format!("> {} | {}", current_time, username))); + } + // Connect to VC + manager.join(guild_id, connect_to).await.expect("Cannot connect>..."); + } CreateEmbed::new() - .author(CreateEmbedAuthor::new("Rustendo")) - .title(format!("Searching for {}", query)) - .footer(CreateEmbedFooter::new(format!(">{} | {}", current_time, username))) + .author(CreateEmbedAuthor::new("Rustendo")) + .title("Searching...") + .description(format!("Looking for {}", query)) + .footer(CreateEmbedFooter::new(format!(">{} | {}", current_time, username))) } pub fn register() -> CreateCommand { CreateCommand::new("play") - .description("Play music") - .add_option( - CreateCommandOption::new(CommandOptionType::String, "query", "Link or search term") - .required(true) - ) + .description("Play music") + .add_option( + CreateCommandOption::new(CommandOptionType::String, "query", "Link or search term") + .required(true) + ) } diff --git a/src/commands/stop.rs b/src/commands/stop.rs index 261934a..c7333dc 100644 --- a/src/commands/stop.rs +++ b/src/commands/stop.rs @@ -2,13 +2,57 @@ use chrono::Local; use serenity::all::{CommandInteraction, Context}; use serenity::builder::{CreateCommand, CreateEmbed, CreateEmbedAuthor, CreateEmbedFooter}; -pub async fn run(_ctx: &Context, command: &CommandInteraction) -> CreateEmbed { +use crate::util::user_util; +pub async fn run(ctx: &Context, command: &CommandInteraction) -> CreateEmbed { let username = command.user.name.as_str(); let current_time = Local::now().format("%Y-%m-%d @ %H:%M:%S"); + + let guild_id = match &command.guild_id { + Some(guild_id) => guild_id, + None => { + return CreateEmbed::new() + .author(CreateEmbedAuthor::new("Rustendo")) + .title("GuildId not found") + .description("Could not find guild id.") + .footer(CreateEmbedFooter::new(format!("> {} | {}", current_time, username))); + } + }; + + if !user_util::is_self_connected_to_vc(&ctx, guild_id) { + // Bot is not connectd to vc; no need to dc + return CreateEmbed::new() + .author(CreateEmbedAuthor::new("Rustendo")) + .title("Bot is not connected") + .description("And therefore I cannot stop playing.") + .footer(CreateEmbedFooter::new(format!("> {} | {}", current_time, username))); + } + + let manager = songbird::get(&ctx) + .await + .expect("Cannot get Songbird") + .clone(); + + let has_handler = manager.get(guild_id.clone()).is_some(); + + if has_handler { + if let Err(e) = manager.remove(guild_id.clone()).await { + return CreateEmbed::new() + .author(CreateEmbedAuthor::new("Rustendo")) + .title("There was an error") + .description(format!("Failed: {:?}", e)) + .footer(CreateEmbedFooter::new(format!("> {} | {}", current_time, username))); + } + return CreateEmbed::new() + .author(CreateEmbedAuthor::new("Rustendo")) + .title("I stopped and left\nJust like your girlfriend.") + .footer(CreateEmbedFooter::new(format!(">{} | {}", current_time, username))) + } + CreateEmbed::new() - .author(CreateEmbedAuthor::new("Rustendo")) - .title("I stopped and left\nJust like your girlfriend.") - .footer(CreateEmbedFooter::new(format!(">{} | {}", current_time, username))) + .author(CreateEmbedAuthor::new("Rustendo")) + .title("Bot is not connected") + .description("And therefore I cannot stop playing.\nSomething happend, which shouldn't have.") + .footer(CreateEmbedFooter::new(format!("> {} | {}", current_time, username))) } @@ -17,4 +61,4 @@ pub fn register() -> CreateCommand { } // >18/02/2024 @ 19:01:59 - bartlo -// >2024-02-19 17:58:39 | moonleay \ No newline at end of file +// >2024-02-19 17:58:39 | moonleay diff --git a/src/util/mod.rs b/src/util/mod.rs index a105933..1a9154c 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1 +1,2 @@ -pub mod config; \ No newline at end of file +pub mod config; +pub mod user_util; \ No newline at end of file diff --git a/src/util/user_util.rs b/src/util/user_util.rs new file mode 100644 index 0000000..4ea3778 --- /dev/null +++ b/src/util/user_util.rs @@ -0,0 +1,42 @@ +use serenity::all::{ChannelId, Context, CreateEmbed, CreateEmbedAuthor, CreateEmbedFooter, GuildId}; + +pub fn is_self_connected_to_vc(ctx: &Context, guild_id: &GuildId) -> bool { + let self_id = &ctx.cache.current_user().id; + + let (_guild_id, channel_id) = { + let guild = &ctx.cache.guild(guild_id).unwrap(); + // This may be unsafe, idk not sure yet + let channel_id = guild + .voice_states + .get(self_id) + .and_then(|voice_state| voice_state.channel_id); + (guild.id, channel_id) + }; + + // TODO: There has to be a way to improve this. This is bad code and it should be optimized. + let connect_to = match channel_id { + Some(channel) => channel, + None => { + return false + }, + }; + + true +} +// This whole file is jank. I have to rewrite this once I know Rust better + +pub fn get_self_vc_id(ctx: &Context, guild_id: &GuildId) -> ChannelId { + let self_id = &ctx.cache.current_user().id; + let (guild_id, channel_id) = { + let guild = &ctx.cache.guild(guild_id).unwrap(); + // This may be unsafe, idk not sure yet + let channel_id = guild + .voice_states + .get(&self_id) + .and_then(|voice_state| voice_state.channel_id); + (guild.id, channel_id) + }; + + channel_id.unwrap() + +}