diff --git a/Cargo.toml b/Cargo.toml index b5cd5f1..bc23239 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,5 @@ rusqlite = { version = "*", features = ["bundled"] } serenity = { version = "0.7", default-features = false, features = [ "builder", "cache", "client", "framework", "gateway", "model", "standard_framework", "utils", "voice", "rustls_backend"]} parking_lot = "*" failure = "*" +hey_listen = "*" +white_rabbit = "*" diff --git a/bot.conf b/bot.conf index e8c4308..dcde971 100644 --- a/bot.conf +++ b/bot.conf @@ -1,3 +1,4 @@ [Meta] token = NDc4NTQ1NzY1MDc4MjY5OTU2.DlMQjQ.lqep6rd5w-uBOGst_cuEOQptt84 prefix = ! +volume = 0.1 \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 80f6b5a..1e4a4c1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -36,6 +36,7 @@ use utilities::prelude::*; struct Config { token: String, prefix: String, + volume: f32, } impl Default for Config { @@ -43,6 +44,7 @@ impl Default for Config { Self { token: String::new(), prefix: String::new(), + volume: 1.0, } } } @@ -53,6 +55,18 @@ group!({ commands: [ip, list, pause, play, remove, skip, stop] }); +#[help] +fn my_help( + context: &mut Context, + msg: &Message, + args: Args, + help_options: &'static HelpOptions, + groups: &[&'static CommandGroup], + owners: HashSet, +) -> CommandResult { + help_commands::with_embeds(context, msg, args, &help_options, groups, owners) +} + fn main() -> VerboseResult<()> { // read config file let config_file = ConfigHandler::read_config("bot.conf")?; @@ -77,6 +91,10 @@ fn main() -> VerboseResult<()> { create_error!("couldn't find prefix inside meta section"); } } + + if let Some(volume) = info.get("volume") { + volume.set_value(&mut config.volume)?; + } } None => { create_error!("couldn't find Meta section in config file"); @@ -91,7 +109,7 @@ fn main() -> VerboseResult<()> { { let mut data = client.data.write(); data.insert::( - MediaData::new("Penis1", Arc::clone(&client.voice_manager)) + MediaData::new("Penis1", Arc::clone(&client.voice_manager), config.volume) .expect("failed to create media data handle"), ); } @@ -121,40 +139,10 @@ fn main() -> VerboseResult<()> { .prefix(&config.prefix) .owners(owners) }) - .group(&GENERAL_GROUP), + .group(&GENERAL_GROUP) + .help(&MY_HELP), ); - /* - - client.with_framework( - StandardFramework::new() - .configure(|c| c.prefix(&config.prefix).on_mention(true)) - .cmd("play", Play::new(media_data.clone())) - .cmd("pause", Pause::new(media_data.clone())) - .cmd( - "help", - Help::new( - &config.prefix, - vec![ - "play".to_string(), - "pause".to_string(), - "stop".to_string(), - "help".to_string(), - "list".to_string(), - "skip".to_string(), - "remove".to_string(), - "ip".to_string(), - ], - ), - ) - .cmd("stop", Stop::new(media_data.clone())) - .cmd("list", List::new(media_data.clone())) - .cmd("skip", Skip::new(media_data.clone())) - .cmd("ip", IP::new()) - .cmd("remove", Remove::new(media_data.clone())), - ); - */ - let _ = client .start() .map_err(|why| println!("Client ended: {:?}", why)); diff --git a/src/player/commands/play.rs b/src/player/commands/play.rs index ca912da..c1d0133 100644 --- a/src/player/commands/play.rs +++ b/src/player/commands/play.rs @@ -42,13 +42,13 @@ fn play(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult { } else if first_arg.starts_with("http") { handle_http_request(media, ctx, msg, first_arg)?; } else { - let mut arg_list = String::new(); + let mut arg_list = args.single::()?; for arg in args.iter::() { arg_list += &format!(" {}", arg?.trim()); } - handle_song_request(media, ctx, msg, &arg_list)?; + handle_song_request(media, ctx, msg, &arg_list)? } } @@ -76,6 +76,7 @@ fn append_songs( ) -> VerboseResult<()> { media.playlist_mut().append(&mut source); + println!("start playing"); MediaData::start_playing(ctx, media, msg)?; Ok(()) @@ -216,6 +217,8 @@ fn handle_song_request( msg: &serenity::model::channel::Message, pattern: &str, ) -> VerboseResult<()> { + println!("song request ({})", pattern); + let mut songs = Vec::new(); { @@ -244,10 +247,14 @@ fn handle_song_request( } } + println!("{:?}", &songs); + if !songs.is_empty() { let mut rng = thread_rng(); songs.shuffle(&mut rng); + println!("append songs"); + append_songs(media, ctx, msg, songs)?; } else { msg.channel_id diff --git a/src/player/mediadata.rs b/src/player/mediadata.rs index d261304..19790c8 100644 --- a/src/player/mediadata.rs +++ b/src/player/mediadata.rs @@ -4,21 +4,26 @@ use serenity::prelude::*; use serenity::voice::ffmpeg; use serenity::voice::LockedAudio; +use parking_lot::lock_api::{MutexGuard, RawMutex}; use serenity::client::bridge::voice::ClientVoiceManager; use serenity::prelude::Mutex; use std::sync::Arc; use super::prelude::*; +use std::fs; + use rusqlite::{params, Connection}; use utilities::prelude::*; +#[derive(Debug)] pub struct Song { pub name: String, } pub struct MediaData { + volume: f32, playlist: Vec, current_song: Option, song_name: String, @@ -33,6 +38,7 @@ impl MediaData { pub fn new( file: &str, voice_manager: Arc>, + volume: f32, ) -> Result { let connection = match Connection::open(file) { Ok(file) => file, @@ -54,6 +60,7 @@ impl MediaData { }; Ok(MediaData { + volume, playlist: Vec::new(), current_song: None, song_name: String::new(), @@ -75,24 +82,19 @@ impl MediaData { self.song_name = String::new(); self.next_callback = None; - if let Some(media) = ctx.data.read().get::() { - let mut manager = media.voice_manager.lock(); + let mut manager = self.voice_manager.lock(); - let guild_id = guild_id(ctx, msg)?; + let guild_id = guild_id(ctx, msg)?; - { - let handler = match handler(guild_id, &mut manager) { - Some(handler) => handler, - None => return Ok(()), - }; + let handler = match handler(guild_id, &mut manager) { + Some(handler) => handler, + None => return Ok(()), + }; - println!("stopped handler"); + println!("stopped handler"); - handler.stop(); - } - - manager.remove(guild_id); - } + handler.stop(); + manager.remove(guild_id); Ok(()) } @@ -135,62 +137,152 @@ impl MediaData { // if there isnt already a song playing, start a new one if !already_started { + println!("next song"); Self::next_song(ctx, mediadata, msg)?; } Ok(()) } + fn check_for_next(&mut self, ctx: &Context, msg: &Message) -> VerboseResult { + println!("check for next"); + + while !self.playlist().is_empty() { + let first = self.playlist_mut().remove(0).name; + + println!("check: {} ({})", &first, self.playlist().len()); + + if fs::metadata(&first).is_err() { + msg.channel_id + .say( + &ctx.http, + format!( + "\"{}\" doesn't exist locally anymore and will be removed from data base", + &first + ), + ) + .map_err(|err| format!("{}", err))?; + + let sql = self.db(); + + if let Err(_) = sql.execute("DELETE FROM Vulva3 WHERE name = ?", params![&first]) { + create_error!("failed executing sql delete"); + } + } else { + return Ok(first); + } + } + + println!("no song found!"); + create_error!("no suitable song found!") + } + + fn check_for_channel( + manager: &mut MutexGuard, + ctx: &Context, + msg: &Message, + ) -> VerboseResult<()> { + println!("check for channel!"); + + let guild = guild(ctx, msg)?; + let guild_id = guild.read().id; + + println!("got guild id"); + + let author_channel_id = match guild + .read() + .voice_states + .get(&msg.author.id) + .and_then(|voice_state| voice_state.channel_id) + { + Some(channel) => channel, + None => create_error!("author is not in a voice channel!"), + }; + + println!("got author channel"); + + match manager.get(guild_id) { + Some(handler) => { + // check if the bot is in a channel + if let None = handler.channel_id { + println!("handler had no channel"); + manager.join(guild_id, author_channel_id); + } + } + None => { + println!("manager had no handler"); + manager.join(guild_id, author_channel_id); + } + } + + Ok(()) + } + pub fn next_song(ctx: &Context, mediadata: &mut MediaData, msg: &Message) -> VerboseResult<()> { + println!("start next song"); let voice_manager = mediadata.voice_manager.clone(); let mut manager = voice_manager.lock(); + println!("got manager lock"); + let guild_id = guild_id(ctx, msg)?; + println!("got guild id"); + let mut need_to_leave = false; - { + if mediadata.playlist().is_empty() { + need_to_leave = true; + *mediadata.song_mut() = None; + *mediadata.song_name_mut() = String::new(); + + if let Some(handler) = handler(guild_id, &mut manager) { + handler.stop(); + } + } else { + let first = mediadata.check_for_next(ctx, msg)?; + + Self::check_for_channel(&mut manager, ctx, msg)?; + let handler = { match handler(guild_id, &mut manager) { Some(handler) => handler, None => { + println!("failed getting handler"); create_error!("error getting handler"); } } }; - if mediadata.playlist().is_empty() { - need_to_leave = true; - handler.stop(); - *mediadata.song_mut() = None; - *mediadata.song_name_mut() = String::new(); - } else { - handler.stop(); + println!("got handler"); - let first = mediadata.playlist_mut().remove(0); + let source = match ffmpeg(first.clone()) { + Ok(mpeg) => mpeg, + Err(_) => create_error!(format!("failed loading: {}", &first)), + }; - let source = match ffmpeg(first.name.clone()) { - Ok(mpeg) => mpeg, - Err(_) => { - mediadata.playlist_mut().clear(); + handler.stop(); - return Ok(()); - } - }; + let song = handler.play_returning(source); - *mediadata.song_mut() = Some(handler.play_returning(source)); - *mediadata.song_name_mut() = first.name.clone(); - - msg.channel_id - .say(&ctx.http, format!("Playing song: {}", first.name)) - .map_err(|err| format!("{}", err))?; + { + let mut song_lock = song.lock(); + song_lock.volume(mediadata.volume); } + + *mediadata.song_mut() = Some(song); + *mediadata.song_name_mut() = first.clone(); + + msg.channel_id + .say(&ctx.http, format!("Playing song: {}", first)) + .map_err(|err| format!("{}", err))?; } if need_to_leave { manager.remove(guild_id); } + println!("successfully started next song"); Ok(()) } } diff --git a/src/player/player.rs b/src/player/player.rs index 3a2b4c7..f79172f 100644 --- a/src/player/player.rs +++ b/src/player/player.rs @@ -62,23 +62,16 @@ pub fn channel_contains_author( }; if let Some(media) = ctx.data.read().get::() { - let mut manager = media.voice_manager.lock(); + let manager = media.voice_manager.lock(); - match manager.get(guild_id) { - Some(handler) => match handler.channel_id { - Some(bot_channel_id) => { - if bot_channel_id != author_channel_id { - create_error!("author is not in the same voice channel as the bot!"); - } + if let Some(handler) = manager.get(guild_id) { + // check if the bot is in a channel + if let Some(bot_channel_id) = handler.channel_id { + if bot_channel_id != author_channel_id { + create_error!("author is not in the same voice channel as the bot!"); } - None => { - manager.join(guild_id, author_channel_id); - } - }, - None => { - manager.join(guild_id, author_channel_id); } - } + }; } Ok(())