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.1 | 274 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 274 insertions(+) create mode 100644 transcode.sh.1 (limited to 'transcode.sh.1') diff --git a/transcode.sh.1 b/transcode.sh.1 new file mode 100644 index 0000000..9001e8a --- /dev/null +++ b/transcode.sh.1 @@ -0,0 +1,274 @@ +.TH TRANSCODE.SH 1 "2026-02-02" "1.0.0" "User Commands" +.SH NAME +transcode.sh \- batch transcode helper for media files using ffmpeg +.SH SYNOPSIS +.B transcode.sh +[\fIOPTION\fR]... [\fB\-\-\fR] \fIFILE\fR... +.SH DESCRIPTION +.B transcode.sh +is a batch transcoding wrapper around +.BR ffmpeg (1) +that processes one or more media files in place, replacing each with a +re-encoded version. +.PP +Encoding parameters are not hard-coded; instead they are supplied by +.IR presets , +which are small shell snippets stored under the preset directory (see +.B FILES +below). Each preset must define a Bash array named +.B ffargs +containing the extra arguments passed to +.BR ffmpeg (1). +.PP +The script probes every input file with +.BR ffprobe (1) +to detect the input video codec and pixel format. Files whose codec +appears in the skip list are silently skipped. The output pixel format +is derived automatically so that chroma subsampling (4:2:0, 4:2:2, +4:4:4) and bit depth (8, 10, 12, 16\-bit) are preserved. +.PP +All streams, metadata and chapter markers from the input are retained by +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. +.SH OPTIONS +.TP +.BR \-c ", " \-\-continue +Continue processing the next file even if +.BR ffmpeg (1) +fails on the current one. Without this flag the script exits immediately +on the first failure. +.TP +.BR \-f " \fIPATH\fR, " \-\-encodefile " \fIPATH\fR, " \-\-encodefile= \fIPATH\fR +Read the list of files to encode from \fIPATH\fR (one file per line) +instead of taking files from the command line. +.TP +.BR \-n ", " \-\-dry\-run +Print what would be done without actually invoking +.BR ffmpeg (1). +Combine with +.B \-v +to see the detected codec and pixel format information. +.TP +.BR \-N " \fIVALUE\fR, " \-\-nice " \fIVALUE\fR, " \-\-nice= \fIVALUE\fR +Run +.BR ffmpeg (1) +under +.BR nice (1) +with the given niceness value. Defaults to +.BR 19 +(lowest priority). +.TP +.BR \-s ", " \-\-saving +After each successful encode, append a line to the savings log file +recording the filename, original size in bytes, new size in bytes and the +percentage saved. Requires +.BR bc (1). +.TP +.BR \-\-saving\-file " \fIPATH\fR, " \-\-saving\-file= \fIPATH\fR +Path to the savings log file written by +.BR \-\-saving . +Defaults to +.B transcode_savings +in the current working directory. +.TP +.BR \-S " \fILIST\fR, " \-\-skip\-codec " \fILIST\fR, " \-\-skip\-codec= \fILIST\fR +Comma-, space- or colon-separated list of video codec names to skip. +Files whose detected input codec appears in this list are left untouched. +The per-user skip list from +.B skip.conf +(see +.BR FILES ) +is always loaded in addition to codecs supplied here. +.TP +.BR \-l ", " \-\-only\-if\-smaller +After encoding, replace the original only when the new file is strictly +smaller. If the transcoded file is larger the temporary file is removed +and the original is kept unchanged. +.TP +.BR \-p " \fINAME\fR, " \-\-preset " \fINAME\fR, " \-\-preset= \fINAME\fR +Load the preset named \fINAME\fR from the preset directory. Defaults to +.BR default . +.TP +.BR \-h ", " \-\-help ", " \-? +Print a short help message and exit. +.TP +.BR \-q ", " \-\-quiet +Suppress all normal output. Takes precedence over +.BR \-v / \-\-verbose . +.TP +.BR \-v ", " \-\-verbose +Emit additional informational messages (detected codec, pixel format, +etc.). +.TP +.B \-\-version +Print version, author and license information and exit. +.TP +.B \-\-color +Force colored output even when stdout is not a terminal or +.B NO_COLOR +is set. +.TP +.B \-\-no\-color +Disable colored output unconditionally. +.TP +.B \-\- +End of options. All subsequent arguments are treated as file names even +if they begin with +.BR \- . +.SH ENVIRONMENT +.TP +.B NO_COLOR +When set (to any value), colored output is disabled. See +.IR https://no-color.org/ . +.TP +.B FORCE_COLOR +When set, colored output is enabled regardless of +.B NO_COLOR +or terminal detection. +.TP +.B DEBUG +Set to +.B 1 +to enable structured debug messages (high-level state reporting). +.TP +.B TRACE +Set to +.B 1 +to enable Bash execution tracing +.RB ( set\ \-x ), +which prints every command as it is executed. +.TP +.B XDG_CONFIG_HOME +Base directory for user configuration. Defaults to +.BR $HOME/.config . +.SH FILES +.TP +.IR "${XDG_CONFIG_HOME:-$HOME/.config}/transcode.sh/presets/.sh" +Preset files. Each preset is sourced as Bash code and must define an +array variable named +.B ffargs +containing additional arguments for +.BR ffmpeg (1). +The variable +.B output_pixel_format +is available to presets and contains the automatically selected output +pixel format string. +.IP +Example preset: +.RS +.nf +ffargs=( \-c:v:0 libsvtav1 \-crf 30 \-preset 6 \-pix_fmt "$output_pixel_format" ) +.fi +.RE +.IP +.B Warning: +presets are executed as shell code. Only use presets from trusted +sources. +.TP +.IR "${XDG_CONFIG_HOME:-$HOME/.config}/transcode.sh/skip.conf" +Optional per-user codec skip list. Each line should contain one codec +name (as reported by +.BR ffprobe (1)). +Files whose input video codec matches an entry are skipped without +encoding. +.SH EXIT STATUS +.TP +.B 0 +Success (or all skipped files were intentionally skipped). +.TP +.B 1 +Runtime failure (e.g. +.BR ffmpeg (1) +error on one or more files). +.TP +.B 2 +Usage error (invalid option or missing argument). +.TP +.B 3 +Configuration error (missing or invalid preset). +.TP +.B 127 +A required dependency +.RB ( ffmpeg , +.BR ffprobe , +.BR nice , +or +.B bc +when +.B \-\-saving +is active) was not found. +.SH EXAMPLES +Transcode a single file using the default preset: +.PP +.RS +.nf +transcode.sh video.mp4 +.fi +.RE +.PP +Transcode a batch of files listed in a file and log size savings: +.PP +.RS +.nf +transcode.sh \-s \-f list.txt +.fi +.RE +.PP +Dry-run with verbosity to inspect detected formats: +.PP +.RS +.nf +transcode.sh \-n \-v my_movie.mkv +.fi +.RE +.PP +Use a custom preset and only keep the result if it is smaller: +.PP +.RS +.nf +transcode.sh \-p av1_fast \-l /media/films/*.mkv +.fi +.RE +.PP +Run at a less aggressive niceness and skip already-AV1 files: +.PP +.RS +.nf +transcode.sh \-N 10 \-S av1 input.mkv +.fi +.RE +.PP +Use +.BR ffmpeg (1) +installed via Homebrew (macOS): +.PP +.RS +.nf +PATH="/opt/homebrew/bin:$PATH" transcode.sh input.mp4 +.fi +.RE +.SH NOTES +The script resets +.B PATH +to +.I /bin:/usr/bin:/usr/local/bin +for security. If +.BR ffmpeg (1) +is installed outside these directories (e.g. via Homebrew or Nix), +prepend the correct directory to +.B PATH +before invoking +.BR transcode.sh . +.SH SEE ALSO +.BR ffmpeg (1), +.BR ffprobe (1), +.BR nice (1), +.BR bc (1) +.SH AUTHOR +Dennis Fink +.SH LICENSE +BSD\-3\-Clause -- cgit v1.3.1