feat: swordfish-user
Also move tesseract implementation to swordfish cuz only the bot uses it.
This commit is contained in:
parent
ebafd93110
commit
8eb622f479
71
Cargo.lock
generated
71
Cargo.lock
generated
@ -289,9 +289,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clang-sys"
|
name = "clang-sys"
|
||||||
version = "1.6.1"
|
version = "1.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f"
|
checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"glob",
|
"glob",
|
||||||
"libc",
|
"libc",
|
||||||
@ -315,6 +315,16 @@ dependencies = [
|
|||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "command_attr"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "git+https://github.com/nshout/serenity-self#6b62ca61aa592d4fd22dc42848388c5fb3889161"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "convert_case"
|
name = "convert_case"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@ -1141,12 +1151,12 @@ checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libloading"
|
name = "libloading"
|
||||||
version = "0.7.4"
|
version = "0.8.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
|
checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"winapi",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1974,7 +1984,42 @@ dependencies = [
|
|||||||
"bitflags 2.4.1",
|
"bitflags 2.4.1",
|
||||||
"bytes",
|
"bytes",
|
||||||
"chrono",
|
"chrono",
|
||||||
"command_attr",
|
"command_attr 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"dashmap",
|
||||||
|
"flate2",
|
||||||
|
"futures",
|
||||||
|
"fxhash",
|
||||||
|
"levenshtein",
|
||||||
|
"mime_guess",
|
||||||
|
"parking_lot",
|
||||||
|
"percent-encoding",
|
||||||
|
"reqwest",
|
||||||
|
"secrecy",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"static_assertions",
|
||||||
|
"time",
|
||||||
|
"tokio",
|
||||||
|
"tokio-tungstenite",
|
||||||
|
"tracing",
|
||||||
|
"typemap_rev",
|
||||||
|
"typesize",
|
||||||
|
"url",
|
||||||
|
"uwl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serenity"
|
||||||
|
version = "0.13.0-alpha2"
|
||||||
|
source = "git+https://github.com/nshout/serenity-self#6b62ca61aa592d4fd22dc42848388c5fb3889161"
|
||||||
|
dependencies = [
|
||||||
|
"arrayvec",
|
||||||
|
"async-trait",
|
||||||
|
"base64 0.21.5",
|
||||||
|
"bitflags 2.4.1",
|
||||||
|
"bytes",
|
||||||
|
"chrono",
|
||||||
|
"command_attr 0.5.1 (git+https://github.com/nshout/serenity-self)",
|
||||||
"dashmap",
|
"dashmap",
|
||||||
"flate2",
|
"flate2",
|
||||||
"futures",
|
"futures",
|
||||||
@ -2174,9 +2219,11 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
"image",
|
"image",
|
||||||
|
"leptess",
|
||||||
"regex",
|
"regex",
|
||||||
|
"rusty-tesseract",
|
||||||
"serde",
|
"serde",
|
||||||
"serenity",
|
"serenity 0.12.0",
|
||||||
"swordfish-common",
|
"swordfish-common",
|
||||||
"tokio",
|
"tokio",
|
||||||
"toml",
|
"toml",
|
||||||
@ -2186,16 +2233,22 @@ dependencies = [
|
|||||||
name = "swordfish-common"
|
name = "swordfish-common"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"leptess",
|
|
||||||
"log",
|
"log",
|
||||||
"mongodb",
|
"mongodb",
|
||||||
"rusty-tesseract",
|
|
||||||
"serde",
|
"serde",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "swordfish-user"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"serenity 0.13.0-alpha2",
|
||||||
|
"swordfish-common",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.109"
|
version = "1.0.109"
|
||||||
|
@ -3,5 +3,5 @@ resolver = "1"
|
|||||||
members = [
|
members = [
|
||||||
"swordfish-common",
|
"swordfish-common",
|
||||||
"swordfish"
|
"swordfish"
|
||||||
]
|
, "swordfish-user"]
|
||||||
default-members = ["swordfish"]
|
default-members = ["swordfish"]
|
||||||
|
@ -6,9 +6,7 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
leptess = "0.14.0"
|
|
||||||
log = "0.4.20"
|
log = "0.4.20"
|
||||||
rusty-tesseract = "1.1.9"
|
|
||||||
serde = "1.0.195"
|
serde = "1.0.195"
|
||||||
tokio = "1.35.1"
|
tokio = "1.35.1"
|
||||||
tracing = "0.1.40"
|
tracing = "0.1.40"
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
#![feature(lazy_cell)]
|
#![feature(lazy_cell)]
|
||||||
#![feature(string_remove_matches)]
|
#![feature(string_remove_matches)]
|
||||||
pub use log;
|
pub use log;
|
||||||
|
pub use tokio;
|
||||||
pub use tracing::{debug, error, info, trace, warn};
|
pub use tracing::{debug, error, info, trace, warn};
|
||||||
use tracing_subscriber::{self, fmt, EnvFilter};
|
use tracing_subscriber::{self, fmt, EnvFilter};
|
||||||
pub mod constants;
|
pub mod constants;
|
||||||
pub mod database;
|
pub mod database;
|
||||||
pub mod structs;
|
pub mod structs;
|
||||||
pub mod tesseract;
|
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
pub fn setup_logger(level: &str) -> Result<(), ()> {
|
pub fn setup_logger(level: &str) -> Result<(), ()> {
|
||||||
|
13
swordfish-user/Cargo.toml
Normal file
13
swordfish-user/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "swordfish-user"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serenity = { git = "https://github.com/nshout/serenity-self", version = "0.13.0-alpha2" }
|
||||||
|
|
||||||
|
|
||||||
|
[dependencies.swordfish-common]
|
||||||
|
path = "../swordfish-common"
|
202
swordfish-user/src/main.rs
Normal file
202
swordfish-user/src/main.rs
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
use std::env;
|
||||||
|
|
||||||
|
use serenity::all::{Embed, MessageUpdateEvent};
|
||||||
|
use serenity::async_trait;
|
||||||
|
use serenity::model::channel::Message;
|
||||||
|
use serenity::prelude::*;
|
||||||
|
use swordfish_common::setup_logger;
|
||||||
|
use swordfish_common::{constants, database, utils};
|
||||||
|
use swordfish_common::{debug, tokio};
|
||||||
|
use swordfish_common::{error, info, trace};
|
||||||
|
|
||||||
|
const GITHUB_URL: &str = "https://github.com/teppyboy/swordfish";
|
||||||
|
|
||||||
|
async fn parse_katana(ctx: &Context, msg: &Message) -> Result<(), String> {
|
||||||
|
if msg.embeds.len() == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let embed = &msg.embeds[0];
|
||||||
|
parse_katana_embed(embed).await;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn parse_katana_embed(embed: &Embed) {
|
||||||
|
match embed.author {
|
||||||
|
Some(ref author) => match author.name.as_str() {
|
||||||
|
"Card Collection" => {
|
||||||
|
let cards = utils::katana::parse_cards_from_katana_kc_ow(
|
||||||
|
&embed.description.as_ref().unwrap(),
|
||||||
|
);
|
||||||
|
if cards.len() == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
debug!("Importing cards from Katana 'Card Collection'");
|
||||||
|
match database::katana::write_cards(cards).await {
|
||||||
|
Ok(_) => {
|
||||||
|
debug!("Imported successully");
|
||||||
|
}
|
||||||
|
Err(why) => {
|
||||||
|
error!("Failed to import card: {:?}", why);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
None => {}
|
||||||
|
};
|
||||||
|
match embed.title {
|
||||||
|
Some(ref title) => match title.as_str() {
|
||||||
|
"Character Lookup" => {
|
||||||
|
let card = match utils::katana::parse_cards_from_katana_klu_lookup(
|
||||||
|
&embed.description.as_ref().unwrap(),
|
||||||
|
) {
|
||||||
|
Some(card) => card,
|
||||||
|
None => {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
debug!("Importing a card from Katana 'Character Lookup'");
|
||||||
|
match database::katana::write_card(card).await {
|
||||||
|
Ok(_) => {
|
||||||
|
debug!("Imported successully");
|
||||||
|
}
|
||||||
|
Err(why) => {
|
||||||
|
error!("Failed to import card: {:?}", why);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"Character Results" => {
|
||||||
|
let fields = match embed.fields.len() {
|
||||||
|
0 => {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_ => &embed.fields,
|
||||||
|
};
|
||||||
|
let embed_field = fields.get(0).unwrap();
|
||||||
|
let cards = utils::katana::parse_cards_from_katana_klu_results(&embed_field.value);
|
||||||
|
if cards.len() == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
debug!("Importing cards from Katana 'Character Results'");
|
||||||
|
match database::katana::write_cards(cards).await {
|
||||||
|
Ok(_) => {
|
||||||
|
debug!("Imported successully");
|
||||||
|
}
|
||||||
|
Err(why) => {
|
||||||
|
error!("Failed to import card: {:?}", why);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
None => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn parse_qingque_event(ctx: &Context, event: MessageUpdateEvent) -> Result<(), String> {
|
||||||
|
if event.embeds.is_none() || event.embeds.clone().unwrap().len() == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let embed = &event.embeds.unwrap()[0];
|
||||||
|
let embed_title = match embed.title {
|
||||||
|
Some(ref title) => title,
|
||||||
|
None => {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match embed_title.as_str() {
|
||||||
|
"Top Wishlist" => {
|
||||||
|
let cards = utils::katana::parse_cards_from_qingque_atopwl(
|
||||||
|
&embed.description.as_ref().unwrap(),
|
||||||
|
);
|
||||||
|
debug!("Importing cards from Qingque 'Top Wishlist'");
|
||||||
|
match database::katana::write_cards(cards).await {
|
||||||
|
Ok(_) => {
|
||||||
|
debug!("Imported successully");
|
||||||
|
}
|
||||||
|
Err(why) => {
|
||||||
|
error!("Failed to import card: {:?}", why);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn parse_katana_event(ctx: &Context, event: MessageUpdateEvent) -> Result<(), String> {
|
||||||
|
if event.embeds.is_none() || event.embeds.clone().unwrap().len() == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let embed = &event.embeds.unwrap()[0];
|
||||||
|
parse_katana_embed(embed).await;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Handler;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl EventHandler for Handler {
|
||||||
|
async fn message(&self, ctx: Context, msg: Message) {
|
||||||
|
if msg.author.id.get() == constants::KATANA_ID {
|
||||||
|
parse_katana(&ctx, &msg).await.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async fn message_update(
|
||||||
|
&self,
|
||||||
|
ctx: Context,
|
||||||
|
old_if_available: Option<Message>,
|
||||||
|
new: Option<Message>,
|
||||||
|
event: MessageUpdateEvent,
|
||||||
|
) {
|
||||||
|
let author = match event.author {
|
||||||
|
Some(ref v) => v,
|
||||||
|
None => {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if author.id == ctx.cache.current_user().id {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let content = match event.content {
|
||||||
|
Some(ref v) => v,
|
||||||
|
None => {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
trace!("Message update: {}, sender: {}", content, author.id);
|
||||||
|
match author.id.get() {
|
||||||
|
constants::KATANA_ID => {
|
||||||
|
parse_katana_event(&ctx, event).await.unwrap();
|
||||||
|
}
|
||||||
|
constants::QINGQUE_ID => {
|
||||||
|
parse_qingque_event(&ctx, event).await.unwrap();
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
// Login with a user token from the environment
|
||||||
|
let log_level = env::var("LOG_LEVEL").unwrap_or("info".to_string());
|
||||||
|
setup_logger(log_level.as_str()).expect("Failed to setup logger");
|
||||||
|
let token = env::var("DISCORD_TOKEN").expect("Token not found");
|
||||||
|
info!("Swordfish v{} - {}", env!("CARGO_PKG_VERSION"), GITHUB_URL);
|
||||||
|
info!("Log level: {}", log_level);
|
||||||
|
info!("Initializing database...");
|
||||||
|
swordfish_common::database::init().await;
|
||||||
|
info!("Initializing Discord client...");
|
||||||
|
let mut client = Client::builder(token)
|
||||||
|
.event_handler(Handler)
|
||||||
|
.await
|
||||||
|
.expect("Error creating client");
|
||||||
|
|
||||||
|
// start listening for events by starting a single shard
|
||||||
|
if let Err(why) = client.start().await {
|
||||||
|
error!("An error occurred while running the client: {:?}", why);
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,9 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
dotenvy = "0.15.7"
|
dotenvy = "0.15.7"
|
||||||
image = "0.24.7"
|
image = "0.24.7"
|
||||||
|
leptess = "0.14.0"
|
||||||
regex = "1.10.2"
|
regex = "1.10.2"
|
||||||
|
rusty-tesseract = "1.1.9"
|
||||||
serde = "1.0.193"
|
serde = "1.0.193"
|
||||||
serenity = { version = "0.12.0", features = ["builder"] }
|
serenity = { version = "0.12.0", features = ["builder"] }
|
||||||
tokio = { version = "1.35.1", features = ["full"] }
|
tokio = { version = "1.35.1", features = ["full"] }
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::tesseract::{libtesseract, subprocess};
|
||||||
use crate::CONFIG;
|
use crate::CONFIG;
|
||||||
use image::imageops::colorops::contrast_in_place;
|
use image::imageops::colorops::contrast_in_place;
|
||||||
use image::io::Reader as ImageReader;
|
use image::io::Reader as ImageReader;
|
||||||
@ -8,7 +9,6 @@ use std::io::Cursor;
|
|||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
use swordfish_common::database::katana as db;
|
use swordfish_common::database::katana as db;
|
||||||
use swordfish_common::structs::Card;
|
use swordfish_common::structs::Card;
|
||||||
use swordfish_common::tesseract::{libtesseract, subprocess};
|
|
||||||
use swordfish_common::{trace, warn};
|
use swordfish_common::{trace, warn};
|
||||||
use tokio::task;
|
use tokio::task;
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ mod debug;
|
|||||||
mod helper;
|
mod helper;
|
||||||
mod katana;
|
mod katana;
|
||||||
mod template;
|
mod template;
|
||||||
|
mod tesseract;
|
||||||
|
|
||||||
const GITHUB_URL: &str = "https://github.com/teppyboy/swordfish";
|
const GITHUB_URL: &str = "https://github.com/teppyboy/swordfish";
|
||||||
static CONFIG: OnceLock<Config> = OnceLock::new();
|
static CONFIG: OnceLock<Config> = OnceLock::new();
|
||||||
@ -95,10 +96,10 @@ async fn parse_qingque_event(ctx: &Context, event: MessageUpdateEvent) -> Result
|
|||||||
let cards = utils::katana::parse_cards_from_qingque_atopwl(
|
let cards = utils::katana::parse_cards_from_qingque_atopwl(
|
||||||
&embed.description.as_ref().unwrap(),
|
&embed.description.as_ref().unwrap(),
|
||||||
);
|
);
|
||||||
trace!("Begin importing cards");
|
debug!("Importing cards from Qingque 'Top Wishlist'");
|
||||||
match database::katana::write_cards(cards).await {
|
match database::katana::write_cards(cards).await {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
trace!("Imported successully");
|
debug!("Imported successully");
|
||||||
}
|
}
|
||||||
Err(why) => {
|
Err(why) => {
|
||||||
error!("Failed to import card: {:?}", why);
|
error!("Failed to import card: {:?}", why);
|
||||||
@ -206,10 +207,10 @@ async fn parse_katana_embed(embed: &Embed) {
|
|||||||
if cards.len() == 0 {
|
if cards.len() == 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
trace!("Begin importing cards");
|
debug!("Importing cards from Katana 'Card Collection'");
|
||||||
match database::katana::write_cards(cards).await {
|
match database::katana::write_cards(cards).await {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
trace!("Imported successully");
|
debug!("Imported successully");
|
||||||
}
|
}
|
||||||
Err(why) => {
|
Err(why) => {
|
||||||
error!("Failed to import card: {:?}", why);
|
error!("Failed to import card: {:?}", why);
|
||||||
@ -231,10 +232,10 @@ async fn parse_katana_embed(embed: &Embed) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
trace!("Begin importing a card");
|
debug!("Importing a card from Katana 'Character Lookup'");
|
||||||
match database::katana::write_card(card).await {
|
match database::katana::write_card(card).await {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
trace!("Imported successully");
|
debug!("Imported successully");
|
||||||
}
|
}
|
||||||
Err(why) => {
|
Err(why) => {
|
||||||
error!("Failed to import card: {:?}", why);
|
error!("Failed to import card: {:?}", why);
|
||||||
@ -253,10 +254,10 @@ async fn parse_katana_embed(embed: &Embed) {
|
|||||||
if cards.len() == 0 {
|
if cards.len() == 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
trace!("Begin importing cards");
|
debug!("Importing cards from Katana 'Character Results'");
|
||||||
match database::katana::write_cards(cards).await {
|
match database::katana::write_cards(cards).await {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
trace!("Imported successully");
|
debug!("Imported successully");
|
||||||
}
|
}
|
||||||
Err(why) => {
|
Err(why) => {
|
||||||
error!("Failed to import card: {:?}", why);
|
error!("Failed to import card: {:?}", why);
|
||||||
|
Loading…
Reference in New Issue
Block a user