RMusicBot/src/player/commands/play.rs

289 lines
8 KiB
Rust
Raw Normal View History

2018-11-14 14:29:58 +00:00
use parking_lot;
use serenity;
use serenity::voice::LockedAudio;
use std::cell::RefCell;
2018-11-14 15:43:53 +00:00
use std::fs;
2018-11-23 21:06:35 +00:00
use std::ops::{Deref, DerefMut};
2018-11-14 14:29:58 +00:00
use std::sync::{Arc, MutexGuard};
2018-11-14 15:43:53 +00:00
use rand::{seq::SliceRandom, thread_rng};
2018-11-14 14:29:58 +00:00
use super::super::prelude::*;
2019-04-03 09:42:06 +00:00
use rusqlite::params;
use rusqlite::types::{FromSql, ToSql};
2018-11-14 14:29:58 +00:00
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);
}
2018-11-14 15:43:53 +00:00
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);
2018-11-23 21:06:35 +00:00
let check_finished = {
let media_clone = self.media.clone();
let channel_id = msg.channel_id;
let manager_lock_clone = manager_lock.clone();
2018-11-24 11:52:42 +00:00
Arc::new(move || {
2018-11-23 21:06:35 +00:00
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);
//MediaData::start_thread(&self.media, msg.channel_id, &manager_lock);
2018-11-14 15:43:53 +00:00
}
2018-11-14 14:29:58 +00:00
fn handle_http_request(
&self,
ctx: &mut serenity::client::Context,
msg: &serenity::model::channel::Message,
url: &String,
) {
2019-04-03 09:42:06 +00:00
let sql = self.media.lock_db();
let mut stmt = sql
.prepare("SELECT name FROM Vulva3 WHERE link = ?")
.unwrap();
let rows = stmt
.query_map(&[url], |row| row.get(0) as rusqlite::Result<String>)
.expect("failed requesting db");
let mut names = Vec::new();
for name_result in rows {
names.push(name_result.unwrap());
}
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(),
);
return;
}
2018-11-15 14:10:27 +00:00
let source = match youtube_dl(&url) {
2018-11-14 14:29:58 +00:00
Ok(source) => source,
Err(why) => {
println!("Err starting source: {:?}", why);
2019-04-03 09:42:06 +00:00
print_error!(msg
.channel_id
.say(format!("Error using youtube-dl: {}", why)));
2018-11-14 14:29:58 +00:00
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);
2019-04-03 09:42:06 +00:00
sql.execute(
"INSERT INTO Vulva3 (name, link)
VALUES (?1, ?2)",
params![song.name, url],
)
.expect("failed inserting song");
}
print_error!(msg.channel_id.say(info));
2018-11-14 15:43:53 +00:00
self.append_songs(ctx, msg, source);
2018-11-14 14:29:58 +00:00
}
fn handle_local_request(
&self,
ctx: &mut serenity::client::Context,
msg: &serenity::model::channel::Message,
) {
2019-04-03 09:42:06 +00:00
//print_error!(self.media.reset(ctx, msg));
2018-11-14 14:29:58 +00:00
2019-04-03 09:42:06 +00:00
let sql = self.media.lock_db();
2018-11-14 15:43:53 +00:00
2019-04-03 09:42:06 +00:00
let mut stmt = sql.prepare("SELECT name FROM Vulva3").unwrap();
2018-11-14 15:43:53 +00:00
2019-04-03 09:42:06 +00:00
let rows = stmt
.query_map(params![], |row| row.get(0) as rusqlite::Result<String>)
.expect("failed requesting db");
2018-11-14 15:43:53 +00:00
2019-04-03 09:42:06 +00:00
let mut songs = Vec::new();
for name_result in rows {
songs.push(Song {
name: name_result.unwrap(),
});
2018-11-14 15:43:53 +00:00
}
let mut rng = thread_rng();
songs.shuffle(&mut rng);
self.append_songs(ctx, msg, songs);
2018-11-14 14:29:58 +00:00
}
2019-04-03 09:42:06 +00:00
fn handle_song_request(
&self,
ctx: &mut serenity::client::Context,
msg: &serenity::model::channel::Message,
pattern: &str,
) {
let sql = self.media.lock_db();
let mut stmt = sql
.prepare(&format!(
"SELECT name FROM Vulva3 WHERE name LIKE '%{}%'",
pattern
))
.unwrap();
let rows = stmt
.query_map(params![], |row| row.get(0) as rusqlite::Result<String>)
.expect("failed requesting db");
let mut songs = Vec::new();
for name_result in rows {
songs.push(Song {
name: name_result.unwrap(),
});
}
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)));
}
}
2018-11-14 14:29:58 +00:00
}
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> {
2018-11-23 12:18:07 +00:00
if !channel_contains_author(ctx, msg) {
println!(
"user {} is not in the same voice channel as the bot",
msg.author.name
);
return Ok(());
}
2018-11-14 14:29:58 +00:00
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 {
2019-04-03 09:42:06 +00:00
self.handle_song_request(ctx, msg, &arg);
2018-11-14 14:29:58 +00:00
}
} else {
print_error!(msg.channel_id.say("Unsupported argument list"));
}
Ok(())
}
}