FEATURE: Implement force re-processing
All checks were successful
Publish Python Package to PyPI / deploy (push) Successful in 15s

Adds a `--force-reprocess` flag to override the new default behavior of skipping existing files. The README has been updated accordingly.
This commit is contained in:
2025-06-06 11:15:03 -04:00
parent 6e13ce070f
commit 99b501daec
3 changed files with 43 additions and 7 deletions

View File

@ -50,6 +50,10 @@ This tool is perfect for users who want to standardize their media library's aud
* Files are skipped entirely if no audio streams in the target languages meet the criteria for transcoding, preventing empty or unnecessary output files. * Files are skipped entirely if no audio streams in the target languages meet the criteria for transcoding, preventing empty or unnecessary output files.
* **Efficient Processing:**
* The script automatically skips processing a file if an output file with the target name already exists. This allows you to safely re-run the script on the same directory to only process new files. Use the `--force-reprocess` flag to override this behavior.
* **Flexible Output:** * **Flexible Output:**
* Save processed files alongside originals or in a specified output directory, maintaining the source folder structure if applicable. * Save processed files alongside originals or in a specified output directory, maintaining the source folder structure if applicable.
@ -99,11 +103,15 @@ __*This will use all available CPU cores for maximum speed.*__
`eac3-transcode --input "video.mkv" --langs "eng,spa" --bitrate "640k" --jobs 4` `eac3-transcode --input "video.mkv" --langs "eng,spa" --bitrate "640k" --jobs 4`
5. **Force the script to re-process all files, even those that already exist:**
`eac3-transcode --input "/path/to/your/video_folder/" --force-reprocess`
## Command-Line Options ## Command-Line Options
**Usage:** **Usage:**
`eac3-transcode [-h] -i INPUT_PATH [-o OUTPUT_DIRECTORY_BASE] [-br AUDIO_BITRATE] [-l LANGUAGES] [-j JOBS] [--dry-run]` `eac3-transcode [-h] -i INPUT_PATH [-o OUTPUT_DIRECTORY_BASE] [-br AUDIO_BITRATE] [-l LANGUAGES] [-j JOBS] [--dry-run] [--force-reprocess]`
An advanced video transcoder that processes files to use E-AC3 for specific audio tracks, filters by language, and can process entire folders. An advanced video transcoder that processes files to use E-AC3 for specific audio tracks, filters by language, and can process entire folders.
**Options:** **Options:**
@ -129,15 +137,23 @@ An advanced video transcoder that processes files to use E-AC3 for specific audi
* `--dry-run` * `--dry-run`
**(Optional)** Analyze files and report actions without executing ffmpeg. No files will be modified. **(Optional)** Analyze files and report actions without executing ffmpeg. No files will be modified.
* `--force-reprocess`
**(Optional)** Force reprocessing of all files, even if an output file with the target name already exists.
## How It Works ## How It Works
1. **File Discovery:** The script scans the input path for `.mkv` and `.mp4` files. 1. **File Discovery:** The script scans the input path for `.mkv` and `.mp4` files.
2. **Stream Analysis (using `ffprobe`):** For each file: 2. **Pre-flight Checks:**
* **Existence Check:** The script first determines the final output filename. If that file already exists and `--force-reprocess` is NOT used, the script skips the file and moves to the next one.
3. **Stream Analysis (using `ffprobe`):** For each file:
* It extracts information about all audio streams: codec, channels, and language tags. * It extracts information about all audio streams: codec, channels, and language tags.
3. **Decision Logic:** 4. **Decision Logic:**
* **Language Filter:** Only audio streams matching the languages provided with the `-l LANGUAGES, --langs LANGUAGES` option are considered for keeping. **This defaults to `eng,jpn`**. Others are marked to be dropped. * **Language Filter:** Only audio streams matching the languages provided with the `-l LANGUAGES, --langs LANGUAGES` option are considered for keeping. **This defaults to `eng,jpn`**. Others are marked to be dropped.
@ -147,7 +163,7 @@ An advanced video transcoder that processes files to use E-AC3 for specific audi
* **File Skipping:** If no audio streams are marked for 'transcode', the entire file is skipped. * **File Skipping:** If no audio streams are marked for 'transcode', the entire file is skipped.
4. **Processing (using `ffmpeg`):** 5. **Processing (using `ffmpeg`):**
* If not in `--dry-run` mode, a new FFmpeg command is constructed. This processing is done in parallel for multiple files, with a progress bar updating you on the status of the batch. * If not in `--dry-run` mode, a new FFmpeg command is constructed. This processing is done in parallel for multiple files, with a progress bar updating you on the status of the batch.
@ -171,7 +187,11 @@ An advanced video transcoder that processes files to use E-AC3 for specific audi
* **No files processed / "Skipping 'filename': No audio streams in the desired languages... meet criteria..."**: * **No files processed / "Skipping 'filename': No audio streams in the desired languages... meet criteria..."**:
* This is expected behavior if the files scanned do not contain any audio tracks in the target languages that require transcoding to E-AC3. This message reflects the default languages (`eng,jpn`) or the ones you specified with `--langs`. Use `--dry-run` to confirm the logic without waiting for processing. * This is expected if files don't meet the criteria. Check the log message:
* **"Output file already exists.":** This is the default behavior. The script will not re-process a file if the output (`filename_eac3.mkv`) is already present. Use `--force-reprocess` if you want to overwrite it.
* **"No audio streams... meet criteria":** This means no audio tracks in the target languages require transcoding to E-AC3. This reflects the default languages (`eng,jpn`) or the ones you specified with `--langs`.
* **Permission Errors:** * **Permission Errors:**

