Leek optimizations
This commit is contained in:
parent
b6a32859a1
commit
2cb9db95d1
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -1,4 +1,4 @@
|
|||
/target
|
||||
uberbot_*.toml
|
||||
uberbot.toml
|
||||
/Cargo.lock
|
||||
/target
|
||||
uberbot_*.toml
|
||||
uberbot.toml
|
||||
/Cargo.lock
|
||||
|
|
45
.vscode/launch.json
vendored
45
.vscode/launch.json
vendored
|
@ -1,45 +0,0 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug executable 'uberbot'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"build",
|
||||
"--bin=uberbot",
|
||||
"--package=uberbot"
|
||||
],
|
||||
"filter": {
|
||||
"name": "uberbot",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug unit tests in executable 'uberbot'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"test",
|
||||
"--no-run",
|
||||
"--bin=uberbot",
|
||||
"--package=uberbot"
|
||||
],
|
||||
"filter": {
|
||||
"name": "uberbot",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -3,6 +3,9 @@ name = "uberbot"
|
|||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1.15", features = ["rt", "macros", "signal"] }
|
||||
anyhow = "1.0"
|
||||
|
@ -17,4 +20,4 @@ toml = "0.5"
|
|||
serde = "1.0"
|
||||
arrayvec = "0.7"
|
||||
rand = "0.8"
|
||||
async-circe = "0.1.1"
|
||||
async-circe = { git = "https://git.karx.xyz/circe/async-circe" }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
host = "karx.xyz"
|
||||
port = 6697
|
||||
username = "uberbot"
|
||||
channels = ["#main, #no-normies"]
|
||||
channels = ["#main", "#no-normies"]
|
||||
mode = "+B"
|
||||
|
||||
# Spotify config
|
||||
|
|
|
@ -1,24 +1,46 @@
|
|||
use arrayvec::ArrayString;
|
||||
use arrayvec::{ArrayString, CapacityError};
|
||||
use rand::Rng;
|
||||
use std::{error::Error, fmt::{Debug, Display}};
|
||||
|
||||
pub fn mock(target: &str) -> ArrayString<512> {
|
||||
#[derive(Debug)]
|
||||
pub struct LeekCapacityError(CapacityError);
|
||||
|
||||
impl Display for LeekCapacityError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for LeekCapacityError {}
|
||||
|
||||
impl<T> From<CapacityError<T>> for LeekCapacityError {
|
||||
fn from(e: CapacityError<T>) -> Self {
|
||||
Self { 0: e.simplify() }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
type LeekResult = Result<ArrayString<512>, LeekCapacityError>;
|
||||
|
||||
pub fn mock(input: &str) -> LeekResult {
|
||||
let mut builder = ArrayString::<512>::new();
|
||||
|
||||
for char in target.chars() {
|
||||
for ch in input.chars() {
|
||||
if rand::random() {
|
||||
builder.push(char.to_ascii_uppercase());
|
||||
builder.try_push(ch.to_ascii_uppercase())?;
|
||||
} else {
|
||||
builder.push(char.to_ascii_lowercase());
|
||||
builder.try_push(ch.to_ascii_lowercase())?;
|
||||
}
|
||||
}
|
||||
|
||||
builder
|
||||
Ok(builder)
|
||||
}
|
||||
|
||||
pub fn leetify(target: &str) -> ArrayString<512> {
|
||||
pub fn leetify(input: &str) -> LeekResult {
|
||||
let mut builder = ArrayString::<512>::new();
|
||||
|
||||
for char in target.chars() {
|
||||
builder.push(match char {
|
||||
for ch in input.chars() {
|
||||
builder.try_push(match ch {
|
||||
'a' => '4',
|
||||
'e' => '3',
|
||||
'i' => '1',
|
||||
|
@ -27,9 +49,52 @@ pub fn leetify(target: &str) -> ArrayString<512> {
|
|||
's' => '5',
|
||||
't' => '7',
|
||||
'b' => '8',
|
||||
_ => char,
|
||||
});
|
||||
_ => ch,
|
||||
})?;
|
||||
}
|
||||
|
||||
builder
|
||||
Ok(builder)
|
||||
}
|
||||
|
||||
pub fn owoify(input: &str) -> LeekResult {
|
||||
let mut builder: ArrayString<512> = ArrayString::from(input)?;
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut last_char = '\0';
|
||||
for byte in input.bytes() {
|
||||
let mut ch = char::from(byte);
|
||||
if !ch.is_ascii() {
|
||||
continue;
|
||||
}
|
||||
// owoify character
|
||||
ch = match ch.to_ascii_lowercase() {
|
||||
'r' | 'l' => 'w',
|
||||
_ => ch,
|
||||
};
|
||||
// stutter (e.g. "o-ohayou gozaimasu!")
|
||||
if last_char == ' ' && rng.gen_bool(0.2) {
|
||||
builder.try_push(ch)?;
|
||||
builder.try_push('-')?;
|
||||
}
|
||||
match ch {
|
||||
// nya-ify
|
||||
'a' | 'e' | 'i' | 'o' | 'u' if last_char == 'n' => {
|
||||
builder.try_push('y')?;
|
||||
}
|
||||
// textmoji
|
||||
'.' => {
|
||||
builder.try_push_str(match rng.gen_range(0..6) {
|
||||
1 => " OwO",
|
||||
2 => " :3",
|
||||
3 => " >w<",
|
||||
4 => " >_<",
|
||||
5 => " ^•ﻌ•^",
|
||||
_ => " ^^",
|
||||
})?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
builder.try_push(ch)?;
|
||||
last_char = ch;
|
||||
}
|
||||
Ok(builder)
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ use htmlescape::decode_html;
|
|||
use rspotify::clients::BaseClient;
|
||||
use rspotify::model::PlayableItem;
|
||||
use rspotify::{model::Id, ClientCredsSpotify, Credentials};
|
||||
use tracing::debug;
|
||||
|
||||
fn calculate_playtime(secs: u64) -> (u64, u64) {
|
||||
let mut dur_sec = secs;
|
||||
|
@ -22,7 +21,7 @@ async fn resolve_spotify(
|
|||
// if spotify.token.lock().await.unwrap().as_ref().unwrap().is_expired() {
|
||||
// spotify.request_token().await?;
|
||||
// }
|
||||
debug!(
|
||||
tracing::debug!(
|
||||
"Resolving Spotify resource '{}' with id '{}'",
|
||||
resource_type, resource_id
|
||||
);
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
use arrayvec::{ArrayString, CapacityError};
|
||||
use rand::Rng;
|
||||
use serde_json::Value;
|
||||
use std::result::Result;
|
||||
use tracing::debug;
|
||||
|
||||
pub async fn get_waifu_pic(category: &str) -> anyhow::Result<Option<String>> {
|
||||
let api_resp = reqwest::get(format!("https://api.waifu.pics/sfw/{}", category))
|
||||
|
@ -10,62 +6,9 @@ pub async fn get_waifu_pic(category: &str) -> anyhow::Result<Option<String>> {
|
|||
.text()
|
||||
.await?;
|
||||
let api_resp = api_resp.trim();
|
||||
debug!("API response: {}", api_resp);
|
||||
tracing::debug!("API response: {}", api_resp);
|
||||
let value: Value = serde_json::from_str(&api_resp)?;
|
||||
let url = value["url"].as_str().map(|v| v.to_string());
|
||||
Ok(url)
|
||||
}
|
||||
|
||||
pub struct OwoCapacityError(CapacityError);
|
||||
|
||||
impl<T> From<CapacityError<T>> for OwoCapacityError {
|
||||
fn from(e: CapacityError<T>) -> Self {
|
||||
Self { 0: e.simplify() }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn owoify_out_of_place(
|
||||
input: &str,
|
||||
output: &mut ArrayString<512>,
|
||||
) -> Result<(), OwoCapacityError> {
|
||||
let input: ArrayString<512> = ArrayString::from(input)?;
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut last_char = '\0';
|
||||
for byte in input.bytes() {
|
||||
let mut ch = char::from(byte);
|
||||
if !ch.is_ascii() {
|
||||
continue;
|
||||
}
|
||||
// owoify character
|
||||
ch = match ch.to_ascii_lowercase() {
|
||||
'r' | 'l' => 'w',
|
||||
_ => ch,
|
||||
};
|
||||
// stutter (e.g. "o-ohayou gozaimasu!")
|
||||
if last_char == ' ' && rng.gen_bool(0.2) {
|
||||
output.try_push(ch)?;
|
||||
output.try_push('-')?;
|
||||
}
|
||||
match ch {
|
||||
// nya-ify
|
||||
'a' | 'e' | 'i' | 'o' | 'u' if last_char == 'n' => {
|
||||
output.try_push('y')?;
|
||||
}
|
||||
// textmoji
|
||||
'.' => {
|
||||
output.try_push_str(match rng.gen_range(0..6) {
|
||||
1 => " OwO",
|
||||
2 => " :3",
|
||||
3 => " >w<",
|
||||
4 => " >_<",
|
||||
5 => " ^•ﻌ•^",
|
||||
_ => " ^^",
|
||||
})?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
output.try_push(ch)?;
|
||||
last_char = ch;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
65
src/main.rs
65
src/main.rs
|
@ -1,6 +1,6 @@
|
|||
use async_circe::{commands::Command, Client, Config};
|
||||
use bots::title::Titlebot;
|
||||
use bots::weeb;
|
||||
use bots::{weeb, leek};
|
||||
use rspotify::Credentials;
|
||||
use serde::Deserialize;
|
||||
use std::fs::File;
|
||||
|
@ -61,7 +61,7 @@ async fn main() -> anyhow::Result<()> {
|
|||
.with_env_filter(EnvFilter::from_env("UBERBOT_LOG"))
|
||||
.init();
|
||||
|
||||
let mut file = File::open("uberbot.toml")?;
|
||||
let mut file = File::open(env::var("UBERBOT_CONFIG").unwrap_or_else(|_| "uberbot.toml".to_string()))?;
|
||||
let mut client_conf = String::new();
|
||||
file.read_to_string(&mut client_conf)?;
|
||||
|
||||
|
@ -80,7 +80,9 @@ async fn main() -> anyhow::Result<()> {
|
|||
client_config.port,
|
||||
client_config.username,
|
||||
);
|
||||
tracing::debug!("Creating circe client");
|
||||
let mut client = Client::new(config).await?;
|
||||
tracing::debug!("Identifying with IRC");
|
||||
client.identify().await?;
|
||||
|
||||
let state = AppState {
|
||||
|
@ -130,6 +132,26 @@ async fn handle_message(state: &mut AppState, command: Command) -> anyhow::Resul
|
|||
Ok(())
|
||||
}
|
||||
|
||||
enum LeekCommand {
|
||||
Owo, Leet, Mock
|
||||
}
|
||||
async fn execute_leek(state: &mut AppState, cmd: LeekCommand, channel: &str, nick: &str) -> anyhow::Result<()> {
|
||||
match state.last_msgs.get(nick) {
|
||||
Some(msg) => {
|
||||
let output = match cmd {
|
||||
LeekCommand::Owo => leek::owoify(msg)?,
|
||||
LeekCommand::Leet => leek::leetify(msg)?,
|
||||
LeekCommand::Mock => leek::mock(msg)?
|
||||
};
|
||||
state.client.privmsg(channel, &output).await?;
|
||||
}
|
||||
None => {
|
||||
state.client.privmsg(channel, "No last messages found.").await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_privmsg(
|
||||
state: &mut AppState,
|
||||
nick: String,
|
||||
|
@ -166,42 +188,13 @@ async fn handle_privmsg(
|
|||
state.client.privmsg(&channel, response).await?;
|
||||
}
|
||||
"mock" => {
|
||||
let user = match remainder {
|
||||
Some(u) => match u {
|
||||
"" => &nick,
|
||||
_ => u,
|
||||
},
|
||||
None => &nick,
|
||||
}
|
||||
.trim();
|
||||
if let Some(prev_msg) = state.last_msgs.get(user) {
|
||||
let resp = bots::leek::mock(prev_msg);
|
||||
state.client.privmsg(&channel, &resp).await?;
|
||||
} else {
|
||||
state
|
||||
.client
|
||||
.privmsg(&channel, "No previous messages to mock!")
|
||||
.await?;
|
||||
}
|
||||
execute_leek(state, LeekCommand::Mock, channel, remainder.unwrap_or(&nick)).await?;
|
||||
}
|
||||
"leet" => {
|
||||
let user = match remainder {
|
||||
Some(u) => match u {
|
||||
"" => &nick,
|
||||
_ => u,
|
||||
},
|
||||
None => &nick,
|
||||
}
|
||||
.trim();
|
||||
if let Some(prev_msg) = state.last_msgs.get(user) {
|
||||
let resp = bots::leek::leetify(prev_msg);
|
||||
state.client.privmsg(&channel, &resp).await?;
|
||||
} else {
|
||||
state
|
||||
.client
|
||||
.privmsg(&channel, "No previous messages to leetify!")
|
||||
.await?;
|
||||
}
|
||||
execute_leek(state, LeekCommand::Leet, channel, remainder.unwrap_or(&nick)).await?;
|
||||
}
|
||||
"owo" => {
|
||||
execute_leek(state, LeekCommand::Owo, channel, remainder.unwrap_or(&nick)).await?;
|
||||
}
|
||||
_ => {
|
||||
state.client.privmsg(&channel, "Unknown command").await?;
|
||||
|
|
Loading…
Reference in a new issue