147 lines
5.0 KiB
Rust
147 lines
5.0 KiB
Rust
use std::sync::Arc;
|
|
|
|
use log::{debug, warn, error};
|
|
|
|
use serenity::model::prelude::GuildId;
|
|
use serenity::{prelude::*, async_trait};
|
|
use serenity::builder::CreateApplicationCommand;
|
|
use serenity::model::application::interaction::application_command::ApplicationCommandInteraction;
|
|
use siren::ServiceError;
|
|
use songbird::{EventHandler, Songbird};
|
|
|
|
use crate::bot::commands::audio::{leave, add_song, get_songbird};
|
|
use crate::db::guilds::QueryGuild;
|
|
|
|
use super::{create_response, edit_response, join_by_user};
|
|
|
|
pub async fn run(ctx: &Context, command: &ApplicationCommandInteraction) {
|
|
// Get the track url
|
|
let track_url = match command.data.options.get(0) {
|
|
Some(t) => match &t.value {
|
|
Some(v) => match v.as_str() {
|
|
Some(s) => s.to_owned(),
|
|
None => {
|
|
warn!("Missing track option");
|
|
if let Err(why) = create_response(&ctx, &command, format!("Track option is missing")).await {
|
|
error!("Failed to create response message: {}", why);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
None => {
|
|
warn!("Missing track option");
|
|
if let Err(why) = create_response(&ctx, &command, format!("Track option is missing")).await {
|
|
error!("Failed to create response message: {}", why);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
None => {
|
|
warn!("Missing track option");
|
|
if let Err(why) = create_response(&ctx, &command, format!("Track option is missing")).await {
|
|
error!("Failed to create response message: {}", why);
|
|
}
|
|
return;
|
|
}
|
|
};
|
|
|
|
// Create the initial response
|
|
if let Err(why) = create_response(&ctx, &command, format!("Processing command...")).await {
|
|
error!("Failed to create response message: {}", why);
|
|
return;
|
|
}
|
|
|
|
let manager = get_songbird(ctx).await;
|
|
match join_by_user(&ctx.cache, manager,&command.guild_id, &command.user).await {
|
|
Ok(_) => {
|
|
let guild_id = match command.guild_id {
|
|
Some(g) => g,
|
|
None => {
|
|
if let Err(why) = edit_response(&ctx, &command, "Unable to join voice channel".to_string()).await {
|
|
error!("Failed to edit response message: {}", why);
|
|
}
|
|
return;
|
|
}
|
|
};
|
|
debug!("Play command executed with track: {:?}", track_url);
|
|
let manager = get_songbird(ctx).await;
|
|
match play_track(manager, guild_id, track_url).await {
|
|
Ok(_) => {
|
|
if let Err(why) = edit_response(&ctx, &command, "Playing track".to_string()).await {
|
|
error!("Failed to edit response message: {}", why);
|
|
}
|
|
},
|
|
Err(err) => {
|
|
warn!("Failed to play track: {}", err);
|
|
if let Err(why) = edit_response(&ctx, &command, format!("Failed to play track: {}", err)).await {
|
|
error!("Failed to edit response message: {}", why);
|
|
}
|
|
}
|
|
};
|
|
},
|
|
Err(err) => {
|
|
warn!("{}", err);
|
|
if let Err(why) = edit_response(&ctx, &command, format!("{}", err)).await {
|
|
error!("Failed to edit response message: {}", why);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub async fn play_track(manager: Arc<Songbird>, guild_id: GuildId, track_url: String) -> Result<(), ServiceError> {
|
|
if let Some(handler_lock) = manager.get(guild_id) {
|
|
let is_queue_empty = {
|
|
let call_handler = handler_lock.lock().await;
|
|
call_handler.queue().is_empty()
|
|
};
|
|
let guild = QueryGuild::get(guild_id.0 as i64)?;
|
|
match add_song(handler_lock.clone(), &track_url, is_queue_empty, Some(guild.volume as f32)).await {
|
|
Ok(added_song) => {
|
|
let track_title = added_song.title.unwrap();
|
|
debug!("Added track: {}", track_title);
|
|
let mut handler = handler_lock.lock().await;
|
|
handler.remove_all_global_events();
|
|
handler.add_global_event(songbird::Event::Track(songbird::TrackEvent::End), TrackEndNotifier { guild_id, call: manager })
|
|
},
|
|
Err(err) => {
|
|
warn!("Failed to add song: {}", err);
|
|
if let Err(why) = leave(manager, &Some(guild_id)).await {
|
|
error!("Failed to leave voice channel: {}", why);
|
|
}
|
|
return Err(ServiceError { status: 422, message: err.to_string() })
|
|
}
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand {
|
|
command.name("play").description("Plays the given track").create_option(|option| { option
|
|
.name("track")
|
|
.description("The track to be played")
|
|
.kind(serenity::model::prelude::command::CommandOptionType::String)
|
|
.required(true)
|
|
})
|
|
}
|
|
|
|
struct TrackEndNotifier {
|
|
pub call: std::sync::Arc<songbird::Songbird>,
|
|
pub guild_id: serenity::model::id::GuildId
|
|
}
|
|
|
|
#[async_trait]
|
|
impl EventHandler for TrackEndNotifier {
|
|
async fn act(&self, ctx: &songbird::events::EventContext<'_>) -> Option<songbird::events::Event> {
|
|
if let songbird::EventContext::Track(_track_list) = ctx {
|
|
if let Some(call) = self.call.get(self.guild_id) {
|
|
let mut handler = call.lock().await;
|
|
if handler.queue().is_empty() {
|
|
debug!("Queue is empty, leaving voice channel");
|
|
handler.leave().await.unwrap();
|
|
}
|
|
}
|
|
}
|
|
None
|
|
}
|
|
}
|