use serenity; use serenity::model::channel::Message; 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, Mutex as StdMutex}; 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, sql_data_base: Connection, pub voice_manager: Arc>, } impl MediaData { pub fn new( file: &str, voice_manager: Arc>, volume: f32, ) -> Result { let connection = match Connection::open(file) { Ok(file) => file, Err(_) => return Err(format!("can't open {}", file)), }; match connection.execute( "CREATE TABLE IF NOT EXISTS Vulva3 ( name TEXT PRIMARY KEY, link TEXT NOT NULL )", params![], ) { Ok(_) => (), Err(err) => { println!("{}", err); return Err(format!("can't create table")); } }; Ok(MediaData { volume, playlist: Vec::new(), current_song: None, song_name: String::new(), sql_data_base: connection, voice_manager, }) } pub fn reset( &mut self, ctx: &serenity::client::Context, msg: &serenity::model::channel::Message, ) -> Result<(), String> { self.playlist.clear(); self.current_song = None; self.song_name = String::new(); let mut manager = self.voice_manager.lock(); let guild_id = guild_id(ctx, msg)?; let handler = match handler(guild_id, &mut manager) { Some(handler) => handler, None => return Ok(()), }; println!("stopped handler"); handler.stop(); manager.remove(guild_id); Ok(()) } pub fn db(&self) -> &Connection { &self.sql_data_base } pub fn song(&self) -> &Option { &self.current_song } pub fn song_mut(&mut self) -> &mut Option { &mut self.current_song } 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.song_name } pub fn song_name_mut(&mut self) -> &mut String { &mut self.song_name } pub fn start_playing( ctx: &Context, mediadata: &mut MediaData, msg: &Message, ) -> VerboseResult<()> { // check if there is already playing let already_started = mediadata.song().is_some(); // 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"); } } }; println!("got handler"); let source = match ffmpeg(first.clone()) { Ok(mpeg) => mpeg, Err(_) => create_error!(format!("failed loading: {}", &first)), }; handler.stop(); let song = handler.play_returning(source); { 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(()) } } unsafe impl Send for MediaData {} unsafe impl Sync for MediaData {} pub struct Media; impl TypeMapKey for Media { type Value = Arc>; }