use crate::messages::music::now_playing::update_now_playing_msg; use crate::providers::music::lavalink::Lavalink; use crate::providers::music::lyrics::get_lyrics; use crate::providers::music::queue::MusicQueue; use crate::utils::context_data::MusicPlayers; use crate::utils::error::BotResult; use bot_serenityutils::core::MessageHandle; use lavalink_rs::LavalinkClient; use serenity::client::Context; use serenity::http::Http; use serenity::model::id::{ChannelId, GuildId}; use std::mem; use std::sync::Arc; use tokio::sync::{Mutex, RwLock}; pub struct MusicPlayer { client: Arc, http: Arc, queue: MusicQueue, guild_id: GuildId, now_playing_msg: Option>>, leave_flag: bool, paused: bool, } impl MusicPlayer { /// Creates a new music player pub fn new(client: Arc, http: Arc, guild_id: GuildId) -> Self { Self { client, http, guild_id, queue: MusicQueue::new(), now_playing_msg: None, leave_flag: false, paused: false, } } /// Joins a given voice channel pub async fn join( ctx: &Context, guild_id: GuildId, voice_channel_id: ChannelId, ) -> BotResult>> { let manager = songbird::get(ctx).await.unwrap(); let (_, connection) = manager.join_gateway(guild_id, voice_channel_id).await; let connection = connection?; let player = { let mut data = ctx.data.write().await; let client = data.get::().unwrap(); client.create_session(&connection).await?; let player = MusicPlayer::new(Arc::clone(client), Arc::clone(&ctx.http), guild_id); let player = Arc::new(Mutex::new(player)); let players = data.get_mut::().unwrap(); players.insert(guild_id.0, Arc::clone(&player)); player }; Ok(player) } /// Returns a mutable reference to the inner queue pub fn queue(&mut self) -> &mut MusicQueue { &mut self.queue } /// Skips to the next song pub async fn skip(&mut self) -> BotResult<()> { self.client.stop(self.guild_id.0).await?; Ok(()) } /// Stops playback and leaves the channel pub async fn stop(&mut self) -> BotResult<()> { self.queue.clear(); self.client.stop(self.guild_id.0).await?; Ok(()) } /// Returns the lyrics for the currently playing song pub async fn lyrics(&self) -> BotResult> { if let Some(current) = self.queue.current() { let title = current.title(); let artist = current.author(); get_lyrics(artist, title).await } else { Ok(None) } } /// Plays the next song in the queue pub async fn play_next(&mut self) -> BotResult<()> { while !self.try_play_next().await? {} Ok(()) } /// Tries to play the next song pub async fn try_play_next(&mut self) -> BotResult { let mut next = if let Some(n) = self.queue.next() { n } else { return Ok(true); }; let url = if let Some(url) = next.url().await { url } else { return Ok(false); }; let query_information = match self.client.auto_search_tracks(url).await { Ok(i) => i, Err(e) => { log::error!("Failed to search for song: {}", e); return Ok(false); } }; let track = query_information.tracks[0].clone(); self.client.play(self.guild_id.0, track).start().await?; self.queue.set_current(next); Ok(true) } /// Sets the new now playing message of the queue pub async fn set_now_playing(&mut self, message: Arc>) { let _ = self.delete_now_playing().await; self.now_playing_msg = Some(message) } /// Updates the now playing message pub async fn update_now_playing(&self) -> BotResult<()> { if let (Some(current), Some(np)) = (self.queue.current(), &self.now_playing_msg) { update_now_playing_msg(&self.http, np, &mut current.clone(), self.is_paused()).await?; } Ok(()) } /// Deletes the now playing message pub async fn delete_now_playing(&mut self) -> BotResult<()> { if let Some(np) = mem::take(&mut self.now_playing_msg) { let np = np.read().await; let msg = np.get_message(&self.http).await?; msg.delete(&self.http).await?; } Ok(()) } /// Pauses playback pub async fn toggle_paused(&mut self) -> BotResult<()> { self.paused = !self.paused; self.client.set_pause(self.guild_id.0, self.paused).await?; Ok(()) } /// Returns if playback is paused pub fn is_paused(&self) -> bool { self.paused } /// Returns the now playing message of the player pub fn now_playing_message(&self) -> &Option>> { &self.now_playing_msg } /// Deletes the now playing message from the player pub fn clear_now_playing(&mut self) { self.now_playing_msg = None; } /// Sets the leave flag to the given value pub fn set_leave_flag(&mut self, flag: bool) { self.leave_flag = flag; } }