346 lines
10 KiB
Rust
346 lines
10 KiB
Rust
use anyhow::{Context, Result};
|
|
use poise::{
|
|
serenity_prelude::{CreateEmbed, EmbedMessageBuilding, MessageBuilder},
|
|
CreateReply,
|
|
};
|
|
use songbird::input::{Input, YoutubeDl};
|
|
use tracing::{debug, log::warn};
|
|
|
|
use crate::{personality, CommandContext, Error};
|
|
|
|
#[poise::command(slash_command)]
|
|
pub async fn join(ctx: CommandContext<'_>) -> Result<(), Error> {
|
|
let Some((guild_id, Some(channel_id))) = ctx.guild().and_then(|g| {
|
|
g.voice_states
|
|
.get(&ctx.author().id)
|
|
.map(|vs| (g.id, vs.channel_id))
|
|
}) else {
|
|
ctx.say("You're not in a voice channel, silly.").await?;
|
|
return Ok(());
|
|
};
|
|
|
|
let manager = songbird::get(ctx.serenity_context())
|
|
.await
|
|
.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_id) = ctx.guild().map(|g| g.id) 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() {
|
|
ctx.say("I'm not even in a voice channel!").await?;
|
|
return Ok(());
|
|
}
|
|
|
|
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_id) = ctx.guild().map(|g| g.id) 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((guild_id, Some(channel_id))) = ctx.guild().and_then(|g| {
|
|
g.voice_states
|
|
.get(&ctx.author().id)
|
|
.map(|vs| (g.id, vs.channel_id))
|
|
}) else {
|
|
ctx.say("You're not 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 reply = poise::CreateReply::default()
|
|
.content(personality::get_random_loading_message())
|
|
.embed(
|
|
CreateEmbed::new()
|
|
.image("https://media.giphy.com/media/H1dxi6xdh4NGQCZSvz/giphy.gif"),
|
|
);
|
|
let response = ctx.send(reply).await?;
|
|
|
|
let mut handler = handler_lock.lock().await;
|
|
|
|
debug!("Trying to play: {}", url);
|
|
let mut source: Input = YoutubeDl::new(ctx.data().http_client.clone(), url.clone()).into();
|
|
let metadata = source.aux_metadata().await?;
|
|
|
|
debug!("Playing: {:?}", metadata);
|
|
let title = metadata.title.clone().unwrap_or(String::from("This video"));
|
|
|
|
let mut msg = MessageBuilder::new();
|
|
|
|
// Optional sassy commentary!
|
|
match personality::get_sassy_commentary(&title).await {
|
|
Ok(commentary) => {
|
|
msg.push_line(&commentary).push_line("");
|
|
}
|
|
Err(e) => {
|
|
warn!("Failed to get sassy commentary for \"{title}\": {e}");
|
|
}
|
|
};
|
|
|
|
msg.push_bold("Now playing: ").push_named_link(title, url);
|
|
|
|
response
|
|
.edit(ctx, CreateReply::default().content(msg.build()))
|
|
.await?;
|
|
|
|
let mut queue = ctx.data().queue.lock();
|
|
if !queue.is_empty() {
|
|
let _ = queue.stop();
|
|
}
|
|
queue.add_next(source, &mut handler)?;
|
|
queue.resume()?;
|
|
} else {
|
|
ctx.say("Neither of us are in a voice channel, silly.")
|
|
.await?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[poise::command(slash_command)]
|
|
pub async fn queue(
|
|
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_id) = ctx.guild().map(|g| g.id) 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((guild_id, Some(channel_id))) = ctx.guild().and_then(|g| {
|
|
g.voice_states
|
|
.get(&ctx.author().id)
|
|
.map(|vs| (g.id, vs.channel_id))
|
|
}) else {
|
|
ctx.say("You're not 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 reply = poise::CreateReply::default()
|
|
.content(personality::get_random_loading_message())
|
|
.embed(
|
|
CreateEmbed::new()
|
|
.image("https://media.giphy.com/media/H1dxi6xdh4NGQCZSvz/giphy.gif"),
|
|
);
|
|
let response = ctx.send(reply).await?;
|
|
|
|
let mut handler = handler_lock.lock().await;
|
|
|
|
debug!("Trying to play: {}", url);
|
|
let mut source: Input = YoutubeDl::new(ctx.data().http_client.clone(), url.clone()).into();
|
|
let metadata = source.aux_metadata().await?;
|
|
|
|
debug!("Playing: {:?}", metadata);
|
|
let title = metadata.title.clone().unwrap_or(String::from("This video"));
|
|
|
|
let mut msg = MessageBuilder::new();
|
|
|
|
// Optional sassy commentary!
|
|
match personality::get_sassy_commentary(&title).await {
|
|
Ok(commentary) => {
|
|
msg.push_line(&commentary).push_line("");
|
|
}
|
|
Err(e) => {
|
|
warn!("Failed to get sassy commentary for \"{title}\": {e}");
|
|
}
|
|
};
|
|
|
|
msg.push_bold("Queued: ").push_named_link(title, url);
|
|
|
|
response
|
|
.edit(ctx, CreateReply::default().content(msg.build()))
|
|
.await?;
|
|
|
|
let mut queue = ctx.data().queue.lock();
|
|
queue.add_to_end(source, &mut handler)?;
|
|
} else {
|
|
ctx.say("Neither of us are in a voice channel, silly.")
|
|
.await?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[poise::command(slash_command)]
|
|
pub async fn stop(ctx: CommandContext<'_>) -> Result<(), Error> {
|
|
let Some(guild_id) = ctx.guild().map(|g| g.id) 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_some() {
|
|
{
|
|
let mut queue = ctx.data().queue.lock();
|
|
queue.stop()?;
|
|
}
|
|
ctx.say("Alright, I guess I'll stop.").await?;
|
|
} else {
|
|
ctx.say("I'm not even in a channel to begin with. Silly.")
|
|
.await?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[poise::command(slash_command)]
|
|
pub async fn skip(ctx: CommandContext<'_>) -> Result<(), Error> {
|
|
let Some(guild_id) = ctx.guild().map(|g| g.id) 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_some() {
|
|
{
|
|
let mut queue = ctx.data().queue.lock();
|
|
let _ = queue.stop();
|
|
queue.resume()?;
|
|
}
|
|
ctx.say("Skipping!").await?;
|
|
} else {
|
|
ctx.say("I'm not even in a channel to begin with. Silly.")
|
|
.await?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[poise::command(slash_command)]
|
|
pub async fn pause(ctx: CommandContext<'_>) -> Result<(), Error> {
|
|
let Some(guild_id) = ctx.guild().map(|g| g.id) 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_some() {
|
|
{
|
|
let mut queue = ctx.data().queue.lock();
|
|
queue.pause()?;
|
|
}
|
|
ctx.say("Pausing!").await?;
|
|
} else {
|
|
ctx.say("I'm not even in a channel to begin with. Silly.")
|
|
.await?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[poise::command(slash_command)]
|
|
pub async fn resume(ctx: CommandContext<'_>) -> Result<(), Error> {
|
|
let Some(guild_id) = ctx.guild().map(|g| g.id) 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_some() {
|
|
{
|
|
let mut queue = ctx.data().queue.lock();
|
|
queue.resume()?;
|
|
}
|
|
ctx.say("Resuming!").await?;
|
|
} else {
|
|
ctx.say("I'm not even in a channel to begin with. Silly.")
|
|
.await?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[poise::command(slash_command)]
|
|
pub async fn clear(ctx: CommandContext<'_>) -> Result<(), Error> {
|
|
let Some(guild_id) = ctx.guild().map(|g| g.id) 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_some() {
|
|
{
|
|
let mut queue = ctx.data().queue.lock();
|
|
queue.clear();
|
|
}
|
|
ctx.say("Cleared the queue!").await?;
|
|
} else {
|
|
ctx.say("I'm not even in a channel to begin with. Silly.")
|
|
.await?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|