From 9035c0cec8405cd96b585197d6069c553d503ba1 Mon Sep 17 00:00:00 2001 From: Gabriel Fontes Date: Fri, 28 Jan 2022 03:16:44 -0300 Subject: [PATCH] refactor --- Cargo.toml | 2 +- src/discord/mod.rs | 148 +++++++++++++++++++++++++++++++-------------- src/lib.rs | 2 +- 3 files changed, 103 insertions(+), 49 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ca8ad7c..16ef691 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ features = [ "rustls-tls" ] [dependencies.songbird] version = "0.2" default-features = false -features = [ "serenity-rustls", "driver", "gateway" ] +features = [ "serenity-rustls", "driver", "gateway", "builtin-queue" ] [dependencies.tokio] version = "1.0" diff --git a/src/discord/mod.rs b/src/discord/mod.rs index 6110316..22c6566 100644 --- a/src/discord/mod.rs +++ b/src/discord/mod.rs @@ -1,3 +1,4 @@ +use anyhow::{anyhow, Result}; use serenity::{ async_trait, client::{Context, EventHandler}, @@ -8,15 +9,18 @@ use serenity::{ model::channel::Message, utils::MessageBuilder, }; +use songbird::input::Input; +use std::sync::Arc; use sunk::{ search::{self, SearchPage}, + song::Song, Streamable, }; use crate::MusicClient; #[group] -#[commands(play)] +#[commands(song, random)] pub struct General; pub struct Handler; @@ -26,12 +30,11 @@ impl EventHandler for Handler {} #[command] #[only_in(guilds)] -#[aliases(p, queue, song)] -#[example("~play Down Under")] -#[description("Tocar uma música")] -async fn play(ctx: &Context, msg: &Message, args: Args) -> CommandResult { +#[aliases(s, p, play)] +#[example("~song Down Under")] +#[description("Play a named song")] +async fn song(ctx: &Context, msg: &Message, args: Args) -> CommandResult { let data = ctx.data.read().await; - let music_client = data .get::() .expect("Couldn't retrieve music client"); @@ -46,50 +49,101 @@ async fn play(ctx: &Context, msg: &Message, args: Args) -> CommandResult { match result.first() { Some(song) => { - let guild = msg.guild(&ctx.cache).await.unwrap(); - let guild_id = guild.id; - - let caller_channel = guild - .voice_states - .get(&msg.author.id) - .and_then(|voice_state| voice_state.channel_id); - - let connect_to = match caller_channel { - Some(channel) => channel, - None => { - msg.reply(ctx, "Você não está em um canal de voz").await?; - return Ok(()); - } - }; - - let manager = songbird::get(ctx).await.unwrap(); - let handler = manager.join(guild_id, connect_to).await; - let mut channel_handler = handler.0.lock().await; - - let url = song.stream_url(&music_client)?; - let input = songbird::ffmpeg(url).await.unwrap(); - - channel_handler.play_only_source(input); - - let message = MessageBuilder::new() - .push("Agora tocando ") - .push_bold_safe(format!( - "{} - {} ({})", - song.artist.clone().unwrap_or_default(), - song.title, - song.album.clone().unwrap_or_default(), - )) - .build(); - - msg.channel_id.say(&ctx.http, &message).await?; - + queue_song(ctx, msg, &song, &music_client).await?; Ok(()) } None => { - msg.channel_id - .say(&ctx.http, "Nenhuma música encontrada") - .await?; - Ok(()) + let text = "No song matching search found"; + msg.reply(&ctx.http, text).await?; + Err(anyhow!(text).into()) } } } + +#[command] +#[only_in(guilds)] +#[aliases(r, random, rand)] +#[example("~random")] +#[description("Play a random song")] +async fn random(ctx: &Context, msg: &Message) -> CommandResult { + let data = ctx.data.read().await; + let music_client = data + .get::() + .expect("Couldn't retrieve music client"); + + let result = Song::random(&music_client, 1).await?; + + match result.first() { + Some(song) => { + queue_song(ctx, msg, &song, &music_client).await?; + Ok(()) + } + None => { + let text = "No song found"; + msg.reply(&ctx.http, text).await?; + Err(anyhow!(text).into()) + } + } +} + +async fn queue_song( + ctx: &Context, + msg: &Message, + song: &Song, + client: &sunk::Client, +) -> Result<()> { + let input = load_song(song, client).await?; + let call = join_channel(&ctx, &msg).await?; + let mut handler = call.lock().await; + handler.enqueue_source(input); + + let song_info = format!( + "{} - {} ({}) ", + song.artist.clone().unwrap_or_default(), + song.title, + song.album.clone().unwrap_or_default(), + ); + + msg.reply( + &ctx.http, + &MessageBuilder::new() + .push("Added ") + .push_bold_safe(song_info) + .push("to the queue") + .build(), + ) + .await?; + + Ok(()) +} + +async fn join_channel<'a>( + ctx: &Context, + msg: &Message, +) -> Result>> { + let guild = msg.guild(&ctx.cache).await.unwrap(); + let guild_id = guild.id; + + let caller_channel = guild + .voice_states + .get(&msg.author.id) + .and_then(|voice_state| voice_state.channel_id); + + let connect_to = match caller_channel { + Some(channel) => channel, + None => { + let text = "You must be in a voice channel to use this command"; + msg.reply(ctx, text).await?; + return Err(anyhow!(text)); + } + }; + + let manager = songbird::get(ctx).await.unwrap(); + let handler = manager.join(guild_id, connect_to).await.0; + Ok(handler) +} + +async fn load_song(song: &Song, client: &sunk::Client) -> Result { + let url = song.stream_url(&client)?; + Ok(songbird::ffmpeg(url).await?) +} diff --git a/src/lib.rs b/src/lib.rs index 4df42cc..15e4176 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ pub mod client; -pub use client::{MusicClient, Client}; +pub use client::{Client, MusicClient}; pub mod discord;