#!/usr/bin/env bash # Make a video smaller, or turn a picture into another format. # # panama-transcode video 1080p|720p|480p # panama-transcode image jpg|png|webp # # The two things people actually right-click a media file to do. macOS has # Quick Actions for both; Linux file managers have neither, and the usual # answer is a web uploader or a forgotten ffmpeg incantation. # # Two rules, both about not losing work: # # * The input is never written to. Output goes beside it with a suffix. # * An existing output is never overwritten. The suffix gains a number # rather than replacing something somebody made earlier. # # ffmpeg does the work and is already a declared dependency; this only decides # the arguments, which is the part worth writing down once. set -uo pipefail err() { printf 'panama-transcode: %s\n' "$*" >&2; } command -v ffmpeg >/dev/null 2>&1 || { err 'ffmpeg is not installed'; exit 1; } # A path that does not exist yet, beside the input. free_path() { local dir="$1" stem="$2" suffix="$3" ext="$4" local candidate="$dir/$stem-$suffix.$ext" local counter=2 while [[ -e "$candidate" ]]; do candidate="$dir/$stem-$suffix-$counter.$ext" counter=$(( counter + 1 )) done printf '%s' "$candidate" } notify() { command -v notify-send >/dev/null 2>&1 || return 0 notify-send --icon="${3:-video-x-generic}" "$1" "$2" 2>/dev/null || true } cmd_video() { local input="${1:-}" preset="${2:-1080p}" [[ -f "$input" ]] || { err 'that file does not exist'; return 2; } local height case "$preset" in 1080p) height=1080 ;; 720p) height=720 ;; 480p) height=480 ;; *) err "unknown size: $preset"; return 2 ;; esac local dir stem output dir="$(dirname "$input")" stem="$(basename "${input%.*}")" output="$(free_path "$dir" "$stem" "$preset" mp4)" notify "Transcoding" "$(basename "$input") → $preset" video-x-generic # -2 rather than -1 on width: H.264 needs even dimensions, and an odd one # fails at the very end of a long encode. if ffmpeg -nostdin -loglevel error -i "$input" \ -vf "scale=-2:'min($height,ih)'" \ -c:v libx264 -crf 23 -preset medium \ -c:a aac -b:a 128k \ "$output" [1080p|720p|480p] panama-transcode image [jpg|png|webp] Writes beside the input, never over it, and never over an existing output. USAGE ;; *) err "unknown command: $1"; exit 2 ;; esac