|
|
|
@ -2,8 +2,8 @@ use gelbooru_api::{posts, Client};
|
|
|
|
|
use serde::Deserialize;
|
|
|
|
|
use std::collections::HashSet;
|
|
|
|
|
use std::{
|
|
|
|
|
io::{BufRead, Write},
|
|
|
|
|
process::Command,
|
|
|
|
|
io::{BufRead, Write},
|
|
|
|
|
process::Command,
|
|
|
|
|
};
|
|
|
|
|
use toml;
|
|
|
|
|
|
|
|
|
@ -11,144 +11,144 @@ const CONFIG: &str = "./config.toml";
|
|
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
|
struct Config {
|
|
|
|
|
keybinds: Keybinds,
|
|
|
|
|
search: Search,
|
|
|
|
|
storage: Storage,
|
|
|
|
|
keybinds: Keybinds,
|
|
|
|
|
search: Search,
|
|
|
|
|
storage: Storage,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
|
struct Keybinds {
|
|
|
|
|
quit: char,
|
|
|
|
|
delete: char,
|
|
|
|
|
accept: char,
|
|
|
|
|
quit: char,
|
|
|
|
|
delete: char,
|
|
|
|
|
accept: char,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
|
struct Search {
|
|
|
|
|
tags: Vec<String>,
|
|
|
|
|
tags: Vec<String>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
|
struct Storage {
|
|
|
|
|
pending: String,
|
|
|
|
|
rejected: String,
|
|
|
|
|
verified: String,
|
|
|
|
|
pending: String,
|
|
|
|
|
rejected: String,
|
|
|
|
|
verified: String,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::main]
|
|
|
|
|
async fn main() {
|
|
|
|
|
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(&config.storage, &config.search).await,
|
|
|
|
|
"-v" => verify_mode(&config.keybinds, &config.storage),
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
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(&config.storage, &config.search).await,
|
|
|
|
|
"-v" => verify_mode(&config.keybinds, &config.storage),
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 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")
|
|
|
|
|
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(&search.tags).send(&client);
|
|
|
|
|
let client = Client::public();
|
|
|
|
|
let posts = posts().random(true).tags(&search.tags).send(&client);
|
|
|
|
|
|
|
|
|
|
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 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 = pending_set
|
|
|
|
|
.lines()
|
|
|
|
|
.chain(rejected_set.lines())
|
|
|
|
|
.chain(verified_set.lines())
|
|
|
|
|
.collect::<HashSet<_>>();
|
|
|
|
|
let image_set = pending_set
|
|
|
|
|
.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(&storage.pending)
|
|
|
|
|
.unwrap();
|
|
|
|
|
let posts = posts.await.unwrap();
|
|
|
|
|
let mut file = std::fs::OpenOptions::new()
|
|
|
|
|
.write(true)
|
|
|
|
|
.append(true) // This is needed to append to file
|
|
|
|
|
.open(&storage.pending)
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
for post in posts.posts {
|
|
|
|
|
let imgurl = post.image_url();
|
|
|
|
|
if !image_set.contains(imgurl) {
|
|
|
|
|
write!(file, "{}\n", imgurl).unwrap();
|
|
|
|
|
}
|
|
|
|
|
for post in posts.posts {
|
|
|
|
|
let imgurl = post.image_url();
|
|
|
|
|
if !image_set.contains(imgurl) {
|
|
|
|
|
write!(file, "{}\n", imgurl).unwrap();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
.collect();
|
|
|
|
|
let mut file = file.lines();
|
|
|
|
|
while let Some(image_uri) = file.next() {
|
|
|
|
|
//Open image
|
|
|
|
|
Command::new("xdg-open")
|
|
|
|
|
.arg(image_uri)
|
|
|
|
|
.spawn()
|
|
|
|
|
.expect("open command failed to start");
|
|
|
|
|
//Print Legend
|
|
|
|
|
println!(
|
|
|
|
|
"{} to quit; {} to delete; {} to accept",
|
|
|
|
|
&keybinds.quit, &keybinds.delete, &keybinds.accept,
|
|
|
|
|
);
|
|
|
|
|
// Wait for input
|
|
|
|
|
if input_parse(storage, keybinds, image_uri) {
|
|
|
|
|
std::fs::write(
|
|
|
|
|
&storage.pending,
|
|
|
|
|
format!(
|
|
|
|
|
"{}\n{}",
|
|
|
|
|
image_uri,
|
|
|
|
|
file.map(|s| s.to_owned() + "\n").collect::<String>()
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
let file: String = std::fs::read(&storage.pending)
|
|
|
|
|
.expect("File not found")
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|c| *c as char)
|
|
|
|
|
.collect();
|
|
|
|
|
let mut file = file.lines();
|
|
|
|
|
while let Some(image_uri) = file.next() {
|
|
|
|
|
//Open image
|
|
|
|
|
Command::new("xdg-open")
|
|
|
|
|
.arg(image_uri)
|
|
|
|
|
.spawn()
|
|
|
|
|
.expect("open command failed to start");
|
|
|
|
|
//Print Legend
|
|
|
|
|
println!(
|
|
|
|
|
"{} to quit; {} to delete; {} to accept",
|
|
|
|
|
&keybinds.quit, &keybinds.delete, &keybinds.accept
|
|
|
|
|
);
|
|
|
|
|
// Wait for input
|
|
|
|
|
if input_parse(storage, keybinds, image_uri) {
|
|
|
|
|
std::fs::write(
|
|
|
|
|
&storage.pending,
|
|
|
|
|
format!(
|
|
|
|
|
"{}\n{}",
|
|
|
|
|
image_uri,
|
|
|
|
|
file.map(|s| s.to_owned() + "\n").collect::<String>()
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
std::fs::write(&storage.pending, "").unwrap();
|
|
|
|
|
}
|
|
|
|
|
std::fs::write(&storage.pending, "").unwrap();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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(&storage.verified)
|
|
|
|
|
.unwrap();
|
|
|
|
|
write!(file, "{}\n", image_uri).unwrap();
|
|
|
|
|
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(&storage.rejected)
|
|
|
|
|
.unwrap();
|
|
|
|
|
write!(file, "{}\n", image_uri).unwrap();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
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(&storage.verified)
|
|
|
|
|
.unwrap();
|
|
|
|
|
write!(file, "{}\n", image_uri).unwrap();
|
|
|
|
|
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(&storage.rejected)
|
|
|
|
|
.unwrap();
|
|
|
|
|
write!(file, "{}\n", image_uri).unwrap();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|