diff --git a/src/commands/music.rs b/src/commands/music.rs index fbe606c..2272710 100644 --- a/src/commands/music.rs +++ b/src/commands/music.rs @@ -2,6 +2,7 @@ pub mod deafen; pub mod join; pub mod leave; pub mod notifier; +pub mod metadata; pub mod mute; pub mod pause; pub mod play; diff --git a/src/commands/music/metadata.rs b/src/commands/music/metadata.rs new file mode 100644 index 0000000..365f4ad --- /dev/null +++ b/src/commands/music/metadata.rs @@ -0,0 +1,7 @@ +use songbird::{input::AuxMetadata, typemap::TypeMapKey}; + +pub struct Metadata; + +impl TypeMapKey for Metadata { + type Value = AuxMetadata; +} diff --git a/src/commands/music/play.rs b/src/commands/music/play.rs index 941e5d5..18a4002 100644 --- a/src/commands/music/play.rs +++ b/src/commands/music/play.rs @@ -1,7 +1,9 @@ use crate::{commands::embeds::error_embed, Context, Error}; +use crate::commands::music::metadata::Metadata; use fancy_regex::Regex; use regex::Regex as Regex_Classic; +use songbird::tracks::{TrackHandle, TrackQueue}; use std::process::Command; use std::time::Duration; use poise::CreateReply; @@ -81,17 +83,19 @@ pub async fn play( let urls: Vec = regex_youtube.captures_iter(&list).map(|capture| capture[1].to_string()).collect(); - let mut sources: Vec = vec![]; + for (index, url) in urls.clone().iter().enumerate() { + let src = YoutubeDl::new_ytdl_like("yt-dlp", http_client.clone(), url.to_string()); + let aux_metadata = src.clone().aux_metadata().await.unwrap(); + let track = handler.enqueue_input(src.clone().into()).await; + let _ = track.typemap().write().await.insert::(aux_metadata); - for url in urls { - let src = YoutubeDl::new_ytdl_like("yt-dlp", http_client.clone(), url); - let _ = handler.enqueue_input(src.clone().into()).await; - sources.push(src); + if index == 0 { + let embed = generate_playlist_embed(ctx, track, urls.len()).await; + let response = CreateReply::default().embed(embed.unwrap()); + ctx.send(response).await?; + } } - - let embed = generate_playlist_embed(ctx, sources).await; - let response = CreateReply::default().embed(embed.unwrap()); - ctx.send(response).await?; + } else { if is_spotify { let exec = format!("node ./src/spotify --url {}", song); @@ -106,23 +110,31 @@ pub async fn play( } let src = YoutubeDl::new_ytdl_like("yt-dlp", http_client, song); - let _ = handler.enqueue_input(src.clone().into()).await; - - let embed = generate_embed(ctx, src).await; + let embed = generate_embed(ctx, src.clone(), handler.queue()).await; let response = CreateReply::default().embed(embed.unwrap()); ctx.send(response).await?; + + let aux_metadata = src.clone().aux_metadata().await.unwrap(); + + let track = handler.enqueue_input(src.clone().into()).await; + let _ = track.typemap().write().await.insert::(aux_metadata); } } Ok(()) } -async fn generate_embed(ctx: Context<'_>, src: YoutubeDl) -> Result { +async fn generate_embed(ctx: Context<'_>, src: YoutubeDl, queue: &TrackQueue) -> Result { let metadata = src.clone().aux_metadata().await.unwrap(); let AuxMetadata {title, thumbnail, source_url, artist, duration, ..} = metadata; let timestamp = Timestamp::now(); let duration_minutes = duration.unwrap_or(Duration::new(0, 0)).clone().as_secs() / 60; let duration_seconds = duration.unwrap_or(Duration::new(0, 0)).clone().as_secs() % 60; + let mut description = format!("Song added to queue @ {}", queue.len()); + + if queue.len() == 0 { + description = format!("Playing now!"); + } let embed = CreateEmbed::default() .author(CreateEmbedAuthor::new("Track enqueued").icon_url(ctx.author().clone().face())) @@ -133,32 +145,32 @@ async fn generate_embed(ctx: Context<'_>, src: YoutubeDl) -> Result, sources: Vec) -> Result { - let src = sources.get(0).unwrap(); - - let metadata = src.clone().aux_metadata().await.unwrap(); - let AuxMetadata {title, thumbnail, source_url, artist, duration, ..} = metadata; - let timestamp = Timestamp::now(); - let duration_minutes = duration.unwrap_or(Duration::new(0, 0)).clone().as_secs() / 60; - let duration_seconds = duration.unwrap_or(Duration::new(0, 0)).clone().as_secs() % 60; - - let description = format!("Enqueued tracks: {}", sources.len() - 1); - - let embed = CreateEmbed::default() - .author(CreateEmbedAuthor::new("Playlist enqueued").icon_url(ctx.author().clone().face())) - .colour(Colour::from_rgb(255, 58, 97)) - .title(title.unwrap()) - .url(source_url.unwrap()) - .thumbnail(thumbnail.unwrap_or(ctx.cache().current_user().face())) - .field("Artist", artist.unwrap_or("Unknown Artist".to_string()), true) - .field("Duration", format!("{:02}:{:02}", duration_minutes, duration_seconds), true) - .field("DJ", ctx.author().name.clone(), true) + .description(description) + .timestamp(timestamp) + .footer(CreateEmbedFooter::new(ctx.cache().current_user().name.to_string()).icon_url(ctx.cache().current_user().face())); + + Ok(embed) +} + +async fn generate_playlist_embed(ctx: Context<'_>, track: TrackHandle, queue_length: usize) -> Result { + let meta_typemap = track.typemap().read().await; + let metadata = meta_typemap.get::().unwrap(); + let AuxMetadata {title, thumbnail, source_url, artist, duration, ..} = metadata; + let timestamp = Timestamp::now(); + let duration_minutes = duration.unwrap_or(Duration::new(0, 0)).clone().as_secs() / 60; + let duration_seconds = duration.unwrap_or(Duration::new(0, 0)).clone().as_secs() % 60; + + let description = format!("Enqueued tracks: {}", queue_length - 1); + + let embed = CreateEmbed::default() + .author(CreateEmbedAuthor::new("Playlist enqueued").icon_url(ctx.author().clone().face())) + .colour(Colour::from_rgb(255, 58, 97)) + .title(title.as_ref().unwrap()) + .url(source_url.as_ref().unwrap()) + .thumbnail(thumbnail.as_ref().unwrap_or(&ctx.cache().current_user().face())) + .field("Artist", artist.as_ref().unwrap_or(&"Unknown Artist".to_string()), true) + .field("Duration", format!("{:02}:{:02}", duration_minutes, duration_seconds), true) + .field("DJ", ctx.author().name.clone(), true) .description(description) .timestamp(timestamp) .footer(CreateEmbedFooter::new(ctx.cache().current_user().name.to_string()).icon_url(ctx.cache().current_user().face())); diff --git a/src/commands/music/queue.rs b/src/commands/music/queue.rs index 324f1ae..c94f691 100644 --- a/src/commands/music/queue.rs +++ b/src/commands/music/queue.rs @@ -1,5 +1,11 @@ +use std::time::Duration; + use crate::{commands::embeds::error_embed, Context, Error}; +use crate::commands::music::metadata::Metadata; use poise::CreateReply; +use serenity::{builder::{CreateEmbedAuthor, CreateEmbedFooter}, model::{Colour, Timestamp}}; +use poise::serenity_prelude::CreateEmbed; +use songbird::input::AuxMetadata; /// Shows next tracks in queue; \ /// aliases: queue, q @@ -22,20 +28,31 @@ pub async fn queue( if let Some(handler_lock) = manager.get(guild_id) { let handler = handler_lock.lock().await; let queue = handler.queue(); - let mut queue_res = String::from("Queue: \n"); + let mut queue_res = String::from(""); + + for (index, song) in queue.current_queue().iter().enumerate() { + let meta_typemap = song.typemap().read().await; + let metadata = meta_typemap.get::().unwrap(); + let AuxMetadata { title, artist, duration, ..} = metadata; + + let duration_minutes = duration.unwrap_or(Duration::new(0, 0)).clone().as_secs() / 60; + let duration_seconds = duration.unwrap_or(Duration::new(0, 0)).clone().as_secs() % 60; + + // println!("{:?}", metadata.clone()); - for (i, song) in queue.current_queue().iter().enumerate() { queue_res.push_str(&format!( - "{}. {} - {}\n", - i + 1, - song.uuid(), - "Artist" - // song.metadata().artist.clone().unwrap_or_else(|| String::from("Unknown")) + "{}. {} - {} [{:02}:{:02}] \n", + index, + title.as_ref().unwrap(), + artist.as_ref().unwrap(), + duration_minutes, + duration_seconds )); } - ctx.say(queue_res).await?; - + ctx.send( + CreateReply::default().embed(embed(ctx, queue_res).await.unwrap()) + ).await?; } else { let msg = "I am not in a voice channel!"; ctx.send( @@ -45,3 +62,19 @@ pub async fn queue( Ok(()) } + +async fn embed(ctx: Context<'_>, queue: String) -> Result { + + let title = "Now playing"; + let timestamp = Timestamp::now(); + + let embed = CreateEmbed::default() + .author(CreateEmbedAuthor::new("Queue").icon_url(ctx.author().clone().face())) + .colour(Colour::from_rgb(255, 58, 97)) + .title(title) + .description(queue) + .timestamp(timestamp) + .footer(CreateEmbedFooter::new(ctx.cache().current_user().name.to_string()).icon_url(ctx.cache().current_user().face())); + + Ok(embed) +} diff --git a/src/commands/music/seek.rs b/src/commands/music/seek.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/commands/music/shuffle.rs b/src/commands/music/shuffle.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/commands/music/soundboard.rs b/src/commands/music/soundboard.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/commands/music/soundboard/effect.rs b/src/commands/music/soundboard/effect.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/commands/music/soundboard/override.rs b/src/commands/music/soundboard/override.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/commands/music/volume.rs b/src/commands/music/volume.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/commands/tools.rs b/src/commands/tools.rs index 4bbb587..75d982d 100644 --- a/src/commands/tools.rs +++ b/src/commands/tools.rs @@ -1,7 +1,9 @@ pub mod ping; pub mod register; pub mod help; +pub mod posix; pub use ping::ping; pub use register::register; pub use help::help; +pub use posix::posix; diff --git a/src/commands/tools/ai.rs b/src/commands/tools/ai.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/commands/tools/dice.rs b/src/commands/tools/dice.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/commands/tools/dictionary.rs b/src/commands/tools/dictionary.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/commands/tools/ip.rs b/src/commands/tools/ip.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/commands/tools/metar.rs b/src/commands/tools/metar.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/commands/tools/owoify.rs b/src/commands/tools/owoify.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/commands/tools/posix.rs b/src/commands/tools/posix.rs new file mode 100644 index 0000000..2d89683 --- /dev/null +++ b/src/commands/tools/posix.rs @@ -0,0 +1,23 @@ +use std::time::SystemTime; + +use poise::CreateReply; + +use crate::{commands::embeds::embed, Context, Error}; + +/// Prints current time in POSIX format +#[poise::command( + prefix_command, + slash_command, + category = "Tools" +)] +pub async fn posix( + ctx: Context<'_> +) -> Result<(), Error> { + let time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_millis(); + + ctx.send( + CreateReply::default().embed(embed(ctx, "The time is", &format!("{} ms", time), "since Jan 1st 1970").await.unwrap()) + ).await?; + + Ok(()) +} diff --git a/src/commands/tools/qr.rs b/src/commands/tools/qr.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/commands/tools/taf.rs b/src/commands/tools/taf.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/commands/tools/uptime.rs b/src/commands/tools/uptime.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/commands/tools/verse.rs b/src/commands/tools/verse.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/commands/tools/weather.rs b/src/commands/tools/weather.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/main.rs b/src/main.rs index b3806e7..1bda848 100644 --- a/src/main.rs +++ b/src/main.rs @@ -56,6 +56,7 @@ async fn main() { tools::ping(), tools::register(), tools::help(), + tools::posix(), ]; let options = poise::FrameworkOptions {