Files
corro-dj/apps/master/src/commands/play.rs
T
2026-03-17 22:35:13 +01:00

179 lines
5.2 KiB
Rust

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),
)
}