From 2a38c282dd57c2051a568549d62c80d6036e8920 Mon Sep 17 00:00:00 2001 From: Nathan Perry Date: Sun, 17 Nov 2019 21:31:28 -0500 Subject: most restructuring done --- src/commands/meme/create.rs | 42 ++++---- src/commands/meme/delete.rs | 13 ++- src/commands/meme/history.rs | 82 ++++++++------- src/commands/meme/invoke.rs | 33 ++++--- src/commands/meme/mod.rs | 11 ++- src/commands/mod.rs | 230 ++++++++++++++++--------------------------- src/commands/playback.rs | 48 +++++---- src/commands/roll.rs | 22 ++--- src/commands/sound_levels.rs | 23 +++-- 9 files changed, 242 insertions(+), 262 deletions(-) (limited to 'src/commands') diff --git a/src/commands/meme/create.rs b/src/commands/meme/create.rs index 245f067..0851961 100644 --- a/src/commands/meme/create.rs +++ b/src/commands/meme/create.rs @@ -8,7 +8,7 @@ use std::{ use diesel::result::Error as DieselError; use serenity::{ - framework::standard::Args, + framework::standard::{Args, Delimiter}, model::channel::Message, prelude::*, }; @@ -19,7 +19,6 @@ use crate::{ parse_times, ytdl_url, }, - commands::send, db::{ Audio, connection, @@ -27,10 +26,16 @@ use crate::{ NewMeme, }, Result, + util::CtxExt, }; -pub fn addmeme(_: &mut Context, msg: &Message, args: Args) -> Result<()> { - let mut args = Args::new(args.rest(), &[" ".to_owned(), "\n".to_owned(), "\t".to_owned()]); +lazy_static! { + static ref delims: Vec = vec![' '.into(), '\n'.into(), '\t'.into()]; +} + +#[command] +pub fn addmeme(ctx: &mut Context, msg: &Message, args: Args) -> Result<()> { + let mut args = Args::new(args.rest(), delims.as_ref()); let title = args.single_quoted::()?; let text = args.rest().to_owned(); @@ -40,7 +45,7 @@ pub fn addmeme(_: &mut Context, msg: &Message, args: Args) -> Result<()> { let conn = connection()?; let image = msg.attachments.first() - .ok_or(::failure::err_msg("no attachment")) + .ok_or(anyhow!("no attachment")) .and_then(|att| { let data = att.download()?; Image::create(&conn, &att.filename, data, msg.author.id.0) @@ -49,7 +54,7 @@ pub fn addmeme(_: &mut Context, msg: &Message, args: Args) -> Result<()> { if image.is_none() && text.is_none() { warn!("tried to create non-audio meme with no image or text"); - return send(msg.channel_id, "hahAA it's empty xdddd", msg.tts); + return ctx.send(msg.channel_id, "hahAA it's empty xdddd", msg.tts); } let save_result = NewMeme { @@ -62,12 +67,12 @@ pub fn addmeme(_: &mut Context, msg: &Message, args: Args) -> Result<()> { use diesel::result::DatabaseErrorKind; match save_result { - Ok(_) => msg.react("👌"), + Ok(_) => msg.react(ctx, "👌"), Err(e) => { if let Some(DieselError::DatabaseError(DatabaseErrorKind::UniqueViolation, _)) = e.downcast_ref::() { error!("tried to create meme that already exists"); - msg.react("❌")?; - return send(msg.channel_id, "that meme already exists", msg.tts); + msg.react(ctx, "❌")?; + return ctx.send(msg.channel_id, "that meme already exists", msg.tts); } return Err(e); @@ -75,8 +80,9 @@ pub fn addmeme(_: &mut Context, msg: &Message, args: Args) -> Result<()> { } } -pub fn addaudiomeme(_: &mut Context, msg: &Message, args: Args) -> Result<()> { - let mut args = Args::new(args.rest(), &[" ".to_owned(), "\n".to_owned(), "\t".to_owned()]); +#[command] +pub fn addaudiomeme(ctx: &mut Context, msg: &Message, args: Args) -> Result<()> { + let mut args = Args::new(args.rest(), delims.as_ref()); let title = args.single_quoted::()?; let audio_str = args.single_quoted::()?; @@ -84,8 +90,8 @@ pub fn addaudiomeme(_: &mut Context, msg: &Message, args: Args) -> Result<()> { let elems = audio_str.split_whitespace().collect::>(); if elems.len() == 0 { - send(msg.channel_id, "are you stupid", msg.tts)?; - return Err(::failure::err_msg("no audio link was provided")) + ctx.send(msg.channel_id, "are you stupid", msg.tts)?; + return Err(anyhow!("no audio link was provided")) } let audio_link = Url::parse(elems[0])?; @@ -133,7 +139,7 @@ pub fn addaudiomeme(_: &mut Context, msg: &Message, args: Args) -> Result<()> { let conn = connection()?; let image = msg.attachments.first() - .ok_or(::failure::err_msg("no attachment")) + .ok_or(anyhow!("no attachment")) .and_then(|att| { let data = att.download()?; Image::create(&conn, &att.filename, data, msg.author.id.0) @@ -145,7 +151,7 @@ pub fn addaudiomeme(_: &mut Context, msg: &Message, args: Args) -> Result<()> { if bytes == 0 { debug!("read 0 bytes from audio reader"); - return send(msg.channel_id, "🔇🔇🔇🔕🔕🔕🔕🔕🔇🔕🔕🔇🔕🔕📣📢📣📢📣", msg.tts); + return ctx.send(msg.channel_id, "🔇🔇🔇🔕🔕🔕🔕🔕🔇🔕🔕🔇🔕🔕📣📢📣📢📣", msg.tts); } let audio_id = Audio::create(&conn, audio_data, msg.author.id.0)?; @@ -160,12 +166,12 @@ pub fn addaudiomeme(_: &mut Context, msg: &Message, args: Args) -> Result<()> { use diesel::result::DatabaseErrorKind; match save_result { - Ok(_) => msg.react("👌"), + Ok(_) => msg.react(ctx, "👌"), Err(e) => { if let Some(DieselError::DatabaseError(DatabaseErrorKind::UniqueViolation, _)) = e.downcast_ref::() { error!("tried to create meme that already exists"); - msg.react("❌")?; - return send(msg.channel_id, "that meme already exists", msg.tts); + msg.react(ctx, "❌")?; + return ctx.send(msg.channel_id, "that meme already exists", msg.tts); } return Err(e); diff --git a/src/commands/meme/delete.rs b/src/commands/meme/delete.rs index 5c6eb13..72226e5 100644 --- a/src/commands/meme/delete.rs +++ b/src/commands/meme/delete.rs @@ -9,25 +9,28 @@ use serenity::{ }; use crate::{ - commands::send, db::{ connection, delete_meme, }, Result, + util::CtxExt, }; -pub fn delmeme(_: &mut Context, msg: &Message, mut args: Args) -> Result<()> { +#[command] +#[aliases("delmem")] +pub fn delmeme(ctx: &mut Context, msg: &Message, mut args: Args) -> Result<()> { let title = args.single_quoted::()?; let conn = connection()?; + match delete_meme(&conn, &title, msg.author.id.0) { - Ok(_) => msg.react("💀"), + Ok(_) => msg.react(ctx, "💀"), Err(e) => { if let Some(NotFound) = e.downcast_ref::() { - msg.react("❓")?; + msg.react(ctx, "❓")?; info!("attempted to delete nonexistent meme: '{}'", title); - send(msg.channel_id, "nice try", msg.tts)?; + ctx.send(msg.channel_id, "nice try", msg.tts)?; return Ok(()); } diff --git a/src/commands/meme/history.rs b/src/commands/meme/history.rs index e5f15f5..6c03bef 100644 --- a/src/commands/meme/history.rs +++ b/src/commands/meme/history.rs @@ -13,7 +13,6 @@ use timeago::{ }; use crate::{ - commands::send, db::{ connection, InvocationRecord, @@ -22,6 +21,7 @@ use crate::{ }, must_env_lookup, Result, + util::CtxExt, }; lazy_static! { @@ -36,7 +36,9 @@ lazy_static! { static CLEAN_DATE_FORMAT: &'static str = "%b %-e %Y"; -pub fn wat(_: &mut Context, msg: &Message, _: Args) -> Result<()> { +#[command] +#[aliases("what")] +pub fn wat(ctx: &mut Context, msg: &Message, _: Args) -> Result<()> { let conn = connection()?; let record = match InvocationRecord::last(&conn) { @@ -44,10 +46,10 @@ pub fn wat(_: &mut Context, msg: &Message, _: Args) -> Result<()> { Err(e) => { if let Some(NotFound) = e.downcast_ref::() { info!("found no memes in history"); - return send(msg.channel_id, "no one has ever memed before", msg.tts); + return ctx.send(msg.channel_id, "no one has ever memed before", msg.tts); } - send(msg.channel_id, "BAD MEME BAD MEME", msg.tts)?; + ctx.send(msg.channel_id, "BAD MEME BAD MEME", msg.tts)?; return Err(e); }, }; @@ -57,19 +59,19 @@ pub fn wat(_: &mut Context, msg: &Message, _: Args) -> Result<()> { match meme { Ok(ref meme) => { let metadata = Metadata::find(&conn, meme.metadata_id)?; - let author = crate::TARGET_GUILD_ID.member(metadata.created_by as u64)?; + let author = crate::TARGET_GUILD_ID.member(ctx, metadata.created_by as u64)?; - send(msg.channel_id, + ctx.send(msg.channel_id, &format!("that was \"{}\" by {} ({})", meme.title, author.mention(), metadata.created.date().format(CLEAN_DATE_FORMAT)), msg.tts)? }, Err(e) => { if let Some(NotFound) = e.downcast_ref::() { info!("last meme not found in database"); - return send(msg.channel_id, "heuueueeeeh?", msg.tts); + return ctx.send(msg.channel_id, "heuueueeeeh?", msg.tts); } - send(msg.channel_id, "do i look like i know what a jpeg is", msg.tts)?; + ctx.send(msg.channel_id, "do i look like i know what a jpeg is", msg.tts)?; return Err(e); }, }; @@ -77,7 +79,8 @@ pub fn wat(_: &mut Context, msg: &Message, _: Args) -> Result<()> { meme.map(|_| {}) } -pub fn history(_: &mut Context, msg: &Message, mut args: Args) -> Result<()> { +#[command] +pub fn history(ctx: &mut Context, msg: &Message, mut args: Args) -> Result<()> { use itertools::Itertools; lazy_static! { @@ -91,7 +94,7 @@ pub fn history(_: &mut Context, msg: &Message, mut args: Args) -> Result<()> { if n > *MAX_HIST { debug!("user requested more than MAX_HIST ({}) items from history", *MAX_HIST); - send(msg.channel_id, "YER PUSHIN ME OVER THE FUCKIN LINE", true)?; + ctx.send(msg.channel_id, "YER PUSHIN ME OVER THE FUCKIN LINE", true)?; } let n = n.min(*MAX_HIST); @@ -100,7 +103,7 @@ pub fn history(_: &mut Context, msg: &Message, mut args: Args) -> Result<()> { if records.len() == 0 { info!("no memes in history"); - return send(msg.channel_id, "i don't remember anything :(", msg.tts); + return ctx.send(msg.channel_id, "i don't remember anything :(", msg.tts); } info!("reporting meme history (len {})", n); @@ -118,8 +121,8 @@ pub fn history(_: &mut Context, msg: &Message, mut args: Args) -> Result<()> { Metadata::find(&conn, meme.metadata_id).map(|metadata| (metadata, meme)) }) .map(|(metadata, meme)| { - let author_name = crate::TARGET_GUILD_ID.member(metadata.created_by as u64).map(|m| m.display_name().into_owned()).unwrap_or("???".to_owned()); - let invoker_name = crate::TARGET_GUILD_ID.member(rec.user_id as u64).map(|m| m.display_name().into_owned()).unwrap_or("???".to_owned()); + let author_name = crate::TARGET_GUILD_ID.member(ctx, metadata.created_by as u64).map(|m| m.display_name().into_owned()).unwrap_or("???".to_owned()); + let invoker_name = crate::TARGET_GUILD_ID.member(ctx, rec.user_id as u64).map(|m| m.display_name().into_owned()).unwrap_or("???".to_owned()); format!("{}. [{}{}] \"{}\" by {} ({}). invoked by {}.", i + 1, rand, ago, meme.title, author_name, metadata.created.date().format(CLEAN_DATE_FORMAT), invoker_name) }) .unwrap_or_else(|e| { @@ -129,16 +132,18 @@ pub fn history(_: &mut Context, msg: &Message, mut args: Args) -> Result<()> { } } - let invoker_name = crate::TARGET_GUILD_ID.member(rec.user_id as u64).map(|m| m.display_name().into_owned()).unwrap_or("???".to_owned()); + let invoker_name = crate::TARGET_GUILD_ID.member(ctx, rec.user_id as u64).map(|m| m.display_name().into_owned()).unwrap_or("???".to_owned()); format!("{}. [{}{}] not found. invoked by {}.", i + 1, rand, ago, invoker_name) }) }) .join("\n"); - send(msg.channel_id, &resp, false) + ctx.send(msg.channel_id, &resp, false) } -pub fn stats(_: &mut Context, msg: &Message, _: Args) -> Result<()> { +#[command] +#[aliases("stat")] +pub fn stats(ctx: &mut Context, msg: &Message, _: Args) -> Result<()> { use db; use serenity::model::{ id::UserId, @@ -151,11 +156,11 @@ pub fn stats(_: &mut Context, msg: &Message, _: Args) -> Result<()> { debug!("reporting stats"); - let rand_user: User = UserId(stats.most_random_meme_user).to_user()?; - let direct_user: User = UserId(stats.most_directly_named_meme_user).to_user()?; + let rand_user: User = UserId(stats.most_random_meme_user).to_user(ctx)?; + let direct_user: User = UserId(stats.most_directly_named_meme_user).to_user(ctx)?; - let rand_user = rand_user.nick_in(*TARGET_GUILD_ID).unwrap_or(rand_user.name); - let direct_user = direct_user.nick_in(*TARGET_GUILD_ID).unwrap_or(direct_user.name); + let rand_user = rand_user.nick_in(ctx, *TARGET_GUILD_ID).unwrap_or(rand_user.name); + let direct_user = direct_user.nick_in(ctx, *TARGET_GUILD_ID).unwrap_or(direct_user.name); let s = format!( r#" @@ -197,10 +202,11 @@ and *{}* was the most-memed overall ({})"#, stats.most_popular_random_meme, stats.most_popular_random_meme_count, stats.most_popular_meme_overall, stats.most_popular_meme_overall_count, ); - send(msg.channel_id, s, msg.tts) + ctx.send(msg.channel_id, s, msg.tts) } -pub fn memers(_: &mut Context, msg: &Message, _args: Args) -> Result<()> { +#[command] +pub fn memers(ctx: &mut Context, msg: &Message, _args: Args) -> Result<()> { use db; use itertools::Itertools; use serenity::model::{ @@ -211,8 +217,8 @@ pub fn memers(_: &mut Context, msg: &Message, _args: Args) -> Result<()> { let s = db::memers()? .into_iter() .map(|info| { - let user = UserId(info.user_id).to_user()?; - let username = user.nick_in(*TARGET_GUILD_ID).unwrap_or(user.name); + let user = UserId(info.user_id).to_user(ctx)?; + let username = user.nick_in(ctx, *TARGET_GUILD_ID).unwrap_or(user.name); let res = format!( "**{}**: {} total, {} random, {} specific. favorite meme: *{}* ({})", @@ -230,15 +236,15 @@ pub fn memers(_: &mut Context, msg: &Message, _args: Args) -> Result<()> { .into_iter() .join("\n"); - send(msg.channel_id, &s, msg.tts) + ctx.send(msg.channel_id, &s, msg.tts) } -pub fn query(_: &mut Context, msg: &Message, mut args: Args) -> Result<()> { +#[command] +pub fn query(ctx: &mut Context, msg: &Message, mut args: Args) -> Result<()> { use std::borrow::Borrow; use itertools::Itertools; use regex::Regex; - use failure::err_msg; use serenity::model::id::UserId; use crate::{ @@ -252,19 +258,19 @@ pub fn query(_: &mut Context, msg: &Message, mut args: Args) -> Result<()> { static ref AGE_REGEX: Regex = Regex::new(r"(?i)(?:age|order)=(.*)").unwrap(); } - let guild = msg.channel_id.to_channel()? + let guild = msg.channel_id.to_channel(ctx)? .guild() - .ok_or(err_msg("couldn't find guild"))?; + .ok_or(anyhow!("couldn't find guild"))?; let guild = guild.read() - .guild() - .ok_or(err_msg("couldn't find guild"))?; + .guild(ctx) + .ok_or(anyhow!("couldn't find guild"))?; let guild = guild .read(); let creator: Option = { - let creator = args.current_quoted().map(|s| CREATOR_REGEX.is_match(s)).unwrap_or(false); + let creator = args.quoted().current().map(|s| CREATOR_REGEX.is_match(s)).unwrap_or(false); if creator { args.single_quoted::() .ok() @@ -276,12 +282,12 @@ pub fn query(_: &mut Context, msg: &Message, mut args: Args) -> Result<()> { }; let order = { - let order = args.current_quoted().map(|s| AGE_REGEX.is_match(s)).unwrap_or(false); + let order = args.quoted().current().map(|s| AGE_REGEX.is_match(s)).unwrap_or(false); if order { args.single_quoted::().ok() .and_then(|s| AGE_REGEX.captures(&s).and_then(|c| c.get(1)).map(|x| x.as_str().to_owned())) - .map(|s| s.contains("new")) + .map(|s: String| s.contains("new")) .unwrap_or(true) } else { true @@ -291,8 +297,8 @@ pub fn query(_: &mut Context, msg: &Message, mut args: Args) -> Result<()> { let result = db::query_meme(args.rest(), creator, order)? .into_iter() .map(|(meme, metadata)| { - let user = UserId(metadata.created_by as u64).to_user()?; - let username = user.nick_in(*TARGET_GUILD_ID).unwrap_or(user.name); + let user = UserId(metadata.created_by as u64).to_user(ctx)?; + let username = user.nick_in(ctx, *TARGET_GUILD_ID).unwrap_or(user.name); Ok(format!("*{}* by **{}** ({}). text length: **{}**, image: **{}**, audio: **{}**", meme.title, @@ -318,8 +324,8 @@ pub fn query(_: &mut Context, msg: &Message, mut args: Args) -> Result<()> { if result.len() == 0 { info!("no memes matched query"); - return send(msg.channel_id, "no match".to_owned(), msg.tts); + return ctx.send(msg.channel_id, "no match".to_owned(), msg.tts); } - send(msg.channel_id, &result, msg.tts) + ctx.send(msg.channel_id, &result, msg.tts) } \ No newline at end of file diff --git a/src/commands/meme/invoke.rs b/src/commands/meme/invoke.rs index 0f992c2..89ca999 100644 --- a/src/commands/meme/invoke.rs +++ b/src/commands/meme/invoke.rs @@ -2,7 +2,7 @@ use diesel::{ NotFound, result::Error as DieselError, }; -use failure::Error; +use itertools::Itertools; use serenity::{ framework::standard::Args, model::channel::Message, @@ -10,11 +10,7 @@ use serenity::{ }; use crate::{ - audio::CtxExt, - commands::{ - meme::send_meme, - send, - }, + commands::meme::send_meme, db::{ self, connection, @@ -22,18 +18,25 @@ use crate::{ InvocationRecord, }, Result, + util::CtxExt, }; +#[command] +#[aliases("mem")] #[inline] pub fn meme(ctx: &mut Context, msg: &Message, args: Args) -> Result<()> { _meme(ctx, msg, args, AudioPlayback::Optional) } +#[command] +#[aliases("audiomeme", "audiomem")] #[inline] pub fn audio_meme(ctx: &mut Context, msg: &Message, args: Args) -> Result<()> { _meme(ctx, msg, args, AudioPlayback::Required) } +#[command] +#[aliases("silentmeme", "silentmem")] #[inline] pub fn silent_meme(ctx: &mut Context, msg: &Message, args: Args) -> Result<()> { _meme(ctx, msg, args, AudioPlayback::Prohibited) @@ -51,7 +54,7 @@ fn _meme(ctx: &mut Context, msg: &Message, args: Args, audio_playback: AudioPlay return rand_meme(ctx, msg, audio_playback); } - let search = args.full(); + let search = args.raw().join(" "); let conn = connection()?; let mem = match find_meme(&conn, search) { @@ -63,9 +66,9 @@ fn _meme(ctx: &mut Context, msg: &Message, args: Args, audio_playback: AudioPlay Err(e) => { return if let Some(NotFound) = e.downcast_ref::() { info!("requested meme not found in database"); - send(msg.channel_id, "c'mon baby, guesstimate", msg.tts) + ctx.send(msg.channel_id, "c'mon baby, guesstimate", msg.tts) } else { - send(msg.channel_id, "what in ryan's name", msg.tts)?; + ctx.send(msg.channel_id, "what in ryan's name", msg.tts)?; Err(e) }; }, @@ -74,6 +77,8 @@ fn _meme(ctx: &mut Context, msg: &Message, args: Args, audio_playback: AudioPlay send_meme(ctx, &mem, &conn, msg) } +#[command] +#[aliases("rarememe", "raremem")] fn rand_meme(ctx: &Context, message: &Message, audio_playback: AudioPlayback) -> Result<()> { let conn = connection()?; @@ -94,17 +99,19 @@ fn rand_meme(ctx: &Context, message: &Message, audio_playback: AudioPlayback) -> match e.downcast_ref::() { Some(NotFound) => { info!("random meme not found"); - return send(message.channel_id, "i don't know any :(", message.tts) + return ctx.send(message.channel_id, "i don't know any :(", message.tts) }, _ => {}, } - send(message.channel_id, "HELP", message.tts)?; + ctx.send(message.channel_id, "HELP", message.tts)?; return Err(e); }, } } +#[command] +#[aliases("rarememe", "raremem")] pub fn rare_meme(ctx: &mut Context, msg: &Message, _args: Args) -> Result<()> { let should_audio = ctx.users_listening()?; @@ -120,12 +127,12 @@ pub fn rare_meme(ctx: &mut Context, msg: &Message, _args: Args) -> Result<()> { match e.downcast_ref::() { Some(NotFound) => { info!("rare meme not found"); - return send(msg.channel_id, "i don't know any :(", msg.tts) + return ctx.send(msg.channel_id, "i don't know any :(", msg.tts) }, _ => {}, } - send(msg.channel_id, "THE MEME MARKET IS IN FREEFALL", msg.tts)?; + ctx.send(msg.channel_id, "THE MEME MARKET IS IN FREEFALL", msg.tts)?; Err(e) }, diff --git a/src/commands/meme/mod.rs b/src/commands/meme/mod.rs index 3738eab..e5244aa 100644 --- a/src/commands/meme/mod.rs +++ b/src/commands/meme/mod.rs @@ -37,7 +37,7 @@ fn send_meme(ctx: &Context, t: &Meme, conn: &PgConnection, msg: &Message) -> Res let image = t.image(conn); let audio = t.audio(conn); - let create_msg = |m: CreateMessage| { + let create_msg = |m: &mut CreateMessage| { let ret = m.tts(should_tts); match t.content { @@ -49,10 +49,11 @@ fn send_meme(ctx: &Context, t: &Meme, conn: &PgConnection, msg: &Message) -> Res match image { Some(image) => { let image = image?; - msg.channel_id.send_files(vec!(AttachmentType::Bytes((&image.data, &image.filename))), create_msg)?; + msg.channel_id.send_files(ctx, vec!(AttachmentType::Bytes((&image.data, &image.filename))), create_msg)?; }, + None => match t.content { - Some(_) => { msg.channel_id.send_message(create_msg)?; }, + Some(_) => { msg.channel_id.send_message(ctx, create_msg)?; }, None => {}, }, }; @@ -64,7 +65,7 @@ fn send_meme(ctx: &Context, t: &Meme, conn: &PgConnection, msg: &Message) -> Res let audio = audio?; { - let queue_lock = ctx.data.lock().get::().cloned().unwrap(); + let queue_lock = ctx.data.write().get::().cloned().unwrap(); let mut play_queue = queue_lock.write().unwrap(); play_queue.meme_queue.push_back(PlayArgs{ @@ -76,7 +77,7 @@ fn send_meme(ctx: &Context, t: &Meme, conn: &PgConnection, msg: &Message) -> Res }); } - msg.react("📣")?; + msg.react(ctx, "📣")?; } Ok(()) diff --git a/src/commands/mod.rs b/src/commands/mod.rs index f4ff9cb..619335c 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -1,163 +1,107 @@ use serenity::{ framework::StandardFramework, - model::id::{ChannelId, MessageId}, }; -use crate::Result; +use crate::{ + util::CtxExt, +}; +#[cfg(feature = "games")] +use crate::game::*; +pub use self::{ + playback::*, + sound_levels::*, +}; #[cfg(feature = "diesel")] pub use self::meme::*; -pub use self::playback::*; -pub use self::sound_levels::*; pub(crate) mod playback; pub(crate) mod sound_levels; pub(crate) mod roll; +group!("playback", { + options: { + only_in: "guild", + }, + commands: [ + skip, + pause, + resume, + list, + die, + mute, + unmute, + play, + volume, + ], +}); + +group!("general", { + options: { + only_in: "guild", + }, + commands: [ + roll, + ], +}); + pub fn register_commands(f: StandardFramework) -> StandardFramework { - let f: StandardFramework = register_db(f); - f - .command("skip", |c| c - .desc("skip the rest of the current request") - .guild_only(true) - .exec(skip)) - .command("pause", |c| c - .desc("pause playback (currently broken)") - .guild_only(true) - .exec(pause)) - .command("resume", |c| c - .desc("resume playing (currently broken)") - .guild_only(true) - .exec(resume)) - .command("list", |c| c - .known_as("queue") - .desc("list playing and queued requests") - .guild_only(true) - .exec(list)) - .command("die", |c| c - .batch_known_as(vec!["sudoku", "stop"]) - .desc("stop playing and empty the queue") - .guild_only(true) - .exec(die)) - .command("mute", |c| c - .desc("mute thulani (playback continues)") - .guild_only(true) - .exec(mute)) - .command("unmute", |c| c - .desc("unmute thulani") - .guild_only(true) - .exec(unmute)) - .command("play", |c| c - .desc("queue a request") - .guild_only(true) - .exec(play)) - .command("volume", |c| c - .desc("set playback volume") - .guild_only(true) - .exec(volume)) - .command("roll", |c| c - .known_as("calc") - .desc("simulate rolling dice") - .guild_only(true) - .exec(roll::roll)) - .unrecognised_command(|ctx, msg, unrec| { - let url = match msg.content.split_whitespace().skip(1).next() { - Some(x) if x.starts_with("http") => x, - _ => { - info!("bad command formatting: '{}'", unrec); - let _ = send(msg.channel_id, "format your commands right. fuck you.", msg.tts); - return; - } - }; + let result = f + .group(&PLAYBACK_GROUP) + .group(&GENERAL_GROUP); - let _ = self::playback::_play(ctx, msg, &url); - }) -} + #[cfg(feature = "diesel")] + let result = result.group(&MEMES_GROUP); -#[cfg(feature = "diesel")] -mod meme; + #[cfg(feature = "games")] + let result = result.group(&GAME_GROUP); -#[cfg(feature = "diesel")] -fn register_db(f: StandardFramework) -> StandardFramework { - f - .command("meme", |c| c - .guild_only(true) - .help_available(false) - .cmd(meme)) - .command("audiomeme", |c| c - .guild_only(true) - .help_available(false) - .cmd(audio_meme) - ) - .command("silentmeme", |c| c - .guild_only(true) - .help_available(false) - .cmd(silent_meme) - ) - .command("addmeme", |c| c - .guild_only(true) - .desc("first argument is title, everything after is text. one attached image is included if present.") - .cmd(addmeme) - ) - .command("addaudiomeme", |c| c - .guild_only(true) - .desc("title, audio link, text, with optional image") - .cmd(addaudiomeme) - ) - .command("delmeme", |c| c - .guild_only(true) - .desc("delete a meme by name (exact match only)") - .cmd(delmeme) - ) - .command("wat", |c| c - .known_as("what") - .known_as("last") - .known_as("lastmeme") - .guild_only(true) - .desc("check info for last meme") - .cmd(wat) - ) - .command("stats", |c| c - .guild_only(true) - .desc("get meme stats") - .cmd(stats) - ) - .command("history", |c| c - .known_as("hist") - .guild_only(true) - .desc("history of recent messages") - .cmd(history) - ) - .command("rarememe", |c| c - .known_as("rare_meme") - .guild_only(true) - .desc("deliver an underutilized meme") - .cmd(rare_meme) - ) - .command("memers", |c| c - .guild_only(true) - .desc("list stats for all server memers") - .cmd(memers) - ) - .command("query", |c| c - .guild_only(true) - .desc("find a lot of matching memes") - .cmd(query) - ) -} + result.unrecognised_command(|ctx, msg, unrec| { + let url = match msg.content.split_whitespace().skip(1).next() { + Some(x) if x.starts_with("http") => x, + _ => { + info!("bad command formatting: '{}'", unrec); + let _ = ctx.send(msg.channel_id, "format your commands right. fuck you.", msg.tts); + return; + } + }; -#[cfg(not(feature = "diesel"))] -fn register_db(f: StandardFramework) -> StandardFramework { - f + let _ = self::playback::_play(ctx, msg, &url); + }) } -#[inline] -pub(crate) fn send>(channel: ChannelId, text: A, tts: bool) -> Result<()> { - send_result(channel, text, tts).map(|_| ()) -} +#[cfg(feature = "games")] +group!("game", { + options: { + only_in: "guild", + }, + commands: [ + installedgame, + ownedgame, + updategaem, + ], +}); -#[inline] -pub(crate) fn send_result>(channel: ChannelId, text: A, tts: bool) -> Result { - let result = channel.send_message(|m| m.content(text.as_ref()).tts(tts))?; - Ok(result.id) -} +#[cfg(feature = "diesel")] +mod meme; + +#[cfg(feature = "diesel")] +group!("memes", { + options: { + only_in: "guild", + }, + commands: [ + meme, + audio_meme, + silent_Meme, + addmeme, + addaudiomeme, + delmeme, + wat, + stats, + history, + rare_meme, + memers, + query, + ], +}); diff --git a/src/commands/playback.rs b/src/commands/playback.rs index 64d30cd..49ff44c 100644 --- a/src/commands/playback.rs +++ b/src/commands/playback.rs @@ -12,9 +12,9 @@ use crate::{ PlayQueue, VoiceManager, }, - commands::send, Result, TARGET_GUILD_ID, + util::CtxExt, }; pub fn _play(ctx: &Context, msg: &Message, url: &str) -> Result<()> { @@ -23,14 +23,14 @@ pub fn _play(ctx: &Context, msg: &Message, url: &str) -> Result<()> { debug!("playing '{}'", url); if !url.starts_with("http") { warn!("got bad url argument to play: {}", url); - send(msg.channel_id, "bAD LiNk", msg.tts)?; + ctx.send(msg.channel_id, "bAD LiNk", msg.tts)?; return Ok(()); } let url = match Url::parse(url) { Err(e) => { error!("bad url: {}", e); - return send(msg.channel_id, "INVALID URL", msg.tts); + return ctx.send(msg.channel_id, "INVALID URL", msg.tts); }, Ok(u) => u, }; @@ -44,9 +44,9 @@ pub fn _play(ctx: &Context, msg: &Message, url: &str) -> Result<()> { info!("detected imgur link"); if msg.author.id.0 == 106160362109272064 { - send(msg.channel_id, "fuck you conway", true)?; + ctx.send(msg.channel_id, "fuck you conway", true)?; } else { - send(msg.channel_id, "IMGUR IS BAD, YOU TRASH CAN MAN", msg.tts)?; + ctx.send(msg.channel_id, "IMGUR IS BAD, YOU TRASH CAN MAN", msg.tts)?; } return Ok(()); @@ -54,7 +54,7 @@ pub fn _play(ctx: &Context, msg: &Message, url: &str) -> Result<()> { let (start, end) = parse_times(&msg.content); - let queue_lock = ctx.data.lock().get::().cloned().unwrap(); + let queue_lock = ctx.data.write().get::().cloned().unwrap(); let mut play_queue = queue_lock.write().unwrap(); play_queue.general_queue.push_back(PlayArgs{ @@ -68,6 +68,7 @@ pub fn _play(ctx: &Context, msg: &Message, url: &str) -> Result<()> { Ok(()) } +#[command] pub fn play(ctx: &mut Context, msg: &Message, mut args: Args) -> Result<()> { if args.len() == 0 { return _resume(ctx, msg); @@ -77,17 +78,18 @@ pub fn play(ctx: &mut Context, msg: &Message, mut args: Args) -> Result<()> { Ok(url) => url, Err(e) => { error!("unable to parse url from args: {}", e); - return send(msg.channel_id, "BAD LINK", msg.tts); + return ctx.send(msg.channel_id, "BAD LINK", msg.tts); }, }; _play(ctx, msg, &url) } +#[command] pub fn pause(ctx: &mut Context, msg: &Message, _: Args) -> Result<()> { - let queue_lock = ctx.data.lock().get::().cloned().unwrap(); + let queue_lock = ctx.data.write().get::().cloned().unwrap(); - let done = || send(msg.channel_id, "r u srs", msg.tts); + let done = || ctx.send(msg.channel_id, "r u srs", msg.tts); let playing = { let play_queue = queue_lock.read().unwrap(); @@ -115,14 +117,16 @@ pub fn pause(ctx: &mut Context, msg: &Message, _: Args) -> Result<()> { Ok(()) } +#[command] +#[aliases("continue")] pub fn resume(ctx: &mut Context, msg: &Message, _: Args) -> Result<()> { _resume(ctx, msg) } fn _resume(ctx: &mut Context, msg: &Message) -> Result<()> { - let queue_lock = ctx.data.lock().get::().cloned().unwrap(); + let queue_lock = ctx.data.write().get::().cloned().unwrap(); - let done = || send(msg.channel_id, "r u srs", msg.tts); + let done = || ctx.send(msg.channel_id, "r u srs", msg.tts); let playing = { let play_queue = queue_lock.read().unwrap(); @@ -154,8 +158,10 @@ fn _resume(ctx: &mut Context, msg: &Message) -> Result<()> { Ok(()) } +#[command] +#[aliases("next")] pub fn skip(ctx: &mut Context, _msg: &Message, _args: Args) -> Result<()> { - let data = ctx.data.lock(); + let data = ctx.data.write(); let mgr_lock = data.get::().cloned().unwrap(); let mut manager = mgr_lock.lock(); @@ -174,8 +180,10 @@ pub fn skip(ctx: &mut Context, _msg: &Message, _args: Args) -> Result<()> { Ok(()) } +#[command] +#[aliases("sudoku", "fuckoff", "stop")] pub fn die(ctx: &mut Context, msg: &Message, _: Args) -> Result<()> { - let data = ctx.data.lock(); + let data = ctx.data.write(); let mgr_lock = data.get::().cloned().unwrap(); let mut manager = mgr_lock.lock(); @@ -195,18 +203,20 @@ pub fn die(ctx: &mut Context, msg: &Message, _: Args) -> Result<()> { handler.stop(); handler.leave(); } else { - send(msg.channel_id, "YOU die", msg.tts)?; + ctx.send(msg.channel_id, "YOU die", msg.tts)?; debug!("got die with no handler attached"); } Ok(()) } +#[command] +#[aliases("queue")] pub fn list(ctx: &mut Context, msg: &Message, _: Args) -> Result<()> { - let queue_lock = ctx.data.lock().get::().cloned().unwrap(); + let queue_lock = ctx.data.write().get::().cloned().unwrap(); let play_queue = queue_lock.read().unwrap(); - let channel_tmp = msg.channel().unwrap().guild().unwrap(); + let channel_tmp = msg.channel(ctx).unwrap().guild().unwrap(); let channel = channel_tmp.read(); info!("listing queue"); @@ -220,11 +230,11 @@ pub fn list(ctx: &mut Context, msg: &Message, _: Args) -> Result<()> { Right(_) => "memeing".to_owned(), }; - send(msg.channel_id, &format!("Currently {} {} ({})", status, playing_info, info.init_args.initiator), msg.tts)?; + ctx.send(msg.channel_id, &format!("Currently {} {} ({})", status, playing_info, info.init_args.initiator), msg.tts)?; }, None => { debug!("`list` called with no items in queue"); - send(msg.channel_id, "Nothing is playing you meme", msg.tts)?; + ctx.send(msg.channel_id, "Nothing is playing you meme", msg.tts)?; return Ok(()); }, } @@ -237,7 +247,7 @@ pub fn list(ctx: &mut Context, msg: &Message, _: Args) -> Result<()> { Right(_) => "meme".to_owned(), }; - let _ = channel.say(&format!("{} ({})", playing_info, info.initiator)); + let _ = channel.say(ctx, &format!("{} ({})", playing_info, info.initiator)); }); Ok(()) diff --git a/src/commands/roll.rs b/src/commands/roll.rs index b7b98d6..3df91d0 100644 --- a/src/commands/roll.rs +++ b/src/commands/roll.rs @@ -9,23 +9,23 @@ use serenity::{ use statrs; use crate::{ - commands::send, Result, + util::CtxExt, }; #[derive(Parser)] #[grammar = "commands/calc.pest"] struct Calc; -#[derive(Copy, Clone, Fail, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Error, Debug, PartialEq, Eq, Hash)] pub(crate) enum CalcError { - #[fail(display = "pest was unable to parse the input")] + #[error("pest was unable to parse the input")] Pest, - #[fail(display = "invalid number format")] + #[error("invalid number format")] NumberFormat, - #[fail(display = "bad argument count")] + #[error("bad argument count")] ArgCount, } @@ -143,9 +143,7 @@ impl Calc { fn eval_expr(p: Pairs) -> StdResult { CLIMBER.climb( p, - |pair| { - eval_single_pair(pair) - }, + eval_single_pair, |lhs, op, rhs| { let lhs = lhs?; let rhs = rhs?; @@ -198,15 +196,17 @@ mod test { } } -pub fn roll(_ctx: &mut Context, msg: &Message, args: Args) -> Result<()> { +#[command] +#[aliases("calc", "calculate")] +pub fn roll(ctx: &mut Context, msg: &Message, args: Args) -> Result<()> { match Calc::eval(args.rest()) { Ok(result) => { debug!("got calc result '{}'", result); - send(msg.channel_id, &format!("{}", result), msg.tts) + ctx.send(msg.channel_id, &format!("{}", result), msg.tts) }, Err(e) => { error!("error encountered reading calc '{}': {}", args.rest(), e); - send(msg.channel_id, "I COULDN'T READ THAT YOU FUCK", msg.tts) + ctx.send(msg.channel_id, "I COULDN'T READ THAT YOU FUCK", msg.tts) }, } } diff --git a/src/commands/sound_levels.rs b/src/commands/sound_levels.rs index 60803a3..81508a6 100644 --- a/src/commands/sound_levels.rs +++ b/src/commands/sound_levels.rs @@ -6,15 +6,16 @@ use serenity::{ use crate::{ audio::{PlayQueue, VoiceManager}, - commands::send, Result, TARGET_GUILD_ID, + util::CtxExt, }; pub const DEFAULT_VOLUME: f32 = 0.10; +#[command] pub fn mute(ctx: &mut Context, _: &Message, _: Args) -> Result<()> { - let mgr_lock = ctx.data.lock().get::().cloned().unwrap(); + let mgr_lock = ctx.data.write().get::().cloned().unwrap(); let mut manager = mgr_lock.lock(); manager.get_mut(*TARGET_GUILD_ID) @@ -30,8 +31,9 @@ pub fn mute(ctx: &mut Context, _: &Message, _: Args) -> Result<()> { Ok(()) } +#[command] pub fn unmute(ctx: &mut Context, msg: &Message, _: Args) -> Result<()> { - let mgr_lock = ctx.data.lock().get::().cloned().unwrap(); + let mgr_lock = ctx.data.write().get::().cloned().unwrap(); let mut manager = mgr_lock.lock(); manager.get_mut(*TARGET_GUILD_ID) @@ -41,35 +43,36 @@ pub fn unmute(ctx: &mut Context, msg: &Message, _: Args) -> Result<()> { } else { handler.mute(false); trace!("Unmuted"); - let _ = send(msg.channel_id, "REEEEEEEEEEEEEE", msg.tts); + let _ = ctx.send(msg.channel_id, "REEEEEEEEEEEEEE", msg.tts); } }); Ok(()) } +#[command] pub fn volume(ctx: &mut Context, msg: &Message, mut args: Args) -> Result<()> { if args.len() == 0 { let vol = { - let queue_lock = ctx.data.lock().get::().cloned().unwrap(); + let queue_lock = ctx.data.write().get::().cloned().unwrap(); let play_queue = queue_lock.read().unwrap(); (play_queue.volume / DEFAULT_VOLUME * 100.0) as usize }; trace!("reporting volume {}", vol); - return send(msg.channel_id, &format!("volume: {}%", vol), msg.tts); + return ctx.send(msg.channel_id, &format!("volume: {}%", vol), msg.tts); } let vol: usize = match args.single::() { Ok(vol) if vol.is_nan() => { warn!("reporting NaN volume"); - return send(msg.channel_id, "you're a fuck", msg.tts); + return ctx.send(msg.channel_id, "you're a fuck", msg.tts); }, Ok(vol) => vol as usize, Err(e) => { error!("parsing volume arg: {}", e); - return send(msg.channel_id, "???????", msg.tts) + return ctx.send(msg.channel_id, "???????", msg.tts) }, }; @@ -84,7 +87,7 @@ pub fn volume(ctx: &mut Context, msg: &Message, mut args: Args) -> Result<()> { vol = 0.0; } - let queue_lock = ctx.data.lock().get::().cloned().unwrap(); + let queue_lock = ctx.data.write().get::().cloned().unwrap(); { let mut play_queue = queue_lock.write().unwrap(); @@ -92,7 +95,7 @@ pub fn volume(ctx: &mut Context, msg: &Message, mut args: Args) -> Result<()> { info!("volume updated to {}", vol); } - send(msg.channel_id, format!("volume adjusted{}", adjusted_text), msg.tts)?; + ctx.send(msg.channel_id, format!("volume adjusted{}", adjusted_text), msg.tts)?; { let play_queue = queue_lock.read().unwrap(); -- cgit v1.3.1