#!/usr/bin/env bash

# Make a video smaller, or turn a picture into another format.
#
#   panama-transcode video <file> 1080p|720p|480p
#   panama-transcode image <file> 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" </dev/null; then
        notify "Transcoded" "$(basename "$output")" video-x-generic
        printf '%s\n' "$output"
    else
        rm -f "$output"
        notify "Transcode failed" "$(basename "$input")" dialog-error-symbolic
        return 1
    fi
}

cmd_image() {
    local input="${1:-}" format="${2:-jpg}"
    [[ -f "$input" ]] || { err 'that file does not exist'; return 2; }

    case "$format" in
        jpg|png|webp) ;;
        *) err "unknown format: $format"; return 2 ;;
    esac

    local dir stem output
    dir="$(dirname "$input")"
    stem="$(basename "${input%.*}")"
    output="$(free_path "$dir" "$stem" converted "$format")"

    local -a quality=()
    [[ "$format" == "jpg" ]] && quality=(-q:v 3)
    [[ "$format" == "webp" ]] && quality=(-quality 82)

    if ffmpeg -nostdin -loglevel error -i "$input" "${quality[@]}" "$output" </dev/null; then
        notify "Converted" "$(basename "$output")" image-x-generic
        printf '%s\n' "$output"
    else
        rm -f "$output"
        notify "Conversion failed" "$(basename "$input")" dialog-error-symbolic
        return 1
    fi
}

case "${1:-}" in
    video) shift; cmd_video "$@" ;;
    image) shift; cmd_image "$@" ;;
    -h|--help|"")
        cat <<'USAGE'
usage: panama-transcode video <file> [1080p|720p|480p]
       panama-transcode image <file> [jpg|png|webp]

Writes beside the input, never over it, and never over an existing output.
USAGE
        ;;
    *) err "unknown command: $1"; exit 2 ;;
esac
