#!/bin/bash
#
# webgallery.sh
# ---------------------------------------------------------------------------
# Erzeugt aus einem Bilder-/Videoordner eine statische HTML-Galerie zum
# Anschauen im Browser - direkt auf dem Webserver, ohne Datenbank, ohne
# PHP oder sonstige Serverkomponenten. Nur ImageMagick, ffmpeg und exiftool
# werden benoetigt (typischerweise ohnehin schon vorhanden, siehe geocode.sh).
#
# Unterstuetzte Formate:
#   Bilder: jpg, jpeg, png, heic, heif
#   Videos: mp4, mov, avi, mkv, m4v, wmv, 3gp  (Vorschaubild via ffmpeg-Frame)
#
# Liest, sofern vorhanden, die von geocode.sh geschriebenen Felder
# City / Country / CountryCode / Description und zeigt sie unter jedem Bild an.
#
# Verwendung:
#   ./webgallery.sh [Quellverzeichnis] [Ausgabeverzeichnis] [Titel]
#
#   Quellverzeichnis   : Ordner mit den Fotos/Videos
#                        (Standard: /home/uwe/images/upload/P1)
#   Ausgabeverzeichnis : wohin die Galerie (index.html + Thumbnails) soll
#                        (Standard: "<Quellverzeichnis>/galerie",
#                        also standardmaessig /home/uwe/images/upload/P1/galerie)
#   Titel              : Ueberschrift der Galerie (Standard: "Meine Fotos")
#
# Beispiel (nutzt alle Standardwerte):
#   ./webgallery.sh
#
# Danach das Ausgabeverzeichnis per Apache freigeben bzw. dort hineinlegen,
# z.B. per Symlink in /var/www/html/ - dann im Browser aufrufen.
#
# Erneutes Ausfuehren ist guenstig: bereits erzeugte Thumbnails werden nicht
# neu berechnet, solange die Quelldatei sich nicht geaendert hat.
# ---------------------------------------------------------------------------

set -u

# ---------------------------------------------------------------------------
# Konfiguration
# ---------------------------------------------------------------------------
QUELLVERZEICHNIS="${1:-/home/uwe/images/upload/P1}"
#QUELLVERZEICHNIS="${1:-upload/P1}"
AUSGABEVERZEICHNIS="${2:-/var/www/html/galerie}"
TITEL="${3:-Fotos}"
THUMB_BREITE=320               # Breite der Vorschaubilder in Pixel

THUMBDIR="${AUSGABEVERZEICHNIS}/thumbs"
INDEXDATEI="${AUSGABEVERZEICHNIS}/index.html"

# ---------------------------------------------------------------------------
# Vorbereitung
# ---------------------------------------------------------------------------
if [ ! -d "$QUELLVERZEICHNIS" ]; then
    echo "Fehler: Quellverzeichnis '$QUELLVERZEICHNIS' existiert nicht." >&2
    exit 1
fi

for prog in convert exiftool ffmpeg jq; do
    if ! command -v "$prog" >/dev/null 2>&1; then
        echo "Fehler: '$prog' wird benoetigt, ist aber nicht installiert." >&2
        exit 1
    fi
done

mkdir -p "$THUMBDIR"

# ---------------------------------------------------------------------------
# Hilfsfunktionen
# ---------------------------------------------------------------------------

# Prueft, ob eine Datei ein Video ist (anhand der Endung)
ist_video() {
    case "${1,,}" in
        *.mp4|*.mov|*.avi|*.mkv|*.m4v|*.wmv|*.3gp) return 0 ;;
        *) return 1 ;;
    esac
}

# Prueft, ob eine Datei ein unterstuetztes Bild ist (anhand der Endung)
ist_bild() {
    case "${1,,}" in
        *.jpg|*.jpeg|*.png|*.heic|*.heif) return 0 ;;
        *) return 1 ;;
    esac
}

# HTML-Sonderzeichen escapen, damit z.B. "&" oder "<" in Ort/Beschreibung
# nicht das HTML zerstoeren
html_escape() {
    local s="$1"
    s="${s//&/&amp;}"
    s="${s//</&lt;}"
    s="${s//>/&gt;}"
    s="${s//\"/&quot;}"
    printf '%s' "$s"
}

