Compare commits

...

7 Commits

6 changed files with 227 additions and 143 deletions

133
Cargo.lock generated
View File

@ -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",
]

View File

@ -1,6 +1,6 @@
[package]
name = "booru_image_tag_curating_helper"
version = "0.1.0"
name = "bitch"
version = "0.2.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -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"

View File

@ -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
- [x] Bot daemon (Ultimately using cron)
- [x] Masto API (https://git.fai.st/Suguivy/mastodon-image-uploader-bot)

15
config.toml Normal file
View File

@ -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"

View File

@ -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<String>,
}
#[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::<String>();
let image_set2 = std::fs::read(VERIFIED)
.expect("File not found")
.iter()
.map(|c| *c as char)
.collect::<String>();
let image_set3 = std::fs::read(REJECTED)
.expect("File not found")
.iter()
.map(|c| *c as char)
.collect::<String>();
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::<HashSet<_>>();
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
}
}

10
synced_run.sh Executable file
View File

@ -0,0 +1,10 @@
#!/bin/bash
rsync -v\
bot:/home/bot/sleepinggaysbot/*.csv\
. &&\
bitch $@ &&\
rsync -v\
*.csv\
bot:/home/bot/sleepinggaysbot/