diff options
| author | Dennis Fink | 2026-05-14 09:04:48 +0200 |
|---|---|---|
| committer | Dennis Fink | 2026-05-14 09:04:48 +0200 |
| commit | 1674b2212e3606c3e74f454f066d5253c53b274d (patch) | |
| tree | 7fbbe157cad08ac4f367837a5817bf0252d05681 | |
| parent | 077ed51e254b9a6af2259b1952e6134ead98afa2 (diff) | |
| download | transcode.sh-1674b2212e3606c3e74f454f066d5253c53b274d.tar.gz transcode.sh-1674b2212e3606c3e74f454f066d5253c53b274d.zip | |
refactor(script): improve readability of encoding flow
Expand compact shell conditionals into explicit if blocks throughout
config loading, codec parsing, cleanup, and file-list handling. Rename
short local variables in encode_one to more descriptive names, including
the input file, temporary output path, command array, and progress
counters.
Also align preset-list output with the shared msg helper and update
colors for preset names.
This makes the main transcoding path easier to read and maintain without
changing the intended encoding behaviour.
Diffstat (limited to '')
| -rwxr-xr-x | transcode.sh | 203 |
1 files changed, 121 insertions, 82 deletions
diff --git a/transcode.sh b/transcode.sh index 0501974..08ed14e 100755 --- a/transcode.sh +++ b/transcode.sh @@ -148,7 +148,7 @@ declare -A SKIP_CODECS REMAINING_ARGS=() -TMP_FILES=() +TEMPORARY_FILES=() readonly PRESET_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/transcode.sh/presets" CONFIG_FILE="${XDG_CONFIG_HOME:-$HOME/.config}/transcode.sh/config.toml" @@ -472,47 +472,65 @@ load_config() { # [encoding] preset if [[ $_CLI_PRESET -eq 0 ]]; then - val=$(_tomlq_get '.encoding.preset // empty') && [[ -n "$val" ]] && { + val=$(_tomlq_get '.encoding.preset // empty') + if [[ -n "$val" ]]; then debug "Config: preset =" "$val" PRESET_NAME="$val" - } + fi fi # [encoding] nice if [[ $_CLI_NICE -eq 0 ]]; then - val=$(_tomlq_get '.encoding.nice // empty') && [[ -n "$val" ]] && { + val=$(_tomlq_get '.encoding.nice // empty') + if [[ -n "$val" ]]; then debug "Config: nice =" "$val" NICE_VALUE="$val" - } + fi fi # [encoding] only_if_smaller if [[ $_CLI_ONLY_IF_SMALLER -eq 0 ]]; then - val=$(_tomlq_get '.encoding.only_if_smaller // empty') && [[ -n "$val" ]] && { + val=$(_tomlq_get '.encoding.only_if_smaller // empty') + if [[ -n "$val" ]]; then debug "Config: encoding.only_if_smaller =" "$val" - [[ "$val" == "true" ]] && ONLY_IF_SMALLER=1 || ONLY_IF_SMALLER=0 - } + if [[ "$val" == "true" ]]; then + ONLY_IF_SMALLER=1 + else + ONLY_IF_SMALLER=0 + fi + fi fi # [encoding] continue if [[ $_CLI_CONTINUE -eq 0 ]]; then - val=$(_tomlq_get '.encoding.continue // empty') && [[ -n "$val" ]] && { + val=$(_tomlq_get '.encoding.continue // empty') + if [[ -n "$val" ]]; then debug "Config: encoding.continue =" "$val" - [[ "$val" == "true" ]] && CONTINUE_ON_FAIL=1 || CONTINUE_ON_FAIL=0 - } + if [[ "$val" == "true" ]]; then + CONTINUE_ON_FAIL=1 + else + CONTINUE_ON_FAIL=0 + fi + fi fi # [encoding] verify_output if [[ $_CLI_VERIFY_OUTPUT -eq 0 ]]; then - val=$(_tomlq_get '.encoding.verify_output // empty') && [[ -n "$val" ]] && { + val=$(_tomlq_get '.encoding.verify_output // empty') + if [[ -n "$val" ]]; then debug "Config: encoding.verify_output =" "$val" - [[ "$val" == "true" ]] && VERIFY_OUTPUT=1 || VERIFY_OUTPUT=0 - } + if [[ "$val" == "true" ]]; then + VERIFY_OUTPUT=1 + else + VERIFY_OUTPUT=0 + fi + fi fi # [encoding] hwaccel if [[ $_CLI_HWACCEL -eq 0 ]]; then - val=$(_tomlq_get '.encoding.hwaccel // empty') && [[ -n "$val" ]] && { + val=$(_tomlq_get '.encoding.hwaccel // empty') + if [[ -n "$val" ]]; then debug "Config: encoding.hwaccel =" "$val" if [[ "$val" == "false" ]]; then HWACCEL=0 @@ -523,7 +541,7 @@ load_config() { HWACCEL_VALUE="$val" fi fi - } + fi fi # [skip] codecs (TOML array → one element per line via tomlq -r '.skip.codecs[]') @@ -531,7 +549,9 @@ load_config() { # regardless of _CLI_SKIP_CODEC. Both sources merge into SKIP_CODECS. local codec while IFS= read -r codec; do - [[ -n "$codec" ]] && add_skip_codec_token "$codec" + if [[ -n "$codec" ]]; then + add_skip_codec_token "$codec" + fi done < <(tomlq -r '.skip.codecs[]?' "$CONFIG_FILE" 2>/dev/null) # [saving] enabled @@ -552,25 +572,36 @@ load_config() { # [output] verbose if [[ $_CLI_VERBOSE -eq 0 ]]; then - val=$(_tomlq_get '.output.verbose // empty') && [[ -n "$val" ]] && { + val=$(_tomlq_get '.output.verbose // empty') + if [[ -n "$val" ]]; then debug "Config: output.verbose =" "$val" - [[ "$val" == "true" ]] && VERBOSE=1 || VERBOSE=0 - } + if [[ "$val" == "true" ]]; then + VERBOSE=1 + else + VERBOSE=0 + fi + fi fi # [output] quiet if [[ $_CLI_QUIET -eq 0 ]]; then - val=$(_tomlq_get '.output.quiet // empty') && [[ -n "$val" ]] && { + val=$(_tomlq_get '.output.quiet // empty') + if [[ -n "$val" ]]; then debug "Config: output.quiet =" "$val" - [[ "$val" == "true" ]] && QUIET=1 || QUIET=0 - } + if [[ "$val" == "true" ]]; then + QUIET=1 + else + QUIET=0 + fi + fi fi } # Add a codec name to the SKIP_CODECS associative array. # - Normalizes to lowercase # - Ignores empty tokens -# - Used both for CLI --skip-codec and for skip.conf lines +# - Used both for CLI --skip-codec and for codecs defined +# in the config file add_skip_codec_token() { local token="${1,,}" # lowercase if [[ ! -v SKIP_CODECS["$token"] ]]; then @@ -587,8 +618,9 @@ parse_skip_codec_parameter() { local arg="$1" local IFS=',: ' token for token in $arg; do - [[ -z "$token" ]] && continue - add_skip_codec_token "$token" + if [[ ! -z "$token" ]]; then + add_skip_codec_token "$token" + fi done } @@ -694,7 +726,7 @@ list_presets() { local canonical_preset_dir canonical_preset_dir=$(resolve_path "$PRESET_DIR") - printf "${BOLD}${BLUE}Available presets in${ALL_OFF} ${BOLD}${CYAN}%s${ALL_OFF}${BOLD}${BLUE}:${ALL_OFF}\n" "$PRESET_DIR" + msg "Available presets in:" "$PRESET_DIR" local target_path target_name description for f in "${preset_files[@]}"; do @@ -706,16 +738,16 @@ list_presets() { if [[ "$target_path" == "$canonical_preset_dir"/*.sh ]]; then target_name="${target_path##*/}" target_name="${target_name%.sh}" - printf " ${BOLD}${GREEN}%-${max_name_len}s${ALL_OFF} ${BOLD}${YELLOW}-${ALL_OFF} Symlinked to ${BOLD}${GREEN}%s${ALL_OFF}\n" "$name" "$target_name" + printf "${BOLD}${BLUE}%-${max_name_len}s${ALL_OFF} ${BOLD}${YELLOW}-${ALL_OFF} Symlinked to ${BOLD}${BLUE}%s${ALL_OFF}\n" "$name" "$target_name" continue fi fi description=$(sed -n '1s/^[[:space:]]*#[[:space:]]*[Dd]escription:[[:space:]]*//p' "$f") if [[ -n "$description" ]]; then - printf " ${BOLD}${GREEN}%-${max_name_len}s${ALL_OFF} ${BOLD}${YELLOW}-${ALL_OFF} %s\n" "$name" "$description" + printf "${BOLD}${BLUE}%-${max_name_len}s${ALL_OFF} ${BOLD}${YELLOW}-${ALL_OFF} %s\n" "$name" "$description" else - printf " ${BOLD}${GREEN}%-${max_name_len}s${ALL_OFF}\n" "$name" + printf "${BOLD}${BLUE}%-${max_name_len}s${ALL_OFF}\n" "$name" fi done } @@ -1023,9 +1055,11 @@ unset joined cleanup() { # "${TMP_FILES[@]+"${TMP_FILES[@]}"}" expands to nothing when the array is # empty (safe under nounset), unlike [@]:-} which yields one empty iteration. - for t in "${TMP_FILES[@]+"${TMP_FILES[@]}"}"; do + for t in "${TEMPORARY_FILES[@]+"${TEMPORARY_FILES[@]}"}"; do debug "Cleanup temp file:" "$t" - [[ -f "$t" ]] && rm -f -- "$t" || true + if [[ -f "$t" ]]; then + rm -f -- "$t" + fi done } trap cleanup EXIT @@ -1049,28 +1083,30 @@ trap cleanup EXIT # Return: # EXIT_OK on success or if skipped; EXIT_RUNTIME_FAILURE on failure. encode_one() { - local file="$1" - local idx="$2" - local total="$3" + local input_file="$1" + local current_file_index="$2" + local amount_total_files="$3" - [[ -z "$file" ]] && return $EXIT_OK + if [[ -z "$input_file" ]]; then + return $EXIT_OK + fi - msg "Processing [$idx/$total]:" "$file" - [[ ! -f "$file" ]] && { - error "Not found:" "$file" + msg "Processing [$current_file_index/$amount_total_files]:" "$input_file" + if [[ ! -f "$input_file" ]]; then + error "Not found:" "$input_file" return $EXIT_RUNTIME_FAILURE - } - [[ ! -r "$file" ]] && { - error "File is not readable:" "$file" + fi + if [[ ! -r "$input_file" ]]; then + error "File is not readable:" "$input_file" return $EXIT_RUNTIME_FAILURE - } + fi # Probe codec and pixel format in a single ffprobe invocation to halve # the startup overhead on large batches. local probe_out probe_out=$(ffprobe -v error -select_streams v:0 \ -show_entries stream=codec_name,pix_fmt,r_frame_rate \ - -of default=nk=1:nw=1 "file:$file" 2>/dev/null) + -of default=nk=1:nw=1 "file:$input_file" 2>/dev/null) local input_codec input_pixel_format input_frame_rate input_fps @@ -1081,15 +1117,15 @@ encode_one() { input_frame_rate=$(printf "%s\n" "$probe_out" | sed -n '3p') if [[ -z "$input_codec" ]]; then - error "Could not determine input video codec:" "$file" + error "Could not determine input video codec:" "$input_file" return $EXIT_RUNTIME_FAILURE fi if [[ -z "$input_pixel_format" ]]; then - error "Could not determine input pixel format:" "$file" + error "Could not determine input pixel format:" "$input_file" return $EXIT_RUNTIME_FAILURE fi if [[ -z "$input_frame_rate" ]]; then - error "Could not determine input frame rate:" "$file" + error "Could not determine input frame rate:" "$input_file" return $EXIT_RUNTIME_FAILURE fi @@ -1114,8 +1150,9 @@ encode_one() { *422*) subsampling="422" ;; *) subsampling="420" - [[ "$input_pixel_format" != *420* ]] && + if [[ "$input_pixel_format" != *420* ]]; then verbose "Unrecognised chroma subsampling in '$input_pixel_format', falling back to yuv420p" + fi ;; esac @@ -1153,32 +1190,32 @@ encode_one() { load_preset "$PRESET_NAME" - local extension directory tmp base stem + local extension directory temporary_output_file base stem # filename (path without extension) is used only for the savings log. # Note: only the last extension is stripped, so multi-dot names like # "my.show.s01e01.mkv" are logged as "my.show.s01e01". local filename - base="${file##*/}" + base="${input_file##*/}" if [[ "$base" == *.* ]]; then extension="${base##*.}" stem="${base%.*}" - filename="${file%.*}" + filename="${input_file%.*}" else extension="" stem="$base" - filename="$file" + filename="$input_file" fi - directory=$(dirname -- "$file") + directory=$(dirname -- "$input_file") # Temp file is created in the same directory as the input so that `mv` is # atomic on the same filesystem (avoid cross-device rename issues). # mktemp provides cryptographically random names and atomic creation, # unlike $$.$RANDOM which has limited entropy and is predictable. - tmp=$(mktemp -- "$directory/.${stem}_${PRESET_NAME}.XXXXXX${extension:+.$extension}") - TMP_FILES+=("$tmp") - debug "Temporary output path:" "$tmp" + temporary_output_file=$(mktemp -- "$directory/.${stem}_${PRESET_NAME}.XXXXXX${extension:+.$extension}") + TEMPORARY_FILES+=("$temporary_output_file") + debug "Temporary output path:" "$temporary_output_file" # Build ffmpeg command: # - Map all streams, metadata, and chapters @@ -1191,20 +1228,20 @@ encode_one() { hwaccel_args=(-hwaccel "$HWACCEL_VALUE") fi - local cmd=(ffmpeg + local encode_cmd=(ffmpeg -nostdin -y -hide_banner -v error -stats "${hwaccel_args[@]}" - -i "file:$file" + -i "file:$input_file" -map 0 -map_metadata 0 -map_chapters 0 -c copy "${ffargs[@]}" - "file:$tmp") + "file:$temporary_output_file") if [[ $DRY_RUN -eq 1 ]]; then msg "DRY RUN:" "Would encode with preset $PRESET_NAME" @@ -1214,15 +1251,13 @@ encode_one() { verbose "Input frame rate:" "$input_frame_rate" verbose "Input FPS:" "$input_fps" verbose "Output GOP size:" "$output_gop_size" - verbose "Command:" "${cmd[*]}" + verbose "Command:" "${encode_cmd[*]}" return $EXIT_OK fi - msg "Encoding:" "$file" - debug "Nice value:" "$NICE_VALUE" - - if nice -n "$NICE_VALUE" "${cmd[@]}"; then + msg "Encoding:" "$input_file" + if nice -n "$NICE_VALUE" "${encode_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 @@ -1230,48 +1265,50 @@ encode_one() { # 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" + debug "Verifying output integrity:" "$temporary_output_file" + if ! ffprobe -v error "file:$temporary_output_file" >/dev/null 2>&1; then + error "Output failed integrity check:" "$temporary_output_file" + rm -f -- "$temporary_output_file" if [[ $CONTINUE_ON_FAIL -eq 1 ]]; then return $EXIT_RUNTIME_FAILURE else exit $EXIT_RUNTIME_FAILURE fi fi - verbose "Integrity check passed:" "$tmp" + verbose "Integrity check passed:" "$temporary_output_file" fi local original_filesize new_filesize - original_filesize=$(filesize "$file") - new_filesize=$(filesize "$tmp") + original_filesize=$(filesize "$input_file") + new_filesize=$(filesize "$temporary_output_file") # If requested, keep the original if the new file is larger. if [[ $ONLY_IF_SMALLER -eq 1 && $new_filesize -gt $original_filesize ]]; then - msg "Did not replace (new file is larger):" "$file" - rm -f -- "$tmp" + msg "Did not replace (new file is larger):" "$input_file" + rm -f -- "$temporary_output_file" return $EXIT_OK fi - if [[ $SAVING -eq 1 ]]; then - local pct + local filesize_percentage filesize_difference + filesize_difference=$((original_filesize - new_filesize)) + if [[ $original_filesize -gt 0 ]]; then - pct=$(((original_filesize - new_filesize) * 100 / original_filesize)) + filesize_percentage=$((filesize_difference * 100 / original_filesize)) else - pct=0 + filesize_percentage=0 fi # Write a header line if the savings file does not yet exist. if [[ ! -f "$SAVING_FILE" ]]; then printf "filename\toriginal_bytes\tnew_bytes\tsaved_pct\n" >"$SAVING_FILE" + else + printf "%s\t%s\t%s\t%s%%\n" "$filename" "$original_filesize" "$new_filesize" "$filesize_percentage" >>"$SAVING_FILE" fi - printf "%s\t%s\t%s\t%s%%\n" "$filename" "$original_filesize" "$new_filesize" "$pct" >>"$SAVING_FILE" fi - mv -f -- "$tmp" "$file" - msg "Replaced:" "$file" + mv -f -- "$temporary_output_file" "$input_file" + msg "Replaced:" "$input_file" else - error "Encode FAILED:" "$file" + error "Encode FAILED:" "$input_file" if [[ $CONTINUE_ON_FAIL -eq 1 ]]; then return $EXIT_RUNTIME_FAILURE # fail this but keep going else @@ -1289,7 +1326,9 @@ if [[ -n $ENCODE_FILE ]]; then # Build the file list into an array first so we know the total count. mapfile -t FILES_TO_ENCODE < <( while IFS= read -r file || [[ -n "$file" ]]; do - [[ -n "$file" ]] && printf '%s\n' "$file" + if [[ -n "$file" ]]; then + printf '%s\n' "$file" + fi done <"$ENCODE_FILE" ) total=${#FILES_TO_ENCODE[@]} |