# Erzeugt ein Thumbnail fuer eine Datei. Gibt bei Erfolg den relativen Pfad
# (innerhalb des Ausgabeverzeichnisses) auf stdout aus, sonst leer.
erstelle_thumbnail() {
    local quelldatei="$1"
    local basisname
    basisname="$(basename "$quelldatei")"
    local thumbname="${basisname}.thumb.jpg"
    local thumbpfad="${THUMBDIR}/${thumbname}"

    # Bereits vorhanden und aktueller als die Quelldatei? -> nichts tun
    if [ -f "$thumbpfad" ] && [ "$thumbpfad" -nt "$quelldatei" ]; then
        printf 'thumbs/%s' "$thumbname"
        return 0
    fi

    if ist_video "$quelldatei"; then
        # Frame aus dem Video extrahieren, dann daraus das Thumbnail bauen
        local frame
        frame="$(mktemp --suffix=.jpg)"
        ffmpeg -y -ss 00:00:01 -i "$quelldatei" -frames:v 1 -q:v 3 "$frame" -loglevel error
        if [ ! -s "$frame" ]; then
            # Fallback: erster Frame, falls Sekunde 1 nicht existiert (kurze Clips)
            ffmpeg -y -i "$quelldatei" -frames:v 1 -q:v 3 "$frame" -loglevel error
        fi
        if [ -s "$frame" ]; then
            convert "$frame" -thumbnail "${THUMB_BREITE}x${THUMB_BREITE}>" \
                -background black -gravity center -extent "${THUMB_BREITE}x$((THUMB_BREITE * 3 / 4))" \
                "$thumbpfad" 2>/dev/null
        fi
        rm -f "$frame"
    else
        # Bild direkt verarbeiten (funktioniert fuer jpg/png immer;
        # bei heic/heif abhaengig davon, ob das lokale ImageMagick/libheif
        # einen passenden HEVC-Decoder-Plugin besitzt - siehe Hinweis unten)
        convert "$quelldatei[0]" -auto-orient -thumbnail "${THUMB_BREITE}x${THUMB_BREITE}>" \
            "$thumbpfad" 2>/dev/null
    fi

    if [ -s "$thumbpfad" ]; then
        printf 'thumbs/%s' "$thumbname"
    else
        printf ''
    fi
}

# ---------------------------------------------------------------------------
# Metadaten fuer ALLE Dateien in einem einzigen exiftool-Aufruf einlesen
# (viel schneller als ein Aufruf pro Datei)
# ---------------------------------------------------------------------------
echo "Lese Metadaten..."

