#!/usr/bin/env bash set -euo pipefail die() { echo "$*" >&2 exit 1 } usage() { cat <<'EOF' >&2 Usage: convert-to-video.sh /path/to/audio.file Creates a slideshow video from stormux images and the provided audio. EOF exit 1 } require_commands() { for cmd in "$@"; do command -v "$cmd" >/dev/null 2>&1 || die "Missing dependency: $cmd" done } locate_images() { local candidate="." local have_all=true for i in 1 2 3 4 5; do [ -f "$candidate/stormux${i}.png" ] || have_all=false done if [ "$have_all" = true ]; then printf '%s\n' "$candidate" return fi candidate="/usr/share/stormux/slideshow" for i in 1 2 3 4 5; do [ -f "$candidate/stormux${i}.png" ] || die "Missing image: $candidate/stormux${i}.png" done printf '%s\n' "$candidate" } detect_container() { local audio_file="$1" local codec codec="$(ffprobe -v error -select_streams a:0 -show_entries stream=codec_name -of csv=p=0 "$audio_file" || true)" case "$codec" in aac|mp3) echo "mp4" ;; *) echo "mkv" ;; esac } build_video() { local audio_file="$1" local image_dir="$2" local container="$3" local output_filename="$4" local output_dir="$HOME/Videos" mkdir -p "$output_dir" ffmpeg -y \ -stream_loop -1 -framerate 1/35 -start_number 1 -i "$image_dir/stormux%d.png" \ -i "$audio_file" \ -map 0:v:0 -map 1:a:0 \ -c:v libx264 -crf 18 -preset veryfast -r 30 -pix_fmt yuv420p \ -c:a copy \ -shortest \ "$output_dir/${output_filename##*/}" } [ "$#" -eq 1 ] || usage audio="$1" [ -f "$audio" ] || die "Audio file not found: $audio" require_commands ffmpeg ffprobe image_dir="$(locate_images)" container="$(detect_container "$audio")" base="$(basename "$audio")" name="${base%.*}" output="${name}.${container}" build_video "$audio" "$image_dir" "$container" "$output" echo "Wrote $HOME/Videos/$output"