View File

@ -1,6 +1,6 @@
[metadata] [metadata]
name = surround-to-eac3 name = surround-to-eac3
version = 0.3.3 version = 0.3.4
author = Jonathan Rampersad author = Jonathan Rampersad
author_email = jonathan@jono-rams.work author_email = jonathan@jono-rams.work
description = A CLI tool to transcode 5.1 audio in video files to E-AC3. description = A CLI tool to transcode 5.1 audio in video files to E-AC3.

View File

@ -257,6 +257,15 @@ def process_single_file(filepath: str, pbar_position: int, args: argparse.Namesp
output_dir_for_this_file = args.output_directory_base output_dir_for_this_file = args.output_directory_base
final_output_filepath = os.path.join(output_dir_for_this_file, output_filename) final_output_filepath = os.path.join(output_dir_for_this_file, output_filename)
# Check if the output file already exists and we are NOT forcing reprocessing.
if os.path.exists(final_output_filepath) and not args.force_reprocess:
file_specific_logs.append(f" ⏭️ Skipping: Output file already exists. Use --force-reprocess to override.")
with tqdm_lock:
for log_msg in file_specific_logs:
tqdm.write(log_msg)
final_status = "skipped_existing"
return final_status
# Check for identical paths before starting # Check for identical paths before starting
if os.path.abspath(filepath) == os.path.abspath(final_output_filepath): if os.path.abspath(filepath) == os.path.abspath(final_output_filepath):
@ -365,6 +374,11 @@ def main():
action="store_true", # Makes it a flag, e.g., --dry-run action="store_true", # Makes it a flag, e.g., --dry-run
help="Analyze files and report actions without executing ffmpeg." help="Analyze files and report actions without executing ffmpeg."
) )
parser.add_argument(
"--force-reprocess",
action="store_true",
help="Force reprocessing of all files, even if an output file with the target name already exists."
)
args = parser.parse_args() args = parser.parse_args()
@ -403,6 +417,7 @@ def main():
"skipped_no_ops": 0, "skipped_no_ops": 0,
"skipped_no_transcode": 0, "skipped_no_transcode": 0,
"skipped_identical_path": 0, "skipped_identical_path": 0,
"skipped_existing": 0,
"failed": 0 "failed": 0
} }
@ -451,11 +466,12 @@ def main():
print(f"\n{summary_title}") print(f"\n{summary_title}")
print(f"Total files checked: {len(files_to_process_paths)}") print(f"Total files checked: {len(files_to_process_paths)}")
print(f"{processed_label}: {stats['processed']}") print(f"{processed_label}: {stats['processed']}")
total_skipped = stats['skipped_no_ops'] + stats['skipped_no_transcode'] + stats['skipped_identical_path'] total_skipped = stats['skipped_no_ops'] + stats['skipped_no_transcode'] + stats['skipped_identical_path'] + stats['skipped_existing']
print(f"⏭️ Total Skipped: {total_skipped}") print(f"⏭️ Total Skipped: {total_skipped}")
if total_skipped > 0: if total_skipped > 0:
print(f" - No target audio operations: {stats['skipped_no_ops']}") print(f" - No target audio operations: {stats['skipped_no_ops']}")
print(f" - No transcoding required (all copy): {stats['skipped_no_transcode']}") print(f" - No transcoding required (all copy): {stats['skipped_no_transcode']}")
print(f" - Identical input/output path: {stats['skipped_identical_path']}") print(f" - Identical input/output path: {stats['skipped_identical_path']}")
print(f" - Output file already exists: {stats['skipped_existing']}")
print(f"🚨 Failed to process: {stats['failed']}") print(f"🚨 Failed to process: {stats['failed']}")
print("--------------------------") print("--------------------------")