mapfile -d '' DATEILISTE < <(
    find "$QUELLVERZEICHNIS" -maxdepth 1 -type f \
        \( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' \
        -o -iname '*.heic' -o -iname '*.heif' \
        -o -iname '*.mp4' -o -iname '*.mov' -o -iname '*.avi' \
        -o -iname '*.mkv' -o -iname '*.m4v' -o -iname '*.wmv' -o -iname '*.3gp' \) \
        -print0 | sort -z
)

if [ "${#DATEILISTE[@]}" -eq 0 ]; then
    echo "Keine Bilder oder Videos in '$QUELLVERZEICHNIS' gefunden." >&2
    exit 1
fi

METADATEN_JSON="$(exiftool -j -City -Country -CountryCode -Description \
    -CreateDate -DateTimeOriginal -MediaCreateDate -FileName -Directory \
    "${DATEILISTE[@]}" 2>/dev/null)"

# ---------------------------------------------------------------------------
# Nach Aufnahmedatum sortierte TSV-Zeile pro Datei bauen:
#   vollstaendiger_pfad<TAB>datum<TAB>ort<TAB>land<TAB>laendercode<TAB>beschreibung
# ---------------------------------------------------------------------------
ZEILEN="$(echo "$METADATEN_JSON" | jq -r '
    .[] |
    ( .CreateDate // .DateTimeOriginal // .MediaCreateDate // "" ) as $rohdatum |
    # Dateien ohne (gueltiges) Datum sollen beim Sortieren ans Ende rutschen,
    # nicht an den Anfang (sonst stehen sie faelschlich "zuerst")
    ( if ($rohdatum == "" or ($rohdatum | startswith("0000"))) then "9999:99:99 99:99:99" else $rohdatum end ) as $sortdatum |
    [
        (.Directory + "/" + .FileName),
        $sortdatum,
        $rohdatum,
        (.City // "unbekannt"),
        (.Country // "unbekannt"),
        (.CountryCode // "--"),
        (.Description // "")
    ] | @tsv
' | sort -t $'\t' -k2,2)"

# ---------------------------------------------------------------------------
# HTML-Kopf schreiben
# ---------------------------------------------------------------------------
TITEL_ESC="$(html_escape "$TITEL")"

cat > "$INDEXDATEI" <<HTML_KOPF
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>${TITEL_ESC}</title>
<style>
  body { font-family: -apple-system, Arial, sans-serif; background:#181818; color:#eee; margin:0; padding:20px; }
  h1 { text-align:center; font-weight:600; }
  .anzahl { text-align:center; color:#999; margin-bottom:24px; }
  .galerie { display:grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap:16px; }
  .karte { background:#242424; border-radius:8px; overflow:hidden; box-shadow:0 2px 6px rgba(0,0,0,.4); }
  .karte a { display:block; }
  .karte img { width:100%; height:240px; object-fit:cover; display:block; background:#000; }
  .bildbox { position:relative; }
  .video-label::after {
      content:"\25B6"; position:absolute; top:8px; right:8px;
      background:rgba(0,0,0,.6); color:#fff; border-radius:50%;
      width:28px; height:28px; text-align:center; line-height:28px; font-size:14px;
  }
  .info { padding:10px 12px; font-size:13px; line-height:1.5; }
  .ort { font-weight:600; color:#fff; }
  .datum { color:#999; float:right; }
  .beschreibung { color:#bbb; margin-top:4px; display:block; }
</style>
</head>
<body>
<h1>${TITEL_ESC}</h1>
<p class="anzahl">ANZAHL_PLATZHALTER Dateien</p>
<div class="galerie">
HTML_KOPF

# ---------------------------------------------------------------------------
# Fuer jede Datei: Thumbnail erzeugen und HTML-Kachel anhaengen
# ---------------------------------------------------------------------------
ANZAHL=0
while IFS=$'\t' read -r pfad _sortdatum datum ort land landcode beschreibung; do
    [ -z "$pfad" ] && continue
    [ -f "$pfad" ] || continue

    thumb_rel="$(erstelle_thumbnail "$pfad")"
    if [ -z "$thumb_rel" ]; then
        echo "  Warnung: Kein Thumbnail fuer '$pfad' erzeugt (Format nicht dekodierbar?) - wird ausgelassen." >&2
        continue
    fi

    # relativen Pfad zur Originaldatei aus Sicht des Ausgabeverzeichnisses bauen
    original_rel="$(realpath --relative-to="$AUSGABEVERZEICHNIS" "$pfad")"

    ort_esc="$(html_escape "$ort")"
    land_esc="$(html_escape "$land")"
    landcode_esc="$(html_escape "$landcode")"
    beschreibung_esc="$(html_escape "$beschreibung")"
    if [ -z "$datum" ] || [[ "$datum" == 0000* ]]; then
        datum_kurz="unbekannt"
    else
        datum_kurz="${datum%% *}"
        datum_kurz="${datum_kurz//:/-}"
    fi

    video_klasse=""
    if ist_video "$pfad"; then
        video_klasse=" video-label"
    fi

    {
        echo "  <div class=\"karte\">"
        echo "    <a href=\"$(html_escape "$original_rel")\" target=\"_blank\">"
        echo "      <div class=\"bildbox${video_klasse}\">"
        echo "        <img src=\"$(html_escape "$thumb_rel")\" loading=\"lazy\" alt=\"${ort_esc}\">"
        echo "      </div>"
        echo "    </a>"
        echo "    <div class=\"info\">"
        echo "      <span class=\"ort\">${ort_esc}$( [ "$land" != "unbekannt" ] && echo ", ${landcode_esc}" )</span>"
        echo "      <span class=\"datum\">${datum_kurz}</span>"
        if [ -n "$beschreibung_esc" ]; then
            echo "      <span class=\"beschreibung\">${beschreibung_esc}</span>"
        fi
        echo "    </div>"
        echo "  </div>"
    } >> "$INDEXDATEI"

    ANZAHL=$((ANZAHL + 1))
done <<< "$ZEILEN"

cat >> "$INDEXDATEI" <<'HTML_FUSS'
</div>
</body>
</html>
HTML_FUSS

# Platzhalter fuer die Anzahl der Dateien ersetzen
sed -i "s/ANZAHL_PLATZHALTER/${ANZAHL}/" "$INDEXDATEI"

echo "Fertig: ${ANZAHL} Dateien verarbeitet."
echo "Galerie liegt in: ${AUSGABEVERZEICHNIS}"
echo "  -> ${INDEXDATEI}"
