aboutsummaryrefslogtreecommitdiff
path: root/src/commands/playback.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/commands/playback.rs')
-rw-r--r--src/commands/playback.rs119
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,
+ },
+}