mirror of
https://github.com/SinTan1729/movie-rename.git
synced 2024-12-26 12:18:37 -06:00
new: Do argparsing using clap-rs instead of handwritten parser
This commit is contained in:
parent
b62bffd340
commit
67dcd9e378
4 changed files with 139 additions and 93 deletions
94
Cargo.lock
generated
94
Cargo.lock
generated
|
@ -26,6 +26,54 @@ dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstream"
|
||||||
|
version = "0.6.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"anstyle-parse",
|
||||||
|
"anstyle-query",
|
||||||
|
"anstyle-wincon",
|
||||||
|
"colorchoice",
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-parse"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
|
||||||
|
dependencies = [
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-query"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-wincon"
|
||||||
|
version = "3.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-trait"
|
name = "async-trait"
|
||||||
version = "0.1.77"
|
version = "0.1.77"
|
||||||
|
@ -104,6 +152,39 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "4.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da"
|
||||||
|
dependencies = [
|
||||||
|
"clap_builder",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_builder"
|
||||||
|
version = "4.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"clap_lex",
|
||||||
|
"strsim",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorchoice"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
|
@ -468,6 +549,7 @@ dependencies = [
|
||||||
name = "movie-rename"
|
name = "movie-rename"
|
||||||
version = "2.2.2"
|
version = "2.2.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"clap",
|
||||||
"inquire",
|
"inquire",
|
||||||
"load_file",
|
"load_file",
|
||||||
"tmdb-api",
|
"tmdb-api",
|
||||||
|
@ -845,6 +927,12 @@ version = "0.9.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.52"
|
version = "2.0.52"
|
||||||
|
@ -1074,6 +1162,12 @@ dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "want"
|
name = "want"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
|
|
|
@ -20,6 +20,7 @@ tmdb-api = "0.5.0"
|
||||||
inquire = "0.6.2"
|
inquire = "0.6.2"
|
||||||
load_file = "1.0.1"
|
load_file = "1.0.1"
|
||||||
tokio = { version = "1.32.0", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1.32.0", features = ["macros", "rt-multi-thread"] }
|
||||||
|
clap = { version = "4.5.1", features = ["cargo"] }
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
strip = true
|
strip = true
|
||||||
|
|
111
src/functions.rs
111
src/functions.rs
|
@ -1,8 +1,9 @@
|
||||||
|
use clap::{arg, command, ArgAction};
|
||||||
use inquire::{
|
use inquire::{
|
||||||
ui::{Color, IndexPrefix, RenderConfig, Styled},
|
ui::{Color, IndexPrefix, RenderConfig, Styled},
|
||||||
InquireError, Select,
|
InquireError, Select,
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, fs, path::Path, process::exit};
|
use std::{collections::HashMap, fs, path::Path};
|
||||||
use tmdb_api::{
|
use tmdb_api::{
|
||||||
movie::{credits::MovieCredits, search::MovieSearch},
|
movie::{credits::MovieCredits, search::MovieSearch},
|
||||||
prelude::Command,
|
prelude::Command,
|
||||||
|
@ -12,9 +13,6 @@ use torrent_name_parser::Metadata;
|
||||||
|
|
||||||
use crate::structs::{get_long_lang, Language, MovieEntry};
|
use crate::structs::{get_long_lang, Language, MovieEntry};
|
||||||
|
|
||||||
// Get the version from Cargo.toml
|
|
||||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
|
||||||
|
|
||||||
// Function to process movie entries
|
// Function to process movie entries
|
||||||
pub async fn process_file(
|
pub async fn process_file(
|
||||||
filename: &String,
|
filename: &String,
|
||||||
|
@ -209,80 +207,41 @@ pub async fn process_file(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to process the passed arguments
|
// Function to process the passed arguments
|
||||||
pub fn process_args(mut args: Vec<String>) -> (Vec<String>, HashMap<&'static str, bool>) {
|
pub fn process_args() -> (Vec<String>, HashMap<String, bool>) {
|
||||||
// Remove the entry corresponding to the running process
|
let matches = command!()
|
||||||
args.remove(0);
|
.name("movie-rename")
|
||||||
let mut entries = Vec::new();
|
.author("Sayantan Santra <sayantan.santra@gmail.com>")
|
||||||
let mut settings = HashMap::from([("dry_run", false), ("directory", false), ("lucky", false)]);
|
.about("A simple tool to rename movies, written in Rust.")
|
||||||
for arg in args {
|
.arg(arg!(-d --directory "Run in directory mode").action(ArgAction::SetTrue))
|
||||||
match arg.as_str() {
|
.arg(arg!(-n --"dry-run" "Do a dry run").action(ArgAction::SetTrue))
|
||||||
"--help" | "-h" => {
|
.arg(arg!(-l --"i-feel-lucky" "Always choose the first option").action(ArgAction::SetTrue))
|
||||||
println!(" The expected syntax is:");
|
.arg(
|
||||||
println!(
|
arg!([entries] "The files/directories to be processed")
|
||||||
" movie-rename <filename(s)> [-n|--dry-run] [-d|--directory] [-l|--i-feel-lucky] [-v|--version]"
|
.trailing_var_arg(true)
|
||||||
);
|
.num_args(1..)
|
||||||
println!(
|
.required(true),
|
||||||
" There needs to be a config file named config in the $XDG_CONFIG_HOME/movie-rename/ directory."
|
)
|
||||||
);
|
// Use -v instead of -V for version
|
||||||
println!(" It should consist of two lines. The first line should have your TMDb API key.");
|
.disable_version_flag(true)
|
||||||
println!(
|
.arg(arg!(-v --version "Print version").action(ArgAction::Version))
|
||||||
" The second line should have a pattern, that will be used for the rename."
|
.arg_required_else_help(true)
|
||||||
);
|
.get_matches();
|
||||||
println!(" In the pattern, the variables need to be enclosed in {{}}, the supported variables are `title`, `year` and `director`.");
|
|
||||||
println!(
|
// Generate the settings HashMap from read flags
|
||||||
" Default pattern is `{{title}} ({{year}}) - {{director}}`. Extension is always kept."
|
let mut settings = HashMap::new();
|
||||||
);
|
for id in matches.ids().map(|x| x.as_str()) {
|
||||||
println!(" Passing --directory or -d assumes that the arguments are directory names, which contain exactly one movie and optionally subtitles.");
|
if id != "entries" {
|
||||||
println!(" Passing --dry-run or -n does a dry tun and only prints out the new names, without actually doing anything.");
|
settings.insert(id.to_string(), matches.get_flag(id));
|
||||||
println!(
|
|
||||||
" You can join the short flags -d, -n and -l together (e.g. -dn or -dln)."
|
|
||||||
);
|
|
||||||
println!(" Passing --version or -v shows version and exits.");
|
|
||||||
println!(" Pass --help to get this again.");
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
"--version" | "-v" => {
|
|
||||||
println!("movie-rename {VERSION}");
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
"--dry-run" => {
|
|
||||||
println!("Doing a dry run...");
|
|
||||||
settings.entry("dry_run").and_modify(|x| *x = true);
|
|
||||||
}
|
|
||||||
"--i-feel-lucky" => {
|
|
||||||
println!("Choosing the first option automatically...");
|
|
||||||
settings.entry("lucky").and_modify(|x| *x = true);
|
|
||||||
}
|
|
||||||
"--directory" => {
|
|
||||||
println!("Running in directory mode...");
|
|
||||||
settings.entry("directory").and_modify(|x| *x = true);
|
|
||||||
}
|
|
||||||
other => {
|
|
||||||
if other.starts_with('-') {
|
|
||||||
if !other.starts_with("--") && other.len() < 5 {
|
|
||||||
// Process short args
|
|
||||||
if other.contains('l') {
|
|
||||||
println!("Choosing the first option automatically...");
|
|
||||||
settings.entry("lucky").and_modify(|x| *x = true);
|
|
||||||
}
|
|
||||||
if other.contains('d') {
|
|
||||||
println!("Running in directory mode...");
|
|
||||||
settings.entry("directory").and_modify(|x| *x = true);
|
|
||||||
}
|
|
||||||
if other.contains('n') {
|
|
||||||
println!("Doing a dry run...");
|
|
||||||
settings.entry("dry_run").and_modify(|x| *x = true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
eprintln!("Unknown argument passed: {other}");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
entries.push(arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Every unmatched argument should be treated as a file entry
|
||||||
|
let entries: Vec<String> = matches
|
||||||
|
.get_many::<String>("entries")
|
||||||
|
.expect("No entries provided!")
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
|
||||||
(entries, settings)
|
(entries, settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
26
src/main.rs
26
src/main.rs
|
@ -9,11 +9,11 @@ mod structs;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
// Read arguments from commandline
|
|
||||||
let args: Vec<String> = env::args().collect();
|
|
||||||
|
|
||||||
// Process the passed arguments
|
// Process the passed arguments
|
||||||
let (entries, settings) = process_args(args);
|
let (entries, settings) = process_args();
|
||||||
|
let flag_dry_run = *settings.get("dry-run").unwrap_or(&false);
|
||||||
|
let flag_directory = *settings.get("directory").unwrap_or(&false);
|
||||||
|
let flag_lucky = *settings.get("i-feel-lucky").unwrap_or(&false);
|
||||||
|
|
||||||
// Try to read config file, or display error
|
// Try to read config file, or display error
|
||||||
let mut config_file = env::var("XDG_CONFIG_HOME").unwrap_or(String::from("$HOME"));
|
let mut config_file = env::var("XDG_CONFIG_HOME").unwrap_or(String::from("$HOME"));
|
||||||
|
@ -43,20 +43,12 @@ async fn main() {
|
||||||
// Iterate over entries
|
// Iterate over entries
|
||||||
for entry in entries {
|
for entry in entries {
|
||||||
// Check if the file/directory exists on disk and run necessary commands
|
// Check if the file/directory exists on disk and run necessary commands
|
||||||
match settings["directory"] {
|
match flag_directory {
|
||||||
// Normal file
|
// Normal file
|
||||||
false => {
|
false => {
|
||||||
if Path::new(entry.as_str()).is_file() {
|
if Path::new(entry.as_str()).is_file() {
|
||||||
// Process the filename for movie entries
|
// Process the filename for movie entries
|
||||||
process_file(
|
process_file(&entry, &tmdb, pattern, flag_dry_run, flag_lucky, None).await;
|
||||||
&entry,
|
|
||||||
&tmdb,
|
|
||||||
pattern,
|
|
||||||
settings["dry_run"],
|
|
||||||
settings["lucky"],
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
} else {
|
} else {
|
||||||
eprintln!("The file {entry} wasn't found on disk, skipping...");
|
eprintln!("The file {entry} wasn't found on disk, skipping...");
|
||||||
continue;
|
continue;
|
||||||
|
@ -77,8 +69,8 @@ async fn main() {
|
||||||
&filename,
|
&filename,
|
||||||
&tmdb,
|
&tmdb,
|
||||||
pattern,
|
pattern,
|
||||||
settings["dry_run"],
|
flag_dry_run,
|
||||||
settings["lucky"],
|
flag_lucky,
|
||||||
Some(&movie_list),
|
Some(&movie_list),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
@ -109,7 +101,7 @@ async fn main() {
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
println!("[directory] '{entry_clean}' -> '{name}'",);
|
println!("[directory] '{entry_clean}' -> '{name}'",);
|
||||||
if !settings["dry_run"] {
|
if !flag_dry_run {
|
||||||
if !Path::new(name.as_str()).is_dir() {
|
if !Path::new(name.as_str()).is_dir() {
|
||||||
fs::rename(entry, name)
|
fs::rename(entry, name)
|
||||||
.expect("Unable to rename directory!");
|
.expect("Unable to rename directory!");
|
||||||
|
|
Loading…
Reference in a new issue