#!/usr/bin/env bash set -Eeuo pipefail DELETE_ORIGINALS=false MEDIA_EXTS=("mp4" "mkv" "mov" "avi" "webm" "m4v") SEARCH_DIR="." STYLE="FontName=Arial,FontSize=18,PrimaryColour=&HFFFFFF&,BackColour=&H000000&,BorderStyle=3,Outline=1,Shadow=0,MarginV=10,Alignment=2" usage() { cat </dev/null || { echo "ffmpeg not found." exit 1 } escape_path() { printf "%s" "$1" | sed "s/'/'\\\\''/g" } for ext in "${MEDIA_EXTS[@]}"; do while IFS= read -r -d '' media; do dir=$(dirname "$media") filename=$(basename "$media") base="${filename%.*}" extension="${filename##*.}" subtitle="" shopt -s nullglob nocaseglob for candidate in \ "$dir/$base.srt" \ "$dir/$base.vtt" \ "$dir/$base".*.srt \ "$dir/$base".*.vtt; do [[ -e "$candidate" ]] || continue subtitle="$candidate" break done shopt -u nullglob nocaseglob [[ -n "$subtitle" ]] || continue output="$dir/${base}_subbed.${extension}" echo echo "==================================" echo "Media: $media" echo "Subtitle: $subtitle" echo "Output: $output" echo "==================================" escaped_sub=$(escape_path "$subtitle") ffmpeg \ -hide_banner \ -y \ -i "$media" \ -vf "subtitles='${escaped_sub}':force_style='${STYLE}'" \ -c:v libx264 \ -preset medium \ -crf 18 \ -c:a copy \ "$output" \ < /dev/null if [[ $? -eq 0 ]]; then echo "✓ Finished" if $DELETE_ORIGINALS; then rm -f "$media" "$subtitle" echo "Deleted originals." fi else echo "✗ Failed: $media" fi done < <(find "$SEARCH_DIR" -type f -iname "*.${ext}" -print0) done echo echo "Done."