From 4276428a8bf439e1b9edca507243194fbe1b1633 Mon Sep 17 00:00:00 2001 From: hodasemi Date: Fri, 12 Jul 2019 10:39:03 +0200 Subject: [PATCH] Start implementing serenity 0.6 --- src/main.rs | 32 ++- src/player/commands/help.rs | 37 --- src/player/commands/ip.rs | 65 ++--- src/player/commands/list.rs | 85 +++--- src/player/commands/mod.rs | 1 - src/player/commands/pause.rs | 54 ++-- src/player/commands/play.rs | 518 +++++++++++++++++----------------- src/player/commands/remove.rs | 78 +++-- src/player/commands/skip.rs | 141 ++++----- src/player/commands/stop.rs | 48 ++-- src/player/mediadata.rs | 93 +++--- src/player/player.rs | 16 +- src/player/prelude.rs | 15 +- src/player/voicemanager.rs | 2 +- 14 files changed, 557 insertions(+), 628 deletions(-) delete mode 100644 src/player/commands/help.rs diff --git a/src/main.rs b/src/main.rs index 24541b0..6882230 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,8 +11,24 @@ mod confighandler; mod macros; mod player; -use serenity::client::Client; -use serenity::framework::StandardFramework; +use serenity::{ + framework::standard::{ + help_commands, + macros::{check, command, group, help}, + Args, CheckResult, CommandGroup, CommandOptions, CommandResult, DispatchError, HelpOptions, + StandardFramework, + }, + model::{ + channel::{Channel, Message}, + gateway::Ready, + id::UserId, + }, + utils::{content_safe, ContentSafeOptions}, +}; + +// This imports `typemap`'s `Key` as `TypeMapKey`. +use serenity::prelude::*; + use std::sync::Arc; use confighandler::*; @@ -32,6 +48,12 @@ impl Default for Config { } } +group!({ + name: "general", + options: {}, + commands: [ip] +}); + fn main() { // read config file let config_file = check_result_return!(read_config("bot.conf")); @@ -71,13 +93,15 @@ fn main() { // voice manager into it. This allows the voice manager to be accessible by // event handlers and framework commands. { - let mut data = client.data.lock(); + let mut data = client.data.write(); data.insert::(Arc::clone(&client.voice_manager)); } let media_data = Arc::new(MediaData::new("Penis1").expect("failed to create media data handle")); + /* + client.with_framework( StandardFramework::new() .configure(|c| c.prefix(&config.prefix).on_mention(true)) @@ -109,4 +133,6 @@ fn main() { let _ = client .start() .map_err(|why| println!("Client ended: {:?}", why)); + + */ } diff --git a/src/player/commands/help.rs b/src/player/commands/help.rs deleted file mode 100644 index 47af381..0000000 --- a/src/player/commands/help.rs +++ /dev/null @@ -1,37 +0,0 @@ -use serenity; - -pub struct Help { - prefix: String, - commands: Vec, -} - -impl Help { - pub fn new(prefix: &String, commands: Vec) -> Help { - Help { - prefix: prefix.clone(), - commands: commands, - } - } -} - -impl serenity::framework::standard::Command for Help { - #[allow(unreachable_code, unused_mut)] - fn execute( - &self, - _: &mut serenity::client::Context, - msg: &serenity::model::channel::Message, - _: serenity::framework::standard::Args, - ) -> ::std::result::Result<(), serenity::framework::standard::CommandError> { - let mut output = String::new(); - - output += "Available commands:\n"; - - for command in &self.commands { - output += &format!("\t{}{}\n", self.prefix, command); - } - - print_error!(msg.channel_id.say(output)); - - Ok(()) - } -} diff --git a/src/player/commands/ip.rs b/src/player/commands/ip.rs index 670c488..7951251 100644 --- a/src/player/commands/ip.rs +++ b/src/player/commands/ip.rs @@ -1,44 +1,35 @@ -use serenity; +use serenity::{ + framework::standard::{macros::command, Args, CommandResult}, + model::channel::Message, +}; + +// This imports `typemap`'s `Key` as `TypeMapKey`. +use serenity::prelude::*; use std::process::{Command, Stdio}; use std::str::from_utf8; -pub struct IP {} +#[command] +fn ip(ctx: &mut Context, msg: &Message, args: Args) -> CommandResult { + let args = ["ifconfig.me"]; -impl IP { - pub fn new() -> IP { - IP {} - } -} - -impl serenity::framework::standard::Command for IP { - #[allow(unreachable_code, unused_mut)] - fn execute( - &self, - _: &mut serenity::client::Context, - msg: &serenity::model::channel::Message, - _: serenity::framework::standard::Args, - ) -> ::std::result::Result<(), serenity::framework::standard::CommandError> { - let args = ["ifconfig.me"]; - - let out = match Command::new("curl") - .args(&args) - .stdin(Stdio::null()) - .output() - { - Ok(out) => out, - Err(_) => return Ok(()), - }; - - if !out.status.success() { - return Ok(()); - } - - match from_utf8(out.stdout.as_slice()) { - Ok(string) => print_error!(msg.author.direct_message(|m| m.content(string))), - Err(_) => print_error!(msg.channel_id.say("error getting IP string")), - }; - - Ok(()) + let out = match Command::new("curl") + .args(&args) + .stdin(Stdio::null()) + .output() + { + Ok(out) => out, + Err(_) => return Ok(()), + }; + + if !out.status.success() { + return Ok(()); } + + match from_utf8(out.stdout.as_slice()) { + Ok(string) => print_error!(msg.author.direct_message(|m| m.content(string))), + Err(_) => print_error!(msg.channel_id.say("error getting IP string")), + }; + + Ok(()) } diff --git a/src/player/commands/list.rs b/src/player/commands/list.rs index 433e378..853dff3 100644 --- a/src/player/commands/list.rs +++ b/src/player/commands/list.rs @@ -1,61 +1,52 @@ -use serenity; - -use std::sync::Arc; - use super::super::prelude::*; -pub struct List { - media: Arc, -} +use serenity::prelude::*; +use serenity::{ + framework::standard::{macros::command, Args, CommandResult}, + model::channel::Message, +}; -impl List { - pub fn new(media_data: Arc) -> List { - List { media: media_data } +#[command] +fn list(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult { + if !channel_contains_author(ctx, msg) { + println!( + "user {} is not in the same voice channel as the bot", + msg.author.name + ); + return Ok(()); } -} -impl serenity::framework::standard::Command for List { - #[allow(unreachable_code, unused_mut)] - fn execute( - &self, - ctx: &mut serenity::client::Context, - msg: &serenity::model::channel::Message, - _: serenity::framework::standard::Args, - ) -> ::std::result::Result<(), serenity::framework::standard::CommandError> { - if !channel_contains_author(ctx, msg) { - println!( - "user {} is not in the same voice channel as the bot", - msg.author.name - ); + let mut output = String::new(); + + let data = ctx.data.read(); + let media = match data.get::() { + Ok(media) => media, + Err(_) => { + msg.channel_id.say("could not find media data"); return Ok(()); } + }; - let mut output = String::new(); + let playlist = media.playlist(); - { - let playlist_mutex = self.media.playlist_mut()?; - let playlist = playlist_mutex.borrow(); + output += &format!( + "{} {} queued\n", + playlist.len(), + if playlist.len() == 1 { "song" } else { "songs" } + ); - output += &format!( - "{} {} queued\n", - playlist.len(), - if playlist.len() == 1 { "song" } else { "songs" } - ); + let max_output = 5; - let max_output = 5; - - for (i, song) in playlist.iter().enumerate() { - if i < max_output { - output += &format!("\t{}.\t{}\n", i + 1, song.name.clone()); - } else { - output += &format!("\t... and {} more", playlist.len() - max_output); - break; - } - } + for (i, song) in playlist.iter().enumerate() { + if i < max_output { + output += &format!("\t{}.\t{}\n", i + 1, song.name.clone()); + } else { + output += &format!("\t... and {} more", playlist.len() - max_output); + break; } - - print_error!(msg.channel_id.say(output)); - - Ok(()) } + + print_error!(msg.channel_id.say(output)); + + Ok(()) } diff --git a/src/player/commands/mod.rs b/src/player/commands/mod.rs index a17cffc..bd90598 100644 --- a/src/player/commands/mod.rs +++ b/src/player/commands/mod.rs @@ -1,4 +1,3 @@ -pub mod help; pub mod ip; pub mod list; pub mod pause; diff --git a/src/player/commands/pause.rs b/src/player/commands/pause.rs index e772148..c6db390 100644 --- a/src/player/commands/pause.rs +++ b/src/player/commands/pause.rs @@ -1,45 +1,33 @@ use serenity; -use std::ops::DerefMut; -use std::sync::Arc; - use super::super::prelude::*; -pub struct Pause { - media: Arc, -} +use serenity::prelude::*; +use serenity::{ + framework::standard::{macros::command, Args, CommandResult}, + model::channel::Message, +}; -impl Pause { - pub fn new(media_data: Arc) -> Pause { - Pause { media: media_data } +#[command] +fn pause(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult { + if !channel_contains_author(ctx, msg) { + println!( + "user {} is not in the same voice channel as the bot", + msg.author.name + ); + return Ok(()); } -} -impl serenity::framework::standard::Command for Pause { - #[allow(unreachable_code, unused_mut)] - fn execute( - &self, - ctx: &mut serenity::client::Context, - msg: &serenity::model::channel::Message, - _: serenity::framework::standard::Args, - ) -> ::std::result::Result<(), serenity::framework::standard::CommandError> { - if !channel_contains_author(ctx, msg) { - println!( - "user {} is not in the same voice channel as the bot", - msg.author.name - ); + let data = ctx.data.read(); + let media = match data.get::() { + Ok(media) => media, + Err(_) => { + msg.channel_id.say("could not find media data"); return Ok(()); } + }; - let song_lock = self.media.song_mut()?; + media.song().pause(); - if let Some(song) = song_lock.borrow_mut().deref_mut() { - let song_clone = song.clone(); - let mut audio_lock = song_clone.lock(); - - audio_lock.pause(); - } - - Ok(()) - } + Ok(()) } diff --git a/src/player/commands/play.rs b/src/player/commands/play.rs index d983751..1cd7bf5 100644 --- a/src/player/commands/play.rs +++ b/src/player/commands/play.rs @@ -1,8 +1,5 @@ use parking_lot; -use serenity; -use serenity::voice::LockedAudio; - use std::cell::RefCell; use std::ops::{Deref, DerefMut}; use std::sync::{Arc, MutexGuard}; @@ -13,301 +10,300 @@ use super::super::prelude::*; use rusqlite::params; -pub struct Play { - media: Arc, +use serenity::prelude::*; +use serenity::voice::LockedAudio; +use serenity::{ + framework::standard::{macros::command, Args, CommandResult}, + model::channel::Message, +}; + +#[command] +fn play(ctx: &mut Context, msg: &Message, args: Args) -> CommandResult { + if !channel_contains_author(ctx, msg) { + println!( + "user {} is not in the same voice channel as the bot", + msg.author.name + ); + return Ok(()); + } + + let data = ctx.data.read(); + let mut media = match data.get_mut::() { + Ok(media) => media, + Err(_) => { + msg.channel_id.say("could not find media data"); + return Ok(()); + } + }; + + if args.len() == 0 { + if !Self::check_for_continue(self.media.song_mut()?) { + print_error!(msg.channel_id.say("Must provide a URL to a video or audio")); + } + } else if args.len() == 1 { + let arg = match args.single::() { + Ok(arg) => arg, + // can't happen, since we tested for length == 1 + Err(_) => return Ok(()), + }; + + if arg == "--local" { + self.handle_local_request(ctx, msg)?; + } else if arg.starts_with("http") { + self.handle_http_request(ctx, msg, &arg)?; + } else { + self.handle_song_request(ctx, msg, &arg)?; + } + } else { + print_error!(msg.channel_id.say("Unsupported argument list")); + } + + Ok(()) } -impl Play { - pub fn new(media_data: Arc) -> Play { - Play { media: media_data } +fn check_for_continue(song_lock: MutexGuard>>) -> bool { + match song_lock.borrow_mut().deref_mut() { + Some(song) => { + let song_clone = song.clone(); + let mut audio_lock = song_clone.lock(); + + audio_lock.play(); + true + } + None => false, + } +} + +fn check_join_channel( + manager_lock: &Arc>, + msg: &serenity::model::channel::Message, +) { + let guild = match msg.guild() { + Some(guild) => guild, + None => { + display_error!(msg.channel_id.say("Groups and DMs not supported")); + + return; + } + }; + + let guild_id = guild.read().id; + + let channel_id = guild + .read() + .voice_states + .get(&msg.author.id) + .and_then(|voice_state| voice_state.channel_id); + + let connect_to = match channel_id { + Some(channel) => channel, + None => { + display_error!(msg.reply("Not in a voice channel")); + + return; + } + }; + + let mut manager = manager_lock.lock(); + + manager.join(guild_id, connect_to); +} + +fn append_songs( + media: &mut MediaData, + ctx: &mut serenity::client::Context, + msg: &serenity::model::channel::Message, + mut source: Vec, +) -> Result<(), String> { + { + let playlist_mutex = self.media.playlist_mut()?; + playlist_mutex.borrow_mut().append(&mut source); } - fn check_for_continue(song_lock: MutexGuard>>) -> bool { - match song_lock.borrow_mut().deref_mut() { - Some(song) => { - let song_clone = song.clone(); - let mut audio_lock = song_clone.lock(); + if let Some(manager_lock) = ctx.data.lock().get::().cloned() { + Self::check_join_channel(&manager_lock, msg); - audio_lock.play(); - true - } - None => false, - } + let check_finished = { + let media_clone = self.media.clone(); + let channel_id = msg.channel_id; + let manager_lock_clone = manager_lock.clone(); + + Arc::new(move || { + let callback = match media_clone.next_callback.borrow().deref() { + Some(callback) => callback.clone(), + None => { + println!("next_callback not set!"); + return; + } + }; + + MediaData::next_song(&media_clone, channel_id, &manager_lock_clone, callback); + }) + }; + + MediaData::start_playing(&self.media, check_finished, msg.channel_id, &manager_lock); } - fn check_join_channel( - manager_lock: &Arc>, - msg: &serenity::model::channel::Message, - ) { - let guild = match msg.guild() { - Some(guild) => guild, - None => { - display_error!(msg.channel_id.say("Groups and DMs not supported")); + Ok(()) +} - return; - } +fn handle_http_request( + media: &mut MediaData, + ctx: &mut serenity::client::Context, + msg: &serenity::model::channel::Message, + url: &String, +) -> Result<(), String> { + let sql = self.media.lock_db()?; + + let mut stmt = match sql.prepare("SELECT name FROM Vulva3 WHERE link = ?") { + Ok(statement) => statement, + Err(_) => return Err("failed preparing data base access".to_string()), + }; + + let rows = match stmt.query_map(&[url], |row| row.get(0) as rusqlite::Result) { + Ok(rows) => rows, + Err(_) => return Err("failed querying rows".to_string()), + }; + + let mut names = Vec::new(); + for name_result in rows { + let name = match name_result { + Ok(name) => name, + Err(_) => return Err("failed getting name from row".to_string()), }; - let guild_id = guild.read().id; - - let channel_id = guild - .read() - .voice_states - .get(&msg.author.id) - .and_then(|voice_state| voice_state.channel_id); - - let connect_to = match channel_id { - Some(channel) => channel, - None => { - display_error!(msg.reply("Not in a voice channel")); - - return; - } - }; - - let mut manager = manager_lock.lock(); - - manager.join(guild_id, connect_to); + names.push(name); } - fn append_songs( - &self, - ctx: &mut serenity::client::Context, - msg: &serenity::model::channel::Message, - mut source: Vec, - ) -> Result<(), String> { - { - let playlist_mutex = self.media.playlist_mut()?; - playlist_mutex.borrow_mut().append(&mut source); - } + if names.len() > 0 { + print_error!(msg.channel_id.say("song already loaded!")); - if let Some(manager_lock) = ctx.data.lock().get::().cloned() { - Self::check_join_channel(&manager_lock, msg); + self.append_songs( + ctx, + msg, + names.iter().map(|n| Song { name: n.clone() }).collect(), + )?; - let check_finished = { - let media_clone = self.media.clone(); - let channel_id = msg.channel_id; - let manager_lock_clone = manager_lock.clone(); - - Arc::new(move || { - let callback = match media_clone.next_callback.borrow().deref() { - Some(callback) => callback.clone(), - None => { - println!("next_callback not set!"); - return; - } - }; - - MediaData::next_song(&media_clone, channel_id, &manager_lock_clone, callback); - }) - }; - - MediaData::start_playing(&self.media, check_finished, msg.channel_id, &manager_lock); - } - - Ok(()) + return Ok(()); } - fn handle_http_request( - &self, - ctx: &mut serenity::client::Context, - msg: &serenity::model::channel::Message, - url: &String, - ) -> Result<(), String> { - let sql = self.media.lock_db()?; + let source = match youtube_dl(&url) { + Ok(source) => source, + Err(why) => { + println!("Err starting source: {:?}", why); - let mut stmt = match sql.prepare("SELECT name FROM Vulva3 WHERE link = ?") { - Ok(statement) => statement, - Err(_) => return Err("failed preparing data base access".to_string()), - }; - - let rows = match stmt.query_map(&[url], |row| row.get(0) as rusqlite::Result) { - Ok(rows) => rows, - Err(_) => return Err("failed querying rows".to_string()), - }; - - let mut names = Vec::new(); - for name_result in rows { - let name = match name_result { - Ok(name) => name, - Err(_) => return Err("failed getting name from row".to_string()), - }; - - names.push(name); - } - - if names.len() > 0 { - print_error!(msg.channel_id.say("song already loaded!")); - - self.append_songs( - ctx, - msg, - names.iter().map(|n| Song { name: n.clone() }).collect(), - )?; + print_error!(msg + .channel_id + .say(format!("Error using youtube-dl: {}", why))); return Ok(()); } + }; - let source = match youtube_dl(&url) { - Ok(source) => source, - Err(why) => { - println!("Err starting source: {:?}", why); + let mut info = if source.len() == 1 { + "Finished downloading song:".to_string() + } else { + "Finished downloading songs:".to_string() + }; - print_error!(msg - .channel_id - .say(format!("Error using youtube-dl: {}", why))); + for song in &source { + info = format!("{}\n\t{}", info, song.name); - return Ok(()); - } - }; - - let mut info = if source.len() == 1 { - "Finished downloading song:".to_string() - } else { - "Finished downloading songs:".to_string() - }; - - for song in &source { - info = format!("{}\n\t{}", info, song.name); - - if sql - .execute( - "INSERT INTO Vulva3 (name, link) + if sql + .execute( + "INSERT INTO Vulva3 (name, link) VALUES (?1, ?2)", - params![song.name, url], - ) - .is_err() - { - return Err("failed inserting songs into db".to_string()); - } + params![song.name, url], + ) + .is_err() + { + return Err("failed inserting songs into db".to_string()); } - - print_error!(msg.channel_id.say(info)); - - self.append_songs(ctx, msg, source)?; - - Ok(()) } - fn handle_local_request( - &self, - ctx: &mut serenity::client::Context, - msg: &serenity::model::channel::Message, - ) -> Result<(), String> { - let sql = self.media.lock_db()?; + print_error!(msg.channel_id.say(info)); - let mut stmt = match sql.prepare("SELECT name FROM Vulva3") { - Ok(statement) => statement, - Err(_) => return Err("failed preparing data base access".to_string()), + self.append_songs(ctx, msg, source)?; + + Ok(()) +} + +fn handle_local_request( + media: &mut MediaData, + ctx: &mut serenity::client::Context, + msg: &serenity::model::channel::Message, +) -> Result<(), String> { + let sql = self.media.lock_db()?; + + let mut stmt = match sql.prepare("SELECT name FROM Vulva3") { + Ok(statement) => statement, + Err(_) => return Err("failed preparing data base access".to_string()), + }; + + let rows = match stmt.query_map(params![], |row| row.get(0) as rusqlite::Result) { + Ok(rows) => rows, + Err(_) => return Err("failed querying rows".to_string()), + }; + + let mut songs = Vec::new(); + for name_result in rows { + let name = match name_result { + Ok(name) => name, + Err(_) => return Err("failed getting name from row".to_string()), }; - let rows = match stmt.query_map(params![], |row| row.get(0) as rusqlite::Result) { - Ok(rows) => rows, - Err(_) => return Err("failed querying rows".to_string()), + songs.push(Song { name }); + } + + let mut rng = thread_rng(); + songs.shuffle(&mut rng); + + self.append_songs(ctx, msg, songs)?; + + Ok(()) +} + +fn handle_song_request( + media: &mut MediaData, + ctx: &mut serenity::client::Context, + msg: &serenity::model::channel::Message, + pattern: &str, +) -> Result<(), String> { + let sql = self.media.lock_db()?; + + let mut stmt = match sql.prepare(&format!( + "SELECT name FROM Vulva3 WHERE name LIKE '%{}%'", + pattern + )) { + Ok(statement) => statement, + Err(_) => return Err("failed preparing data base access".to_string()), + }; + + let rows = match stmt.query_map(params![], |row| row.get(0) as rusqlite::Result) { + Ok(rows) => rows, + Err(_) => return Err("failed querying rows".to_string()), + }; + + let mut songs = Vec::new(); + for name_result in rows { + let name = match name_result { + Ok(name) => name, + Err(_) => return Err("failed getting name from row".to_string()), }; - let mut songs = Vec::new(); - for name_result in rows { - let name = match name_result { - Ok(name) => name, - Err(_) => return Err("failed getting name from row".to_string()), - }; - - songs.push(Song { name }); - } + songs.push(Song { name }); + } + if !songs.is_empty() { let mut rng = thread_rng(); songs.shuffle(&mut rng); self.append_songs(ctx, msg, songs)?; - - Ok(()) + } else { + print_error!(msg + .channel_id + .say(format!("no song found with pattern {}", pattern))); } - fn handle_song_request( - &self, - ctx: &mut serenity::client::Context, - msg: &serenity::model::channel::Message, - pattern: &str, - ) -> Result<(), String> { - let sql = self.media.lock_db()?; - - let mut stmt = match sql.prepare(&format!( - "SELECT name FROM Vulva3 WHERE name LIKE '%{}%'", - pattern - )) { - Ok(statement) => statement, - Err(_) => return Err("failed preparing data base access".to_string()), - }; - - let rows = match stmt.query_map(params![], |row| row.get(0) as rusqlite::Result) { - Ok(rows) => rows, - Err(_) => return Err("failed querying rows".to_string()), - }; - - let mut songs = Vec::new(); - for name_result in rows { - let name = match name_result { - Ok(name) => name, - Err(_) => return Err("failed getting name from row".to_string()), - }; - - songs.push(Song { name }); - } - - if !songs.is_empty() { - let mut rng = thread_rng(); - songs.shuffle(&mut rng); - - self.append_songs(ctx, msg, songs)?; - } else { - print_error!(msg - .channel_id - .say(format!("no song found with pattern {}", pattern))); - } - - Ok(()) - } -} - -impl serenity::framework::standard::Command for Play { - #[allow(unreachable_code, unused_mut)] - fn execute( - &self, - mut ctx: &mut serenity::client::Context, - msg: &serenity::model::channel::Message, - mut args: serenity::framework::standard::Args, - ) -> ::std::result::Result<(), serenity::framework::standard::CommandError> { - if !channel_contains_author(ctx, msg) { - println!( - "user {} is not in the same voice channel as the bot", - msg.author.name - ); - return Ok(()); - } - - if args.len() == 0 { - if !Self::check_for_continue(self.media.song_mut()?) { - print_error!(msg.channel_id.say("Must provide a URL to a video or audio")); - } - } else if args.len() == 1 { - let arg = match args.single::() { - Ok(arg) => arg, - // can't happen, since we tested for length == 1 - Err(_) => return Ok(()), - }; - - if arg == "--local" { - self.handle_local_request(ctx, msg)?; - } else if arg.starts_with("http") { - self.handle_http_request(ctx, msg, &arg)?; - } else { - self.handle_song_request(ctx, msg, &arg)?; - } - } else { - print_error!(msg.channel_id.say("Unsupported argument list")); - } - - Ok(()) - } + Ok(()) } diff --git a/src/player/commands/remove.rs b/src/player/commands/remove.rs index 5a7b88d..44e096c 100644 --- a/src/player/commands/remove.rs +++ b/src/player/commands/remove.rs @@ -1,56 +1,50 @@ use serenity; use std::fs; -use std::sync::Arc; use super::super::prelude::*; use rusqlite::params; -pub struct Remove { - media: Arc, -} +use serenity::prelude::*; +use serenity::{ + framework::standard::{macros::command, Args, CommandResult}, + model::channel::Message, +}; -impl Remove { - pub fn new(media_data: Arc) -> Remove { - Remove { media: media_data } - } -} - -impl serenity::framework::standard::Command for Remove { - #[allow(unreachable_code, unused_mut)] - fn execute( - &self, - mut _ctx: &mut serenity::client::Context, - msg: &serenity::model::channel::Message, - mut _args: serenity::framework::standard::Args, - ) -> ::std::result::Result<(), serenity::framework::standard::CommandError> { - // (1) - - let song_name = self.media.name_mut()?; - let name: String = song_name.borrow().clone(); - - let sql = self.media.lock_db()?; - - if let Err(_) = sql.execute("DELETE FROM Vulva3 WHERE name = ?", params![name]) { - return Err(serenity::framework::standard::CommandError( - "failed executing sql delete".to_string(), - )); +#[command] +fn remove(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult { + let data = ctx.data.read(); + let media = match data.get::() { + Ok(media) => media, + Err(_) => { + msg.channel_id.say("could not find media data"); + return Ok(()); } + }; - if !name.is_empty() { - match fs::remove_file(&name) { - Ok(_) => print_error!(msg - .channel_id - .say(format!("Remove current song ({}) from local disk", name))), - Err(err) => print_error!(msg.channel_id.say(format!( - "Error removing file ({}): {:?}", - name, - err.kind() - ))), - }; - } + let song_name = media.song_name(); + let sql = media.db(); - Ok(()) + if let Err(_) = sql.execute("DELETE FROM Vulva3 WHERE name = ?", params![song_name]) { + return Err(serenity::framework::standard::CommandError( + "failed executing sql delete".to_string(), + )); } + + if !song_name.is_empty() { + match fs::remove_file(&song_name) { + Ok(_) => print_error!(msg.channel_id.say(format!( + "Remove current song ({}) from local disk", + song_name + ))), + Err(err) => print_error!(msg.channel_id.say(format!( + "Error removing file ({}): {:?}", + song_name, + err.kind() + ))), + }; + } + + Ok(()) } diff --git a/src/player/commands/skip.rs b/src/player/commands/skip.rs index efabe8f..bb68b95 100644 --- a/src/player/commands/skip.rs +++ b/src/player/commands/skip.rs @@ -1,94 +1,99 @@ use serenity; use serenity::voice::ffmpeg; -use std::sync::Arc; - use super::super::prelude::*; -pub struct Skip { - media: Arc, -} +use serenity::prelude::*; +use serenity::{ + framework::standard::{macros::command, Args, CommandResult}, + model::channel::Message, +}; -impl Skip { - pub fn new(media_data: Arc) -> Skip { - Skip { media: media_data } +#[command] +fn skip(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult { + if !channel_contains_author(ctx, msg) { + println!( + "user {} is not in the same voice channel as the bot", + msg.author.name + ); + return Ok(()); } -} -impl serenity::framework::standard::Command for Skip { - #[allow(unreachable_code, unused_mut)] - fn execute( - &self, - ctx: &mut serenity::client::Context, - msg: &serenity::model::channel::Message, - _: serenity::framework::standard::Args, - ) -> ::std::result::Result<(), serenity::framework::standard::CommandError> { - if !channel_contains_author(ctx, msg) { - println!( - "user {} is not in the same voice channel as the bot", - msg.author.name - ); - return Ok(()); - } + if let Some(mut manager_lock) = ctx.data.lock().get::().cloned() { + let mut manager = manager_lock.lock(); - if let Some(mut manager_lock) = ctx.data.lock().get::().cloned() { - let mut manager = manager_lock.lock(); + let guild_id = match guild_id(msg.channel_id) { + Some(id) => id, + None => { + println!("error getting guild id"); + print_error!(msg.channel_id.say("error getting guild id")); - let guild_id = match guild_id(msg.channel_id) { - Some(id) => id, - None => { - println!("error getting guild id"); - print_error!(msg.channel_id.say("error getting guild id")); + return Ok(()); + } + }; + if let Some(handler) = handler(guild_id, &mut manager) { + let data = ctx.data.read(); + let mut media = match data.get_mut::() { + Ok(media) => media, + Err(_) => { + msg.channel_id.say("could not find media data"); return Ok(()); } }; - if let Some(handler) = handler(guild_id, &mut manager) { - let playlist_mutex = self.media.playlist_mut()?; - let mut playlist = playlist_mutex.borrow_mut(); + let mut playlist = media.playlist_mut(); + let mut song = media.song_mut(); - let song_mutex = self.media.song_mut()?; - let mut song = song_mutex.borrow_mut(); + // if current song is the last song in this playlist, just return + if playlist.is_empty() { + print_error!(msg + .channel_id + .say("playlist is empty, no next song available")); - if playlist.is_empty() { - print_error!(msg - .channel_id - .say("playlist is empty, no next song available")); + return Ok(()); + } else { + // remove the current song from the playlist + let first = playlist.remove(0); - return Ok(()); - } else { - let first = playlist.remove(0); + // stop the current song from playing + handler.stop(); - handler.stop(); + // load next song into memory + let source = match ffmpeg(first.name.clone()) { + Ok(mpeg) => mpeg, + Err(_) => { + playlist.clear(); + *song = None; - let source = match ffmpeg(first.name.clone()) { - Ok(mpeg) => mpeg, - Err(_) => { - playlist.clear(); - *song = None; - - return Ok(()); - } - }; - - match self.media.next_callback.borrow().as_ref() { - Some(callback) => { - *song = - Some(handler.play_returning_and_callback(source, callback.clone())); - let song_name = self.media.name_mut()?; - *song_name.borrow_mut() = first.name.clone(); - - print_error!(msg - .channel_id - .say(format!("Skipped current song, now playing: {}", first.name))); - } - None => println!("error getting callback from media"), + return Ok(()); } + }; + + // start the next song if possible + /* + match self.media.next_callback.borrow().as_ref() { + Some(callback) => { + *song = Some(handler.play_returning_and_callback(source, callback.clone())); + let song_name = self.media.name_mut()?; + *song_name.borrow_mut() = first.name.clone(); + + print_error!(msg + .channel_id + .say(format!("Skipped current song, now playing: {}", first.name))); + } + None => println!("error getting callback from media"), } + */ + *song = Some(handler.play_returning(source)); + *media.song_name_mut() = first.name.clone(); + + print_error!(msg + .channel_id + .say(format!("Skipped current song, now playing: {}", first.name))); } } - - Ok(()) } + + Ok(()) } diff --git a/src/player/commands/stop.rs b/src/player/commands/stop.rs index fedee64..2e79312 100644 --- a/src/player/commands/stop.rs +++ b/src/player/commands/stop.rs @@ -1,37 +1,31 @@ -use serenity; - -use std::sync::Arc; - use super::super::prelude::*; -pub struct Stop { - media: Arc, -} +use serenity::prelude::*; +use serenity::{ + framework::standard::{macros::command, Args, CommandResult}, + model::channel::Message, +}; -impl Stop { - pub fn new(media_data: Arc) -> Stop { - Stop { media: media_data } +#[command] +fn stop(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult { + if !channel_contains_author(ctx, msg) { + println!( + "user {} is not in the same voice channel as the bot", + msg.author.name + ); + return Ok(()); } -} -impl serenity::framework::standard::Command for Stop { - #[allow(unreachable_code, unused_mut)] - fn execute( - &self, - ctx: &mut serenity::client::Context, - msg: &serenity::model::channel::Message, - _: serenity::framework::standard::Args, - ) -> ::std::result::Result<(), serenity::framework::standard::CommandError> { - if !channel_contains_author(ctx, msg) { - println!( - "user {} is not in the same voice channel as the bot", - msg.author.name - ); + let data = ctx.data.read(); + let mut media = match data.get_mut::() { + Ok(media) => media, + Err(_) => { + msg.channel_id.say("could not find media data"); return Ok(()); } + }; - print_error!(self.media.reset(ctx, msg)); + print_error!(data.reset(ctx, msg)); - Ok(()) - } + Ok(()) } diff --git a/src/player/mediadata.rs b/src/player/mediadata.rs index b4bac0b..1e75574 100644 --- a/src/player/mediadata.rs +++ b/src/player/mediadata.rs @@ -3,8 +3,7 @@ use serenity::model::id::ChannelId; use serenity::voice::ffmpeg; use serenity::voice::LockedAudio; -use std::cell::RefCell; -use std::sync::{Arc, Mutex, MutexGuard}; +use std::sync::Arc; use super::prelude::*; @@ -15,12 +14,12 @@ pub struct Song { } pub struct MediaData { - playlist: Mutex>>, - current_song: Mutex>>, - song_name: Mutex>, - pub next_callback: RefCell ()>>>, + playlist: Vec, + current_song: Option, + song_name: String, + pub next_callback: Option ()>>, - sql_data_base: Mutex, + sql_data_base: Connection, } impl MediaData { @@ -32,9 +31,9 @@ impl MediaData { match connection.execute( "CREATE TABLE IF NOT EXISTS Vulva3 ( - name TEXT PRIMARY KEY, - link TEXT NOT NULL - )", + name TEXT PRIMARY KEY, + link TEXT NOT NULL + )", params![], ) { Ok(_) => (), @@ -45,38 +44,24 @@ impl MediaData { }; Ok(MediaData { - playlist: Mutex::new(RefCell::new(Vec::new())), - current_song: Mutex::new(RefCell::new(None)), - song_name: Mutex::new(RefCell::new(String::new())), - next_callback: RefCell::new(None), + playlist: Vec::new(), + current_song: None, + song_name: String::new(), + next_callback: None, - sql_data_base: Mutex::new(connection), + sql_data_base: connection, }) } pub fn reset( - &self, + &mut self, ctx: &mut serenity::client::Context, msg: &serenity::model::channel::Message, ) -> Result<(), String> { - { - let playlist = self.playlist_mut()?; - playlist.borrow_mut().clear(); - } - - { - let song = self.song_mut()?; - *song.borrow_mut() = None; - } - - { - let name = self.name_mut()?; - *name.borrow_mut() = String::new(); - } - - { - *self.next_callback.borrow_mut() = None; - } + self.playlist().clear(); + self.song = None; + self.name = String::new(); + self.next_callback = None(); if let Some(manager_lock) = ctx.data.lock().get::().cloned() { let mut manager = manager_lock.lock(); @@ -103,32 +88,32 @@ impl MediaData { Ok(()) } - pub fn lock_db(&self) -> Result, String> { - match self.sql_data_base.lock() { - Ok(sql) => Ok(sql), - Err(_) => Err("failed locking db".to_string()), - } + pub fn db(&self) -> &Connection { + &self.sql_data_base } - pub fn song_mut(&self) -> Result>>, String> { - match self.current_song.lock() { - Ok(sql) => Ok(sql), - Err(_) => Err("failed locking current song".to_string()), - } + pub fn song(&self) -> &Option { + &self.current_song } - pub fn playlist_mut(&self) -> Result>>, String> { - match self.playlist.lock() { - Ok(sql) => Ok(sql), - Err(_) => Err("failed locking playlist".to_string()), - } + pub fn song_mut(&mut self) -> &mut Option { + &mut self.current_song } - pub fn name_mut(&self) -> Result>, String> { - match self.song_name.lock() { - Ok(sql) => Ok(sql), - Err(_) => Err("failed locking current song name".to_string()), - } + pub fn playlist(&self) -> &Vec { + &self.playlist + } + + pub fn playlist_mut(&mut self) -> &mut Vec { + &mut self.playlist + } + + pub fn song_name(&self) -> &String { + &self.name + } + + pub fn song_name_mut(&mut self) -> &mut String { + &mut self.name } pub fn start_playing( diff --git a/src/player/player.rs b/src/player/player.rs index 00fc2e7..974c981 100644 --- a/src/player/player.rs +++ b/src/player/player.rs @@ -1,13 +1,12 @@ -use parking_lot; - +use parking_lot::MutexGuard; use serenity; -use serenity::client::CACHE; use serenity::model::id::{ChannelId, GuildId}; use serenity::voice::Handler; use super::prelude::*; pub fn guild_id(channel_id: ChannelId) -> Option { + /* match CACHE.read().guild_channel(channel_id) { Some(channel) => Some(channel.read().guild_id), None => { @@ -15,14 +14,13 @@ pub fn guild_id(channel_id: ChannelId) -> Option { None } } + */ + None } pub fn handler<'a>( guild_id: GuildId, - manager: &'a mut parking_lot::MutexGuard< - '_, - serenity::client::bridge::voice::ClientVoiceManager, - >, + manager: &'a mut MutexGuard<'_, serenity::client::bridge::voice::ClientVoiceManager>, ) -> Option<&'a mut Handler> { manager.get_mut(guild_id) } @@ -32,7 +30,7 @@ pub fn channel_contains_author( msg: &serenity::model::channel::Message, ) -> bool { let (guild_id, voice_channel_id_bot) = { - match ctx.data.lock().get::().cloned() { + match ctx.data.read().get::().cloned() { Some(manager_lock) => { let mut manager = manager_lock.lock(); let guild_id = match guild_id(msg.channel_id) { @@ -68,7 +66,7 @@ pub fn channel_contains_author( let author = &msg.author; - let guild = match guild_id.to_guild_cached() { + let guild = match guild_id.to_guild_cached(&ctx) { Some(guild) => guild, None => { println!("error getting guild from cache"); diff --git a/src/player/prelude.rs b/src/player/prelude.rs index 3d638e9..cca35ae 100644 --- a/src/player/prelude.rs +++ b/src/player/prelude.rs @@ -1,13 +1,12 @@ pub use super::mediadata::{MediaData, Song}; -pub use super::commands::help::Help; -pub use super::commands::ip::IP; -pub use super::commands::list::List; -pub use super::commands::pause::Pause; -pub use super::commands::play::Play; -pub use super::commands::remove::Remove; -pub use super::commands::skip::Skip; -pub use super::commands::stop::Stop; +pub use super::commands::ip::*; +pub use super::commands::list::*; +pub use super::commands::pause::*; +pub use super::commands::play::*; +pub use super::commands::remove::*; +pub use super::commands::skip::*; +pub use super::commands::stop::*; pub use super::eventhandler::Handler; pub use super::voicemanager::VoiceManager; diff --git a/src/player/voicemanager.rs b/src/player/voicemanager.rs index efaf758..180bcd7 100644 --- a/src/player/voicemanager.rs +++ b/src/player/voicemanager.rs @@ -1,5 +1,5 @@ +use parking_lot::Mutex; use serenity::client::bridge::voice::ClientVoiceManager; -use serenity::prelude::Mutex; use std::sync::Arc; use typemap::Key;