#!/usr/bin/env bash declare -rA presets=( [davinci-resolve]="-c:v dnxhd -profile:v dnxhr_hq -pix_fmt yuv422p -c:a pcm_s16le" [instagram]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)' -pix_fmt yuv420p -c:v h264_nvenc -b:v 3500k -b:a 128k -c:a aac -movflags +faststart" [web-generic]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)' -pix_fmt yuv420p -c:v h264_nvenc -crf 23 -preset medium -c:a aac -b:a 128k -movflags +faststart" [storage]="-c:v hevc_nvenc -preset p7 -b:v 0 -spatial-aq 1 -rc vbr_hq -c:a copy" [whatsapp]="-vf \"scale=-2:480\" -c:v libx264 -preset slow -crf 30 -profile:v baseline -level 3.0 -pix_fmt yuv420p -r 25 -g 50 -c:a aac -b:a 160k -r:a 44100" ) declare -rA containers=( [davinci-resolve]="mov" [instagram]="mp4" [web-generic]="mp4" [storage]="mp4" [whatsapp]="mp4" ) where="${1:-.}" dest="${2:-$where}" selection=$(find "$where" -type f | fzf --multi --preview 'ffprobe -v error -show_format -show_streams {}' --preview-window=up:wrap) preset=$( printf '%s\n' "${!presets[@]}" | \ fzf --multi --prompt "Select a preset" ) flags="${presets[$preset]}" container="${containers[$preset]}" output_dir=$(find "$dest" -type d ! -name '.*' ! -path '*/.*/*' | fzf --preview 'tree -C {}' --preview-window=up:wrap --prompt "Select output directory: ") if gum confirm "Flatten the directory structure?"; then flatten=true else flatten=false fi function transcode_job { local ifile="$1" local output_dir="$2" local flatten="$3" local where="$4" local flags="$5" local container="$6" local fname=$(basename "$ifile") local segment=$(realpath --relative-to="$where" "$ifile") if [ "$flatten" = true ]; then output_file="$output_dir/$fname.$container" else output_file="$output_dir/$segment.$container" fi tmp_file=$(mktemp) echo "Running Command: ffmpeg -y -i $ifile $flags $output_file" >> "$tmp_file" mkdir -p "$(dirname "$output_file")" if ffmpeg -y -i "$ifile" $(echo -n "$flags") "$output_file" 2>> "$tmp_file"; then rm -f "$tmp_file" else # gum log "Failed to transcode $ifile. Check ./error.log for details." cat "$tmp_file" >> error.log rm -f "$tmp_file" fi } export -f transcode_job mapfile -t files <<< "$selection" len=${#files[@]} i=1 for file in "${files[@]}"; do if [[ -f "$file" ]]; then gum spin --spinner dot --title "[$i/$len] Transcoding $file" -- bash -c "source <(declare -f transcode_job); transcode_job \"$file\" \"$output_dir\" \"$flatten\" \"$where\" \"$flags\" \"$container\"" else echo "Skipping invalid file: $file" >&2 fi ((i++)) done