use std::path::PathBuf; use postcard::{from_bytes, to_stdvec}; use serenity::{ all::{ CommandInteraction, Context, CreateCommandOption, CreateInteractionResponse, CreateInteractionResponseMessage, EditInteractionResponse, }, builder::CreateCommand, model::application::{CommandOptionType, ResolvedOption, ResolvedValue}, }; use types::{ jobs::{DownloadJob, JobResponse, Jobs, PlayJob, SearchJob}, misc::new_uuid_v4, }; pub async fn run( ctx: &Context, interaction: &CommandInteraction, nats_client: &async_nats::Client, ) -> Result<(), serenity::Error> { let options = interaction.data.options(); if let Some(ResolvedOption { value: ResolvedValue::String(value), .. }) = options.first() { interaction .create_response( ctx, CreateInteractionResponse::Message( CreateInteractionResponseMessage::new() .content(format!("Searching: {value}...")), ), ) .await?; let url: String; let is_url = value.starts_with("https://"); if !is_url { let search_job = SearchJob { uuid: new_uuid_v4(), query: value.to_string(), }; let response = match nats_client .request("corro-dj.search", to_stdvec(&search_job).unwrap().into()) .await { Ok(resp) => resp, Err(_why) => return Err(serenity::Error::Other("send error")), }; let search_response: JobResponse = from_bytes(&response.payload).unwrap(); if let Some(error) = search_response.error { interaction .edit_response(ctx, EditInteractionResponse::new().content(error)) .await?; return Err(serenity::Error::Other("Search error")); } else if let Some(Jobs::Search(content)) = search_response.content { url = content.url; } else { interaction .edit_response(ctx, EditInteractionResponse::new().content("unknown error")) .await?; return Err(serenity::Error::Other("unknown error")); } } else { url = value.to_string(); } let download_job = DownloadJob { uuid: new_uuid_v4(), url, }; println!("job {:?}", download_job); let response = match nats_client .request( "corro-dj.download", to_stdvec(&download_job).unwrap().into(), ) .await { Ok(resp) => resp, Err(_why) => return Err(serenity::Error::Other("send error")), }; let job_response: JobResponse = from_bytes(&response.payload).unwrap(); println!("response: {:?}", job_response); let text_response: String; if let Some(error) = job_response.error { text_response = error; } else if let Some(Jobs::Download(content)) = job_response.content { text_response = content.path.display().to_string(); } else { text_response = "unkown".to_string(); } interaction .edit_response(ctx, EditInteractionResponse::new().content(&text_response)) .await?; let guild_id = interaction.guild_id.unwrap(); let channel_id = guild_id .get_user_voice_state(&ctx.http, interaction.user.id) .await .unwrap() .channel_id .unwrap(); let play_job = PlayJob { uuid: new_uuid_v4(), path: PathBuf::from(&text_response), guild_id: guild_id.into(), channel_id: channel_id.into(), }; println!("job {:?}", play_job); let _ = match nats_client .request("corro-dj.play", to_stdvec(&play_job).unwrap().into()) .await { Ok(resp) => resp, Err(_why) => return Err(serenity::Error::Other("send error")), }; interaction .edit_response(ctx, EditInteractionResponse::new().content("playing...")) .await?; } else { interaction .create_response( ctx, CreateInteractionResponse::Message( CreateInteractionResponseMessage::new() .content("Please provide a valid string"), ), ) .await?; } Ok(()) } pub fn register() -> CreateCommand { CreateCommand::new("play") .description("Play a song") .add_option( CreateCommandOption::new( CommandOptionType::String, "song", "Name or url of the song to play", ) .required(false), ) }