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",
|
||||
"titleBar.activeBackground": "#3D4311",
|
||||
"titleBar.activeForeground": "#F9FBEF"
|
||||
}
|
||||
},
|
||||
"gitea.repo": "RMusicBot"
|
||||
}
|
|
@ -44,7 +44,7 @@ impl Default for Config {
|
|||
}
|
||||
|
||||
#[group]
|
||||
#[commands(ip, list, pause, play, remove, skip, stop)]
|
||||
#[commands(ip, list, pause, play, remove, skip, stop, tag)]
|
||||
struct General;
|
||||
|
||||
#[help]
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use super::super::prelude::*;
|
||||
|
||||
use rusqlite::params;
|
||||
|
||||
use serenity::prelude::*;
|
||||
use serenity::{
|
||||
framework::standard::{macros::command, Args, CommandResult},
|
||||
|
@ -7,7 +9,7 @@ use serenity::{
|
|||
};
|
||||
|
||||
#[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) {
|
||||
msg.channel_id.say(&ctx.http, err)?;
|
||||
return Ok(());
|
||||
|
@ -26,22 +28,74 @@ fn list(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult {
|
|||
|
||||
let media_lock = media.lock().unwrap();
|
||||
|
||||
let playlist = media_lock.playlist();
|
||||
if args.len() == 0 {
|
||||
let playlist = media_lock.playlist();
|
||||
|
||||
output += &format!(
|
||||
"{} {} queued\n",
|
||||
playlist.len(),
|
||||
if playlist.len() == 1 { "song" } else { "songs" }
|
||||
);
|
||||
output += &format!(
|
||||
"{} {} queued\n",
|
||||
playlist.len(),
|
||||
if playlist.len() == 1 { "song" } else { "songs" }
|
||||
);
|
||||
|
||||
let max_output = 5;
|
||||
let max_output = 5;
|
||||
|
||||
for (i, song) in playlist.iter().enumerate() {
|
||||
if i < max_output {
|
||||
output += &format!("\t{}.\t{}\n", i + 1, song.name.clone());
|
||||
} else {
|
||||
output += &format!("\t... and {} more", playlist.len() - max_output);
|
||||
break;
|
||||
for (i, song) in playlist.iter().enumerate() {
|
||||
if i < max_output {
|
||||
output += &format!("\t{}.\t{}\n", i + 1, song.name.clone());
|
||||
} else {
|
||||
output += &format!("\t... and {} more", playlist.len() - max_output);
|
||||
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 skip;
|
||||
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" {
|
||||
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") {
|
||||
handle_http_request(&mut media_lock, ctx, msg, first_arg)?;
|
||||
} 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)?
|
||||
}
|
||||
}
|
||||
|
||||
println!("current song name: {}", media_lock.song_name());
|
||||
}
|
||||
|
||||
WATCHER.call_once(|| {
|
||||
|
@ -196,7 +207,7 @@ fn handle_http_request(
|
|||
if sql
|
||||
.execute(
|
||||
"INSERT INTO Vulva3 (name, link)
|
||||
VALUES (?1, ?2)",
|
||||
VALUES (?1, ?2)",
|
||||
params![song.name, url],
|
||||
)
|
||||
.is_err()
|
||||
|
@ -307,3 +318,62 @@ fn handle_song_request(
|
|||
|
||||
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 sql = media_lock.db();
|
||||
|
||||
if let Err(_) = sql.execute("DELETE FROM Vulva3 WHERE name = ?", params![song_name]) {
|
||||
return Err(serenity::framework::standard::CommandError(
|
||||
"failed executing sql delete".to_string(),
|
||||
));
|
||||
// check all tables for this entry
|
||||
let mut stmt = match sql.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(),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
// 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() {
|
||||
|
|
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();
|
||||
|
||||
if let Err(_) = sql.execute("DELETE FROM Vulva3 WHERE name = ?", params![&first]) {
|
||||
create_error!("failed executing sql delete");
|
||||
// check all tables for this entry
|
||||
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 {
|
||||
return Ok(first);
|
||||
|
|
|
@ -7,6 +7,7 @@ pub use super::commands::play::*;
|
|||
pub use super::commands::remove::*;
|
||||
pub use super::commands::skip::*;
|
||||
pub use super::commands::stop::*;
|
||||
pub use super::commands::tag::*;
|
||||
|
||||
pub use super::eventhandler::Handler;
|
||||
|
||||
|
|
Loading…
Reference in a new issue