#!/usr/bin/env bash set -euo pipefail IFS=$'\n\t' # -allow a command to fail with !’s side effect on errexit # -use return value from ${PIPESTATUS[0]}, because ! hosed $? ! getopt --test > /dev/null if [[ ${PIPESTATUS[0]} -ne 4 ]]; then echo 'I’m sorry, `getopt --test` failed in this environment.' exit 1 fi OPTIONS=hv LONGOPTS=background:,no-cleanup,help,verbose,dry-run # -regarding ! and PIPESTATUS see above # -temporarily store output to be able to check for errors # -activate quoting/enhanced mode (e.g. by writing out “--options”) # -pass arguments only via -- "$@" to separate them correctly ! PARSED=$(getopt --options=$OPTIONS --longoptions=$LONGOPTS --name "$0" -- "$@") if [[ ${PIPESTATUS[0]} -ne 0 ]]; then # e.g. return value is 1 # then getopt has complained about wrong arguments to stdout exit 2 fi # read getopt’s output this way to handle the quoting right: eval set -- "$PARSED" bg="black" cleanup=y dry=n verbose=n # usage function function show_help() { cat << HEREDOC Usage: audiobook2video [--background white] [--no-cleanup] [--verbose] [--dry-run] [--verbose] audio.m4a cover.jpg optional arguments: -h, --help show this help message and exit --no-cleanup Do not cleanup temporary files --background Change background color for video (default black). See list of color and formats at https://imagemagick.org/script/color.php --dry-run do a dry run, dont change any files -v, --verbose increase the verbosity of the bash script HEREDOC } while true; do case "$1" in --background) bg="$2" shift 2 ;; --no-cleanup) cleanup=n shift ;; -h|--help) show_help exit 0 ;; --dry-run) dry=y shift ;; -v|--verbose) verbose=y shift ;; --) shift break ;; *) echo "Programming error" exit 3 ;; esac done if [ $# -lt 2 ]; then echo "Missing arguments. See help:" show_help exit 1 fi AUDIO_FILENAME="$1" COVER_FILENAME="$2" VIDEO_FILENAME="$(echo "$AUDIO_FILENAME" | cut -f 1 -d '.').mp4" # TODO: Support different backgrounds BACKGROUND_COLOR="$bg" NEW_COVER_FILENAME="$(mktemp --suffix=".png")" # Used in case m4a is not provided NEW_AUDIO_FILENAME="$(mktemp --suffix=".m4a")" if [ ! -f "$AUDIO_FILENAME" ]; then echo "$AUDIO_FILENAME not found" exit 1 fi if [ ! -f "$COVER_FILENAME" ]; then echo "$COVER_FILENAME not found" exit 1 fi echo "Saving background image to $NEW_COVER_FILENAME" convert -background "$BACKGROUND_COLOR" -gravity center -resize 1080x1080 -extent 1920x1080 "$COVER_FILENAME" "$NEW_COVER_FILENAME" # Convert files to M4A if needed case $AUDIO_FILENAME in *.m4a) echo "m4a supported, not converting";; *.m4b) echo "m4b supported, not converting";; *) echo "Saving audio file $NEW_AUDIO_FILENAME" ffmpeg -loglevel fatal -y -i "$AUDIO_FILENAME" -vn -codec:a aac -strict -2 -b:a 384k -r:a 48000 "$NEW_AUDIO_FILENAME" AUDIO_FILENAME="$NEW_AUDIO_FILENAME" ;; esac echo "Starting conversion" ffmpeg -r 1 -loop 1 -y -i "$COVER_FILENAME" -i "$AUDIO_FILENAME" -c:a copy -r 1 -vcodec libx264 -shortest "$VIDEO_FILENAME" echo "Saved: $VIDEO_FILENAME" if [[ $cleanup == "y" ]]; then echo "Cleaning up" rm -f $NEW_AUDIO_FILENAME $NEW_COVER_FILENAME fi