From e9e3458225cfc0fdc20a7d2960ef15d4de349802 Mon Sep 17 00:00:00 2001 From: Nathan Perry Date: Sun, 17 Feb 2019 01:59:22 -0500 Subject: support audio memes --- src/audio/mod.rs | 2 +- src/audio/play_queue.rs | 3 +-- src/audio/timeutil.rs | 3 --- src/audio/ytdl.rs | 9 +++++-- src/commands/meme.rs | 70 ++++++++++++++++++++++++++++++++++++++++++++++--- src/commands/mod.rs | 5 ++++ src/main.rs | 2 +- 7 files changed, 81 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/audio/mod.rs b/src/audio/mod.rs index a7f3e83..eaebf55 100644 --- a/src/audio/mod.rs +++ b/src/audio/mod.rs @@ -19,7 +19,7 @@ use crate::{ }; pub use self::timeutil::parse_times; -pub use self::ytdl::ytdl; +pub use self::ytdl::*; pub use self::play_queue::PlayQueue; mod timeutil; diff --git a/src/audio/play_queue.rs b/src/audio/play_queue.rs index 6f3a130..deb4e2c 100644 --- a/src/audio/play_queue.rs +++ b/src/audio/play_queue.rs @@ -103,11 +103,10 @@ impl PlayQueue { } }, Right(ref vec) => { - ::serenity::voice::opus(true, ::std::io::Cursor::new(vec.clone())) + ::serenity::voice::pcm(true, ::std::io::Cursor::new(vec.clone())) } }; - let mut manager = voice_manager.lock(); let handler = manager.join(*TARGET_GUILD_ID, must_env_lookup::("VOICE_CHANNEL")); diff --git a/src/audio/timeutil.rs b/src/audio/timeutil.rs index d0bd9d5..b2232de 100644 --- a/src/audio/timeutil.rs +++ b/src/audio/timeutil.rs @@ -59,7 +59,6 @@ mod test { assert_eq!(captures.name("seconds").unwrap().as_str(), "3"); assert!(START_REGEX.captures("").is_none()); - assert!(START_REGEX.captures("start s").is_none()); let captures = START_REGEX.captures("start 1").unwrap(); assert_eq!(captures.name("seconds").unwrap().as_str(), "1"); @@ -74,7 +73,6 @@ mod test { assert_eq!(captures.name("seconds").unwrap().as_str(), "3"); assert!(DUR_REGEX.captures("").is_none()); - assert!(DUR_REGEX.captures("dur s").is_none()); let captures = DUR_REGEX.captures("dur 1").unwrap(); assert_eq!(captures.name("seconds").unwrap().as_str(), "1"); @@ -89,7 +87,6 @@ mod test { assert_eq!(captures.name("seconds").unwrap().as_str(), "3"); assert!(END_REGEX.captures("").is_none()); - assert!(END_REGEX.captures("end s").is_none()); let captures = END_REGEX.captures("end 1").unwrap(); assert_eq!(captures.name("seconds").unwrap().as_str(), "1"); diff --git a/src/audio/ytdl.rs b/src/audio/ytdl.rs index d16d166..8384db4 100644 --- a/src/audio/ytdl.rs +++ b/src/audio/ytdl.rs @@ -42,7 +42,7 @@ impl Drop for ChildContainer { } } -pub fn ytdl(uri: &str, start: Option, end: Option) -> Result> { +pub fn ytdl_reader(uri: &str, start: Option, end: Option) -> Result> { let args = [ "-f", "webm[abr>0]/bestaudio/best", @@ -113,5 +113,10 @@ pub fn ytdl(uri: &str, start: Option, end: Option) -> Result .stdout(Stdio::piped()) .spawn()?; - Ok(pcm(true, ChildContainer(command))) + Ok(Box::new(ChildContainer(command))) +} + +pub fn ytdl(uri: &str, start: Option, end: Option) -> Result> { + let command = ytdl_reader(uri, start, end)?; + Ok(pcm(true, command)) } diff --git a/src/commands/meme.rs b/src/commands/meme.rs index 0305e79..922091c 100644 --- a/src/commands/meme.rs +++ b/src/commands/meme.rs @@ -1,9 +1,13 @@ -use std::sync::RwLock; +use std::{ + io::{BufReader, Read}, + sync::RwLock, +}; use diesel::PgConnection; use failure::Error; use lazy_static::lazy_static; use rand::{Rng, thread_rng}; +use url::Url; use serenity::{ builder::CreateMessage, framework::standard::Args, @@ -17,6 +21,8 @@ use crate::{ CtxExt, PlayArgs, PlayQueue, + ytdl_reader, + parse_times, }, commands::{ send, @@ -128,6 +134,59 @@ pub fn addmeme(_: &mut Context, msg: &Message, mut args: Args) -> Result<()> { msg.react("👌") } +pub fn addaudiomeme(_: &mut Context, msg: &Message, mut args: Args) -> Result<()> { + let title = args.single_quoted::()?; + let audio_str = args.single_quoted::()?; + + let elems = audio_str.split_whitespace().collect::>(); + + if elems.len() == 0 { + return Err(::failure::err_msg("no audio link was provided")) + } + + let audio_link = Url::parse(elems[0])?; + let opts = elems[1..].join(" "); + let (start, end) = parse_times(opts); + + let audio_reader = BufReader::new(ytdl_reader(audio_link.as_str(), start, end)?); + + let text = match args.multiple_quoted::() { + Ok(text) => text.join(" "), + Err(_) => "".to_owned(), + }; + + let text = if text.is_empty() { None } else { Some(text) }; + + let conn = connection()?; + + let image = msg.attachments.first() + .ok_or(::failure::err_msg("no attachment")) + .and_then(|att| { + let data = att.download()?; + Image::create(&conn, &att.filename, data, msg.author.id.0) + }) + .ok(); + + let mut audio_data = Vec::new(); + audio_reader.take(5 * 1024 * 1024).read_to_end(&mut audio_data)?; + + if audio_data.len() == 0 { + return send(msg.channel_id, "🔇🔇🔇🔕🔕🔕🔕🔕🔇🔕🔕🔇🔕🔕📣📢📣📢📣", msg.tts); + } + + let audio_id = Audio::create(&conn, audio_data, msg.author.id.0)?; + + NewMeme { + title, + content: text, + image_id: image, + audio_id: Some(audio_id), + metadata_id: 0, + }.save(&conn, msg.author.id.0).map(|_| {})?; + + msg.react("👌") +} + pub fn delmeme(_: &mut Context, msg: &Message, mut args: Args) -> Result<()> { let title = args.single_quoted::()?; @@ -194,16 +253,19 @@ fn send_meme(ctx: &Context, t: &Meme, conn: &PgConnection, msg: &Message) -> Res match t.content { Some(ref text) => ret.content(text), - None => ret + None => ret, } }; 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(vec!(AttachmentType::Bytes((&image.data, &image.filename))), create_msg)?; + }, + None => match t.content { + Some(_) => { msg.channel_id.send_message(create_msg)?; }, + None => {}, }, - None => msg.channel_id.send_message(create_msg)?, }; // note: slight edge-case race condition here: there could have been something queued since we diff --git a/src/commands/mod.rs b/src/commands/mod.rs index b991c18..d5d91e2 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -88,6 +88,11 @@ fn register_db(f: StandardFramework) -> StandardFramework { .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)") diff --git a/src/main.rs b/src/main.rs index 7202556..708d778 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,7 +16,7 @@ extern crate serenity; extern crate sha1; extern crate typemap; extern crate url; -#[macro_use] extern crate itertools; +#[cfg_attr(test, macro_use)] extern crate itertools; extern crate time; extern crate serde_json; -- cgit v1.3.1