use crate::music::{music_events, music_queue}; use crate::util::embed::Embed; use crate::util::user_util; use crate::util::user_util::get_vc_id; use crate::HttpKey; use serenity::all::{Context, CreateEmbed, GuildId, UserId}; use songbird::error::JoinError; use songbird::input::YoutubeDl; use songbird::{Event, TrackEvent}; use std::sync::Arc; /// Either queues the song, or start playing it instantly, depending on if there is already a song playing pub async fn attempt_to_queue_song( ctx: &Context, guild_id: &GuildId, user_id: &UserId, username: &str, query: &str, ) -> CreateEmbed { if !user_util::is_user_connected_to_vc(ctx, guild_id, user_id).await { return Embed::create_error_respose( username, "You are not connected to a VC", "Connect to my vc to start controlling the music.", ); } let connect_to = match get_vc_id(ctx, guild_id, user_id).await { Some(channel_id) => channel_id, None => { return Embed::create_error_respose(username, "Error", "Cannot find channel_id."); } }; let manager: &Arc = &songbird::get(ctx) // TODO match .await .expect("Cannot get Songbird.") .clone(); let self_channel = user_util::get_self_vc_id(ctx, guild_id).await; if !user_util::is_self_connected_to_vc(ctx, guild_id).await { // self is connected to vc, check if user is in same vc if self_channel.is_none() { // Connect to VC manager // TODO match .join(*guild_id, connect_to) .await .expect("Cannot connect>..."); } } else { let self_channel = self_channel.expect("Cannot get self channel"); // TODO: match // Check if user is in the same VC as the bot if self_channel != connect_to { return Embed::create_error_respose( username, "You are not in my VC", "You have to be in my VC in order to controll the music.", ); } } // Get query let do_search = !query.starts_with("http"); let http_client = { let data = ctx.data.read().await; data.get::() .cloned() .expect("Guaranteed to exist in the typemap.") }; // Create source let src = if do_search { YoutubeDl::new_search(http_client, query.to_string()) } else { YoutubeDl::new(http_client, query.to_string()) }; let currently_playing = music_queue::get_now_playing(guild_id).await; music_queue::add_to_queue(guild_id, src.clone()).await; if currently_playing.is_some() { // Add to queue return Embed::create_yt_playing(src, username, "Added to queue").await; } let _query = music_queue::get_head(guild_id) .await .expect("Cannot get head of queue"); music_queue::set_now_playing(guild_id, Some(src.clone())).await; let handler_lock = match manager.get(*guild_id) { Some(handler) => handler, None => { return Embed::create_error_respose( username, "Error", "Cannot get handler of this guild.", ); } }; // Start playing let mut handler = handler_lock.lock().await; let _ = handler.play_input(src.clone().into()); // TODO: Add event handlers handler.add_global_event( Event::Track(TrackEvent::End), music_events::TrackEndNotifier { guild_id: *guild_id, channel_id: connect_to, http: Arc::clone(&ctx.http), cmdctx: Arc::new(ctx.clone()), }, ); Embed::create_yt_playing(src, username, "Now playing").await } /// Play the provided song pub async fn play_song(ctx: &Context, guild_id: &GuildId, target: &YoutubeDl) { let manager = &songbird::get(ctx) // TODO match .await .expect("Cannot get Songbird.") .clone(); if !user_util::is_self_connected_to_vc(ctx, guild_id).await { println!("Bot is not connected to a VC, cannot play."); return; } music_queue::set_now_playing(guild_id, Some(target.clone())).await; let handler_lock = match manager.get(*guild_id) { Some(handler) => handler, None => return, }; let mut handler = handler_lock.lock().await; handler.stop(); // Stop playing the current song let _ = handler.play_input(target.clone().into()); // TODO: Add event handlers } /// Attempt to skip the song, which is currently playing. Do nothing if there is no next song pub async fn attempt_to_skip_current_song( ctx: &Context, guild_id: &GuildId, user_id: &UserId, username: &str, ) -> CreateEmbed { if !user_util::is_user_connected_to_vc(ctx, guild_id, user_id).await { return Embed::create_error_respose( username, "You are not connected to a VC", "Connect to my vc to start controlling the music.", ); } let connect_to = match get_vc_id(ctx, guild_id, user_id).await { Some(channel_id) => channel_id, None => { return Embed::create_error_respose(username, "Error", "Cannot find channel_id."); } }; let manager: &Arc = &songbird::get(ctx) // TODO match .await .expect("Cannot get Songbird.") .clone(); let self_channel = user_util::get_self_vc_id(ctx, guild_id).await; if !user_util::is_self_connected_to_vc(ctx, guild_id).await { // self is connected to vc, check if user is in same vc if self_channel.is_none() { // Connect to VC manager // TODO match .join(*guild_id, connect_to) .await .expect("Cannot connect>..."); } } else { let self_channel = self_channel.expect("Cannot get self channel"); // TODO: match // Check if user is in the same VC as the bot if self_channel != connect_to { return Embed::create_error_respose( username, "You are not in my VC", "You have to be in my VC in order to controll the music.", ); } } let head = music_queue::get_head(guild_id).await; // TODO match if head.is_none() { return Embed::create_error_respose( username, "Cannot find a song to play", "The queue is empty.", ); } let head = head.unwrap(); play_song(ctx, guild_id, &head).await; Embed::create_yt_playing(head, username, "Song skipped; Now playing").await } /// Try to clear the queue and stop playing. Also leave the vc pub async fn attempt_to_stop( ctx: &Context, guild_id: &GuildId, user_id: &UserId, username: &str, ) -> CreateEmbed { if !user_util::is_self_connected_to_vc(ctx, guild_id).await { // Bot is not connectd to vc; no need to dc return Embed::create_error_respose( username, "Bot is not connected", "And therefore there is no need to do anything.", ); } let self_channel = user_util::get_self_vc_id(ctx, guild_id) .await .expect("Cannot get self channel"); let connect_to = get_vc_id(ctx, guild_id, user_id) .await .expect("Cannot get channel id"); // Check if user is in the same VC as the bot if self_channel != connect_to { return Embed::create_error_respose( username, "You are not in my VC.", "Connect to my VC to controll the music.", ); } let stopped = match leave(ctx, guild_id).await { Ok(stopped) => stopped, Err(e) => { println!("Error while stopping: {:?}", e); return Embed::create_error_respose( username, "There was an error", "Tell moonleay to check the logs.", ); } }; if !stopped { Embed::create_error_respose( username, "Can't stop, what ain't running", "I am not connected.\nI cant stop doing something, when I'm not doing it.", ) } else { music_queue::delete_queue(guild_id).await; // Clear queue Embed::create_success_response(username, "I stopped and left", "Just like you girlfriend.") } } /// Make the bot leave the voice channel. Returns Ok(true) if bot was connected, returns Ok(false) if bot was not connected. Returns Err if something went wrong. pub async fn leave(ctx: &Context, guild_id: &GuildId) -> Result { let manager = songbird::get(ctx) .await .expect("Cannot get Songbird") .clone(); let handler = manager.get(*guild_id); let has_handler = handler.is_some(); if has_handler { handler.unwrap().lock().await.stop(); manager.remove(*guild_id).await?; return Ok(true); // Handler removed } Ok(false) // No handler, so it's already stopped }