You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
3.6 KiB
139 lines
3.6 KiB
use super::*;
|
|
|
|
use lazy_static::lazy_static;
|
|
use std::{
|
|
error,
|
|
fmt,
|
|
path::{
|
|
PathBuf,
|
|
Path,
|
|
},
|
|
};
|
|
|
|
lazy_static! {
|
|
pub static ref PROGRAM_NAME: &'static str = Box::leak(std::env::args().next().unwrap().into_boxed_str());
|
|
}
|
|
|
|
/// Print usage then exit with code `1`
|
|
pub fn usage() -> !
|
|
{
|
|
println!(concat!("lolistealer version ", env!("CARGO_PKG_VERSION")));
|
|
println!(concat!(" written by ",env!("CARGO_PKG_AUTHORS")," with <3"));
|
|
println!(" licensed with GNU GPL 3.0 or later\n");
|
|
println!("Usage: {} [-q] [--rating <rating>] [--tags <filter expr>] [<outputs...>]", &PROGRAM_NAME[..]);
|
|
println!("Usage: {} --help", &PROGRAM_NAME[..]);
|
|
|
|
println!("Options:");
|
|
println!(" -q\t\t\tQuiet mode, do not output progress");
|
|
println!(" --rating <rating>\tEither `s`afe, `q`uestionable, or `e`xplicit");
|
|
println!(" --tags <filter expr>\tFilter downloaded images out by tags, see below for format.");
|
|
println!("Tags filter expreession:");
|
|
println!(" tag_name\tMust contain this tag");
|
|
println!(" -tag_name\tMust not contains this tag");
|
|
println!(" +tag_name\tMust contains at least one tag prepended with `+`");
|
|
println!("Note:");
|
|
println!(" Tag filter expreession is a single argument, tags must be seperated with spaces. e.g. 'tag1 -tag2 +tag3 +tag4'");
|
|
#[cfg(feature="async")]
|
|
println!("\n (compiled with threading support)");
|
|
|
|
std::process::exit(1)
|
|
}
|
|
|
|
/// Parse the system args
|
|
pub fn parse_args() -> Result<Mode, Error>
|
|
{
|
|
parse(std::env::args().skip(1))
|
|
}
|
|
|
|
fn try_dir(path: impl AsRef<Path>) -> Result<config::OutputType, Error>
|
|
{
|
|
let path = path.as_ref();
|
|
if path.is_dir() {
|
|
Ok(config::OutputType::Directory(path.to_owned()))
|
|
} else if !path.exists() {
|
|
Ok(config::OutputType::File(path.to_owned()))
|
|
} else {
|
|
Err(Error::FileExists(path.to_owned()))
|
|
}
|
|
}
|
|
|
|
|
|
#[derive(Debug)]
|
|
pub enum Mode {
|
|
Normal(config::Config),
|
|
Help,
|
|
}
|
|
|
|
fn parse<I>(args: I) -> Result<Mode, Error>
|
|
where I: IntoIterator<Item=String>
|
|
{
|
|
let mut args = args.into_iter();
|
|
|
|
let mut rating = config::Rating::default();
|
|
let mut paths = Vec::new();
|
|
let mut one = String::default();
|
|
let mut reading = true;
|
|
let mut tags = Vec::new();
|
|
let mut verbose = Default::default();
|
|
|
|
macro_rules! take_one {
|
|
() => {
|
|
{
|
|
if let Some(new) = args.next() {
|
|
one = new;
|
|
true
|
|
} else {
|
|
false
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
while let Some(arg) = args.next()
|
|
{
|
|
if reading {
|
|
match arg.to_lowercase().trim() {
|
|
"-" => reading = false,
|
|
"--help" => return Ok(Mode::Help),
|
|
"-q" => verbose = config::Verbosity::Silent,
|
|
"--rating" if take_one!() => rating = one.parse::<config::Rating>()?,
|
|
"--tags" if take_one!() => tags = tags::parse(&one),
|
|
_ => paths.push(try_dir(arg)?),
|
|
}
|
|
} else {
|
|
paths.push(try_dir(arg)?);
|
|
}
|
|
}
|
|
|
|
if paths.len() < 1 {
|
|
return Err(Error::NoOutput);
|
|
}
|
|
|
|
Ok(Mode::Normal(config::Config{rating, output: paths, tags, verbose}))
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum Error {
|
|
UnknownRating(String),
|
|
FileExists(PathBuf),
|
|
NoOutput,
|
|
|
|
Internal(Box<dyn error::Error>),
|
|
Unknown,
|
|
}
|
|
impl error::Error for Error{}
|
|
|
|
impl fmt::Display for Error
|
|
{
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
|
{
|
|
match self {
|
|
Error::NoOutput => write!(f, "need at least one output, try `{} --help`", &PROGRAM_NAME[..]),
|
|
Error::UnknownRating(rating) => write!(f, "{} is not a valid rating", rating),
|
|
Error::FileExists(path) => write!(f, "file already exists: {:?}", path),
|
|
Error::Internal(bx) => write!(f, "internal error: {}", bx),
|
|
_ => write!(f, "unknown error"),
|
|
}
|
|
}
|
|
}
|