summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--README.md3
-rwxr-xr-xtranscode.sh49
-rw-r--r--transcode.sh.127
-rw-r--r--transcode.sh.bash-completion2
4 files changed, 76 insertions, 5 deletions
diff --git a/README.md b/README.md
index 95ffb9b..a01de23 100644
--- a/README.md
+++ b/README.md
@@ -153,6 +153,7 @@ quiet = false
|---------|-----|------|----------------|
| `[encoding]` | `preset` | string | `-p` |
| `[encoding]` | `nice` | integer | `-N` |
+| `[encoding]` | `verify_output` | boolean | `--verify-output` |
| `[skip]` | `codecs` | array of strings | `-S` (merged with CLI) |
| `[saving]` | `enabled` | boolean | `-s` |
| `[saving]` | `file` | string | `--saving-file` |
@@ -178,6 +179,8 @@ transcode.sh [OPTION] [--] FILE...
|--------|-------------|
| `-c`, `--continue` | Continue to next file if ffmpeg fails |
| `--no-continue` | Do not continue with the next file if ffmpeg fails |
+| `--verify-output` | Probe output with ffprobe before replacing original (default) |
+| `--no-verify-output` | Skip the post-encode integrity check |
| `--config-file FILE`, `--config-file=FILE` | Load configuration from FILE instead of the default path |
| `-f PATH`, `--encode-file PATH`, `--encodefile=PATH` | Read file list from PATH (one per line) |
| `-n`, `--dry-run` | Show what would be done; don't run ffmpeg |
diff --git a/transcode.sh b/transcode.sh
index 9d66f49..9125627 100755
--- a/transcode.sh
+++ b/transcode.sh
@@ -149,6 +149,7 @@ PRESET_NAME="default"
SAVING=0
SAVING_FILE="transcode_savings"
SAVING_FILE_EXPLICIT=0
+VERIFY_OUTPUT=1
declare -A SKIP_CODECS
REMAINING_ARGS=()
@@ -163,14 +164,15 @@ readonly SKIP_CODECS_FILE="${XDG_CONFIG_HOME:-$HOME/.config}/transcode.sh/skip.c
# Sentinel flags: set to 1 by the CLI option parser so that load_config()
# knows which values have already been provided and must not be overridden.
_CLI_CONFIG_FILE=0
-_CLI_PRESET=0
+_CLI_CONTINUE=0
_CLI_NICE=0
_CLI_ONLY_IF_SMALLER=0
-_CLI_CONTINUE=0
+_CLI_PRESET=0
+_CLI_QUIET=0
_CLI_SAVING=0
_CLI_SAVING_FILE=0
-_CLI_QUIET=0
_CLI_VERBOSE=0
+_CLI_VERIFY_OUTPUT=0
###############################################################################
# EXIT CODES
@@ -244,6 +246,8 @@ ${BOLD}${BLUE}Encoding options:${ALL_OFF}
${BOLD}${YELLOW}--no-only-if-smaller${ALL_OFF} do replace original even if new file is bigger
${BOLD}${YELLOW}-c, --continue${ALL_OFF} continue with the next file even if ffmpeg fails
${BOLD}${YELLOW}--no-continue${ALL_OFF} do not continue with the next file if ffmpeg fails
+ ${BOLD}${YELLOW}--verify-output${ALL_OFF} probe output with ffprobe before replacing original (default)
+ ${BOLD}${YELLOW}--no-verify-output${ALL_OFF} skip the post-encode integrity check
${BOLD}${BLUE}Input options:${ALL_OFF}
${BOLD}${YELLOW}--config-file${ALL_OFF} ${BOLD}${GREEN}FILE${ALL_OFF} load configuration from FILE instead of the default path
@@ -491,6 +495,14 @@ load_config() {
}
fi
+ # [encoding] verify_output
+ if [[ $_CLI_VERIFY_OUTPUT -eq 0 ]]; then
+ val=$(_tomlq_get '.encoding.verify_output // empty') && [[ -n "$val" ]] && {
+ debug "Config: encoding.verify_output =" "$val"
+ [[ "$val" == "true" ]] && VERIFY_OUTPUT=1 || VERIFY_OUTPUT=0
+ }
+ fi
+
# [skip] codecs (TOML array → one element per line via tomlq -r '.skip.codecs[]')
# CLI --skip-codec entries are additive, so we always load config codecs
# regardless of _CLI_SKIP_CODEC. Both sources merge into SKIP_CODECS.
@@ -667,6 +679,16 @@ while [[ $# -gt 0 ]]; do
_CLI_CONTINUE=1
shift
;;
+ --verify-output)
+ VERIFY_OUTPUT=1
+ _CLI_VERIFY_OUTPUT=1
+ shift
+ ;;
+ --no-verify-output)
+ VERIFY_OUTPUT=0
+ _CLI_VERIFY_OUTPUT=1
+ shift
+ ;;
--config-file)
[[ $# -ge 2 ]] || {
error "Missing value for $1"
@@ -837,6 +859,7 @@ debug " preset:" "$PRESET_NAME"
debug " nice:" "$NICE_VALUE"
debug " dry-run:" "$DRY_RUN"
debug " only-if-smaller:" "$ONLY_IF_SMALLER"
+debug " verify-output:" "$VERIFY_OUTPUT"
debug " saving:" "$SAVING"
debug " saving-file:" "$SAVING_FILE"
debug " skip-codecs:" "${joined# }"
@@ -1082,6 +1105,26 @@ encode_one() {
if nice -n "$NICE_VALUE" "${cmd[@]}"; then
+ # Integrity verification: confirm the encoded output is a valid, playable
+ # file before discarding the original. ffprobe exits non-zero and emits
+ # nothing useful if the container is corrupt or contains no readable
+ # streams, so we treat any non-zero exit as a fatal encode failure.
+ # Skip with --no-verify-output when trust in the encoder is high and the
+ # extra probe round-trip is undesirable.
+ if [[ $VERIFY_OUTPUT -eq 1 ]]; then
+ debug "Verifying output integrity:" "$tmp"
+ if ! ffprobe -v error "file:$tmp" >/dev/null 2>&1; then
+ error "Output failed integrity check:" "$tmp"
+ rm -f -- "$tmp"
+ if [[ $CONTINUE_ON_FAIL -eq 1 ]]; then
+ return $EXIT_RUNTIME_FAILURE
+ else
+ exit $EXIT_RUNTIME_FAILURE
+ fi
+ fi
+ verbose "Integrity check passed:" "$tmp"
+ fi
+
local original_filesize new_filesize
original_filesize=$(filesize "$file")
new_filesize=$(filesize "$tmp")
diff --git a/transcode.sh.1 b/transcode.sh.1
index 9a4c894..92cefa2 100644
--- a/transcode.sh.1
+++ b/transcode.sh.1
@@ -34,8 +34,12 @@ default (\fB\-map 0 \-map_metadata 0 \-map_chapters 0 \-c copy\fR); the
preset only needs to override the streams it cares about (typically
video).
.PP
-Encoding is performed into a temporary file in the same directory as the
-input, which ensures an atomic rename on completion.
+After encoding completes,
+.BR ffprobe (1)
+is run against the temporary output file to verify it is a valid,
+playable media file before the original is replaced. If the integrity
+check fails the temporary file is removed and the encode is treated as a
+runtime failure, leaving the original untouched.
.SH OPTIONS
.TP
.BR \-c ", " \-\-continue
@@ -49,6 +53,19 @@ Do not continue processing next file even if
.BR ffmpeg (1)
fails on the current one.
.TP
+.BR \-\-verify\-output
+After encoding, probe the temporary output file with
+.BR ffprobe (1)
+to confirm it is a valid, playable media file before replacing the
+original. Enabled by default.
+.TP
+.BR \-\-no\-verify\-output
+Skip the post-encode integrity check. The original is replaced as long
+as
+.BR ffmpeg (1)
+exits successfully. Useful for large batch jobs on trusted encoders
+where the additional probe round-trip is undesirable.
+.TP
.BR \-\-config\-file " \fIPATH\fR, " \-\-config\-file= \fIPATH\fR
Load configuration from \fIPATH\fR instead of the default location
.RI ( ${XDG_CONFIG_HOME:-$HOME/.config}/transcode.sh/config.toml ).
@@ -270,6 +287,12 @@ String. Default preset name. Equivalent to
Integer. Default niceness value. Equivalent to
.BR \-N .
.TP
+.B [encoding] verify_output
+Boolean. Equivalent to
+.BR \-\-verify\-output / \-\-no\-verify\-output .
+Defaults to
+.BR true .
+.TP
.B [skip] codecs
Array of strings. Merged with any codecs from
.BR \-S .
diff --git a/transcode.sh.bash-completion b/transcode.sh.bash-completion
index 558cf09..9fc4701 100644
--- a/transcode.sh.bash-completion
+++ b/transcode.sh.bash-completion
@@ -120,6 +120,8 @@ _transcode_sh() {
local longopts='
--continue
--no-continue
+ --verify-output
+ --no-verify-output
--config-file
--config-file=
--encode-file