diff --git a/README.md b/README.md index be12a6a..c6057ed 100644 --- a/README.md +++ b/README.md @@ -14,15 +14,37 @@ cargo install --git https://git.deadbsd.org/falso/rmv.git To use `rmv`, you need to specify the path to the directory where the files to be renamed are located, a regular expression pattern to match against the filenames, and a replacement pattern for the matched filenames. -In the `--replacement` argument, you can use reference groups in the pattern by using `\1`, `\2`, etc. For example, if you have a pattern `"S(\d+)E(\d+)"`that matches `"S01E11"` and you want to replace it with `"Season 01 Episode 02"`, you can use the following replacement pattern: `"Season \1 Episode \2"`. +`rmv --path --pattern --replacement ` + +### `--path` + +The `--path` argument specifies the path to the directory where the files to be renamed are located. This argument is required. + +### `--pattern` + +The `--pattern` argument specifies the regular expression pattern to match against the filenames. This argument is required. + +You can use matching groups in the pattern to capture parts of the filename that you want to use in the replacement pattern. For example, the pattern `"S(\d+)E(\d+)"` will match on `"S01E23"` and capture `"01"` in group `1` and `"23"` in group `2`. + +### `--replacement` + +The `--replacement` argument specifies the replacement pattern for the matched filenames. This argument is required. + +You can use reference groups in the pattern by using `\1`, `\2`, etc. to refer to the captured groups in the `--pattern` argument. For example, if you have a pattern `"S(\d+)E(\d+)"` that matches `"S01E11"` and you want to replace it with `"Season 01 Episode 02"`, you can use the following replacement pattern: `"Season \1 Episode \2"`. + +You can also use the following special tags in the replacement pattern: + +* `{full_name}` - file name with extension +* `{name}` - filename without extension +* `{ext}` - extension Here is an example usage: ```shell -$ rmv --path /path/to/files --pattern "S(\d+)E(\d+).*\.(...)" --replacement "Season \1 Episode \2.\3" --wildcard "*.mkv" +$ rmv --path /path/to/files --pattern "S(\d+)E(\d+)" --replacement "Season \1 Episode \2.{ext}" --wildcard "*.mkv" ``` -This will match all filenames in the directory that match the pattern `"S(\d+)E(\d+).*\.(...)"` and replace them with the pattern `"Season \1 Episode \2.\3"`. Only files with the `".mkv"` extension will be considered. +This will match all filenames in the directory that match the pattern `"S(\d+)E(\d+)"` and replace them with the pattern `"Season \1 Episode \2.{ext}"`. Only files with the `".mkv"` extension will be considered. ```shell mv "Not Warez - S01E16 - HDTV-720p.mkv" "Season 01 Episode 16.mkv" @@ -43,11 +65,17 @@ Here are the available options: -s, --pattern Regular expression pattern to match against the filenames in the directory. - The pattern should contain match groups (expressed in parentheses). Example: "S(\d+)E(\d+).*\.(...)" + The pattern should contain match groups (expressed in parentheses). + Example: "S(\d+)E(\d+).*\.(...)" -r, --replacement Replacement pattern for the matched filenames. - You can use `\1`, `\2`, etc. to reference the match groups in the pattern. Example: "Season \1 Episode \2.\3" + You can use `\1`, `\2`, etc. to reference the match groups in the pattern. + There are also the following tags available: + * {full_name} - file name with extension + * {name} - filename without extension + * {ext} - extension + Example: "Season \1 Episode \2.{ext}" -w, --wildcard Filename wildcard to filter the files to be renamed in the directory. diff --git a/src/main.rs b/src/main.rs index 10ef3f8..1455b63 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use clap::Parser; use glob::glob; use regex::Regex; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; #[derive(Parser, Debug)] #[command(author, version, about)] @@ -13,14 +13,24 @@ struct Args { /// Regular expression pattern to match against the filenames in the directory. /// /// The pattern should contain match groups (expressed in parentheses). - /// Example: "S(\d+)E(\d+).*\.(...)" + /// + /// Example: "S(\d+)E(\d+)" #[arg(short = 's', long)] pattern: String, /// Replacement pattern for the matched filenames. /// /// You can use `\1`, `\2`, etc. to reference the match groups in the pattern. - /// Example: "Season \1 Episode \2.\3" + /// + /// There are also the following tags available: + /// + /// * {full_name} - file name with extension + /// + /// * {name} - filename without extension + /// + /// * {ext} - extension + /// + /// Example: "Season \1 Episode \2.{ext}" #[arg(short = 'r', long)] replacement: String, @@ -42,16 +52,34 @@ fn get_file_list(dir_path: &str, wildcard: &str) -> Vec { .collect() } +fn replace_extra_tags(original_file_name: &str, new_file_name: &str) -> String { + let path = Path::new(original_file_name); + let name = path.file_stem().unwrap().to_str().unwrap(); + let extension = path.extension().unwrap().to_str().unwrap(); + + let re = Regex::new(r"(\{[^\{\}]+\})").unwrap(); + re.find_iter(new_file_name) + .map(|m| { + let tag = m.as_str(); + match tag { + "{ext}" => new_file_name.replace(tag, extension), + "{full_name}" => new_file_name.replace(tag, original_file_name), + "{name}" => new_file_name.replace(tag, name), + _ => panic!("Invalid tag: {}", tag), + } + }) + .fold(String::new(), |result, s| result + &s) +} + fn main() { let args = Args::parse(); - let dir_path = &args.path; let pattern = &args.pattern; let replacement = &args.replacement; let wildcard = &args.wildcard; - let files = get_file_list(dir_path, wildcard); let re = Regex::new(pattern).unwrap(); + let files = get_file_list(dir_path, wildcard); for file_name in files { for captures in re.captures_iter(&file_name) { @@ -63,6 +91,7 @@ fn main() { replaced_text = replaced_text.replace(&replace_key, &capture_text); } } + replaced_text = replace_extra_tags(&file_name, &replaced_text); println!("mv \"{}\" \"{}\"", file_name, replaced_text); } }