diff options
Diffstat (limited to 'src/commands/playback.rs')
| -rw-r--r-- | src/commands/playback.rs | 119 |
1 files changed, 92 insertions, 27 deletions
diff --git a/src/commands/playback.rs b/src/commands/playback.rs index e7bf830..d4f3ef2 100644 --- a/src/commands/playback.rs +++ b/src/commands/playback.rs @@ -1,15 +1,21 @@ -use std::{ - fmt::Debug, - sync::Arc, -}; - use grate::tracing; -use serenity::prelude::*; +use serenity::{ + all::UserId, + prelude::*, +}; use songbird::{ - input::YoutubeDl, + input::{ + AuxMetadata, + Compose, + YoutubeDl, + }, Call, Songbird, }; +use std::{ + sync::Arc, + time::Duration, +}; use tap::Conv; use crate::{ @@ -17,6 +23,7 @@ use crate::{ HttpKey, PlaybackKey, }, + db, util, PoiseContext, PoiseData, @@ -80,6 +87,17 @@ pub async fn _play(ctx: PoiseContext<'_>, url: &url::Url) -> anyhow::Result<()> let volume = util::volume(ctx).await; tracing::debug!(volume); + let playback = { + let data = ctx.serenity_context().data.read().await; + data.get::<PlaybackKey>().unwrap().clone() + }; + + let mut input = + YoutubeDl::new_ytdl_like(&crate::config::YTDL_COMMAND, client.clone(), url.to_string()); + + let meta = input.aux_metadata().await?; + let track = input.conv::<songbird::tracks::Track>(); + { let (_sb, call) = songbird(ctx).await?; let mut call = call.lock().await; @@ -88,15 +106,17 @@ pub async fn _play(ctx: PoiseContext<'_>, url: &url::Url) -> anyhow::Result<()> call.join(voice_channel).await?; } - let input = - YoutubeDl::new_ytdl_like(&crate::config::YTDL_COMMAND, client.clone(), url.to_string()); - - let track = input.conv::<songbird::tracks::Track>(); - // TODO: store enqueueing channel so songbird handler can switch channels - let queued = call.enqueue(track).await; - queued.set_volume(volume as _)?; + let handle = call.enqueue(track).await; + handle.set_volume(volume as _)?; + + playback.insert(handle.uuid(), Metadata { + invoker: ctx.author().id, + invoke_info: InvokeInfo::Ytdl { + metadata: meta, + }, + }); } util::react(ctx, '📣').await?; @@ -198,7 +218,7 @@ pub async fn die(ctx: PoiseContext<'_>) -> anyhow::Result<()> { } /// List queued audio. -#[poise::command(prefix_command, guild_only, category = "playback", aliases("queue"))] +#[poise::command(prefix_command, guild_only, category = "playback", aliases("queue", "q"))] pub async fn list(ctx: PoiseContext<'_>) -> anyhow::Result<()> { let current_queue = { let (_sb, call) = songbird(ctx).await?; @@ -218,35 +238,80 @@ pub async fn list(ctx: PoiseContext<'_>) -> anyhow::Result<()> { util::reply(ctx, "nothing queued").await?; } - fn fmt_option<T>(name: &str, opt: Option<T>) -> String + fn fmt_option<T>(fallback: impl AsRef<str>, opt: Option<T>) -> String where T: std::fmt::Display, { if let Some(opt) = opt { format!("{opt}") } else { - format!("<no {name}>") + format!("<{}>", fallback.as_ref()) } } for track in current_queue.into_iter() { let info = track.get_info().await?; + let playback_pos = + humantime::format_duration(Duration::from_secs(info.position.as_secs())).to_string(); let meta = playback_data.get(&track.uuid()).map(|x| x.clone()); - let meta = meta.as_ref(); - let fmt = format!( - "{}: {:?} / {}", - fmt_option("title", meta.and_then(|x| x.title.as_ref())), - humantime::format_duration(info.position), - fmt_option( - "duration", - meta.and_then(|x| x.duration.as_ref().map(|&dur| humantime::format_duration(dur))) - ) - ); + let Some(meta) = meta else { + tracing::warn!("no track metadata"); + + util::reply(ctx, format!("`[unk ]` playing for {playback_pos}")).await?; + continue; + }; + + let fmt = match meta.invoke_info { + InvokeInfo::Ytdl { + metadata, + } => { + format!( + "`[web ]` **{}**: {playback_pos} / {}, queued by {}", + fmt_option("unknown title", metadata.title), + fmt_option( + "unknown duration", + metadata.duration.map(|dur| humantime::format_duration(dur).to_string()) + ), + meta.invoker.mention() + ) + }, + InvokeInfo::Meme { + meme, + } => { + if info.position > Duration::default() { + format!( + "`[meme]` **{}**, {playback_pos}, queued by {}", + meme.title, + meta.invoker.mention() + ) + } else { + format!("`[meme]` **{}**, queued by {}", meme.title, meta.invoker.mention()) + } + }, + }; util::reply(ctx, fmt).await?; } Ok(()) } + +#[derive(Debug, Clone)] +pub struct Metadata { + pub invoker: UserId, + pub invoke_info: InvokeInfo, +} + +#[derive(Debug, Clone)] +pub enum InvokeInfo { + Ytdl { + metadata: AuxMetadata, + }, + + #[cfg(feature = "db")] + Meme { + meme: db::Meme, + }, +} |
