use parking_lot; use serenity; use serenity::voice::LockedAudio; use std::cell::RefCell; use std::fs; use std::ops::DerefMut; use std::sync::{Arc, MutexGuard}; use rand::{seq::SliceRandom, thread_rng}; use super::super::prelude::*; pub struct Play { media: Arc, } 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( &self, ctx: &mut serenity::client::Context, msg: &serenity::model::channel::Message, mut source: Vec, ) { { let playlist_mutex = self.media.playlist_mut(); playlist_mutex.borrow_mut().append(&mut source); } let manager_lock = ctx.data.lock().get::().cloned().unwrap(); Self::check_join_channel(&manager_lock, msg); MediaData::start_thread(&self.media, msg.channel_id, &manager_lock); } fn handle_http_request( &self, ctx: &mut serenity::client::Context, msg: &serenity::model::channel::Message, url: &String, ) { let source = match youtube_dl(&url) { Ok(source) => source, Err(why) => { println!("Err starting source: {:?}", why); print_error!( msg.channel_id .say(format!("Error using youtube-dl: {}", why)) ); return; } }; 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); } print_error!(msg.channel_id.say(info)); self.append_songs(ctx, msg, source); } fn handle_local_request( &self, ctx: &mut serenity::client::Context, msg: &serenity::model::channel::Message, ) { print_error!(self.media.reset(ctx, msg)); let files = fs::read_dir("./").unwrap(); let mut songs = Vec::new(); for file in files { let os_name = file.unwrap().file_name(); let name = os_name.to_str().unwrap(); if name != "RMusicBot" && name != "bot.conf" && name != "start.sh" { songs.push(Song { name: name.to_string(), }); } } let mut rng = thread_rng(); songs.shuffle(&mut rng); self.append_songs(ctx, msg, songs); } } 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 { print_error!(msg.channel_id.say("Unsupported argument list")); } } else { print_error!(msg.channel_id.say("Unsupported argument list")); } Ok(()) } }