From e0a9b18f45858829f88cbe20611aaf696fc5bf6a Mon Sep 17 00:00:00 2001 From: Nathan Perry Date: Fri, 16 Aug 2024 22:35:46 -0400 Subject: restore support for volume commands --- src/commands/game.rs | 14 ++++----- src/commands/meme/history.rs | 33 ++++++++++---------- src/commands/meme/invoke.rs | 23 +++++++------- src/commands/meme/mod.rs | 16 ++++++---- src/commands/mod.rs | 10 +++++-- src/commands/playback.rs | 12 ++++++-- src/commands/sound_levels.rs | 71 ++++++++++++++++++++++++++++++++++++++++++-- src/commands/today/mod.rs | 7 +++-- 8 files changed, 133 insertions(+), 53 deletions(-) (limited to 'src/commands') diff --git a/src/commands/game.rs b/src/commands/game.rs index 78c08ee..3a47b32 100644 --- a/src/commands/game.rs +++ b/src/commands/game.rs @@ -307,14 +307,6 @@ async fn _game( users }; - let inferred = users.is_empty(); - - if inferred && users.len() < 2 || !inferred && users.is_empty() { - tracing::info!("too few known users to make game comparison"); - util::reply(ctx, "yer too lonely").await?; - return Ok(()); - } - let client = { let data = ctx.serenity_context().data.read().await; data.get::().unwrap().clone() @@ -333,6 +325,12 @@ async fn _game( }) .collect::>(); + if user_indexes.len() < 2 { + tracing::info!("too few known users to make game comparison"); + util::reply(ctx, "yer too lonely").await?; + return Ok(()); + } + let data_ref = &data; let user_games = user_indexes .iter() diff --git a/src/commands/meme/history.rs b/src/commands/meme/history.rs index 1acb019..270ae9a 100644 --- a/src/commands/meme/history.rs +++ b/src/commands/meme/history.rs @@ -1,16 +1,3 @@ -use crate::{ - commands::game::get_user_id, - db::{ - self, - connection, - InvocationRecord, - Meme, - Metadata, - }, - util, - PoiseContext, - CONFIG, -}; use chrono::TimeZone; use diesel::{ result::Error as DieselError, @@ -34,7 +21,20 @@ use timeago::{ Formatter, TimeUnit, }; -use windows::core::s; + +use crate::{ + commands::game::get_user_id, + config::CONFIG, + db::{ + self, + connection, + InvocationRecord, + Meme, + Metadata, + }, + util, + PoiseContext, +}; lazy_static! { static ref TIME_FORMATTER: Formatter = { @@ -393,10 +393,7 @@ pub async fn query(ctx: PoiseContext<'_>, rest: util::RestVec) -> anyhow::Result use regex::Regex; use serenity::model::id::UserId; - use crate::{ - db, - CONFIG, - }; + use crate::db; lazy_static! { static ref CREATOR_REGEX: Regex = Regex::new(r"(?i)(?:by|creator)=(.*)").unwrap(); diff --git a/src/commands/meme/invoke.rs b/src/commands/meme/invoke.rs index aff5c23..4b361a3 100644 --- a/src/commands/meme/invoke.rs +++ b/src/commands/meme/invoke.rs @@ -1,6 +1,5 @@ use diesel::{ result::Error as DieselError, - row::NamedRow, NotFound, }; use grate::tracing; @@ -93,10 +92,10 @@ pub(crate) async fn _meme( x.id, false, ) - .await?; + .await?; x - } + }, Err(e) => { return if let Some(NotFound) = e.downcast_ref::() { tracing::info!("requested meme not found in database"); @@ -107,7 +106,7 @@ pub(crate) async fn _meme( util::reply(ctx, "what in ryan's name").await?; Err(e.into()) }; - } + }, }; send_meme(ctx, &mem, &mut conn).await @@ -135,15 +134,15 @@ async fn rand_meme(ctx: PoiseContext<'_>, audio_playback: AudioPlayback) -> anyh mem.id, true, ) - .await?; + .await?; send_meme(ctx, &mem, &mut conn).await?; Ok(()) - } + }, Ok(None) => { tracing::info!("random meme not found"); util::reply(ctx, "i don't know any :(").await?; Ok(()) - } + }, Err(e) => { if let Some(NotFound) = e.downcast_ref::() { tracing::info!("random meme not found"); @@ -154,7 +153,7 @@ async fn rand_meme(ctx: PoiseContext<'_>, audio_playback: AudioPlayback) -> anyh util::reply(ctx, "HELP").await?; Err(e.into()) - } + }, } } @@ -177,16 +176,16 @@ pub async fn rare_meme(ctx: PoiseContext<'_>) -> anyhow::Result<()> { meme.id, true, ) - .await?; + .await?; send_meme(ctx, &meme, &mut conn).await - } + }, Ok(None) => { tracing::info!("rare meme not found"); util::reply(ctx, "i don't know any :(").await?; Ok(()) - } + }, Err(e) => { if let Some(NotFound) = e.downcast_ref::() { @@ -199,6 +198,6 @@ pub async fn rare_meme(ctx: PoiseContext<'_>) -> anyhow::Result<()> { util::reply(ctx, "THE MEME MARKET IS IN FREEFALL").await?; Err(e.into()) - } + }, } } diff --git a/src/commands/meme/mod.rs b/src/commands/meme/mod.rs index eb6aa1d..3883f3e 100644 --- a/src/commands/meme/mod.rs +++ b/src/commands/meme/mod.rs @@ -1,3 +1,8 @@ +use std::{ + borrow::ToOwned, + default::Default, +}; + use diesel_async::AsyncPgConnection; use grate::tracing; use rand::random; @@ -19,10 +24,6 @@ use songbird::input::{ Compose, Input, }; -use std::{ - borrow::ToOwned, - default::Default, -}; pub use self::{ create::*, @@ -38,7 +39,6 @@ use crate::{ }, util, PoiseContext, - CONFIG, }; mod create; @@ -113,6 +113,9 @@ async fn send_meme( return Ok(()); }; + let volume = util::volume(ctx).await; + tracing::debug!(volume); + { let (_sb, call) = songbird(ctx).await?; let mut call = call.lock().await; @@ -121,7 +124,8 @@ async fn send_meme( call.join(voice_channel).await?; } - call.enqueue_input(Input::Lazy(Box::new(audio))).await; + let handle = call.enqueue_input(Input::Lazy(Box::new(audio))).await; + handle.set_volume(volume as _)?; } util::react(ctx, ReactionType::Unicode("📣".to_owned())).await?; diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 2729580..b0ef83b 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -19,8 +19,14 @@ pub(crate) mod today; pub use self::meme::*; pub fn commands() -> Vec> { - let mut commands = - vec![sound_levels::mute(), sound_levels::unmute(), roll::roll(), today::today(), help()]; + let mut commands = vec![ + sound_levels::mute(), + sound_levels::unmute(), + sound_levels::volume(), + roll::roll(), + today::today(), + help(), + ]; commands.extend(playback::commands()); diff --git a/src/commands/playback.rs b/src/commands/playback.rs index 8121136..4d6d0be 100644 --- a/src/commands/playback.rs +++ b/src/commands/playback.rs @@ -14,7 +14,6 @@ use crate::{ util, PoiseContext, PoiseData, - CONFIG, }; pub fn commands() -> impl IntoIterator> { @@ -74,6 +73,9 @@ pub async fn _play(ctx: PoiseContext<'_>, url: &url::Url) -> anyhow::Result<()> data.get::().unwrap().clone() }; + let volume = util::volume(ctx).await; + tracing::debug!(volume); + { let (_sb, call) = songbird(ctx).await?; let mut call = call.lock().await; @@ -86,9 +88,11 @@ pub async fn _play(ctx: PoiseContext<'_>, url: &url::Url) -> anyhow::Result<()> YoutubeDl::new_ytdl_like(&crate::config::YTDL_COMMAND, client.clone(), url.to_string()); let track = input.conv::(); + // TODO: store enqueueing channel so songbird handler can switch channels - call.enqueue(track).await; + let queued = call.enqueue(track).await; + queued.set_volume(volume as _)?; } util::react(ctx, '📣').await?; @@ -197,7 +201,9 @@ pub async fn list(ctx: PoiseContext<'_>) -> anyhow::Result<()> { let call = call.lock().await; let queue = call.queue(); - util::reply(ctx, "(command fix work-in-progress)").await?; + if queue.current_queue().is_empty() { + util::reply(ctx, "nothing queued").await?; + } for track in queue.current_queue().into_iter() { let info = track.get_info().await?; diff --git a/src/commands/sound_levels.rs b/src/commands/sound_levels.rs index 4946f47..2b9048e 100644 --- a/src/commands/sound_levels.rs +++ b/src/commands/sound_levels.rs @@ -1,10 +1,18 @@ +use std::error::Error; + +use serenity::all::{ + Context, + Message, +}; + use crate::{ commands::playback::songbird, + util, PoiseContext, }; /// Mute audio (don't pause). -#[poise::command(prefix_command, guild_only)] +#[poise::command(prefix_command, guild_only, category = "playback")] pub async fn mute(ctx: PoiseContext<'_>) -> anyhow::Result<()> { let (_sb, call) = songbird(ctx).await?; @@ -15,7 +23,7 @@ pub async fn mute(ctx: PoiseContext<'_>) -> anyhow::Result<()> { } /// Unmute audio. -#[poise::command(prefix_command, guild_only)] +#[poise::command(prefix_command, guild_only, category = "playback")] pub async fn unmute(ctx: PoiseContext<'_>) -> anyhow::Result<()> { let (_sb, call) = songbird(ctx).await?; @@ -24,3 +32,62 @@ pub async fn unmute(ctx: PoiseContext<'_>) -> anyhow::Result<()> { Ok(()) } + +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)] +struct PercentArg(f64); + +lazy_static::lazy_static! { + static ref ARG_PCT: regex::Regex = regex::Regex::new(r#"(\d+(?:\.\d+)?)\s*%?(.*)"#).unwrap(); +} + +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, thiserror::Error)] +#[error("expected a number with an optional trailing %")] +struct NonPctError; + +#[poise::async_trait] +impl<'a> poise::PopArgument<'a> for PercentArg { + async fn pop_from( + args: &'a str, + attachment_index: usize, + _ctx: &Context, + _msg: &Message, + ) -> Result<(&'a str, usize, Self), (Box, Option)> { + let Some(mtch) = ARG_PCT.captures(args) else { + return Err((Box::new(NonPctError), None)); + }; + + let pct = mtch.get(1).unwrap().as_str().parse::().unwrap(); + let prop = pct / 100.; + let rest = mtch.get(2).unwrap().as_str(); + + Ok((rest, attachment_index, Self(prop))) + } +} + +/// Set volume by percent. +#[poise::command(prefix_command, guild_only, category = "playback")] +pub async fn volume(ctx: PoiseContext<'_>, volume: Option) -> anyhow::Result<()> { + let Some(volume) = volume else { + let cur_vol = util::volume(ctx).await * 100.; + + util::reply(ctx, format!("{cur_vol:.0}%")).await?; + return Ok(()); + }; + + { + let data = ctx.serenity_context().data.read().await; + let vol = data.get::().unwrap(); + vol.insert(util::guild_id(ctx)?, volume.0); + } + + let (_sb, call) = songbird(ctx).await?; + let call = call.lock().await; + + call.queue().modify_queue(|q| { + for elt in q { + elt.set_volume(volume.0 as _)?; + } + + anyhow::Ok(()) + }) +} diff --git a/src/commands/today/mod.rs b/src/commands/today/mod.rs index e48983c..f8f38c7 100644 --- a/src/commands/today/mod.rs +++ b/src/commands/today/mod.rs @@ -13,7 +13,6 @@ use crate::{ commands::playback::songbird, util, PoiseContext, - CONFIG, }; mod prelude; @@ -103,6 +102,9 @@ pub async fn today(ctx: PoiseContext<'_>, #[rest] _rest: Option) -> anyh return Ok(()); }; + let volume = util::volume(ctx).await; + tracing::debug!(volume); + let (_sb, call) = songbird(ctx).await?; let mut call = call.lock().await; @@ -118,7 +120,8 @@ pub async fn today(ctx: PoiseContext<'_>, #[rest] _rest: Option) -> anyh let input = YoutubeDl::new_ytdl_like("yt-dlp", client.clone(), play_args.url.conv::()); - call.enqueue_input(input.into()).await; + let handle = call.enqueue_input(input.into()).await; + handle.set_volume(volume as _)?; let q = call.queue(); q.pause()?; -- cgit v1.3.1