This commit is contained in:
Gabriel Fontes
2022-01-28 03:16:44 -03:00
parent c8c2b86ea6
commit 9035c0cec8
3 changed files with 103 additions and 49 deletions

View File

@@ -26,7 +26,7 @@ features = [ "rustls-tls" ]
[dependencies.songbird] [dependencies.songbird]
version = "0.2" version = "0.2"
default-features = false default-features = false
features = [ "serenity-rustls", "driver", "gateway" ] features = [ "serenity-rustls", "driver", "gateway", "builtin-queue" ]
[dependencies.tokio] [dependencies.tokio]
version = "1.0" version = "1.0"

View File

@@ -1,3 +1,4 @@
use anyhow::{anyhow, Result};
use serenity::{ use serenity::{
async_trait, async_trait,
client::{Context, EventHandler}, client::{Context, EventHandler},
@@ -8,15 +9,18 @@ use serenity::{
model::channel::Message, model::channel::Message,
utils::MessageBuilder, utils::MessageBuilder,
}; };
use songbird::input::Input;
use std::sync::Arc;
use sunk::{ use sunk::{
search::{self, SearchPage}, search::{self, SearchPage},
song::Song,
Streamable, Streamable,
}; };
use crate::MusicClient; use crate::MusicClient;
#[group] #[group]
#[commands(play)] #[commands(song, random)]
pub struct General; pub struct General;
pub struct Handler; pub struct Handler;
@@ -26,12 +30,11 @@ impl EventHandler for Handler {}
#[command] #[command]
#[only_in(guilds)] #[only_in(guilds)]
#[aliases(p, queue, song)] #[aliases(s, p, play)]
#[example("~play Down Under")] #[example("~song Down Under")]
#[description("Tocar uma música")] #[description("Play a named song")]
async fn play(ctx: &Context, msg: &Message, args: Args) -> CommandResult { async fn song(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
let data = ctx.data.read().await; let data = ctx.data.read().await;
let music_client = data let music_client = data
.get::<MusicClient>() .get::<MusicClient>()
.expect("Couldn't retrieve music client"); .expect("Couldn't retrieve music client");
@@ -46,50 +49,101 @@ async fn play(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
match result.first() { match result.first() {
Some(song) => { Some(song) => {
let guild = msg.guild(&ctx.cache).await.unwrap(); queue_song(ctx, msg, &song, &music_client).await?;
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?;
Ok(()) Ok(())
} }
None => { None => {
msg.channel_id let text = "No song matching search found";
.say(&ctx.http, "Nenhuma música encontrada") msg.reply(&ctx.http, text).await?;
.await?; Err(anyhow!(text).into())
Ok(())
} }
} }
} }
#[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::<MusicClient>()
.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<Arc<serenity::prelude::Mutex<songbird::Call>>> {
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<Input> {
let url = song.stream_url(&client)?;
Ok(songbird::ffmpeg(url).await?)
}

View File

@@ -1,4 +1,4 @@
pub mod client; pub mod client;
pub use client::{MusicClient, Client}; pub use client::{Client, MusicClient};
pub mod discord; pub mod discord;