Implement quote search + make history depth configurable
This commit is contained in:
parent
55ba7e1217
commit
9c63ab103d
|
@ -3,10 +3,17 @@ host = "karx.xyz"
|
||||||
port = 6697
|
port = 6697
|
||||||
tls = true
|
tls = true
|
||||||
username = "uberbot"
|
username = "uberbot"
|
||||||
|
nickname = "amazingbot" # optional, default: same as username
|
||||||
channels = ["#main", "#no-normies"]
|
channels = ["#main", "#no-normies"]
|
||||||
mode = "+B"
|
mode = "+B" # optional, default: none
|
||||||
prefix = "u!"
|
prefix = "u!"
|
||||||
|
|
||||||
[spotify]
|
[bot]
|
||||||
|
db_path = "database.db3" # optional, default: uberbot.db3
|
||||||
|
history_depth = 5
|
||||||
|
search_limit = 5 # optional, default: 3
|
||||||
|
|
||||||
|
[spotify] # optional, spotify module disabled if missing
|
||||||
spotify_client_id = ""
|
spotify_client_id = ""
|
||||||
spotify_client_secret = ""
|
spotify_client_secret = ""
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,21 @@
|
||||||
use crate::bot::{Command, Context};
|
use crate::bot::{Command, Context};
|
||||||
use crate::database::Quote;
|
use crate::database::Quote;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
pub struct Grab;
|
pub struct Grab;
|
||||||
pub struct Quot;
|
pub struct Quot;
|
||||||
|
|
||||||
|
pub struct Search {
|
||||||
|
limit: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Search {
|
||||||
|
pub fn new(limit: usize) -> Self {
|
||||||
|
Self { limit }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl Command for Grab {
|
impl Command for Grab {
|
||||||
async fn execute(&mut self, msg: Context<'_>) -> anyhow::Result<String> {
|
async fn execute(&mut self, msg: Context<'_>) -> anyhow::Result<String> {
|
||||||
|
@ -53,3 +64,23 @@ impl Command for Quot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Command for Search {
|
||||||
|
async fn execute(&mut self, msg: Context<'_>) -> anyhow::Result<String> {
|
||||||
|
let query = if let Some(c) = msg.content {
|
||||||
|
c
|
||||||
|
} else {
|
||||||
|
return Ok("Invalid usage.".into());
|
||||||
|
};
|
||||||
|
let results = msg.db.search_quotes(query.into(), self.limit).await?;
|
||||||
|
if results.is_empty() {
|
||||||
|
return Ok("No results.".into());
|
||||||
|
}
|
||||||
|
let mut buf = format!("{}/{} results:\r\n", results.len(), self.limit);
|
||||||
|
for q in results {
|
||||||
|
write!(buf, "\"{}\" ~{}\r\n", q.quote, q.author)?;
|
||||||
|
}
|
||||||
|
Ok(buf)
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ use serde::Deserialize;
|
||||||
pub struct UberConfig {
|
pub struct UberConfig {
|
||||||
pub irc: IrcConfig,
|
pub irc: IrcConfig,
|
||||||
pub spotify: Option<SpotifyConfig>,
|
pub spotify: Option<SpotifyConfig>,
|
||||||
pub db_path: Option<String>,
|
pub bot: BotConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -24,3 +24,10 @@ pub struct IrcConfig {
|
||||||
pub username: String,
|
pub username: String,
|
||||||
pub prefix: String,
|
pub prefix: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct BotConfig {
|
||||||
|
pub db_path: Option<String>,
|
||||||
|
pub history_depth: usize,
|
||||||
|
pub search_limit: Option<usize>
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ enum Task {
|
||||||
oneshot::Sender<rusqlite::Result<Option<Quote>>>,
|
oneshot::Sender<rusqlite::Result<Option<Quote>>>,
|
||||||
Option<String>,
|
Option<String>,
|
||||||
),
|
),
|
||||||
SearchQuotes(oneshot::Sender<rusqlite::Result<Vec<Quote>>>, String),
|
SearchQuotes(oneshot::Sender<rusqlite::Result<Vec<Quote>>>, String, usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DbExecutor {
|
pub struct DbExecutor {
|
||||||
|
@ -59,8 +59,8 @@ impl DbExecutor {
|
||||||
}.optional();
|
}.optional();
|
||||||
tx.send(result).unwrap();
|
tx.send(result).unwrap();
|
||||||
}
|
}
|
||||||
Task::SearchQuotes(tx, query) => {
|
Task::SearchQuotes(tx, query, limit) => {
|
||||||
tx.send(self.yield_quotes("select quote,username from quotes where quote like '%'||?1||'%' order by quote asc limit 5", params![query])).unwrap();
|
tx.send(self.yield_quotes("select quote,username from quotes where quote like '%'||?1||'%' order by quote asc limit ?", params![query, limit])).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,6 +129,7 @@ impl ExecutorConnection {
|
||||||
search_quotes,
|
search_quotes,
|
||||||
Task::SearchQuotes,
|
Task::SearchQuotes,
|
||||||
rusqlite::Result<Vec<Quote>>,
|
rusqlite::Result<Vec<Quote>>,
|
||||||
query: String
|
query: String,
|
||||||
|
limit: usize
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ use crate::bot::Bot;
|
||||||
use crate::commands::eval::Eval;
|
use crate::commands::eval::Eval;
|
||||||
use crate::commands::help::Help;
|
use crate::commands::help::Help;
|
||||||
use crate::commands::leek::{Leet, Mock, Owo};
|
use crate::commands::leek::{Leet, Mock, Owo};
|
||||||
use crate::commands::quotes::{Grab, Quot};
|
use crate::commands::quotes::{Grab, Quot, Search};
|
||||||
use crate::commands::sed::Sed;
|
use crate::commands::sed::Sed;
|
||||||
use crate::commands::spotify::Spotify;
|
use crate::commands::spotify::Spotify;
|
||||||
use crate::commands::title::Title;
|
use crate::commands::title::Title;
|
||||||
|
@ -68,7 +68,7 @@ async fn main() -> anyhow::Result<()> {
|
||||||
|
|
||||||
let cfg: UberConfig = toml::from_str(&client_conf)?;
|
let cfg: UberConfig = toml::from_str(&client_conf)?;
|
||||||
|
|
||||||
let (db_exec, db_conn) = DbExecutor::create(cfg.db_path.as_deref().unwrap_or("uberbot.db3"))?;
|
let (db_exec, db_conn) = DbExecutor::create(cfg.bot.db_path.as_deref().unwrap_or("uberbot.db3"))?;
|
||||||
let exec_thread = thread::spawn(move || db_exec.run());
|
let exec_thread = thread::spawn(move || db_exec.run());
|
||||||
|
|
||||||
let uber_ver = concat!("Überbot ", env!("CARGO_PKG_VERSION"));
|
let uber_ver = concat!("Überbot ", env!("CARGO_PKG_VERSION"));
|
||||||
|
@ -93,7 +93,7 @@ async fn main() -> anyhow::Result<()> {
|
||||||
let (ctx, _) = broadcast::channel(1);
|
let (ctx, _) = broadcast::channel(1);
|
||||||
let (etx, mut erx) = unbounded_channel();
|
let (etx, mut erx) = unbounded_channel();
|
||||||
|
|
||||||
let mut bot = Bot::new(cfg.irc.prefix, db_conn, 3, {
|
let mut bot = Bot::new(cfg.irc.prefix, db_conn, cfg.bot.history_depth, {
|
||||||
let client = client.clone();
|
let client = client.clone();
|
||||||
move |target, msg| Ok(client.send_privmsg(target, msg)?)
|
move |target, msg| Ok(client.send_privmsg(target, msg)?)
|
||||||
});
|
});
|
||||||
|
@ -106,6 +106,7 @@ async fn main() -> anyhow::Result<()> {
|
||||||
bot.add_command("ev".into(), Eval::default());
|
bot.add_command("ev".into(), Eval::default());
|
||||||
bot.add_command("grab".into(), Grab);
|
bot.add_command("grab".into(), Grab);
|
||||||
bot.add_command("quot".into(), Quot);
|
bot.add_command("quot".into(), Quot);
|
||||||
|
bot.add_command("qsearch".into(), Search::new(cfg.bot.search_limit.unwrap_or(3)));
|
||||||
bot.add_trigger(
|
bot.add_trigger(
|
||||||
Regex::new(r"^(?:(?<u>\S+):\s+)?s/(?<r>[^/]*)/(?<w>[^/]*)(?:/(?<f>[a-z]*))?\s*")?,
|
Regex::new(r"^(?:(?<u>\S+):\s+)?s/(?<r>[^/]*)/(?<w>[^/]*)(?:/(?<f>[a-z]*))?\s*")?,
|
||||||
Sed,
|
Sed,
|
||||||
|
|
Loading…
Reference in a new issue