Add tag command
This commit is contained in:
parent
3f6fc4e4e0
commit
d342a5eab5
9 changed files with 280 additions and 23 deletions
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -4,5 +4,6 @@
|
||||||
"activityBar.background": "#2B300C",
|
"activityBar.background": "#2B300C",
|
||||||
"titleBar.activeBackground": "#3D4311",
|
"titleBar.activeBackground": "#3D4311",
|
||||||
"titleBar.activeForeground": "#F9FBEF"
|
"titleBar.activeForeground": "#F9FBEF"
|
||||||
}
|
},
|
||||||
|
"gitea.repo": "RMusicBot"
|
||||||
}
|
}
|
|
@ -44,7 +44,7 @@ impl Default for Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[group]
|
#[group]
|
||||||
#[commands(ip, list, pause, play, remove, skip, stop)]
|
#[commands(ip, list, pause, play, remove, skip, stop, tag)]
|
||||||
struct General;
|
struct General;
|
||||||
|
|
||||||
#[help]
|
#[help]
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use super::super::prelude::*;
|
use super::super::prelude::*;
|
||||||
|
|
||||||
|
use rusqlite::params;
|
||||||
|
|
||||||
use serenity::prelude::*;
|
use serenity::prelude::*;
|
||||||
use serenity::{
|
use serenity::{
|
||||||
framework::standard::{macros::command, Args, CommandResult},
|
framework::standard::{macros::command, Args, CommandResult},
|
||||||
|
@ -7,7 +9,7 @@ use serenity::{
|
||||||
};
|
};
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
fn list(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult {
|
fn list(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||||
if let Err(err) = channel_contains_author(ctx, msg) {
|
if let Err(err) = channel_contains_author(ctx, msg) {
|
||||||
msg.channel_id.say(&ctx.http, err)?;
|
msg.channel_id.say(&ctx.http, err)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -26,22 +28,74 @@ fn list(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult {
|
||||||
|
|
||||||
let media_lock = media.lock().unwrap();
|
let media_lock = media.lock().unwrap();
|
||||||
|
|
||||||
let playlist = media_lock.playlist();
|
if args.len() == 0 {
|
||||||
|
let playlist = media_lock.playlist();
|
||||||
|
|
||||||
output += &format!(
|
output += &format!(
|
||||||
"{} {} queued\n",
|
"{} {} queued\n",
|
||||||
playlist.len(),
|
playlist.len(),
|
||||||
if playlist.len() == 1 { "song" } else { "songs" }
|
if playlist.len() == 1 { "song" } else { "songs" }
|
||||||
);
|
);
|
||||||
|
|
||||||
let max_output = 5;
|
let max_output = 5;
|
||||||
|
|
||||||
for (i, song) in playlist.iter().enumerate() {
|
for (i, song) in playlist.iter().enumerate() {
|
||||||
if i < max_output {
|
if i < max_output {
|
||||||
output += &format!("\t{}.\t{}\n", i + 1, song.name.clone());
|
output += &format!("\t{}.\t{}\n", i + 1, song.name.clone());
|
||||||
} else {
|
} else {
|
||||||
output += &format!("\t... and {} more", playlist.len() - max_output);
|
output += &format!("\t... and {} more", playlist.len() - max_output);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let first_arg = args.single::<String>()?;
|
||||||
|
|
||||||
|
if first_arg == "--tags" {
|
||||||
|
// check all tables for this entry
|
||||||
|
let mut stmt = match media_lock
|
||||||
|
.db()
|
||||||
|
.prepare("SELECT name FROM sqlite_master WHERE type='table'")
|
||||||
|
{
|
||||||
|
Ok(statement) => statement,
|
||||||
|
Err(_) => {
|
||||||
|
return Err(serenity::framework::standard::CommandError(
|
||||||
|
"failed preparing data base access".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let rows = match stmt.query_map(params![], |row| row.get(0) as rusqlite::Result<String>)
|
||||||
|
{
|
||||||
|
Ok(rows) => rows,
|
||||||
|
Err(_) => {
|
||||||
|
return Err(serenity::framework::standard::CommandError(
|
||||||
|
"failed querying rows".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut tag_names = Vec::new();
|
||||||
|
|
||||||
|
for row in rows {
|
||||||
|
let table_name = match row {
|
||||||
|
Ok(name) => name,
|
||||||
|
Err(_) => {
|
||||||
|
return Err(serenity::framework::standard::CommandError(
|
||||||
|
"failed getting name from row".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if table_name != "Vulva3" {
|
||||||
|
tag_names.push(table_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output += &format!("{} available tags:", tag_names.len());
|
||||||
|
|
||||||
|
for tag in tag_names.iter() {
|
||||||
|
output += &format!("\n\t{}", tag);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,3 +5,4 @@ pub mod play;
|
||||||
pub mod remove;
|
pub mod remove;
|
||||||
pub mod skip;
|
pub mod skip;
|
||||||
pub mod stop;
|
pub mod stop;
|
||||||
|
pub mod tag;
|
||||||
|
|
|
@ -48,6 +48,15 @@ fn play(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||||
|
|
||||||
if first_arg == "--local" {
|
if first_arg == "--local" {
|
||||||
handle_local_request(&mut media_lock, ctx, msg)?;
|
handle_local_request(&mut media_lock, ctx, msg)?;
|
||||||
|
} else if first_arg == "--tag" {
|
||||||
|
let _dummy = args.single::<String>()?;
|
||||||
|
let mut arg_list = args.single::<String>()?;
|
||||||
|
|
||||||
|
for arg in args.iter::<String>() {
|
||||||
|
arg_list += &format!(" {}", arg?.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_tag_request(&mut media_lock, ctx, msg, &arg_list)?
|
||||||
} else if first_arg.starts_with("http") {
|
} else if first_arg.starts_with("http") {
|
||||||
handle_http_request(&mut media_lock, ctx, msg, first_arg)?;
|
handle_http_request(&mut media_lock, ctx, msg, first_arg)?;
|
||||||
} else {
|
} else {
|
||||||
|
@ -60,6 +69,8 @@ fn play(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||||
handle_song_request(&mut media_lock, ctx, msg, &arg_list)?
|
handle_song_request(&mut media_lock, ctx, msg, &arg_list)?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
println!("current song name: {}", media_lock.song_name());
|
||||||
}
|
}
|
||||||
|
|
||||||
WATCHER.call_once(|| {
|
WATCHER.call_once(|| {
|
||||||
|
@ -196,7 +207,7 @@ fn handle_http_request(
|
||||||
if sql
|
if sql
|
||||||
.execute(
|
.execute(
|
||||||
"INSERT INTO Vulva3 (name, link)
|
"INSERT INTO Vulva3 (name, link)
|
||||||
VALUES (?1, ?2)",
|
VALUES (?1, ?2)",
|
||||||
params![song.name, url],
|
params![song.name, url],
|
||||||
)
|
)
|
||||||
.is_err()
|
.is_err()
|
||||||
|
@ -307,3 +318,62 @@ fn handle_song_request(
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_tag_request(
|
||||||
|
media: &mut MediaData,
|
||||||
|
ctx: &serenity::client::Context,
|
||||||
|
msg: &serenity::model::channel::Message,
|
||||||
|
pattern: &str,
|
||||||
|
) -> VerboseResult<()> {
|
||||||
|
let mut songs = Vec::new();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut stmt = match media.db().prepare(&format!(
|
||||||
|
"SELECT name FROM sqlite_master WHERE type='table' AND name='{}'",
|
||||||
|
pattern
|
||||||
|
)) {
|
||||||
|
Ok(statement) => statement,
|
||||||
|
Err(_) => create_error!("failed preparing data base access"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut rows = match stmt.query_map(params![], |row| row.get(0) as rusqlite::Result<String>)
|
||||||
|
{
|
||||||
|
Ok(rows) => rows,
|
||||||
|
Err(_) => create_error!("failed querying rows"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let None = rows.next() {
|
||||||
|
msg.channel_id
|
||||||
|
.say(&ctx.http, format!("tag ({}) not found", pattern))
|
||||||
|
.map_err(|err| format!("{}", err))?;
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut stmt = match media.db().prepare(&format!("SELECT name FROM {}", pattern)) {
|
||||||
|
Ok(statement) => statement,
|
||||||
|
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(_) => create_error!("failed querying rows"),
|
||||||
|
};
|
||||||
|
|
||||||
|
for name_result in rows {
|
||||||
|
let name = match name_result {
|
||||||
|
Ok(name) => name,
|
||||||
|
Err(_) => create_error!("failed getting name from row"),
|
||||||
|
};
|
||||||
|
|
||||||
|
songs.push(Song { name });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
songs.shuffle(&mut rng);
|
||||||
|
|
||||||
|
append_songs(media, ctx, msg, songs)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
@ -28,10 +28,44 @@ fn remove(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult {
|
||||||
let song_name = media_lock.song_name();
|
let song_name = media_lock.song_name();
|
||||||
let sql = media_lock.db();
|
let sql = media_lock.db();
|
||||||
|
|
||||||
if let Err(_) = sql.execute("DELETE FROM Vulva3 WHERE name = ?", params![song_name]) {
|
// check all tables for this entry
|
||||||
return Err(serenity::framework::standard::CommandError(
|
let mut stmt = match sql.prepare("SELECT name FROM sqlite_master WHERE type='table'") {
|
||||||
"failed executing sql delete".to_string(),
|
Ok(statement) => statement,
|
||||||
));
|
Err(_) => {
|
||||||
|
return Err(serenity::framework::standard::CommandError(
|
||||||
|
"failed preparing data base access".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let rows = match stmt.query_map(params![], |row| row.get(0) as rusqlite::Result<String>) {
|
||||||
|
Ok(rows) => rows,
|
||||||
|
Err(_) => {
|
||||||
|
return Err(serenity::framework::standard::CommandError(
|
||||||
|
"failed querying rows".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// delete song from all tables
|
||||||
|
for row in rows {
|
||||||
|
let table_name = match row {
|
||||||
|
Ok(name) => name,
|
||||||
|
Err(_) => {
|
||||||
|
return Err(serenity::framework::standard::CommandError(
|
||||||
|
"failed getting name from row".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(_) = sql.execute(
|
||||||
|
&format!("DELETE FROM {} WHERE name = ?", table_name),
|
||||||
|
params![song_name],
|
||||||
|
) {
|
||||||
|
return Err(serenity::framework::standard::CommandError(
|
||||||
|
"failed executing sql delete".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !song_name.is_empty() {
|
if !song_name.is_empty() {
|
||||||
|
|
73
src/player/commands/tag.rs
Normal file
73
src/player/commands/tag.rs
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
use super::super::prelude::*;
|
||||||
|
|
||||||
|
use rusqlite::params;
|
||||||
|
|
||||||
|
use serenity::{
|
||||||
|
framework::standard::{macros::command, Args, CommandResult},
|
||||||
|
model::channel::Message,
|
||||||
|
};
|
||||||
|
|
||||||
|
// This imports `typemap`'s `Key` as `TypeMapKey`.
|
||||||
|
use serenity::prelude::*;
|
||||||
|
|
||||||
|
#[command]
|
||||||
|
fn tag(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||||
|
if let Err(err) = channel_contains_author(ctx, msg) {
|
||||||
|
msg.channel_id.say(&ctx.http, err)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut data = ctx.data.write();
|
||||||
|
let media = match data.get_mut::<Media>() {
|
||||||
|
Some(media) => media,
|
||||||
|
None => {
|
||||||
|
msg.channel_id.say(&ctx.http, "could not find media data")?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let media_lock = media.lock().unwrap();
|
||||||
|
let mut tag = args.single::<String>()?;
|
||||||
|
|
||||||
|
for arg in args.iter::<String>() {
|
||||||
|
tag += &format!(" {}", arg?.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
match media_lock.db().execute(
|
||||||
|
&format!(
|
||||||
|
"CREATE TABLE IF NOT EXISTS {} (
|
||||||
|
name TEXT PRIMARY KEY
|
||||||
|
)",
|
||||||
|
tag
|
||||||
|
),
|
||||||
|
params![],
|
||||||
|
) {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(err) => {
|
||||||
|
println!("{}", err);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let song_name = media_lock.song_name();
|
||||||
|
|
||||||
|
if media_lock
|
||||||
|
.db()
|
||||||
|
.execute(
|
||||||
|
&format!(
|
||||||
|
"INSERT INTO {} (name)
|
||||||
|
VALUES (?1)",
|
||||||
|
tag
|
||||||
|
),
|
||||||
|
params![song_name],
|
||||||
|
)
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
msg.channel_id.say(
|
||||||
|
&ctx.http,
|
||||||
|
format!("could not add tag ({}) for {}", tag, song_name),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -162,8 +162,31 @@ impl MediaData {
|
||||||
|
|
||||||
let sql = self.db();
|
let sql = self.db();
|
||||||
|
|
||||||
if let Err(_) = sql.execute("DELETE FROM Vulva3 WHERE name = ?", params![&first]) {
|
// check all tables for this entry
|
||||||
create_error!("failed executing sql delete");
|
let mut stmt =
|
||||||
|
match sql.prepare("SELECT name FROM sqlite_master WHERE type='table'") {
|
||||||
|
Ok(statement) => statement,
|
||||||
|
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(_) => create_error!("failed querying rows"),
|
||||||
|
};
|
||||||
|
|
||||||
|
for row in rows {
|
||||||
|
let table_name = match row {
|
||||||
|
Ok(name) => name,
|
||||||
|
Err(_) => create_error!("failed getting name from row"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(_) = sql.execute(
|
||||||
|
&format!("DELETE FROM {} WHERE name = {}", table_name, first),
|
||||||
|
params![],
|
||||||
|
) {
|
||||||
|
println!("{} does not contain {}", table_name, first);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Ok(first);
|
return Ok(first);
|
||||||
|
|
|
@ -7,6 +7,7 @@ pub use super::commands::play::*;
|
||||||
pub use super::commands::remove::*;
|
pub use super::commands::remove::*;
|
||||||
pub use super::commands::skip::*;
|
pub use super::commands::skip::*;
|
||||||
pub use super::commands::stop::*;
|
pub use super::commands::stop::*;
|
||||||
|
pub use super::commands::tag::*;
|
||||||
|
|
||||||
pub use super::eventhandler::Handler;
|
pub use super::eventhandler::Handler;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue