Connect and play works again
This commit is contained in:
parent
f89c8706eb
commit
53798b050d
18 changed files with 165 additions and 550 deletions
|
@ -7,8 +7,8 @@ authors = ["hodasemi <michaelh.95@t-online.de>"]
|
|||
[dependencies]
|
||||
typemap = "~0.3"
|
||||
serde_json = "*"
|
||||
rand = "0.6"
|
||||
utilities = { git = "http://dimov.cloud/hodasemi/utilities" }
|
||||
rusqlite = { version = "*", features = ["bundled"] }
|
||||
serenity = { version = "0.6", default-features = false, features = [ "builder", "cache", "client", "framework", "gateway", "model", "standard_framework", "utils", "voice", "rustls_backend"]}
|
||||
lock_api = "0.2.0"
|
||||
serenity = { version = "0.7", default-features = false, features = [ "builder", "cache", "client", "framework", "gateway", "model", "standard_framework", "utils", "voice", "rustls_backend"]}
|
||||
parking_lot = "*"
|
||||
failure = "*"
|
||||
|
|
BIN
Penis1
BIN
Penis1
Binary file not shown.
|
@ -1,204 +0,0 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use std::fmt::Display;
|
||||
use std::fs::File;
|
||||
use std::io::{BufRead, BufReader, Write};
|
||||
use std::str::FromStr;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Value {
|
||||
Value(String),
|
||||
Array(Vec<String>),
|
||||
}
|
||||
|
||||
struct ConfigSection {
|
||||
header: String,
|
||||
body: HashMap<String, Value>,
|
||||
}
|
||||
|
||||
impl Value {
|
||||
pub fn empty() -> Value {
|
||||
Value::Value("".to_string())
|
||||
}
|
||||
|
||||
pub fn value<T>(value: &T) -> Value
|
||||
where
|
||||
T: Display,
|
||||
{
|
||||
Value::Value(format!("{}", value))
|
||||
}
|
||||
|
||||
pub fn array<T>(array: &Vec<T>) -> Value
|
||||
where
|
||||
T: Display,
|
||||
{
|
||||
Value::Array(array.iter().map(|v| format!("{}", v)).collect())
|
||||
}
|
||||
|
||||
pub fn set_value<T>(&self, value: &mut T) -> Result<(), String>
|
||||
where
|
||||
T: FromStr,
|
||||
{
|
||||
match self {
|
||||
Value::Value(value_string) => match value_string.parse::<T>() {
|
||||
Ok(val) => *value = val,
|
||||
Err(_) => return Err(format!("error parsing value {}", value_string)),
|
||||
},
|
||||
_ => return Err("key_value has wrong format".to_string()),
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_array<T>(&self, array: &mut Vec<T>) -> Result<(), String>
|
||||
where
|
||||
T: FromStr,
|
||||
{
|
||||
match self {
|
||||
Value::Array(value_array) => {
|
||||
for value_string in value_array {
|
||||
match value_string.parse::<T>() {
|
||||
Ok(val) => array.push(val),
|
||||
Err(_) => return Err(format!("error parsing value {}", value_string)),
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => return Err("key_value has wrong format".to_string()),
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_config(file_name: &str) -> Result<HashMap<String, HashMap<String, Value>>, String> {
|
||||
let file = match File::open(file_name) {
|
||||
Ok(file) => file,
|
||||
Err(msg) => return Err(format!("error opening config file({}): {}", file_name, msg)),
|
||||
};
|
||||
|
||||
let mut infos = HashMap::new();
|
||||
let mut current_section: Option<ConfigSection> = None;
|
||||
|
||||
for line_res in BufReader::new(file).lines() {
|
||||
if let Ok(line) = line_res {
|
||||
let mut trimmed = line.trim().to_string();
|
||||
|
||||
if trimmed.starts_with("#") || trimmed.is_empty() {
|
||||
continue;
|
||||
} else if trimmed.starts_with("[") && trimmed.ends_with("]") {
|
||||
trimmed.remove(0);
|
||||
trimmed.pop();
|
||||
|
||||
if let Some(ref section) = current_section {
|
||||
infos.insert(section.header.clone(), section.body.clone());
|
||||
}
|
||||
|
||||
current_section = Some(ConfigSection {
|
||||
header: trimmed,
|
||||
body: HashMap::new(),
|
||||
});
|
||||
} else {
|
||||
let mut split = trimmed.split("=");
|
||||
|
||||
let key = match split.nth(0) {
|
||||
Some(key) => key.trim().to_string(),
|
||||
None => {
|
||||
println!("cannot get key from line: {}", trimmed);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let value = match split.last() {
|
||||
Some(value) => value.trim().to_string(),
|
||||
None => {
|
||||
println!("cannot get value from line: {}", trimmed);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
if value.starts_with("[") && value.ends_with("]") {
|
||||
let mut trimmed_value = value;
|
||||
trimmed_value.remove(0);
|
||||
trimmed_value.pop();
|
||||
|
||||
let value_split = trimmed_value.split(";");
|
||||
let value_array = value_split.map(|v| v.trim().to_string()).collect();
|
||||
|
||||
if let Some(ref mut section) = current_section {
|
||||
section.body.insert(key, Value::Array(value_array));
|
||||
}
|
||||
} else {
|
||||
if let Some(ref mut section) = current_section {
|
||||
section.body.insert(key, Value::Value(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// also push the last section
|
||||
if let Some(section) = current_section {
|
||||
infos.insert(section.header, section.body);
|
||||
}
|
||||
|
||||
Ok(infos)
|
||||
}
|
||||
|
||||
pub fn write_config(
|
||||
file_name: &str,
|
||||
sections: &Vec<(String, Vec<(String, Value)>)>,
|
||||
) -> Result<(), String> {
|
||||
let mut file = match File::create(file_name) {
|
||||
Ok(file) => file,
|
||||
Err(msg) => {
|
||||
return Err(format!(
|
||||
"error creating config file({}): {}",
|
||||
file_name, msg
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
for (header, body) in sections {
|
||||
let fmt_header = format!("[{}]\n", header);
|
||||
|
||||
if let Err(_) = file.write_all(fmt_header.as_bytes()) {
|
||||
return Err(format!("failed writing section: {}", fmt_header));
|
||||
}
|
||||
|
||||
for (key, value) in body {
|
||||
let fmt_key_value = format!(
|
||||
"{} = {}\n",
|
||||
key,
|
||||
match value {
|
||||
Value::Value(val) => val.clone(),
|
||||
Value::Array(array) => {
|
||||
let mut array_value = "[".to_string();
|
||||
|
||||
for (i, val) in array.iter().enumerate() {
|
||||
// if element is not the last one
|
||||
if i != array.len() - 1 {
|
||||
array_value = format!("{}{}, ", array_value, val);
|
||||
} else {
|
||||
array_value = format!("{}{}", array_value, val);
|
||||
}
|
||||
}
|
||||
|
||||
format!("{}]", array_value)
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if let Err(_) = file.write_all(fmt_key_value.as_bytes()) {
|
||||
return Err(format!("failed writing key value: {}", fmt_key_value));
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(_) = file.write_all("\n".as_bytes()) {
|
||||
return Err("failed writing new line".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
#![macro_use]
|
||||
|
||||
/// check result macro, where the Ok() is the type which should be returned
|
||||
#[macro_export]
|
||||
macro_rules! check_result {
|
||||
($v:expr) => {
|
||||
match $v {
|
||||
Ok(t) => t,
|
||||
Err(msg) => return Err(msg),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// check result macro, where the Ok() is the type which should be returned, else print error and return
|
||||
#[macro_export]
|
||||
macro_rules! check_result_return {
|
||||
($v:expr) => {
|
||||
match $v {
|
||||
Ok(t) => t,
|
||||
Err(msg) => {
|
||||
println!("{}", msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// check result macro, where the Ok() is the type which should be returned, else print error and return
|
||||
#[macro_export]
|
||||
macro_rules! check_result_return_ok {
|
||||
($v:expr) => {
|
||||
match $v {
|
||||
Ok(t) => t,
|
||||
Err(msg) => {
|
||||
println!("{}", msg);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// check result macro, where the Ok() is void
|
||||
#[macro_export]
|
||||
macro_rules! check_error {
|
||||
($v:expr) => {
|
||||
if let Err(msg) = $v {
|
||||
return Err(msg);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/// check result macro, where the Ok() is void, but just print the error message
|
||||
#[macro_export]
|
||||
macro_rules! display_error {
|
||||
($v:expr) => {
|
||||
if let Err(msg) = $v {
|
||||
println!("{}", msg);
|
||||
return;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/// check result macro, where the Ok() is void, but just print the error message
|
||||
#[macro_export]
|
||||
macro_rules! display_error_ok {
|
||||
($v:expr) => {
|
||||
if let Err(msg) = $v {
|
||||
println!("{}", msg);
|
||||
return Ok(());
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! print_error {
|
||||
($v:expr) => {
|
||||
if let Err(msg) = $v {
|
||||
println!("{}", msg);
|
||||
};
|
||||
};
|
||||
}
|
31
src/main.rs
31
src/main.rs
|
@ -3,12 +3,9 @@
|
|||
extern crate serenity;
|
||||
|
||||
extern crate parking_lot;
|
||||
extern crate rand;
|
||||
extern crate serde_json;
|
||||
extern crate typemap;
|
||||
|
||||
mod confighandler;
|
||||
mod macros;
|
||||
mod player;
|
||||
|
||||
use serenity::{
|
||||
|
@ -31,10 +28,11 @@ use serenity::prelude::*;
|
|||
|
||||
use std::sync::Arc;
|
||||
|
||||
use confighandler::*;
|
||||
use player::prelude::*;
|
||||
use std::collections::HashSet;
|
||||
|
||||
use utilities::prelude::*;
|
||||
|
||||
struct Config {
|
||||
token: String,
|
||||
prefix: String,
|
||||
|
@ -55,9 +53,9 @@ group!({
|
|||
commands: [ip, list, pause, play, remove, skip, stop]
|
||||
});
|
||||
|
||||
fn main() {
|
||||
fn main() -> VerboseResult<()> {
|
||||
// read config file
|
||||
let config_file = check_result_return!(read_config("bot.conf"));
|
||||
let config_file = ConfigHandler::read_config("bot.conf")?;
|
||||
|
||||
let mut config = Config::default();
|
||||
|
||||
|
@ -65,26 +63,23 @@ fn main() {
|
|||
Some(info) => {
|
||||
match info.get("token") {
|
||||
Some(token_pair) => {
|
||||
display_error!(token_pair.set_value(&mut config.token));
|
||||
token_pair.set_value(&mut config.token)?;
|
||||
}
|
||||
None => {
|
||||
println!("couldn't find token inside meta section");
|
||||
return;
|
||||
create_error!("couldn't find token inside meta section");
|
||||
}
|
||||
}
|
||||
match info.get("prefix") {
|
||||
Some(prefix_pair) => {
|
||||
display_error!(prefix_pair.set_value(&mut config.prefix));
|
||||
prefix_pair.set_value(&mut config.prefix)?;
|
||||
}
|
||||
None => {
|
||||
println!("couldn't find prefix inside meta section");
|
||||
return;
|
||||
create_error!("couldn't find prefix inside meta section");
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
println!("couldn't find Meta section in config file");
|
||||
return;
|
||||
create_error!("couldn't find Meta section in config file");
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -95,8 +90,10 @@ fn main() {
|
|||
// event handlers and framework commands.
|
||||
{
|
||||
let mut data = client.data.write();
|
||||
data.insert::<VoiceManager>(Arc::clone(&client.voice_manager));
|
||||
data.insert::<Media>(MediaData::new("Penis1").expect("failed to create media data handle"));
|
||||
data.insert::<Media>(
|
||||
MediaData::new("Penis1", Arc::clone(&client.voice_manager))
|
||||
.expect("failed to create media data handle"),
|
||||
);
|
||||
}
|
||||
|
||||
// We will fetch your bot's owners and id
|
||||
|
@ -161,4 +158,6 @@ fn main() {
|
|||
let _ = client
|
||||
.start()
|
||||
.map_err(|why| println!("Client ended: {:?}", why));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -27,8 +27,8 @@ fn ip(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult {
|
|||
}
|
||||
|
||||
match from_utf8(out.stdout.as_slice()) {
|
||||
Ok(string) => print_error!(msg.author.direct_message(&ctx, |m| m.content(string))),
|
||||
Err(_) => print_error!(msg.channel_id.say(&ctx.http, "error getting IP string")),
|
||||
Ok(string) => msg.author.direct_message(&ctx, |m| m.content(string))?,
|
||||
Err(_) => msg.channel_id.say(&ctx.http, "error getting IP string")?,
|
||||
};
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -8,11 +8,8 @@ use serenity::{
|
|||
|
||||
#[command]
|
||||
fn list(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult {
|
||||
if !channel_contains_author(ctx, msg) {
|
||||
println!(
|
||||
"user {} is not in the same voice channel as the bot",
|
||||
msg.author.name
|
||||
);
|
||||
if let Err(err) = channel_contains_author(ctx, msg) {
|
||||
msg.channel_id.say(&ctx.http, err)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
@ -22,7 +19,7 @@ fn list(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult {
|
|||
let media = match data.get::<Media>() {
|
||||
Some(media) => media,
|
||||
None => {
|
||||
display_error_ok!(msg.channel_id.say(&ctx.http, "could not find media data"));
|
||||
msg.channel_id.say(&ctx.http, "could not find media data")?;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
@ -46,7 +43,7 @@ fn list(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult {
|
|||
}
|
||||
}
|
||||
|
||||
print_error!(msg.channel_id.say(&ctx.http, output));
|
||||
msg.channel_id.say(&ctx.http, output)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -10,11 +10,8 @@ use serenity::{
|
|||
|
||||
#[command]
|
||||
fn pause(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult {
|
||||
if !channel_contains_author(ctx, msg) {
|
||||
println!(
|
||||
"user {} is not in the same voice channel as the bot",
|
||||
msg.author.name
|
||||
);
|
||||
if let Err(err) = channel_contains_author(ctx, msg) {
|
||||
msg.channel_id.say(&ctx.http, err)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
@ -22,7 +19,7 @@ fn pause(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult {
|
|||
let media = match data.get::<Media>() {
|
||||
Some(media) => media,
|
||||
None => {
|
||||
display_error_ok!(msg.channel_id.say(&ctx.http, "could not find media data"));
|
||||
msg.channel_id.say(&ctx.http, "could not find media data")?;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
use lock_api::RawMutex;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
|
||||
use super::super::prelude::*;
|
||||
|
||||
use rusqlite::params;
|
||||
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
|
||||
use serenity::prelude::*;
|
||||
use serenity::voice::LockedAudio;
|
||||
use serenity::{
|
||||
|
@ -15,13 +11,12 @@ use serenity::{
|
|||
model::channel::Message,
|
||||
};
|
||||
|
||||
use utilities::prelude::*;
|
||||
|
||||
#[command]
|
||||
fn play(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||
if !channel_contains_author(ctx, msg) {
|
||||
println!(
|
||||
"user {} is not in the same voice channel as the bot",
|
||||
msg.author.name
|
||||
);
|
||||
if let Err(err) = channel_contains_author(ctx, msg) {
|
||||
msg.channel_id.say(&ctx.http, err)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
@ -29,33 +24,32 @@ fn play(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult {
|
|||
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"));
|
||||
msg.channel_id.say(&ctx.http, "could not find media data")?;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
if args.len() == 0 {
|
||||
if !check_for_continue(media.song_mut()) {
|
||||
print_error!(msg
|
||||
.channel_id
|
||||
.say(&ctx.http, "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" {
|
||||
handle_local_request(media, ctx, msg)?;
|
||||
} else if arg.starts_with("http") {
|
||||
handle_http_request(media, ctx, msg, &arg)?;
|
||||
} else {
|
||||
handle_song_request(media, ctx, msg, &arg)?;
|
||||
msg.channel_id
|
||||
.say(&ctx.http, "Must provide a URL to a video or audio")?;
|
||||
}
|
||||
} else {
|
||||
print_error!(msg.channel_id.say(&ctx.http, "Unsupported argument list"));
|
||||
let first_arg = args.current().unwrap();
|
||||
|
||||
if first_arg == "--local" {
|
||||
handle_local_request(media, ctx, msg)?;
|
||||
} else if first_arg.starts_with("http") {
|
||||
handle_http_request(media, ctx, msg, first_arg)?;
|
||||
} else {
|
||||
let mut arg_list = String::new();
|
||||
|
||||
for arg in args.iter::<String>() {
|
||||
arg_list += &format!(" {}", arg?.trim());
|
||||
}
|
||||
|
||||
handle_song_request(media, ctx, msg, &arg_list)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -74,63 +68,15 @@ fn check_for_continue(song_lock: &Option<LockedAudio>) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_join_channel<T: RawMutex>(
|
||||
manager_lock: &Arc<lock_api::Mutex<T, serenity::client::bridge::voice::ClientVoiceManager>>,
|
||||
ctx: &Context,
|
||||
msg: &Message,
|
||||
) {
|
||||
let guild = check_result_return!(guild(ctx, msg));
|
||||
let guild_id = check_result_return!(guild_id(ctx, msg));
|
||||
|
||||
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(ctx, "Not in a voice channel"));
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let mut manager = manager_lock.lock();
|
||||
manager.join(guild_id, connect_to);
|
||||
}
|
||||
|
||||
fn append_songs(
|
||||
media: &mut MediaData,
|
||||
ctx: &Context,
|
||||
msg: &Message,
|
||||
mut source: Vec<Song>,
|
||||
) -> Result<(), String> {
|
||||
) -> VerboseResult<()> {
|
||||
media.playlist_mut().append(&mut source);
|
||||
|
||||
if let Some(manager_lock) = ctx.data.read().get::<VoiceManager>().cloned() {
|
||||
check_join_channel(&manager_lock, ctx, msg);
|
||||
|
||||
// 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);
|
||||
}
|
||||
MediaData::start_playing(ctx, media, msg)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -139,8 +85,8 @@ fn handle_http_request(
|
|||
media: &mut MediaData,
|
||||
ctx: &serenity::client::Context,
|
||||
msg: &serenity::model::channel::Message,
|
||||
url: &String,
|
||||
) -> Result<(), String> {
|
||||
url: &str,
|
||||
) -> VerboseResult<()> {
|
||||
let mut names = Vec::new();
|
||||
|
||||
{
|
||||
|
@ -148,18 +94,18 @@ fn handle_http_request(
|
|||
|
||||
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()),
|
||||
Err(_) => create_error!("failed preparing data base access"),
|
||||
};
|
||||
|
||||
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()),
|
||||
Err(_) => create_error!("failed querying rows"),
|
||||
};
|
||||
|
||||
for name_result in rows {
|
||||
let name = match name_result {
|
||||
Ok(name) => name,
|
||||
Err(_) => return Err("failed getting name from row".to_string()),
|
||||
Err(_) => create_error!("failed getting name from row"),
|
||||
};
|
||||
|
||||
names.push(name);
|
||||
|
@ -167,7 +113,9 @@ fn handle_http_request(
|
|||
}
|
||||
|
||||
if names.len() > 0 {
|
||||
print_error!(msg.channel_id.say(&ctx.http, "song already loaded!"));
|
||||
msg.channel_id
|
||||
.say(&ctx.http, "song already loaded!")
|
||||
.map_err(|err| format!("{}", err))?;
|
||||
|
||||
append_songs(
|
||||
media,
|
||||
|
@ -181,9 +129,9 @@ fn handle_http_request(
|
|||
Err(why) => {
|
||||
println!("Err starting source: {:?}", why);
|
||||
|
||||
print_error!(msg
|
||||
.channel_id
|
||||
.say(&ctx.http, format!("Error using youtube-dl: {}", why)));
|
||||
msg.channel_id
|
||||
.say(&ctx.http, format!("Error using youtube-dl: {}", why))
|
||||
.map_err(|err| format!("{}", err))?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -209,12 +157,14 @@ fn handle_http_request(
|
|||
)
|
||||
.is_err()
|
||||
{
|
||||
return Err("failed inserting songs into db".to_string());
|
||||
create_error!("failed inserting songs into db");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print_error!(msg.channel_id.say(&ctx.http, info));
|
||||
msg.channel_id
|
||||
.say(&ctx.http, info)
|
||||
.map_err(|err| format!("{}", err))?;
|
||||
|
||||
append_songs(media, ctx, msg, source)?;
|
||||
}
|
||||
|
@ -226,7 +176,7 @@ fn handle_local_request(
|
|||
media: &mut MediaData,
|
||||
ctx: &serenity::client::Context,
|
||||
msg: &serenity::model::channel::Message,
|
||||
) -> Result<(), String> {
|
||||
) -> VerboseResult<()> {
|
||||
let mut songs = Vec::new();
|
||||
|
||||
{
|
||||
|
@ -234,18 +184,18 @@ fn handle_local_request(
|
|||
|
||||
let mut stmt = match sql.prepare("SELECT name FROM Vulva3") {
|
||||
Ok(statement) => statement,
|
||||
Err(_) => return Err("failed preparing data base access".to_string()),
|
||||
Err(_) => create_error!("failed preparing data base access"),
|
||||
};
|
||||
|
||||
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()),
|
||||
Err(_) => create_error!("failed querying rows"),
|
||||
};
|
||||
|
||||
for name_result in rows {
|
||||
let name = match name_result {
|
||||
Ok(name) => name,
|
||||
Err(_) => return Err("failed getting name from row".to_string()),
|
||||
Err(_) => create_error!("failed getting name from row"),
|
||||
};
|
||||
|
||||
songs.push(Song { name });
|
||||
|
@ -265,7 +215,7 @@ fn handle_song_request(
|
|||
ctx: &serenity::client::Context,
|
||||
msg: &serenity::model::channel::Message,
|
||||
pattern: &str,
|
||||
) -> Result<(), String> {
|
||||
) -> VerboseResult<()> {
|
||||
let mut songs = Vec::new();
|
||||
|
||||
{
|
||||
|
@ -276,18 +226,18 @@ fn handle_song_request(
|
|||
pattern
|
||||
)) {
|
||||
Ok(statement) => statement,
|
||||
Err(_) => return Err("failed preparing data base access".to_string()),
|
||||
Err(_) => create_error!("failed preparing data base access"),
|
||||
};
|
||||
|
||||
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()),
|
||||
Err(_) => create_error!("failed querying rows"),
|
||||
};
|
||||
|
||||
for name_result in rows {
|
||||
let name = match name_result {
|
||||
Ok(name) => name,
|
||||
Err(_) => return Err("failed getting name from row".to_string()),
|
||||
Err(_) => create_error!("failed getting name from row"),
|
||||
};
|
||||
|
||||
songs.push(Song { name });
|
||||
|
@ -300,9 +250,9 @@ fn handle_song_request(
|
|||
|
||||
append_songs(media, ctx, msg, songs)?;
|
||||
} else {
|
||||
print_error!(msg
|
||||
.channel_id
|
||||
.say(&ctx.http, format!("no song found with pattern {}", pattern)));
|
||||
msg.channel_id
|
||||
.say(&ctx.http, format!("no song found with pattern {}", pattern))
|
||||
.map_err(|err| format!("{}", err))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -18,7 +18,7 @@ fn remove(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult {
|
|||
let media = match data.get::<Media>() {
|
||||
Some(media) => media,
|
||||
None => {
|
||||
display_error_ok!(msg.channel_id.say(&ctx.http, "could not find media data"));
|
||||
msg.channel_id.say(&ctx.http, "could not find media data")?;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
@ -34,14 +34,14 @@ fn remove(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult {
|
|||
|
||||
if !song_name.is_empty() {
|
||||
match fs::remove_file(&song_name) {
|
||||
Ok(_) => print_error!(msg.channel_id.say(
|
||||
Ok(_) => msg.channel_id.say(
|
||||
&ctx.http,
|
||||
format!("Remove current song ({}) from local disk", song_name)
|
||||
)),
|
||||
Err(err) => print_error!(msg.channel_id.say(
|
||||
format!("Remove current song ({}) from local disk", song_name),
|
||||
)?,
|
||||
Err(err) => msg.channel_id.say(
|
||||
&ctx.http,
|
||||
format!("Error removing file ({}): {:?}", song_name, err.kind())
|
||||
)),
|
||||
format!("Error removing file ({}): {:?}", song_name, err.kind()),
|
||||
)?,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -11,35 +11,24 @@ use serenity::{
|
|||
|
||||
#[command]
|
||||
fn skip(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult {
|
||||
if !channel_contains_author(ctx, msg) {
|
||||
println!(
|
||||
"user {} is not in the same voice channel as the bot",
|
||||
msg.author.name
|
||||
);
|
||||
if let Err(err) = channel_contains_author(ctx, msg) {
|
||||
msg.channel_id.say(&ctx.http, err)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut data = ctx.data.write();
|
||||
|
||||
if let Some(manager_lock) = data.get_mut::<VoiceManager>().cloned() {
|
||||
let mut manager = manager_lock.lock();
|
||||
if let Some(media) = data.get_mut::<Media>() {
|
||||
let voice_manager = media.voice_manager.clone();
|
||||
let mut manager = voice_manager.lock();
|
||||
|
||||
let guild_id = check_result_return_ok!(guild_id(ctx, msg));
|
||||
let guild_id = guild_id(ctx, msg)?;
|
||||
|
||||
if let Some(handler) = handler(guild_id, &mut manager) {
|
||||
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"));
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
// if current song is the last song in this playlist, just return
|
||||
if media.playlist().is_empty() {
|
||||
print_error!(msg
|
||||
.channel_id
|
||||
.say(&ctx.http, "playlist is empty, no next song available"));
|
||||
msg.channel_id
|
||||
.say(&ctx.http, "playlist is empty, no next song available")?;
|
||||
|
||||
return Ok(());
|
||||
} else {
|
||||
|
@ -78,10 +67,10 @@ fn skip(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult {
|
|||
*media.song_mut() = Some(handler.play_returning(source));
|
||||
*media.song_name_mut() = first.name.clone();
|
||||
|
||||
print_error!(msg.channel_id.say(
|
||||
msg.channel_id.say(
|
||||
&ctx.http,
|
||||
format!("Skipped current song, now playing: {}", first.name)
|
||||
));
|
||||
format!("Skipped current song, now playing: {}", first.name),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,11 +8,8 @@ use serenity::{
|
|||
|
||||
#[command]
|
||||
fn stop(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult {
|
||||
if !channel_contains_author(ctx, msg) {
|
||||
println!(
|
||||
"user {} is not in the same voice channel as the bot",
|
||||
msg.author.name
|
||||
);
|
||||
if let Err(err) = channel_contains_author(ctx, msg) {
|
||||
msg.channel_id.say(&ctx.http, err)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
@ -20,12 +17,12 @@ fn stop(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult {
|
|||
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"));
|
||||
msg.channel_id.say(&ctx.http, "could not find media data")?;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
print_error!(media.reset(ctx, msg));
|
||||
media.reset(ctx, msg)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -4,12 +4,16 @@ use serenity::prelude::*;
|
|||
use serenity::voice::ffmpeg;
|
||||
use serenity::voice::LockedAudio;
|
||||
|
||||
use serenity::client::bridge::voice::ClientVoiceManager;
|
||||
use serenity::prelude::Mutex;
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::prelude::*;
|
||||
|
||||
use rusqlite::{params, Connection};
|
||||
|
||||
use utilities::prelude::*;
|
||||
|
||||
pub struct Song {
|
||||
pub name: String,
|
||||
}
|
||||
|
@ -18,13 +22,18 @@ pub struct MediaData {
|
|||
playlist: Vec<Song>,
|
||||
current_song: Option<LockedAudio>,
|
||||
song_name: String,
|
||||
pub next_callback: Option<Arc<Fn() -> ()>>,
|
||||
pub next_callback: Option<Arc<dyn Fn() -> ()>>,
|
||||
|
||||
sql_data_base: Connection,
|
||||
|
||||
pub voice_manager: Arc<Mutex<ClientVoiceManager>>,
|
||||
}
|
||||
|
||||
impl MediaData {
|
||||
pub fn new(file: &str) -> Result<MediaData, String> {
|
||||
pub fn new(
|
||||
file: &str,
|
||||
voice_manager: Arc<Mutex<ClientVoiceManager>>,
|
||||
) -> Result<MediaData, String> {
|
||||
let connection = match Connection::open(file) {
|
||||
Ok(file) => file,
|
||||
Err(_) => return Err(format!("can't open {}", file)),
|
||||
|
@ -51,6 +60,8 @@ impl MediaData {
|
|||
next_callback: None,
|
||||
|
||||
sql_data_base: connection,
|
||||
|
||||
voice_manager,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -64,8 +75,8 @@ impl MediaData {
|
|||
self.song_name = String::new();
|
||||
self.next_callback = None;
|
||||
|
||||
if let Some(manager_lock) = ctx.data.read().get::<VoiceManager>().cloned() {
|
||||
let mut manager = manager_lock.lock();
|
||||
if let Some(media) = ctx.data.read().get::<Media>() {
|
||||
let mut manager = media.voice_manager.lock();
|
||||
|
||||
let guild_id = guild_id(ctx, msg)?;
|
||||
|
||||
|
@ -118,30 +129,23 @@ impl MediaData {
|
|||
ctx: &Context,
|
||||
mediadata: &mut MediaData,
|
||||
msg: &Message,
|
||||
manager_lock: &Arc<
|
||||
serenity::prelude::Mutex<serenity::client::bridge::voice::ClientVoiceManager>,
|
||||
>,
|
||||
) {
|
||||
) -> VerboseResult<()> {
|
||||
// check if there is already playing
|
||||
let already_started = { mediadata.song().is_some() };
|
||||
let already_started = mediadata.song().is_some();
|
||||
|
||||
// if there isnt already a song playing, start a new one
|
||||
if !already_started {
|
||||
Self::next_song(ctx, mediadata, msg, manager_lock);
|
||||
Self::next_song(ctx, mediadata, msg)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn next_song(
|
||||
ctx: &Context,
|
||||
mediadata: &mut MediaData,
|
||||
msg: &Message,
|
||||
manager_lock: &Arc<
|
||||
serenity::prelude::Mutex<serenity::client::bridge::voice::ClientVoiceManager>,
|
||||
>,
|
||||
) {
|
||||
let mut manager = manager_lock.lock();
|
||||
pub fn next_song(ctx: &Context, mediadata: &mut MediaData, msg: &Message) -> VerboseResult<()> {
|
||||
let voice_manager = mediadata.voice_manager.clone();
|
||||
let mut manager = voice_manager.lock();
|
||||
|
||||
let guild_id = check_result_return!(guild_id(ctx, msg));
|
||||
let guild_id = guild_id(ctx, msg)?;
|
||||
|
||||
let mut need_to_leave = false;
|
||||
|
||||
|
@ -150,8 +154,7 @@ impl MediaData {
|
|||
match handler(guild_id, &mut manager) {
|
||||
Some(handler) => handler,
|
||||
None => {
|
||||
println!("error getting handler");
|
||||
return;
|
||||
create_error!("error getting handler");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -171,22 +174,24 @@ impl MediaData {
|
|||
Err(_) => {
|
||||
mediadata.playlist_mut().clear();
|
||||
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
*mediadata.song_mut() = Some(handler.play_returning(source));
|
||||
*mediadata.song_name_mut() = first.name.clone();
|
||||
|
||||
print_error!(msg
|
||||
.channel_id
|
||||
.say(&ctx.http, format!("Playing song: {}", first.name)));
|
||||
msg.channel_id
|
||||
.say(&ctx.http, format!("Playing song: {}", first.name))
|
||||
.map_err(|err| format!("{}", err))?;
|
||||
}
|
||||
}
|
||||
|
||||
if need_to_leave {
|
||||
manager.remove(guild_id);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
pub mod eventhandler;
|
||||
pub mod mediadata;
|
||||
pub mod player;
|
||||
pub mod voicemanager;
|
||||
mod youtube;
|
||||
|
||||
pub mod commands;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use lock_api::{MutexGuard, RawMutex};
|
||||
use parking_lot::lock_api::{MutexGuard, RawMutex};
|
||||
use serenity;
|
||||
use serenity::model::channel::Message;
|
||||
use serenity::model::guild::Guild;
|
||||
|
@ -8,6 +8,8 @@ use serenity::voice::Handler;
|
|||
|
||||
use std::sync::Arc;
|
||||
|
||||
use utilities::prelude::*;
|
||||
|
||||
// This imports `typemap`'s `Key` as `TypeMapKey`.
|
||||
use serenity::prelude::*;
|
||||
|
||||
|
@ -45,64 +47,39 @@ pub fn handler<'a, T: RawMutex>(
|
|||
pub fn channel_contains_author(
|
||||
ctx: &mut serenity::client::Context,
|
||||
msg: &serenity::model::channel::Message,
|
||||
) -> bool {
|
||||
let (guild_id, voice_channel_id_bot) = {
|
||||
match ctx.data.read().get::<VoiceManager>().cloned() {
|
||||
Some(manager_lock) => {
|
||||
let mut manager = manager_lock.lock();
|
||||
let guild_id = match guild_id(ctx, msg) {
|
||||
Ok(id) => id,
|
||||
Err(_) => return true,
|
||||
};
|
||||
) -> VerboseResult<()> {
|
||||
let guild = guild(ctx, msg)?;
|
||||
let guild_id = guild.read().id;
|
||||
|
||||
let handler = match handler(guild_id, &mut manager) {
|
||||
Some(handler) => handler,
|
||||
None => {
|
||||
println!("error getting handler");
|
||||
return true;
|
||||
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!"),
|
||||
};
|
||||
|
||||
if let Some(media) = ctx.data.read().get::<Media>() {
|
||||
let mut manager = media.voice_manager.lock();
|
||||
|
||||
match manager.get(guild_id) {
|
||||
Some(handler) => match handler.channel_id {
|
||||
Some(bot_channel_id) => {
|
||||
if bot_channel_id != author_channel_id {
|
||||
create_error!("author is not in the same voice channel as the bot!");
|
||||
}
|
||||
};
|
||||
|
||||
(
|
||||
guild_id,
|
||||
match handler.channel_id {
|
||||
Some(id) => id,
|
||||
None => {
|
||||
println!("error getting channel_id for bot");
|
||||
return true;
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
None => {
|
||||
manager.join(guild_id, author_channel_id);
|
||||
}
|
||||
},
|
||||
None => {
|
||||
manager.join(guild_id, author_channel_id);
|
||||
}
|
||||
None => return false,
|
||||
}
|
||||
};
|
||||
|
||||
let author = &msg.author;
|
||||
|
||||
let guild = match guild_id.to_guild_cached(&ctx) {
|
||||
Some(guild) => guild,
|
||||
None => {
|
||||
println!("error getting guild from cache");
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
let guild_lock = guild.read();
|
||||
|
||||
let voice_state = match guild_lock.voice_states.get(&author.id) {
|
||||
Some(state) => state,
|
||||
None => {
|
||||
println!("error getting voice state from user {}", author.name);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(voice_channel_id_user) = voice_state.channel_id {
|
||||
if voice_channel_id_bot != voice_channel_id_user {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ pub use super::commands::skip::*;
|
|||
pub use super::commands::stop::*;
|
||||
|
||||
pub use super::eventhandler::Handler;
|
||||
pub use super::voicemanager::VoiceManager;
|
||||
|
||||
pub use super::youtube::youtube_dl;
|
||||
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
use serenity::client::bridge::voice::ClientVoiceManager;
|
||||
use serenity::prelude::Mutex;
|
||||
use std::sync::Arc;
|
||||
use typemap::Key;
|
||||
|
||||
pub struct VoiceManager;
|
||||
|
||||
impl Key for VoiceManager {
|
||||
type Value = Arc<Mutex<ClientVoiceManager>>;
|
||||
}
|
|
@ -72,7 +72,7 @@ pub fn youtube_dl(uri: &str) -> Result<Vec<Song>, String> {
|
|||
));
|
||||
}
|
||||
|
||||
let files = check_result!(convert_output(&out));
|
||||
let files = convert_output(&out)?;
|
||||
|
||||
for file in &files {
|
||||
println!("file: {}", file);
|
||||
|
|
Loading…
Reference in a new issue