Add several commands to the bot
This commit is contained in:
parent
dc41eb26f8
commit
dd4210ad6f
5 changed files with 308 additions and 248 deletions
2
bot.conf
2
bot.conf
|
@ -1,3 +1,3 @@
|
||||||
[Meta]
|
[Meta]
|
||||||
token = NDc4NTQ1NzY1MDc4MjY5OTU2.DlMQjQ.lqep6rd5w-uBOGst_cuEOQptt84
|
token = NDc4NTQ1NzY1MDc4MjY5OTU2.DlMQjQ.lqep6rd5w-uBOGst_cuEOQptt84
|
||||||
|
prefix = !
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufRead, BufReader, Write};
|
use std::io::{BufRead, BufReader, Write};
|
||||||
|
|
238
src/main.rs
238
src/main.rs
|
@ -1,4 +1,3 @@
|
||||||
#[macro_use]
|
|
||||||
extern crate serenity;
|
extern crate serenity;
|
||||||
|
|
||||||
extern crate parking_lot;
|
extern crate parking_lot;
|
||||||
|
@ -12,11 +11,10 @@ mod macros;
|
||||||
// feature, it's not as ergonomic to work with as it could be. The client
|
// feature, it's not as ergonomic to work with as it could be. The client
|
||||||
// provides a clean bridged integration with voice.
|
// provides a clean bridged integration with voice.
|
||||||
use serenity::client::bridge::voice::ClientVoiceManager;
|
use serenity::client::bridge::voice::ClientVoiceManager;
|
||||||
use serenity::client::{Client, Context, EventHandler, CACHE};
|
use serenity::client::{Client, Context, EventHandler};
|
||||||
use serenity::framework::StandardFramework;
|
use serenity::framework::StandardFramework;
|
||||||
use serenity::model::channel::Message;
|
use serenity::model::channel::Message;
|
||||||
use serenity::model::gateway::Ready;
|
use serenity::model::gateway::Ready;
|
||||||
use serenity::model::misc::Mentionable;
|
|
||||||
// Import the `Context` from the client and `parking_lot`'s `Mutex`.
|
// Import the `Context` from the client and `parking_lot`'s `Mutex`.
|
||||||
//
|
//
|
||||||
// `parking_lot` offers much more efficient implementations of `std::sync`'s
|
// `parking_lot` offers much more efficient implementations of `std::sync`'s
|
||||||
|
@ -55,29 +53,54 @@ impl EventHandler for Handler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Config {
|
||||||
|
token: String,
|
||||||
|
prefix: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Config {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
token: String::new(),
|
||||||
|
prefix: String::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// read config file
|
// read config file
|
||||||
let config = check_result_return!(read_config("bot.conf"));
|
let config_file = check_result_return!(read_config("bot.conf"));
|
||||||
|
|
||||||
let token = match config.get("Meta") {
|
let mut config = Config::default();
|
||||||
Some(info) => match info.get("token") {
|
|
||||||
|
match config_file.get("Meta") {
|
||||||
|
Some(info) => {
|
||||||
|
match info.get("token") {
|
||||||
Some(token_pair) => {
|
Some(token_pair) => {
|
||||||
let mut token = String::new();
|
display_error!(token_pair.set_value(&mut config.token));
|
||||||
display_error!(token_pair.set_value(&mut token));
|
|
||||||
token
|
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
println!("couldn't find token inside meta section");
|
println!("couldn't find token inside meta section");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
match info.get("prefix") {
|
||||||
|
Some(prefix_pair) => {
|
||||||
|
display_error!(prefix_pair.set_value(&mut config.prefix));
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
println!("couldn't find prefix inside meta section");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
None => {
|
None => {
|
||||||
println!("couldn't find Meta section in config file");
|
println!("couldn't find Meta section in config file");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut client = Client::new(&token, Handler).expect("Err creating client");
|
let mut client = Client::new(&config.token, Handler).expect("Err creating client");
|
||||||
|
|
||||||
// Obtain a lock to the data owned by the client, and insert the client's
|
// Obtain a lock to the data owned by the client, and insert the client's
|
||||||
// voice manager into it. This allows the voice manager to be accessible by
|
// voice manager into it. This allows the voice manager to be accessible by
|
||||||
|
@ -91,16 +114,24 @@ fn main() {
|
||||||
|
|
||||||
client.with_framework(
|
client.with_framework(
|
||||||
StandardFramework::new()
|
StandardFramework::new()
|
||||||
.configure(|c| c.prefix("~").on_mention(true))
|
.configure(|c| c.prefix(&config.prefix).on_mention(true))
|
||||||
.cmd("deafen", deafen)
|
|
||||||
.cmd("join", join)
|
|
||||||
.cmd("leave", leave)
|
|
||||||
.cmd("mute", mute)
|
|
||||||
.cmd("play", Play::new(media_data.clone()))
|
.cmd("play", Play::new(media_data.clone()))
|
||||||
.cmd("pause", Pause::new(media_data.clone()))
|
.cmd("pause", Pause::new(media_data.clone()))
|
||||||
.cmd("ping", ping)
|
.cmd(
|
||||||
.cmd("undeafen", undeafen)
|
"help",
|
||||||
.cmd("unmute", unmute),
|
Help::new(
|
||||||
|
&config.prefix,
|
||||||
|
vec![
|
||||||
|
"play".to_string(),
|
||||||
|
"pause".to_string(),
|
||||||
|
"stop".to_string(),
|
||||||
|
"help".to_string(),
|
||||||
|
"list".to_string(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.cmd("stop", Stop::new(media_data.clone()))
|
||||||
|
.cmd("list", List::new(media_data.clone())),
|
||||||
);
|
);
|
||||||
|
|
||||||
let _ = client
|
let _ = client
|
||||||
|
@ -108,175 +139,6 @@ fn main() {
|
||||||
.map_err(|why| println!("Client ended: {:?}", why));
|
.map_err(|why| println!("Client ended: {:?}", why));
|
||||||
}
|
}
|
||||||
|
|
||||||
command!(deafen(ctx, msg) {
|
|
||||||
let guild_id = match CACHE.read().guild_channel(msg.channel_id) {
|
|
||||||
Some(channel) => channel.read().guild_id,
|
|
||||||
None => {
|
|
||||||
check_msg(msg.channel_id.say("Groups and DMs not supported"));
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut manager_lock = ctx.data.lock().get::<VoiceManager>().cloned().unwrap();
|
|
||||||
let mut manager = manager_lock.lock();
|
|
||||||
|
|
||||||
let handler = match manager.get_mut(guild_id) {
|
|
||||||
Some(handler) => handler,
|
|
||||||
None => {
|
|
||||||
check_msg(msg.reply("Not in a voice channel"));
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if handler.self_deaf {
|
|
||||||
check_msg(msg.channel_id.say("Already deafened"));
|
|
||||||
} else {
|
|
||||||
handler.deafen(true);
|
|
||||||
|
|
||||||
check_msg(msg.channel_id.say("Deafened"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
command!(join(ctx, msg) {
|
|
||||||
let guild = match msg.guild() {
|
|
||||||
Some(guild) => guild,
|
|
||||||
None => {
|
|
||||||
check_msg(msg.channel_id.say("Groups and DMs not supported"));
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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 => {
|
|
||||||
check_msg(msg.reply("Not in a voice channel"));
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut manager_lock = ctx.data.lock().get::<VoiceManager>().cloned().unwrap();
|
|
||||||
let mut manager = manager_lock.lock();
|
|
||||||
|
|
||||||
if manager.join(guild_id, connect_to).is_some() {
|
|
||||||
check_msg(msg.channel_id.say(&format!("Joined {}", connect_to.mention())));
|
|
||||||
} else {
|
|
||||||
check_msg(msg.channel_id.say("Error joining the channel"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
command!(leave(ctx, msg) {
|
|
||||||
let guild_id = match CACHE.read().guild_channel(msg.channel_id) {
|
|
||||||
Some(channel) => channel.read().guild_id,
|
|
||||||
None => {
|
|
||||||
check_msg(msg.channel_id.say("Groups and DMs not supported"));
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut manager_lock = ctx.data.lock().get::<VoiceManager>().cloned().unwrap();
|
|
||||||
let mut manager = manager_lock.lock();
|
|
||||||
let has_handler = manager.get(guild_id).is_some();
|
|
||||||
|
|
||||||
if has_handler {
|
|
||||||
manager.remove(guild_id);
|
|
||||||
|
|
||||||
check_msg(msg.channel_id.say("Left voice channel"));
|
|
||||||
} else {
|
|
||||||
check_msg(msg.reply("Not in a voice channel"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
command!(mute(ctx, msg) {
|
|
||||||
let guild_id = match CACHE.read().guild_channel(msg.channel_id) {
|
|
||||||
Some(channel) => channel.read().guild_id,
|
|
||||||
None => {
|
|
||||||
check_msg(msg.channel_id.say("Groups and DMs not supported"));
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut manager_lock = ctx.data.lock().get::<VoiceManager>().cloned().unwrap();
|
|
||||||
let mut manager = manager_lock.lock();
|
|
||||||
|
|
||||||
let handler = match manager.get_mut(guild_id) {
|
|
||||||
Some(handler) => handler,
|
|
||||||
None => {
|
|
||||||
check_msg(msg.reply("Not in a voice channel"));
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if handler.self_mute {
|
|
||||||
check_msg(msg.channel_id.say("Already muted"));
|
|
||||||
} else {
|
|
||||||
handler.mute(true);
|
|
||||||
|
|
||||||
check_msg(msg.channel_id.say("Now muted"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
command!(ping(_context, msg) {
|
|
||||||
check_msg(msg.channel_id.say("Pong!"));
|
|
||||||
});
|
|
||||||
|
|
||||||
command!(undeafen(ctx, msg) {
|
|
||||||
let guild_id = match CACHE.read().guild_channel(msg.channel_id) {
|
|
||||||
Some(channel) => channel.read().guild_id,
|
|
||||||
None => {
|
|
||||||
check_msg(msg.channel_id.say("Error finding channel info"));
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut manager_lock = ctx.data.lock().get::<VoiceManager>().cloned().unwrap();
|
|
||||||
let mut manager = manager_lock.lock();
|
|
||||||
|
|
||||||
if let Some(handler) = manager.get_mut(guild_id) {
|
|
||||||
handler.deafen(false);
|
|
||||||
|
|
||||||
check_msg(msg.channel_id.say("Undeafened"));
|
|
||||||
} else {
|
|
||||||
check_msg(msg.channel_id.say("Not in a voice channel to undeafen in"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
command!(unmute(ctx, msg) {
|
|
||||||
let guild_id = match CACHE.read().guild_channel(msg.channel_id) {
|
|
||||||
Some(channel) => channel.read().guild_id,
|
|
||||||
None => {
|
|
||||||
check_msg(msg.channel_id.say("Error finding channel info"));
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let mut manager_lock = ctx.data.lock().get::<VoiceManager>().cloned().unwrap();
|
|
||||||
let mut manager = manager_lock.lock();
|
|
||||||
|
|
||||||
if let Some(handler) = manager.get_mut(guild_id) {
|
|
||||||
handler.mute(false);
|
|
||||||
|
|
||||||
check_msg(msg.channel_id.say("Unmuted"));
|
|
||||||
} else {
|
|
||||||
check_msg(msg.channel_id.say("Not in a voice channel to undeafen in"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/// Checks that a message successfully sent; if not, then logs why to stdout.
|
/// Checks that a message successfully sent; if not, then logs why to stdout.
|
||||||
fn check_msg(result: SerenityResult<Message>) {
|
fn check_msg(result: SerenityResult<Message>) {
|
||||||
if let Err(why) = result {
|
if let Err(why) = result {
|
||||||
|
|
245
src/player.rs
245
src/player.rs
|
@ -1,5 +1,7 @@
|
||||||
use parking_lot;
|
use parking_lot;
|
||||||
|
|
||||||
|
use youtube::convert_file_name;
|
||||||
|
|
||||||
use serenity;
|
use serenity;
|
||||||
use serenity::client::CACHE;
|
use serenity::client::CACHE;
|
||||||
use serenity::model::id::{ChannelId, GuildId};
|
use serenity::model::id::{ChannelId, GuildId};
|
||||||
|
@ -7,7 +9,7 @@ use serenity::voice::{AudioSource, Handler, LockedAudio};
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
use std::sync::Arc;
|
use std::sync::{Arc, Mutex, MutexGuard};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time;
|
use std::time;
|
||||||
|
|
||||||
|
@ -27,7 +29,7 @@ pub struct Song {
|
||||||
|
|
||||||
pub struct MediaData {
|
pub struct MediaData {
|
||||||
playlist: RefCell<Vec<Song>>,
|
playlist: RefCell<Vec<Song>>,
|
||||||
current_song: RefCell<Option<LockedAudio>>,
|
current_song: Mutex<RefCell<Option<LockedAudio>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn guild_id(channel_id: ChannelId) -> Option<GuildId> {
|
fn guild_id(channel_id: ChannelId) -> Option<GuildId> {
|
||||||
|
@ -51,6 +53,10 @@ fn handler<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MediaData {
|
impl MediaData {
|
||||||
|
fn song_mut(&self) -> MutexGuard<RefCell<Option<LockedAudio>>> {
|
||||||
|
self.current_song.lock().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
fn start_thread(
|
fn start_thread(
|
||||||
media: &Arc<MediaData>,
|
media: &Arc<MediaData>,
|
||||||
channel_id: ChannelId,
|
channel_id: ChannelId,
|
||||||
|
@ -62,7 +68,9 @@ impl MediaData {
|
||||||
let manager_clone = manager_lock.clone();
|
let manager_clone = manager_lock.clone();
|
||||||
|
|
||||||
thread::spawn(move || loop {
|
thread::spawn(move || loop {
|
||||||
let mut borrow = media_clone.current_song.borrow_mut();
|
{
|
||||||
|
let song_lock = media_clone.song_mut();
|
||||||
|
let mut borrow = song_lock.borrow_mut();
|
||||||
|
|
||||||
if let Some(ref mut song) = borrow.deref_mut() {
|
if let Some(ref mut song) = borrow.deref_mut() {
|
||||||
let song_lock = song.clone();
|
let song_lock = song.clone();
|
||||||
|
@ -79,6 +87,8 @@ impl MediaData {
|
||||||
.lock()
|
.lock()
|
||||||
.remove(check_option!(guild_id(channel_id)));
|
.remove(check_option!(guild_id(channel_id)));
|
||||||
|
|
||||||
|
println!("left channel");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,7 +101,9 @@ impl MediaData {
|
||||||
if !playlist.is_empty() {
|
if !playlist.is_empty() {
|
||||||
let mut manager = manager_clone.lock();
|
let mut manager = manager_clone.lock();
|
||||||
|
|
||||||
if let Some(handler) = handler(check_option!(guild_id(channel_id)), &mut manager) {
|
if let Some(handler) =
|
||||||
|
handler(check_option!(guild_id(channel_id)), &mut manager)
|
||||||
|
{
|
||||||
let first = playlist.remove(0);
|
let first = playlist.remove(0);
|
||||||
|
|
||||||
*borrow = Some(handler.play_returning(first.source));
|
*borrow = Some(handler.play_returning(first.source));
|
||||||
|
@ -101,12 +113,21 @@ impl MediaData {
|
||||||
super::youtube::convert_file_name(first.name)
|
super::youtube::convert_file_name(first.name)
|
||||||
)));
|
)));
|
||||||
} else {
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
manager_clone
|
||||||
|
.lock()
|
||||||
|
.remove(check_option!(guild_id(channel_id)));
|
||||||
|
|
||||||
|
println!("left channel");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let two_sec = time::Duration::new(2, 0);
|
let five_sec = time::Duration::from_secs(5);
|
||||||
thread::sleep(two_sec);
|
thread::sleep(five_sec);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +171,7 @@ impl Default for MediaData {
|
||||||
fn default() -> MediaData {
|
fn default() -> MediaData {
|
||||||
MediaData {
|
MediaData {
|
||||||
playlist: RefCell::new(Vec::new()),
|
playlist: RefCell::new(Vec::new()),
|
||||||
current_song: RefCell::new(None),
|
current_song: Mutex::new(RefCell::new(None)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,6 +187,54 @@ impl Play {
|
||||||
pub fn new(media_data: Arc<MediaData>) -> Play {
|
pub fn new(media_data: Arc<MediaData>) -> Play {
|
||||||
Play { media: media_data }
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl serenity::framework::standard::Command for Play {
|
impl serenity::framework::standard::Command for Play {
|
||||||
|
@ -177,25 +246,23 @@ impl serenity::framework::standard::Command for Play {
|
||||||
mut args: serenity::framework::standard::Args,
|
mut args: serenity::framework::standard::Args,
|
||||||
) -> ::std::result::Result<(), serenity::framework::standard::CommandError> {
|
) -> ::std::result::Result<(), serenity::framework::standard::CommandError> {
|
||||||
let url = match args.single::<String>() {
|
let url = match args.single::<String>() {
|
||||||
Ok(url) => url,
|
Ok(url) => {
|
||||||
Err(_) => {
|
|
||||||
super::check_msg(msg.channel_id.say("Must provide a URL to a video or audio"));
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if !url.starts_with("http") {
|
if !url.starts_with("http") {
|
||||||
super::check_msg(msg.channel_id.say("Must provide a valid URL"));
|
super::check_msg(msg.channel_id.say("Must provide a valid URL"));
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut manager_lock = ctx.data
|
url
|
||||||
.lock()
|
}
|
||||||
.get::<super::VoiceManager>()
|
Err(_) => {
|
||||||
.cloned()
|
if !Self::check_for_continue(self.media.song_mut()) {
|
||||||
.unwrap();
|
super::check_msg(msg.channel_id.say("Must provide a URL to a video or audio"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let mut source = match super::youtube::youtube_dl(&url) {
|
let mut source = match super::youtube::youtube_dl(&url) {
|
||||||
Ok(source) => source,
|
Ok(source) => source,
|
||||||
|
@ -210,6 +277,14 @@ impl serenity::framework::standard::Command for Play {
|
||||||
|
|
||||||
self.media.playlist.borrow_mut().append(&mut source);
|
self.media.playlist.borrow_mut().append(&mut source);
|
||||||
|
|
||||||
|
let mut manager_lock = ctx.data
|
||||||
|
.lock()
|
||||||
|
.get::<super::VoiceManager>()
|
||||||
|
.cloned()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Self::check_join_channel(&manager_lock, msg);
|
||||||
|
|
||||||
MediaData::start_thread(&self.media, msg.channel_id, &manager_lock);
|
MediaData::start_thread(&self.media, msg.channel_id, &manager_lock);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -234,7 +309,9 @@ impl serenity::framework::standard::Command for Pause {
|
||||||
_: &serenity::model::channel::Message,
|
_: &serenity::model::channel::Message,
|
||||||
_: serenity::framework::standard::Args,
|
_: serenity::framework::standard::Args,
|
||||||
) -> ::std::result::Result<(), serenity::framework::standard::CommandError> {
|
) -> ::std::result::Result<(), serenity::framework::standard::CommandError> {
|
||||||
if let Some(song) = self.media.current_song.borrow_mut().deref_mut() {
|
let song_lock = self.media.song_mut();
|
||||||
|
|
||||||
|
if let Some(song) = song_lock.borrow_mut().deref_mut() {
|
||||||
let song_clone = song.clone();
|
let song_clone = song.clone();
|
||||||
let mut audio_lock = song_clone.lock();
|
let mut audio_lock = song_clone.lock();
|
||||||
|
|
||||||
|
@ -244,3 +321,129 @@ impl serenity::framework::standard::Command for Pause {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct List {
|
||||||
|
media: Arc<MediaData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl List {
|
||||||
|
pub fn new(media_data: Arc<MediaData>) -> List {
|
||||||
|
List { media: media_data }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl serenity::framework::standard::Command for List {
|
||||||
|
#[allow(unreachable_code, unused_mut)]
|
||||||
|
fn execute(
|
||||||
|
&self,
|
||||||
|
_: &mut serenity::client::Context,
|
||||||
|
msg: &serenity::model::channel::Message,
|
||||||
|
_: serenity::framework::standard::Args,
|
||||||
|
) -> ::std::result::Result<(), serenity::framework::standard::CommandError> {
|
||||||
|
let mut output = String::new();
|
||||||
|
|
||||||
|
let playlist = self.media.playlist.borrow();
|
||||||
|
|
||||||
|
output += &format!(
|
||||||
|
"{} {} queued\n",
|
||||||
|
playlist.len(),
|
||||||
|
if playlist.len() == 1 { "song" } else { "songs" }
|
||||||
|
);
|
||||||
|
|
||||||
|
for (i, song) in playlist.iter().enumerate() {
|
||||||
|
output += &format!("\t{}.\t{}\n", i + 1, convert_file_name(song.name.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
super::check_msg(msg.channel_id.say(output));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Help {
|
||||||
|
prefix: String,
|
||||||
|
commands: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Help {
|
||||||
|
pub fn new(prefix: &String, commands: Vec<String>) -> Help {
|
||||||
|
Help {
|
||||||
|
prefix: prefix.clone(),
|
||||||
|
commands: commands,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl serenity::framework::standard::Command for Help {
|
||||||
|
#[allow(unreachable_code, unused_mut)]
|
||||||
|
fn execute(
|
||||||
|
&self,
|
||||||
|
_: &mut serenity::client::Context,
|
||||||
|
msg: &serenity::model::channel::Message,
|
||||||
|
_: serenity::framework::standard::Args,
|
||||||
|
) -> ::std::result::Result<(), serenity::framework::standard::CommandError> {
|
||||||
|
let mut output = String::new();
|
||||||
|
|
||||||
|
output += "Available commands:\n";
|
||||||
|
|
||||||
|
for command in &self.commands {
|
||||||
|
output += &format!("\t{}{}\n", self.prefix, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
super::check_msg(msg.channel_id.say(output));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Stop {
|
||||||
|
media: Arc<MediaData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stop {
|
||||||
|
pub fn new(media_data: Arc<MediaData>) -> Stop {
|
||||||
|
Stop { media: media_data }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl serenity::framework::standard::Command for Stop {
|
||||||
|
#[allow(unreachable_code, unused_mut)]
|
||||||
|
fn execute(
|
||||||
|
&self,
|
||||||
|
ctx: &mut serenity::client::Context,
|
||||||
|
msg: &serenity::model::channel::Message,
|
||||||
|
_: serenity::framework::standard::Args,
|
||||||
|
) -> ::std::result::Result<(), serenity::framework::standard::CommandError> {
|
||||||
|
self.media.playlist.borrow_mut().clear();
|
||||||
|
|
||||||
|
{
|
||||||
|
let song = self.media.song_mut();
|
||||||
|
*song.borrow_mut() = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut manager_lock = ctx.data
|
||||||
|
.lock()
|
||||||
|
.get::<super::VoiceManager>()
|
||||||
|
.cloned()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut manager = manager_lock.lock();
|
||||||
|
let guild_id = match guild_id(msg.channel_id) {
|
||||||
|
Some(guild_id) => guild_id,
|
||||||
|
None => return Ok(()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let handler = match handler(guild_id, &mut manager) {
|
||||||
|
Some(handler) => handler,
|
||||||
|
None => return Ok(()),
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("stopped handler");
|
||||||
|
|
||||||
|
handler.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -60,13 +60,6 @@ fn convert_output(out: &Output) -> Result<Vec<String>, String> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_output(out: &Output) {
|
|
||||||
match from_utf8(out.stdout.as_slice()) {
|
|
||||||
Ok(string) => println!("value: {}", string),
|
|
||||||
Err(_) => println!("error converting output"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn youtube_dl(uri: &str) -> Result<Vec<Song>, String> {
|
pub fn youtube_dl(uri: &str) -> Result<Vec<Song>, String> {
|
||||||
let args = ["-f", "webm[abr>0]/bestaudio/best", uri];
|
let args = ["-f", "webm[abr>0]/bestaudio/best", uri];
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue