From d6b6cb1bfd71e95aeda2e784c214ddffcc777fd1 Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Sun, 22 Feb 2026 08:41:04 +0100 Subject: feat: initial release of transcode.sh v1.0.0 Batch transcode helper for media files using ffmpeg. Encoding parameters are supplied by user-defined preset files (shell snippets that set an `ffargs` array) stored under ${XDG_CONFIG_HOME:-$HOME/.config}/transcode.sh/presets/. Key capabilities: - Probes input codec and pixel format via ffprobe; derives an output pixel format that preserves chroma subsampling and bit depth. - Per-user and per-invocation codec skip lists to leave already-encoded files untouched. - Atomic in-place replacement: encodes to a temp file in the same directory, then renames on success. - --only-if-smaller: discard the result if it is larger than the original. - --saving: append filename, original/new sizes and percentage saved to a log file after each successful encode. - --dry-run, --verbose, --quiet, --nice and --continue flags. - Respects the NO_COLOR standard. - Script hardening: strict PATH, safe IFS, errtrace, nounset, pipefail. Also included: - Man page (transcode.sh.1) - Bash completion script (transcode.sh.bash-completion) - README.md - .gitmessage commit message template License: BSD-3-Clause --- transcode.sh.bash-completion | 149 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 transcode.sh.bash-completion (limited to 'transcode.sh.bash-completion') diff --git a/transcode.sh.bash-completion b/transcode.sh.bash-completion new file mode 100644 index 0000000..ce153dd --- /dev/null +++ b/transcode.sh.bash-completion @@ -0,0 +1,149 @@ +# bash completion for transcode.sh +# Install to: +# /etc/bash_completion.d/transcode.sh +# or source manually: +# source transcode.sh.bash-completion +# +# Each option that takes an argument is supported in all three forms: +# short -f list.txt +# long space --encodefile list.txt +# long equals --encodefile=list.txt + +_transcode_sh() { + local cur prev words cword + _init_completion || return + + local -r preset_dir="${XDG_CONFIG_HOME:-$HOME/.config}/transcode.sh/presets" + + # --------------------------------------------------------------------------- + # Helper: collect preset names from the preset directory + # --------------------------------------------------------------------------- + _transcode_presets() { + local presets=() + if [[ -d "$preset_dir" ]]; then + local f + while IFS= read -r f; do + f="${f##*/}" # basename + f="${f%.sh}" # strip .sh extension + presets+=("$f") + done < <(find "$preset_dir" -maxdepth 1 -name '*.sh' -type f 2>/dev/null) + fi + printf '%s\n' "${presets[@]}" + } + + local codecs='h264 hevc av1 vp8 vp9 mpeg2video mpeg4 mjpeg theora' + local nice_vals='0 5 10 15 19' + + # --------------------------------------------------------------------------- + # Handle --option=VALUE: cur contains the entire "--opt=val" token. + # Strip the "opt=" prefix and delegate to the appropriate completer. + # This must be checked before the $prev dispatch below. + # --------------------------------------------------------------------------- + case "$cur" in + --encodefile=*) + cur="${cur#*=}" + _filedir + return + ;; + --saving-file=*) + cur="${cur#*=}" + _filedir + return + ;; + --nice=*) + cur="${cur#*=}" + COMPREPLY=( $(compgen -W "$nice_vals" -- "$cur") ) + return + ;; + --skip-codec=*) + cur="${cur#*=}" + COMPREPLY=( $(compgen -W "$codecs" -- "$cur") ) + return + ;; + --preset=*) + cur="${cur#*=}" + COMPREPLY=( $(compgen -W "$(_transcode_presets)" -- "$cur") ) + return + ;; + esac + + # --------------------------------------------------------------------------- + # Handle VALUE after short form (-f, -N, -S, -p) and + # long space form (--encodefile, --nice, --saving-file, --skip-codec, --preset). + # $prev is the option word, $cur is the value being typed. + # --------------------------------------------------------------------------- + case "$prev" in + -f|--encodefile) + _filedir + return + ;; + -N|--nice) + COMPREPLY=( $(compgen -W "$nice_vals" -- "$cur") ) + return + ;; + --saving-file) + _filedir + return + ;; + -S|--skip-codec) + COMPREPLY=( $(compgen -W "$codecs" -- "$cur") ) + return + ;; + -p|--preset) + COMPREPLY=( $(compgen -W "$(_transcode_presets)" -- "$cur") ) + return + ;; + esac + + # --------------------------------------------------------------------------- + # Complete option names themselves. + # For options that accept an argument we list both the bare long form + # (--nice) and the equals form (--nice=) so the user can choose their + # preferred style. compopt -o nospace is applied when the sole match + # ends with '=' to avoid an unwanted trailing space in that case. + # --------------------------------------------------------------------------- + case "$cur" in + --*) + local longopts=' + --continue + --encodefile + --encodefile= + --dry-run + --nice + --nice= + --saving + --saving-file + --saving-file= + --skip-codec + --skip-codec= + --only-if-smaller + --preset + --preset= + --help + --quiet + --verbose + --version + --color + --no-color + ' + COMPREPLY=( $(compgen -W "$longopts" -- "$cur") ) + # Suppress the trailing space when the only completion ends with '=' + [[ ${#COMPREPLY[@]} -eq 1 && "${COMPREPLY[0]}" == *= ]] \ + && compopt -o nospace + return + ;; + -*) + local shortopts='-c -f -n -N -s -S -l -p -h -? -q -v --' + COMPREPLY=( $(compgen -W "$shortopts" -- "$cur") ) + return + ;; + esac + + # --------------------------------------------------------------------------- + # Default: complete positional FILE arguments with common media extensions + # --------------------------------------------------------------------------- + _filedir '@(mkv|mp4|mov|avi|webm|flv|wmv|m4v|ts|mts|m2ts|mpg|mpeg|ogv|3gp|rm|rmvb)' +} + +complete -F _transcode_sh transcode.sh +complete -F _transcode_sh transcode -- cgit v1.3.1