2018-11-14 14:29:58 +00:00
|
|
|
use serenity;
|
2019-07-12 12:41:51 +00:00
|
|
|
use serenity::model::channel::Message;
|
|
|
|
use serenity::prelude::*;
|
2018-11-14 15:43:53 +00:00
|
|
|
use serenity::voice::ffmpeg;
|
2018-11-15 14:10:27 +00:00
|
|
|
use serenity::voice::LockedAudio;
|
2018-11-14 14:29:58 +00:00
|
|
|
|
2019-09-15 11:19:32 +00:00
|
|
|
use parking_lot::lock_api::{MutexGuard, RawMutex};
|
2019-09-14 14:34:00 +00:00
|
|
|
use serenity::client::bridge::voice::ClientVoiceManager;
|
|
|
|
use serenity::prelude::Mutex;
|
2019-07-12 08:39:03 +00:00
|
|
|
use std::sync::Arc;
|
2018-11-14 14:29:58 +00:00
|
|
|
|
|
|
|
use super::prelude::*;
|
|
|
|
|
2019-09-15 11:19:32 +00:00
|
|
|
use std::fs;
|
|
|
|
|
2019-04-03 09:42:06 +00:00
|
|
|
use rusqlite::{params, Connection};
|
|
|
|
|
2019-09-14 14:34:00 +00:00
|
|
|
use utilities::prelude::*;
|
|
|
|
|
2019-09-15 11:19:32 +00:00
|
|
|
#[derive(Debug)]
|
2018-11-14 14:29:58 +00:00
|
|
|
pub struct Song {
|
|
|
|
pub name: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct MediaData {
|
2019-09-15 11:19:32 +00:00
|
|
|
volume: f32,
|
2019-07-12 08:39:03 +00:00
|
|
|
playlist: Vec<Song>,
|
|
|
|
current_song: Option<LockedAudio>,
|
|
|
|
song_name: String,
|
2019-09-14 14:34:00 +00:00
|
|
|
pub next_callback: Option<Arc<dyn Fn() -> ()>>,
|
2019-04-03 09:42:06 +00:00
|
|
|
|
2019-07-12 08:39:03 +00:00
|
|
|
sql_data_base: Connection,
|
2019-09-14 14:34:00 +00:00
|
|
|
|
|
|
|
pub voice_manager: Arc<Mutex<ClientVoiceManager>>,
|
2018-11-14 14:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl MediaData {
|
2019-09-14 14:34:00 +00:00
|
|
|
pub fn new(
|
|
|
|
file: &str,
|
|
|
|
voice_manager: Arc<Mutex<ClientVoiceManager>>,
|
2019-09-15 11:19:32 +00:00
|
|
|
volume: f32,
|
2019-09-14 14:34:00 +00:00
|
|
|
) -> Result<MediaData, String> {
|
2019-04-03 09:42:06 +00:00
|
|
|
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 (
|
2019-07-12 08:39:03 +00:00
|
|
|
name TEXT PRIMARY KEY,
|
|
|
|
link TEXT NOT NULL
|
|
|
|
)",
|
2019-04-03 09:42:06 +00:00
|
|
|
params![],
|
|
|
|
) {
|
|
|
|
Ok(_) => (),
|
|
|
|
Err(err) => {
|
|
|
|
println!("{}", err);
|
|
|
|
return Err(format!("can't create table"));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(MediaData {
|
2019-09-15 11:19:32 +00:00
|
|
|
volume,
|
2019-07-12 08:39:03 +00:00
|
|
|
playlist: Vec::new(),
|
|
|
|
current_song: None,
|
|
|
|
song_name: String::new(),
|
|
|
|
next_callback: None,
|
2019-04-03 09:42:06 +00:00
|
|
|
|
2019-07-12 08:39:03 +00:00
|
|
|
sql_data_base: connection,
|
2019-09-14 14:34:00 +00:00
|
|
|
|
|
|
|
voice_manager,
|
2019-04-03 09:42:06 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-11-14 14:29:58 +00:00
|
|
|
pub fn reset(
|
2019-07-12 08:39:03 +00:00
|
|
|
&mut self,
|
2019-07-12 12:41:51 +00:00
|
|
|
ctx: &serenity::client::Context,
|
2018-11-14 14:29:58 +00:00
|
|
|
msg: &serenity::model::channel::Message,
|
|
|
|
) -> Result<(), String> {
|
2019-07-12 12:41:51 +00:00
|
|
|
self.playlist.clear();
|
|
|
|
self.current_song = None;
|
|
|
|
self.song_name = String::new();
|
|
|
|
self.next_callback = None;
|
2018-11-14 14:29:58 +00:00
|
|
|
|
2019-09-15 11:19:32 +00:00
|
|
|
let mut manager = self.voice_manager.lock();
|
2018-11-14 14:29:58 +00:00
|
|
|
|
2019-09-15 11:19:32 +00:00
|
|
|
let guild_id = guild_id(ctx, msg)?;
|
2018-11-14 14:29:58 +00:00
|
|
|
|
2019-09-15 11:19:32 +00:00
|
|
|
let handler = match handler(guild_id, &mut manager) {
|
|
|
|
Some(handler) => handler,
|
|
|
|
None => return Ok(()),
|
|
|
|
};
|
2018-11-14 14:29:58 +00:00
|
|
|
|
2019-09-15 11:19:32 +00:00
|
|
|
println!("stopped handler");
|
2018-11-23 21:06:35 +00:00
|
|
|
|
2019-09-15 11:19:32 +00:00
|
|
|
handler.stop();
|
|
|
|
manager.remove(guild_id);
|
2018-11-14 14:29:58 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-07-12 08:39:03 +00:00
|
|
|
pub fn db(&self) -> &Connection {
|
|
|
|
&self.sql_data_base
|
2019-04-03 09:42:06 +00:00
|
|
|
}
|
|
|
|
|
2019-07-12 08:39:03 +00:00
|
|
|
pub fn song(&self) -> &Option<LockedAudio> {
|
|
|
|
&self.current_song
|
2018-11-14 14:29:58 +00:00
|
|
|
}
|
|
|
|
|
2019-07-12 08:39:03 +00:00
|
|
|
pub fn song_mut(&mut self) -> &mut Option<LockedAudio> {
|
|
|
|
&mut self.current_song
|
2018-11-14 14:29:58 +00:00
|
|
|
}
|
|
|
|
|
2019-07-12 08:39:03 +00:00
|
|
|
pub fn playlist(&self) -> &Vec<Song> {
|
|
|
|
&self.playlist
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn playlist_mut(&mut self) -> &mut Vec<Song> {
|
|
|
|
&mut self.playlist
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn song_name(&self) -> &String {
|
2019-07-12 12:41:51 +00:00
|
|
|
&self.song_name
|
2019-07-12 08:39:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn song_name_mut(&mut self) -> &mut String {
|
2019-07-12 12:41:51 +00:00
|
|
|
&mut self.song_name
|
2018-11-21 08:58:06 +00:00
|
|
|
}
|
|
|
|
|
2018-11-23 21:06:35 +00:00
|
|
|
pub fn start_playing(
|
2019-07-12 12:41:51 +00:00
|
|
|
ctx: &Context,
|
|
|
|
mediadata: &mut MediaData,
|
|
|
|
msg: &Message,
|
2019-09-14 14:34:00 +00:00
|
|
|
) -> VerboseResult<()> {
|
2018-11-23 21:06:35 +00:00
|
|
|
// check if there is already playing
|
2019-09-14 14:34:00 +00:00
|
|
|
let already_started = mediadata.song().is_some();
|
2018-11-14 14:29:58 +00:00
|
|
|
|
2018-11-23 21:06:35 +00:00
|
|
|
// if there isnt already a song playing, start a new one
|
|
|
|
if !already_started {
|
2019-09-15 11:19:32 +00:00
|
|
|
println!("next song");
|
2019-09-14 14:34:00 +00:00
|
|
|
Self::next_song(ctx, mediadata, msg)?;
|
2018-11-14 14:29:58 +00:00
|
|
|
}
|
2019-09-14 14:34:00 +00:00
|
|
|
|
|
|
|
Ok(())
|
2018-11-14 14:29:58 +00:00
|
|
|
}
|
|
|
|
|
2019-09-15 11:19:32 +00:00
|
|
|
fn check_for_next(&mut self, ctx: &Context, msg: &Message) -> VerboseResult<String> {
|
|
|
|
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<T: RawMutex>(
|
|
|
|
manager: &mut MutexGuard<T, ClientVoiceManager>,
|
|
|
|
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(())
|
|
|
|
}
|
|
|
|
|
2019-09-14 14:34:00 +00:00
|
|
|
pub fn next_song(ctx: &Context, mediadata: &mut MediaData, msg: &Message) -> VerboseResult<()> {
|
2019-09-15 11:19:32 +00:00
|
|
|
println!("start next song");
|
2019-09-14 14:34:00 +00:00
|
|
|
let voice_manager = mediadata.voice_manager.clone();
|
|
|
|
let mut manager = voice_manager.lock();
|
2018-11-14 14:29:58 +00:00
|
|
|
|
2019-09-15 11:19:32 +00:00
|
|
|
println!("got manager lock");
|
|
|
|
|
2019-09-14 14:34:00 +00:00
|
|
|
let guild_id = guild_id(ctx, msg)?;
|
2018-11-14 14:29:58 +00:00
|
|
|
|
2019-09-15 11:19:32 +00:00
|
|
|
println!("got guild id");
|
|
|
|
|
2018-11-23 21:06:35 +00:00
|
|
|
let mut need_to_leave = false;
|
|
|
|
|
2019-09-15 11:19:32 +00:00
|
|
|
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)?;
|
|
|
|
|
2018-11-23 21:06:35 +00:00
|
|
|
let handler = {
|
|
|
|
match handler(guild_id, &mut manager) {
|
|
|
|
Some(handler) => handler,
|
|
|
|
None => {
|
2019-09-15 11:19:32 +00:00
|
|
|
println!("failed getting handler");
|
2019-09-14 14:34:00 +00:00
|
|
|
create_error!("error getting handler");
|
2018-11-23 21:06:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-09-15 11:19:32 +00:00
|
|
|
println!("got handler");
|
2018-11-17 18:59:10 +00:00
|
|
|
|
2019-09-15 11:19:32 +00:00
|
|
|
let source = match ffmpeg(first.clone()) {
|
|
|
|
Ok(mpeg) => mpeg,
|
|
|
|
Err(_) => create_error!(format!("failed loading: {}", &first)),
|
|
|
|
};
|
2018-11-14 15:43:53 +00:00
|
|
|
|
2019-09-15 11:19:32 +00:00
|
|
|
handler.stop();
|
2018-11-14 15:43:53 +00:00
|
|
|
|
2019-09-15 11:19:32 +00:00
|
|
|
let song = handler.play_returning(source);
|
2018-11-14 14:29:58 +00:00
|
|
|
|
2019-09-15 11:19:32 +00:00
|
|
|
{
|
|
|
|
let mut song_lock = song.lock();
|
|
|
|
song_lock.volume(mediadata.volume);
|
2018-11-14 14:29:58 +00:00
|
|
|
}
|
2019-09-15 11:19:32 +00:00
|
|
|
|
|
|
|
*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))?;
|
2018-11-14 14:29:58 +00:00
|
|
|
}
|
|
|
|
|
2018-11-23 21:06:35 +00:00
|
|
|
if need_to_leave {
|
|
|
|
manager.remove(guild_id);
|
|
|
|
}
|
2019-09-14 14:34:00 +00:00
|
|
|
|
2019-09-15 11:19:32 +00:00
|
|
|
println!("successfully started next song");
|
2019-09-14 14:34:00 +00:00
|
|
|
Ok(())
|
2018-11-14 14:29:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe impl Send for MediaData {}
|
|
|
|
unsafe impl Sync for MediaData {}
|
2019-07-12 12:41:51 +00:00
|
|
|
|
|
|
|
pub struct Media;
|
|
|
|
|
|
|
|
impl TypeMapKey for Media {
|
|
|
|
type Value = MediaData;
|
|
|
|
}
|