Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 52 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -88,11 +89,11 @@ visit [ffmpeg's documentation](https://ffmpeg.org/ffmpeg.html).
<summary>Re-encode multiple videos to H265 and the audio to opus</summary>

```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
Expand All @@ -109,11 +110,11 @@ Keypoints:
<summary>Convert PNG images to JPG</summary>

```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
Expand All @@ -127,12 +128,12 @@ Keypoints:
<summary>Add a watermark to multiple videos</summary>

```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
Expand All @@ -147,11 +148,11 @@ Keypoints:
<summary>Resize multiple videos</summary>

```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
Expand All @@ -165,13 +166,13 @@ Keypoints:
<summary>Swap video containers</summary>

```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}}.<desired file extension>` 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
Expand All @@ -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 <FFMPEG_OPTIONS> --output <OUTPUT>
Usage: ffzap [OPTIONS] --output <OUTPUT>

Options:
-t, --thread-count <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 <FFMPEG_OPTIONS>
Options you want to pass to ffmpeg. For the output file name, use --output

-i, --input-directory <INPUT_DIRECTORY>...
-i, --input <INPUT>...
The files you want to process

--input-file <INPUT_FILE>
--file-list <FILE_LIST>
Path to a file containing paths to process. One path per line

--overwrite
Expand All @@ -222,15 +223,15 @@ Options:

-o, --output <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
Expand All @@ -242,6 +243,37 @@ Options:

</details>


### 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 <files here> -f "<options here>" -o "<output pattern here>"
```

**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 <path to list here> -f "<options here>" -o "<output pattern here>"
```

---

For further details and motivation behind these changes, refer to [issue 16](https://github.com/CodeF0x/ffzap/issues/16).


### License

You are free to:
Expand Down
60 changes: 50 additions & 10 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,36 @@ struct CmdArgs {
ffmpeg_options: Option<String>,

/// 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<Vec<String>>,

// 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<Vec<String>>,

/// 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<String>,

// 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<String>,

/// If ffmpeg should overwrite files if they already exist. Default is false
Expand Down Expand Up @@ -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<String>;
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()
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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::<Vec<&str>>(),
None => vec![]
Some(options) => options.split(' ').collect::<Vec<&str>>(),
None => vec![],
};

let mut final_file_name =
Expand Down Expand Up @@ -221,15 +254,19 @@ 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,
);
if cmd_args.delete {
logger.log_info(
"Keeping the file due to the error above".to_string(),
thread,
verbose
verbose,
)
}
logger.log_info(
Expand All @@ -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.");
Expand Down