diff --git a/Cargo.lock b/Cargo.lock index 0533986..8ed3278 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,20 +24,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" [[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "booru_image_tag_curating_helper" +name = "bitch" version = "0.1.0" dependencies = [ "futures", "gelbooru-api", + "serde", "tokio", + "toml", ] +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bumpalo" version = "3.12.0" @@ -127,7 +129,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn", + "syn 1.0.107", ] [[package]] @@ -144,9 +146,15 @@ checksum = "ebf883b7aacd7b2aeb2a7b338648ee19f57c140d4ee8e52c68979c6b2f7f2263" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] +[[package]] +name = "equivalent" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" + [[package]] name = "fnv" version = "1.0.7" @@ -209,7 +217,7 @@ checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -257,6 +265,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + [[package]] name = "hermit-abi" version = "0.2.6" @@ -362,6 +376,16 @@ dependencies = [ "cxx-build", ] +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "itoa" version = "1.0.5" @@ -474,18 +498,18 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "proc-macro2" -version = "1.0.51" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.23" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" dependencies = [ "proc-macro2", ] @@ -594,22 +618,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.152" +version = "1.0.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +checksum = "bd51c3db8f9500d531e6c12dd0fd4ad13d133e9117f5aebac3cdbb8b6d9824b0" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.152" +version = "1.0.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +checksum = "27738cfea0d944ab72c3ed01f3d5f23ec4322af8a1431e40ce630e4c01ea74fd" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.25", ] [[package]] @@ -623,6 +647,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +dependencies = [ + "serde", +] + [[package]] name = "slab" version = "0.4.7" @@ -659,6 +692,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15e3fc8c0c74267e2df136e5e5fb656a464158aa57624053375eb9c8c6e25ae2" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "termcolor" version = "1.2.0" @@ -685,7 +729,7 @@ checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -723,7 +767,7 @@ checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -737,6 +781,40 @@ dependencies = [ "webpki", ] +[[package]] +name = "toml" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c500344a19072298cd05a7224b3c0c629348b78692bf48466c5238656e315a78" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tower-service" version = "0.3.2" @@ -830,7 +908,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.107", "wasm-bindgen-shared", ] @@ -852,7 +930,7 @@ checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -994,3 +1072,12 @@ name = "windows_x86_64_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" + +[[package]] +name = "winnow" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81a2094c43cc94775293eaa0e499fbc30048a6d824ac82c0351a8c0bf9112529" +dependencies = [ + "memchr", +] diff --git a/Cargo.toml b/Cargo.toml index a971054..724ea00 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "booru_image_tag_curating_helper" +name = "bitch" version = "0.1.0" edition = "2021" @@ -9,3 +9,5 @@ edition = "2021" gelbooru-api = "0.4.0" futures = "0.3" tokio = { version = "1", features = ["macros", "rt-multi-thread"] } +toml = "0.7.3" +serde = "1.0.169" \ No newline at end of file diff --git a/README.md b/README.md index a69a1aa..e81fe8d 100644 --- a/README.md +++ b/README.md @@ -4,25 +4,20 @@ Tool for curating booru image bots # TODO ## CLI -- Sellection keys ✅ -- Sellection legend ✅ -- Image Dysplay ✅ (xdg-open :woozy:) +- [x] Sellection keys +- [x] Sellection legend +- [x] Image Dysplay (xdg-open :woozy:) ## DB -- CSV structure ✅ (Multiple files of just one line, and i refuse to not say its still CSV) -- Read ✅ -- Write ✅ +- [x] CSV structure (Multiple files of just one line, and i refuse to not say its still CSV) +- [x] Read +- [x] Write ## Config file ### Hardcoded for now -- Tags -- Keybinds -- DB config (CSV for now) -- API URLS (MAYBE I CAN JUST CURL?) +- [x] Tags +- [x] Keybinds +- [x] DB config (CSV for now) ## Downloader -- Downloader ✅ (Gelbooru API) +- [x] Downloader (Gelbooru API) ## Uploader -- Bot daemon ✅ (Ultimately using cron) -- Masto API ✅ (https://git.fai.st/Suguivy/mastodon-image-uploader-bot) -## Webapp -- Flask app -- Form -- Image frame \ No newline at end of file +- [x] Bot daemon (Ultimately using cron) +- [x] Masto API (https://git.fai.st/Suguivy/mastodon-image-uploader-bot) \ No newline at end of file diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..a1eb123 --- /dev/null +++ b/config.toml @@ -0,0 +1,15 @@ +[keybinds] +# What to input on the cli, cannot be "_" +quit = 'q' +delete = 'd' +accept = 'a' + +[search] +# Tags used in the gelbooru api on search +tags = ["2girls", "sleeping"] + +[storage] +# Routes to the files used by the program +pending = "./pending.csv" +rejected = "./rejected.csv" +verified = "./urls.csv" diff --git a/src/main.rs b/src/main.rs index fb10d87..9dd836e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,65 +1,80 @@ use gelbooru_api::{posts, Client}; +use serde::Deserialize; use std::collections::HashSet; use std::{ io::{BufRead, Write}, process::Command, }; +use toml; -const LEGEND: &str = "[q]uit, [d]elete, [b][a]p"; -const PENDING: &str = "./pending.csv"; -const REJECTED: &str = "./rejected.csv"; -const VERIFIED: &str = "./verified.csv"; +const CONFIG: &str = "./config.toml"; -const TAGS: [&str; 2] = ["2girls", "sleeping"]; +#[derive(Deserialize)] +struct Config { + keybinds: Keybinds, + search: Search, + storage: Storage, +} + +#[derive(Deserialize)] +struct Keybinds { + quit: char, + delete: char, + accept: char, +} + +#[derive(Deserialize)] +struct Search { + tags: Vec, +} + +#[derive(Deserialize)] +struct Storage { + pending: String, + rejected: String, + verified: String, +} #[tokio::main] async fn main() { - pull(); - + let config: Config = parse_config(CONFIG); let mut arg = std::env::args().skip(1); match &arg .next() .expect("Not enough arguments, please use -f or -v")[..] { - "-f" => fetch_mode(Vec::from(TAGS)).await, - "-v" => verify_mode(), + "-f" => fetch_mode(&config.storage, &config.search).await, + "-v" => verify_mode(&config.keybinds, &config.storage), _ => {} } - - push(); } -async fn fetch_mode(tags: Vec<&str>) { +/// Parses the given filename to a config struct +fn parse_config(filename: &str) -> Config { + let toml_file = std::fs::read_to_string(filename) + .expect("No config file, consider geting the original one and moodifing it"); + toml::from_str(&toml_file).expect("Malformed config file, check the original one for reference") +} + +async fn fetch_mode(storage: &Storage, search: &Search) { let client = Client::public(); - let posts = posts().random(true).tags(&tags).send(&client); + let posts = posts().random(true).tags(&search.tags).send(&client); - let image_set1 = std::fs::read(PENDING) - .expect("File not found") - .iter() - .map(|c| *c as char) - .collect::(); - let image_set2 = std::fs::read(VERIFIED) - .expect("File not found") - .iter() - .map(|c| *c as char) - .collect::(); - let image_set3 = std::fs::read(REJECTED) - .expect("File not found") - .iter() - .map(|c| *c as char) - .collect::(); + let pending_set = std::fs::read_to_string(&storage.pending).expect("No pending file"); + let rejected_set = std::fs::read_to_string(&storage.rejected).expect("No rejected file"); + let verified_set = std::fs::read_to_string(&storage.verified).expect("No verified file"); - let image_set = image_set1 + let image_set = pending_set .lines() - .chain(image_set2.lines()) - .chain(image_set3.lines()) + .chain(rejected_set.lines()) + .chain(verified_set.lines()) .collect::>(); let posts = posts.await.unwrap(); let mut file = std::fs::OpenOptions::new() .write(true) .append(true) // This is needed to append to file - .open(PENDING) + .open(&storage.pending) .unwrap(); for post in posts.posts { @@ -70,8 +85,8 @@ async fn fetch_mode(tags: Vec<&str>) { } } -fn verify_mode() { - let file: String = std::fs::read(PENDING) +fn verify_mode(keybinds: &Keybinds, storage: &Storage) { + let file: String = std::fs::read(&storage.pending) .expect("File not found") .iter() .map(|c| *c as char) @@ -84,11 +99,14 @@ fn verify_mode() { .spawn() .expect("open command failed to start"); //Print Legend - println!("{}", LEGEND); + println!( + "{} to quit; {} to delete; {} to accept", + &keybinds.quit, &keybinds.delete, &keybinds.accept, + ); // Wait for input - if input_parse(image_uri) { + if input_parse(storage, keybinds, image_uri) { std::fs::write( - PENDING, + &storage.pending, format!( "{}\n{}", image_uri, @@ -99,81 +117,38 @@ fn verify_mode() { return; } } - std::fs::write(PENDING, "").unwrap(); + std::fs::write(&storage.pending, "").unwrap(); } -fn pull() { - let mut c1 = Command::new("scp") - .arg("bot:/home/bot/sleepinggaysbot/urls.csv") - .arg("verified.csv") - .spawn() - .expect("open command failed to start"); - let mut c2 = Command::new("scp") - .arg("bot:/home/bot/sleepinggaysbot/rejected.csv") - .arg("rejected.csv") - .spawn() - .expect("open command failed to start"); - let mut c3 = Command::new("scp") - .arg("bot:/home/bot/sleepinggaysbot/pending.csv") - .arg("pending.csv") - .spawn() - .expect("open command failed to start"); - c1.wait().unwrap(); - c2.wait().unwrap(); - c3.wait().unwrap(); - -} - -fn push() { - let mut c1 = Command::new("scp") - .arg("verified.csv") - .arg("bot:/home/bot/sleepinggaysbot/urls.csv") - .spawn() - .expect("open command failed to start"); - let mut c2 = Command::new("scp") - .arg("rejected.csv") - .arg("bot:/home/bot/sleepinggaysbot/rejected.csv") - .spawn() - .expect("open command failed to start"); - let mut c3 = Command::new("scp") - .arg("pending.csv") - .arg("bot:/home/bot/sleepinggaysbot/pending.csv") - .spawn() - .expect("open command failed to start"); - c1.wait().unwrap(); - c2.wait().unwrap(); - c3.wait().unwrap(); -} - -fn input_parse(image_uri: &str) -> bool { - let key = std::io::stdin() - .lock() - .lines() - .next() - .unwrap() - .unwrap() - .chars() - .next() - .unwrap_or('n'); - match key { - 'b' | 'a' => { +fn input_parse(storage: &Storage, keybinds: &Keybinds, image_uri: &str) -> bool { + loop { + let key = std::io::stdin() + .lock() + .lines() + .next() + .unwrap() + .unwrap() + .chars() + .next() + .unwrap_or('_'); + if &key == &keybinds.quit { + return true; + } else if &key == &keybinds.accept { let mut file = std::fs::OpenOptions::new() .write(true) .append(true) // This is needed to append to file - .open(VERIFIED) + .open(&storage.verified) .unwrap(); write!(file, "{}\n", image_uri).unwrap(); - } - 'q' => return true, - 'd' => { + return false; + } else if &key == &keybinds.delete { let mut file = std::fs::OpenOptions::new() .write(true) .append(true) // This is needed to append to file - .open(REJECTED) + .open(&storage.rejected) .unwrap(); write!(file, "{}\n", image_uri).unwrap(); + return false; } - _ => return input_parse(image_uri), - }; - false + } } diff --git a/synced_run.sh b/synced_run.sh new file mode 100755 index 0000000..0f9a9dc --- /dev/null +++ b/synced_run.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +rsync -v\ + bot:/home/bot/sleepinggaysbot/*.csv\ + . &&\ +bitch $@ &&\ +rsync -v\ + *.csv\ + bot:/home/bot/sleepinggaysbot/ +