RMusicBot/src/player/commands/play.rs

194 lines
5.3 KiB
Rust

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<MediaData>,
}
impl Play {
pub fn new(media_data: Arc<MediaData>) -> Play {
Play { media: media_data }
}
fn check_for_continue(song_lock: MutexGuard<RefCell<Option<LockedAudio>>>) -> 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<parking_lot::Mutex<serenity::client::bridge::voice::ClientVoiceManager>>,
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<Song>,
) {
{
let playlist_mutex = self.media.playlist_mut();
playlist_mutex.borrow_mut().append(&mut source);
}
let manager_lock = ctx.data.lock().get::<VoiceManager>().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::<String>() {
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(())
}
}