diff --git a/README.md b/README.md index 43a7e30..4be8d03 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@ Because it uses ffmpeg under the hood, it supports any media file processing tha - [Practical examples](#more-practical-examples) 3. [Requirements](#requirements) 4. [All available options](#available-options) -5. [License](#license) +5. [Migrating to 1.0.0](#migrating-to-100) +6. [License](#license) ### Installation @@ -88,11 +89,11 @@ visit [ffmpeg's documentation](https://ffmpeg.org/ffmpeg.html). Re-encode multiple videos to H265 and the audio to opus ```bash -ffzap --input-file files.txt -f "-c:v libx265 -preset medium -crf 23 -c:a libopus -b:a 128k" -o "Output/{{name}}.mp4" -t 2 +ffzap --file-list files.txt -f "-c:v libx265 -preset medium -crf 23 -c:a libopus -b:a 128k" -o "Output/{{name}}.mp4" -t 2 ``` Keypoints: -- use `--input-file` to pass a list of file names to process +- use `--file-list` to pass a list of file names to process - re-encode the video to H265 using `-c:v libx265` - `-preset medium` to balance out speed and file size - `-crf 23` to achieve good quality with reasonable file size @@ -109,11 +110,11 @@ Keypoints: Convert PNG images to JPG ```bash -ffzap --input-file files.txt -f "-c:v mjpeg -q:v 2" -o "Output/{{name}}.jpg" -t 6 +ffzap --file-list files.txt -f "-c:v mjpeg -q:v 2" -o "Output/{{name}}.jpg" -t 6 ``` Keypoints: -- use `--input-file` to pass a list of file names to process +- use `--file-list` to pass a list of file names to process - convert the image to JPG using `-c:v mjpeg` - `-q:v 2` to set very high quality - `-t 6` runs six processes in parallel, converting six files at once @@ -127,12 +128,12 @@ Keypoints: Add a watermark to multiple videos ```bash -ffzap --input-file files.txt -f "-i watermark.png -filter_complex [1]format=rgba,lut=a=val*0.3[watermark];[0][watermark]overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2 -c:a copy" -o "{{name}}_watermark.mp4" -t 2 +ffzap --file-list files.txt -f "-i watermark.png -filter_complex [1]format=rgba,lut=a=val*0.3[watermark];[0][watermark]overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2 -c:a copy" -o "{{name}}_watermark.mp4" -t 2 ``` (Note that this command may not work in Windows Powershell as it requires a different escaping format) Keypoints: -- use `--input-file` to pass a list of file names to process (these are the files the watermark gets added to) +- use `--file-list` to pass a list of file names to process (these are the files the watermark gets added to) - select to watermark file with `-i watermark.png` **inside** `-f` - `-filter_complex` applies the watermark with 70% opacity to the center of each video - `-c:a copy` copies the audio @@ -147,11 +148,11 @@ Keypoints: Resize multiple videos ```bash -ffzap --input-file files.txt -f "-vf scale=1280:720 -c:a copy" -o "{{name}}_resized.mp4" -t 2 +ffzap --file-list files.txt -f "-vf scale=1280:720 -c:a copy" -o "{{name}}_resized.mp4" -t 2 ``` Keypoints: -- use `--input-file` to pass a list of file names to process +- use `--file-list` to pass a list of file names to process - `-vf scale=1280:720` sets the video resolution to HD - `-c:a copy` copies the audio - `-t 2` processes two files in parallel @@ -165,13 +166,13 @@ Keypoints: Swap video containers ```bash -ffzap --input-file files.txt -o "{{name}}.mkv" -t 2 +ffzap --file-list files.txt -o "{{name}}.mkv" -t 2 ``` (It is assumed the source files have a container that's interchangable with MKV) Keypoints: -- use `--input-file` to pass a list of file names to process +- use `--file-list` to pass a list of file names to process - `-o "{{name}}.` to swap all files to the desired container format (in this case MKV) - No `-f` because it's not needed - `-t 2` processes two files in parallel @@ -194,21 +195,21 @@ Keypoints: $ ffzap --help ⚡ A multithreaded CLI for digital media processing using ffmpeg. If ffmpeg can do it, ffzap can do it - as many files in parallel as your system can handle. -Usage: ffzap [OPTIONS] --ffmpeg-options --output +Usage: ffzap [OPTIONS] --output Options: -t, --thread-count The amount of threads you want to utilize. most systems can handle 2. Go higher if you have a powerful computer. Default is 2. Can't be lower than 1 - + [default: 2] -f, --ffmpeg-options Options you want to pass to ffmpeg. For the output file name, use --output - -i, --input-directory ... + -i, --input ... The files you want to process - --input-file + --file-list Path to a file containing paths to process. One path per line --overwrite @@ -222,15 +223,15 @@ Options: -o, --output Specify the output file pattern. Use placeholders to customize file paths: - + {{dir}} - Entire specified file path, e.g. ./path/to/file.txt -> ?./path/to/ - + {{name}} - Original file's name (without extension) - + {{ext}} - Original file's extension - + Example: /destination/{{dir}}/{{name}}_transcoded.{{ext}} - + Outputs the file in /destination, mirroring the original structure and keeping both the file extension and name, while adding _transcoded to the name. -h, --help @@ -242,6 +243,37 @@ Options: + +### Migrating to 1.0.0 + +In version `1.0.0`, the following changes were made: + +- `--input-directory` has been deprecated and replaced by `--input`. +- `--input-file` has been deprecated and replaced by `--file-list`. + +#### 1. Replacing `--input-directory` with `--input`: + +Instead of using `--input-directory`, you now have to use `--input` to specify the files you want to process: + +```bash +ffzap --input -f "" -o "" +``` + +**Note:** The short form `-i` remains unaffected by this change. + +#### 2. Replacing `--input-file` with `--file-list`: + +Instead of `--input-file`, use `--file-list` to specify a file containing a list of files to process: + +```bash +ffzap --file-list -f "" -o "" +``` + +--- + +For further details and motivation behind these changes, refer to [issue 16](https://github.com/CodeF0x/ffzap/issues/16). + + ### License You are free to: diff --git a/src/main.rs b/src/main.rs index 0071a34..e3edfcc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,11 +24,36 @@ struct CmdArgs { ffmpeg_options: Option, /// The files you want to process. - #[arg(short, long, num_args = 1.., required_unless_present = "input_file", conflicts_with = "input_file")] + #[arg(short, long, num_args = 1.., required_unless_present = "file_list", required_unless_present = "input_directory", required_unless_present = "input_file", conflicts_with = "file_list", conflicts_with = "input_directory", conflicts_with = "input_file")] + input: Option>, + + // DEPRECATED: and kept for showing an error if still used + #[arg(long, num_args = 1.., required_unless_present = "input", required_unless_present = "input_file", required_unless_present = "file_list", conflicts_with = "file_list", conflicts_with = "input", conflicts_with = "file_list", conflicts_with = "input_file", hide = true)] input_directory: Option>, /// Path to a file containing paths to process. One path per line - #[arg(long, required_unless_present = "input_directory", conflicts_with = "input_directory")] + #[arg( + long, + required_unless_present = "input", + required_unless_present = "input_directory", + required_unless_present = "input_file", + conflicts_with = "input", + conflicts_with = "input_directory", + conflicts_with = "input_file" + )] + file_list: Option, + + // DEPRECATED: kept for showing an error if still used + #[arg( + long, + required_unless_present = "input_directory", + required_unless_present = "input", + required_unless_present = "file_list", + conflicts_with = "input_directory", + conflicts_with = "input", + conflicts_with = "file_list", + hide = true + )] input_file: Option, /// If ffmpeg should overwrite files if they already exist. Default is false @@ -62,8 +87,17 @@ struct CmdArgs { fn main() { let cmd_args = CmdArgs::parse(); + if let Some(_) = cmd_args.input_directory { + eprintln!("Error: --input-directory is deprecated and will get removed in the next release. Use --input instead."); + exit(1); + } + if let Some(_) = cmd_args.input_file { + eprintln!("Error: --input-file is deprecated and will get removed in the next release. Use --file-list instead."); + exit(1); + } + let paths: Vec; - if let Some(input_file_path) = cmd_args.input_file { + if let Some(input_file_path) = cmd_args.file_list { paths = match fs::read_to_string(&input_file_path) { Ok(contents) => contents .trim() @@ -92,7 +126,7 @@ fn main() { } } } else { - paths = cmd_args.input_directory.unwrap(); + paths = cmd_args.input.unwrap(); } let paths = Arc::new(Mutex::new(paths)); @@ -133,9 +167,8 @@ fn main() { logger.log_info(format!("Processing {}", path.display()), thread, verbose); let split_options = match &ffmpeg_options { - Some(options) => - options.split(' ').collect::>(), - None => vec![] + Some(options) => options.split(' ').collect::>(), + None => vec![], }; let mut final_file_name = @@ -221,7 +254,11 @@ fn main() { progress.inc(1); } else { logger.log_error( - format!("Error processing file {}. Error is: {}", path.display(), String::from_utf8_lossy(&output.stderr)), + format!( + "Error processing file {}. Error is: {}", + path.display(), + String::from_utf8_lossy(&output.stderr) + ), thread, verbose, ); @@ -229,7 +266,7 @@ fn main() { logger.log_info( "Keeping the file due to the error above".to_string(), thread, - verbose + verbose, ) } logger.log_info( @@ -238,7 +275,10 @@ fn main() { verbose, ); - failed_paths.lock().unwrap().push(path.display().to_string()); + failed_paths + .lock() + .unwrap() + .push(path.display().to_string()); } } else { eprintln!("[THREAD {thread}] -- There was an error running ffmpeg. Please check if it's correctly installed and working as intended.");