[WIP] Rewrite with Poise

Still some missing commands
This commit is contained in:
Alex Page 2023-03-01 22:29:07 -05:00
parent f00c76f2c5
commit 1342253a76
3 changed files with 166 additions and 526 deletions

View file

@ -1,326 +1,110 @@
use serenity::client::Context;
use serenity::model::interactions::application_command::{
ApplicationCommandInteraction, ApplicationCommandInteractionDataOptionValue,
};
use serenity::utils::{EmbedMessageBuilding, MessageBuilder};
use anyhow::{Context, Result};
use poise::serenity_prelude::{EmbedMessageBuilding, MessageBuilder};
use songbird::create_player;
use songbird::input::Input;
use tracing::debug;
use crate::{CurrentVolume, CurrentlyPlayingTrack};
use crate::{CommandContext, Error};
pub async fn join(ctx: &Context, command: &ApplicationCommandInteraction) -> String {
let guild_id = command.guild_id.unwrap();
let guild = guild_id.to_guild_cached(&ctx.cache).await.unwrap();
let channel_id = guild
.voice_states
.get(&command.user.id)
.and_then(|voice_state| voice_state.channel_id);
let connect_to = match channel_id {
Some(channel) => channel,
None => {
return "You're not in a voice channel. How do I know where to go?".to_string();
}
#[poise::command(slash_command)]
pub async fn join(ctx: CommandContext<'_>) -> Result<(), Error> {
let Some(guild) = ctx.guild() else {
ctx.say("You're not in a server, silly.").await?;
return Ok(());
};
let manager = songbird::get(ctx)
.await
.expect("Songbird Voice client placed in at initialisation.")
.clone();
let _handler = manager.join(guild_id, connect_to).await;
"Joining your channel!".to_string()
}
pub async fn leave(ctx: &Context, command: &ApplicationCommandInteraction) -> String {
let guild_id = command.guild_id.unwrap();
let manager = songbird::get(ctx)
.await
.expect("Songbird Voice client placed in at initialisation.")
.clone();
let has_handler = manager.get(guild_id).is_some();
if has_handler {
if let Err(e) = manager.remove(guild_id).await {
return format!("Failed: {:?}", e);
}
"Goodbye!".to_string()
} else {
"I can't leave if I'm not there to bein with!".to_string()
}
}
pub async fn play(ctx: &mut Context, command: &ApplicationCommandInteraction) -> String {
let options = command
.data
.options
.get(0)
.expect("Expected url option")
.resolved
.as_ref()
.expect("Expected url object");
let url = match options {
ApplicationCommandInteractionDataOptionValue::String(url) => url,
_ => {
return "You didn't tell me what to play.".to_string();
}
let Some(Some(channel_id)) = guild.voice_states.get(&ctx.author().id).map(|vs| vs.channel_id) else {
ctx.say("You're not in a voice channel, silly.").await?;
return Ok(());
};
if !url.starts_with("http") {
return "That's not a real URL. I'm onto you.".to_string();
}
let guild_id = command.guild_id.unwrap();
let manager = songbird::get(ctx)
let manager = songbird::get(ctx.serenity_context())
.await
.expect("Songbird Voice client placed in at initialisation.")
.context("Expected a songbird manager")?
.clone();
let _handler = manager.join(guild.id, channel_id).await;
ctx.say("Joining your channel!").await?;
Ok(())
}
#[poise::command(slash_command)]
pub async fn leave(ctx: CommandContext<'_>) -> Result<(), Error> {
let Some(guild) = ctx.guild() else {
ctx.say("You're not in a server, silly.").await?;
return Ok(());
};
let manager = songbird::get(ctx.serenity_context())
.await
.context("Expected a songbird manager")?
.clone();
// Try to join the caller's channel
if manager.get(guild_id).is_none() {
join(ctx, command).await;
if manager.get(guild.id).is_none() {
ctx.say("I'm not even in a voice channel!").await?;
return Ok(());
}
if let Some(handler_lock) = manager.get(guild_id) {
let _handler = manager.remove(guild.id).await;
ctx.say("Okay bye!").await?;
Ok(())
}
#[poise::command(slash_command)]
pub async fn play(
ctx: CommandContext<'_>,
#[description = "The URL of the song to play"] url: Option<String>,
) -> Result<(), Error> {
let Some(url) = url else {
ctx.say("You need to give me a URL to play!").await?;
return Ok(());
};
let Some(guild) = ctx.guild() else {
ctx.say("You're not in a server, silly.").await?;
return Ok(());
};
let manager = songbird::get(ctx.serenity_context())
.await
.context("Expected a songbird manager")?
.clone();
if manager.get(guild.id).is_none() {
let Some(Some(channel_id)) = guild.voice_states.get(&ctx.author().id).map(|vs| vs.channel_id) else {
ctx.say("Neither of us are in a voice channel, silly.").await?;
return Ok(());
};
let _handler = manager.join(guild.id, channel_id).await;
}
if let Some(handler_lock) = manager.get(guild.id) {
let mut handler = handler_lock.lock().await;
let source = match songbird::input::Restartable::ytdl(url.clone(), false).await {
Ok(source) => source,
Err(why) => {
println!("Err starting source: {:?}", why);
debug!("Trying to play: {}", url);
let source = songbird::ytdl(&url).await?;
debug!("Playing: {:?}", source.metadata);
let title = source
.metadata
.title
.clone()
.unwrap_or(String::from("This video"));
let msg = MessageBuilder::new()
.push("Now playing: ")
.push_named_link(title, url)
.build();
ctx.say(msg).await?;
return "Something went horribly wrong. Go yell at Valter.".to_string();
}
};
let source_input: Input = source.into();
let message = {
if let Some(title) = &source_input.metadata.title {
let mut msg = MessageBuilder::new();
msg.push_line("Playing this:");
msg.push_named_link(title, url);
msg.build()
} else {
"Playing something, I dunno what.".to_string()
}
};
let (mut audio, track_handle) = create_player(source_input);
let mut data = ctx.data.write().await;
let current_track = data.get_mut::<CurrentlyPlayingTrack>().unwrap();
*current_track = Some(track_handle);
let volume = data.get::<CurrentVolume>().unwrap();
audio.set_volume(*volume);
let (audio, track_handle) = create_player(source);
let mut currently_playing = ctx.data().currently_playing.lock();
*currently_playing = Some(track_handle);
handler.play_only(audio);
message
} else {
"Somehow neither of us are in a voice channel to begin with.".to_string()
}
}
pub async fn queue(ctx: &mut Context, command: &ApplicationCommandInteraction) -> String {
let options = command
.data
.options
.get(0)
.expect("Expected url option")
.resolved
.as_ref()
.expect("Expected url object");
let url = match options {
ApplicationCommandInteractionDataOptionValue::String(url) => url,
_ => {
return "You didn't tell me what to play.".to_string();
}
};
if !url.starts_with("http") {
return "That's not a real URL. I'm onto you.".to_string();
}
let guild_id = command.guild_id.unwrap();
let manager = songbird::get(ctx)
.await
.expect("Songbird Voice client placed in at initialisation.")
.clone();
// Try to join the caller's channel
if manager.get(guild_id).is_none() {
join(ctx, command).await;
}
if let Some(handler_lock) = manager.get(guild_id) {
let mut handler = handler_lock.lock().await;
let source = match songbird::input::Restartable::ytdl(url.clone(), false).await {
Ok(source) => source,
Err(why) => {
println!("Err starting source: {:?}", why);
return "Something went horribly wrong. Go yell at Valter.".to_string();
}
};
let source_input: Input = source.into();
let message = {
if let Some(title) = &source_input.metadata.title {
let mut msg = MessageBuilder::new();
msg.push_line(format!(
"Queueing this up at position {}:",
handler.queue().len()
));
msg.push_named_link(title, url);
msg.build()
} else {
format!(
"Queueing something up at position {}, I dunno what.",
handler.queue().len()
)
.to_string()
}
};
let (mut audio, track_handle) = create_player(source_input);
let mut data = ctx.data.write().await;
let current_track = data.get_mut::<CurrentlyPlayingTrack>().unwrap();
*current_track = Some(track_handle);
let volume = data.get::<CurrentVolume>().unwrap();
audio.set_volume(*volume);
handler.enqueue(audio);
message
} else {
"Somehow neither of us are in a voice channel to begin with.".to_string()
}
}
pub async fn skip(ctx: &Context, command: &ApplicationCommandInteraction) -> String {
let guild_id = command.guild_id.unwrap();
let manager = songbird::get(ctx)
.await
.expect("Songbird Voice client placed in at initialisation.")
.clone();
if let Some(handler_lock) = manager.get(guild_id) {
let handler = handler_lock.lock().await;
let queue = handler.queue();
let _ = queue.skip();
format!("Yeah, I didn't like this one very much anyway. Skip! Now we're at number {} in the queue.", queue.len())
} else {
"I'm not even in a channel to begin with. Silly.".to_string()
}
}
pub async fn stop(ctx: &Context, command: &ApplicationCommandInteraction) -> String {
let guild_id = command.guild_id.unwrap();
let manager = songbird::get(ctx)
.await
.expect("Songbird Voice client placed in at initialisation.")
.clone();
if let Some(handler_lock) = manager.get(guild_id) {
let mut handler = handler_lock.lock().await;
handler.stop();
"Alright, I guess I'll stop.".to_string()
} else {
"I'm not even in a channel to begin with. Silly.".to_string()
}
}
pub async fn set_volume(ctx: &mut Context, command: &ApplicationCommandInteraction) -> String {
let options = command
.data
.options
.get(0)
.expect("Expected volume option")
.resolved
.as_ref()
.expect("Expected volume object");
let volume = match options {
ApplicationCommandInteractionDataOptionValue::Number(volume) => *volume,
_ => {
return "You've gotta give me a volume level to set.".to_string();
}
};
if !(0.0..=100.0).contains(&volume) {
return "Volume has to be between 0 and 100.".to_string();
}
let mut data = ctx.data.write().await;
let current_volume = data.get_mut::<CurrentVolume>().unwrap();
let new_volume = (volume / 100.0) as f32;
*current_volume = new_volume;
let current_track = data.get::<CurrentlyPlayingTrack>().unwrap();
if let Some(track) = current_track {
if track.set_volume(new_volume).is_err() {
return format!(
"Setting volume to {}%, but it didn't work for the current track for some reason.",
volume
);
}
}
format!("Setting volume to {}%.", volume)
}
pub async fn set_loop(ctx: &mut Context, command: &ApplicationCommandInteraction) -> String {
let options = command
.data
.options
.get(0)
.expect("Expected loop option")
.resolved
.as_ref()
.expect("Expected loop object");
let loops = match options {
ApplicationCommandInteractionDataOptionValue::Boolean(loops) => *loops,
_ => {
return "Do you want me to loop the song or not? Be specific.".to_string();
}
};
let data = ctx.data.write().await;
let current_track = data.get::<CurrentlyPlayingTrack>().unwrap();
if let Some(track) = current_track {
if loops {
track.enable_loop().expect("Couldn't enable looping");
"Loopin'!".to_string()
} else {
track.disable_loop().expect("Couldn't disable looping");
"This is the last time this track will EVER be played.".to_string()
}
} else {
"I can't loop a song if there is no song to loop.".to_string()
ctx.say("Neither of us are in a voice channel, silly.")
.await?;
}
Ok(())
}