RMusicBot/src/player/commands/play.rs

310 lines
8.3 KiB
Rust
Raw Normal View History

2019-07-12 12:41:51 +00:00
use lock_api::RawMutex;
2018-11-14 14:29:58 +00:00
2019-07-12 12:41:51 +00:00
use std::sync::Arc;
2018-11-14 14:29:58 +00:00
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;
2019-07-12 08:39:03 +00:00
use serenity::prelude::*;
use serenity::voice::LockedAudio;
use serenity::{
framework::standard::{macros::command, Args, CommandResult},
model::channel::Message,
};
#[command]
2019-07-12 12:41:51 +00:00
fn play(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult {
2019-07-12 08:39:03 +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
}
2019-07-12 12:41:51 +00:00
let mut data = ctx.data.write();
let media = match data.get_mut::<Media>() {
Some(media) => media,
None => {
display_error_ok!(msg.channel_id.say(&ctx.http, "could not find media data"));
2019-07-12 08:39:03 +00:00
return Ok(());
2018-11-14 14:29:58 +00:00
}
2019-07-12 08:39:03 +00:00
};
2018-11-14 14:29:58 +00:00
2019-07-12 08:39:03 +00:00
if args.len() == 0 {
2019-07-12 12:41:51 +00:00
if !check_for_continue(media.song_mut()) {
print_error!(msg
.channel_id
.say(&ctx.http, "Must provide a URL to a video or audio"));
2019-07-12 08:39:03 +00:00
}
} 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(()),
2018-11-14 14:29:58 +00:00
};
2019-07-12 08:39:03 +00:00
if arg == "--local" {
2019-07-12 12:41:51 +00:00
handle_local_request(media, ctx, msg)?;
2019-07-12 08:39:03 +00:00
} else if arg.starts_with("http") {
2019-07-12 12:41:51 +00:00
handle_http_request(media, ctx, msg, &arg)?;
2019-07-12 08:39:03 +00:00
} else {
2019-07-12 12:41:51 +00:00
handle_song_request(media, ctx, msg, &arg)?;
2018-11-14 15:43:53 +00:00
}
2019-07-12 08:39:03 +00:00
} else {
2019-07-12 12:41:51 +00:00
print_error!(msg.channel_id.say(&ctx.http, "Unsupported argument list"));
2019-07-12 08:39:03 +00:00
}
2018-11-14 15:43:53 +00:00
2019-07-12 08:39:03 +00:00
Ok(())
}
2019-04-28 12:13:36 +00:00
2019-07-12 12:41:51 +00:00
fn check_for_continue(song_lock: &Option<LockedAudio>) -> bool {
match song_lock {
2019-07-12 08:39:03 +00:00
Some(song) => {
let song_clone = song.clone();
let mut audio_lock = song_clone.lock();
2019-04-28 12:13:36 +00:00
2019-07-12 08:39:03 +00:00
audio_lock.play();
true
}
None => false,
}
}
2019-04-28 12:13:36 +00:00
2019-07-12 12:41:51 +00:00
fn check_join_channel<T: RawMutex>(
manager_lock: &Arc<lock_api::Mutex<T, serenity::client::bridge::voice::ClientVoiceManager>>,
ctx: &Context,
msg: &Message,
2019-07-12 08:39:03 +00:00
) {
2019-07-12 12:41:51 +00:00
let guild = check_result_return!(guild(ctx, msg));
let guild_id = check_result_return!(guild_id(ctx, msg));
2018-11-14 15:43:53 +00:00
2019-07-12 08:39:03 +00:00
let channel_id = guild
.read()
.voice_states
.get(&msg.author.id)
.and_then(|voice_state| voice_state.channel_id);
2019-04-03 09:42:06 +00:00
2019-07-12 08:39:03 +00:00
let connect_to = match channel_id {
Some(channel) => channel,
None => {
2019-07-12 12:41:51 +00:00
display_error!(msg.reply(ctx, "Not in a voice channel"));
2019-04-03 09:42:06 +00:00
2019-07-12 08:39:03 +00:00
return;
2019-04-03 09:42:06 +00:00
}
2019-07-12 08:39:03 +00:00
};
2019-04-03 09:42:06 +00:00
2019-07-12 08:39:03 +00:00
let mut manager = manager_lock.lock();
manager.join(guild_id, connect_to);
}
2019-04-03 09:42:06 +00:00
2019-07-12 08:39:03 +00:00
fn append_songs(
media: &mut MediaData,
2019-07-12 12:41:51 +00:00
ctx: &Context,
msg: &Message,
2019-07-12 08:39:03 +00:00
mut source: Vec<Song>,
) -> Result<(), String> {
2019-07-12 12:41:51 +00:00
media.playlist_mut().append(&mut source);
2019-04-03 09:42:06 +00:00
2019-07-12 12:41:51 +00:00
if let Some(manager_lock) = ctx.data.read().get::<VoiceManager>().cloned() {
check_join_channel(&manager_lock, ctx, msg);
2018-11-14 14:29:58 +00:00
2019-07-12 12:41:51 +00:00
// let check_finished = {
// let channel_id = msg.channel_id;
// let manager_lock_clone = manager_lock.clone();
// Arc::new(move || {
// let callback = match media.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(ctx, media, msg, &manager_lock);
2019-07-12 08:39:03 +00:00
}
2018-11-14 14:29:58 +00:00
2019-07-12 08:39:03 +00:00
Ok(())
}
2018-11-14 14:29:58 +00:00
2019-07-12 08:39:03 +00:00
fn handle_http_request(
media: &mut MediaData,
2019-07-12 12:41:51 +00:00
ctx: &serenity::client::Context,
2019-07-12 08:39:03 +00:00
msg: &serenity::model::channel::Message,
url: &String,
) -> Result<(), String> {
2019-07-12 12:41:51 +00:00
let mut names = Vec::new();
2019-07-12 08:39:03 +00:00
2019-07-12 12:41:51 +00:00
{
let sql = media.db();
2019-07-12 08:39:03 +00:00
2019-07-12 12:41:51 +00:00
let mut stmt = match sql.prepare("SELECT name FROM Vulva3 WHERE link = ?") {
Ok(statement) => statement,
Err(_) => return Err("failed preparing data base access".to_string()),
};
2019-07-12 08:39:03 +00:00
2019-07-12 12:41:51 +00:00
let rows = match stmt.query_map(&[url], |row| row.get(0) as rusqlite::Result<String>) {
Ok(rows) => rows,
Err(_) => return Err("failed querying rows".to_string()),
};
2019-07-12 12:41:51 +00:00
for name_result in rows {
let name = match name_result {
Ok(name) => name,
Err(_) => return Err("failed getting name from row".to_string()),
};
names.push(name);
}
2019-07-12 08:39:03 +00:00
}
2019-07-12 08:39:03 +00:00
if names.len() > 0 {
2019-07-12 12:41:51 +00:00
print_error!(msg.channel_id.say(&ctx.http, "song already loaded!"));
2019-07-12 12:41:51 +00:00
append_songs(
media,
2019-07-12 08:39:03 +00:00
ctx,
msg,
names.iter().map(|n| Song { name: n.clone() }).collect(),
)?;
2019-07-12 12:41:51 +00:00
} else {
let source = match youtube_dl(&url) {
Ok(source) => source,
Err(why) => {
println!("Err starting source: {:?}", why);
2019-04-28 12:13:36 +00:00
2019-07-12 12:41:51 +00:00
print_error!(msg
.channel_id
.say(&ctx.http, format!("Error using youtube-dl: {}", why)));
2018-11-14 14:29:58 +00:00
2019-07-12 12:41:51 +00:00
return Ok(());
}
};
2018-11-14 15:43:53 +00:00
2019-07-12 12:41:51 +00:00
let mut info = if source.len() == 1 {
"Finished downloading song:".to_string()
} else {
"Finished downloading songs:".to_string()
};
2019-07-12 08:39:03 +00:00
2019-07-12 12:41:51 +00:00
{
let sql = media.db();
2018-11-14 15:43:53 +00:00
2019-07-12 12:41:51 +00:00
for song in &source {
info = format!("{}\n\t{}", info, song.name);
2019-04-28 12:13:36 +00:00
2019-07-12 12:41:51 +00:00
if sql
.execute(
"INSERT INTO Vulva3 (name, link)
2019-07-12 08:39:03 +00:00
VALUES (?1, ?2)",
2019-07-12 12:41:51 +00:00
params![song.name, url],
)
.is_err()
{
return Err("failed inserting songs into db".to_string());
}
}
2018-11-14 15:43:53 +00:00
}
2019-07-12 12:41:51 +00:00
print_error!(msg.channel_id.say(&ctx.http, info));
2018-11-14 15:43:53 +00:00
2019-07-12 12:41:51 +00:00
append_songs(media, ctx, msg, source)?;
}
2019-04-28 12:13:36 +00:00
2019-07-12 08:39:03 +00:00
Ok(())
}
2019-04-03 09:42:06 +00:00
2019-07-12 08:39:03 +00:00
fn handle_local_request(
media: &mut MediaData,
2019-07-12 12:41:51 +00:00
ctx: &serenity::client::Context,
2019-07-12 08:39:03 +00:00
msg: &serenity::model::channel::Message,
) -> Result<(), String> {
2019-07-12 12:41:51 +00:00
let mut songs = Vec::new();
2019-07-12 08:39:03 +00:00
2019-07-12 12:41:51 +00:00
{
let sql = media.db();
2019-07-12 08:39:03 +00:00
2019-07-12 12:41:51 +00:00
let mut stmt = match sql.prepare("SELECT name FROM Vulva3") {
Ok(statement) => statement,
Err(_) => return Err("failed preparing data base access".to_string()),
};
2019-07-12 08:39:03 +00:00
2019-07-12 12:41:51 +00:00
let rows = match stmt.query_map(params![], |row| row.get(0) as rusqlite::Result<String>) {
Ok(rows) => rows,
Err(_) => return Err("failed querying rows".to_string()),
2019-04-28 12:13:36 +00:00
};
2019-04-03 09:42:06 +00:00
2019-07-12 12:41:51 +00:00
for name_result in rows {
let name = match name_result {
Ok(name) => name,
Err(_) => return Err("failed getting name from row".to_string()),
};
songs.push(Song { name });
}
2019-07-12 08:39:03 +00:00
}
2019-04-03 09:42:06 +00:00
2019-07-12 08:39:03 +00:00
let mut rng = thread_rng();
songs.shuffle(&mut rng);
2019-04-28 12:13:36 +00:00
2019-07-12 12:41:51 +00:00
append_songs(media, ctx, msg, songs)?;
2019-04-03 09:42:06 +00:00
2019-07-12 08:39:03 +00:00
Ok(())
}
2019-04-03 09:42:06 +00:00
2019-07-12 08:39:03 +00:00
fn handle_song_request(
media: &mut MediaData,
2019-07-12 12:41:51 +00:00
ctx: &serenity::client::Context,
2019-07-12 08:39:03 +00:00
msg: &serenity::model::channel::Message,
pattern: &str,
) -> Result<(), String> {
2019-07-12 12:41:51 +00:00
let mut songs = Vec::new();
2019-07-12 08:39:03 +00:00
2019-07-12 12:41:51 +00:00
{
let sql = media.db();
let mut stmt = match sql.prepare(&format!(
"SELECT name FROM Vulva3 WHERE name LIKE '%{}%'",
pattern
)) {
Ok(statement) => statement,
Err(_) => return Err("failed preparing data base access".to_string()),
};
2019-07-12 08:39:03 +00:00
2019-07-12 12:41:51 +00:00
let rows = match stmt.query_map(params![], |row| row.get(0) as rusqlite::Result<String>) {
Ok(rows) => rows,
Err(_) => return Err("failed querying rows".to_string()),
2019-07-12 08:39:03 +00:00
};
2019-04-28 12:13:36 +00:00
2019-07-12 12:41:51 +00:00
for name_result in rows {
let name = match name_result {
Ok(name) => name,
Err(_) => return Err("failed getting name from row".to_string()),
};
songs.push(Song { name });
}
2019-04-03 09:42:06 +00:00
}
2018-11-14 14:29:58 +00:00
2019-07-12 08:39:03 +00:00
if !songs.is_empty() {
let mut rng = thread_rng();
songs.shuffle(&mut rng);
2018-11-14 14:29:58 +00:00
2019-07-12 12:41:51 +00:00
append_songs(media, ctx, msg, songs)?;
2019-07-12 08:39:03 +00:00
} else {
print_error!(msg
.channel_id
2019-07-12 12:41:51 +00:00
.say(&ctx.http, format!("no song found with pattern {}", pattern)));
2018-11-14 14:29:58 +00:00
}
2019-07-12 08:39:03 +00:00
Ok(())
2018-11-14 14:29:58 +00:00
}