use nats_libs::{job::JobClient, kv::KVClient}; use serenity::{ all::{CommandInteraction, Context, CreateCommandOption}, builder::CreateCommand, model::application::{CommandOptionType, ResolvedOption, ResolvedValue}, }; use serenity_libs::functions::CustomInteraction; use types::{ error::{CorroError, CorroErrorType}, jobs::{DownloadJob, JobsMap, JobsResponseMap, PlayJob, SearchJob}, misc::{new_uuid_v4, parse_url_or_default}, queue::{Queue, YoutubeSong}, }; use url::Url; use crate::common::Services; pub async fn run( services: &Services, ctx: &Context, interaction: &CommandInteraction, ) -> Result<(), CorroError> { let options = interaction.data.options(); if let Some(ResolvedOption { value: ResolvedValue::String(value), .. }) = options.first() { let guild_id = interaction.guild_id.unwrap(); let mut queue = match services.jetstream_kv.get_queue(guild_id.into()).await { Ok(queue) => queue, Err(_why) => { let queue = Queue { guild_id: guild_id.into(), uuid: new_uuid_v4(), songs: vec![], }; match services .jetstream_kv .set_queue(guild_id.into(), &queue) .await { Ok(_sequence) => queue, Err(why) => { return Err(why); } } } }; println!("{:?}", queue); match interaction .create_text_response(ctx, format!("Searching: {value}...")) .await { Ok(_) => {} Err(why) => return Err(why), }; let url: Url; let is_url = value.starts_with("https://") || value.starts_with("http://"); if !is_url { let search_response = match services .nats_client .send_job(JobsMap::Search(SearchJob { uuid: new_uuid_v4(), query: value.to_string(), })) .await { Ok(resp) => match resp { JobsResponseMap::Search(resp) => resp, _ => { return Err(CorroError { error_type: CorroErrorType::JobError, message: "Unexpected return type".to_string(), }); } }, Err(why) => return Err(why), }; url = search_response.song.url; } else { url = parse_url_or_default(value.to_string()); } let download_response = match services .nats_client .send_job(JobsMap::Download(DownloadJob { uuid: new_uuid_v4(), url, })) .await { Ok(resp) => match resp { JobsResponseMap::Download(resp) => resp, _ => { return Err(CorroError { error_type: CorroErrorType::JobError, message: "Unexpected return type".to_string(), }); } }, Err(why) => return Err(why), }; queue.songs.push(YoutubeSong { title: download_response.test.clone(), thumbnail_url: Url::parse("https://example.com").unwrap(), url: Url::parse("https://example.com").unwrap(), artist: download_response.test, }); match services.jetstream_kv.set_queue(guild_id.into(), &queue).await { Ok(_sequence) => (), Err(why) => { return Err(why); } } let channel_id = guild_id .get_user_voice_state(&ctx.http, interaction.user.id) .await .unwrap() .channel_id .unwrap(); match services .nats_client .send_job(JobsMap::Play(PlayJob { uuid: new_uuid_v4(), path: download_response.path, channel_id: channel_id.into(), guild_id: guild_id.into(), })) .await { Ok(resp) => match resp { JobsResponseMap::Play(resp) => resp, _ => { return Err(CorroError { error_type: CorroErrorType::JobError, message: "Unexpected return type".to_string(), }); } }, Err(why) => return Err(why), }; match interaction .edit_text_response(ctx, "Playing...".to_string()) .await { Ok(_) => {} Err(why) => return Err(why), }; } 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(true), ) }