Metadata-Version: 2.4
Name: kurmann-mediaset-creator
Version: 1.2.1
Summary: CLI-Tool zur Erstellung von Mediensets (statisches HTML mit OG-Tags, Vorschaubildern und ZIP-Download) aus Videodateien.
Project-URL: Homepage, https://github.com/kurmann/mediaset-creator
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: typer>=0.12
Requires-Dist: rich>=13
Requires-Dist: jinja2>=3
Requires-Dist: python-ulid>=2
Requires-Dist: kurmann-vorschaubild-manager>=2.0.2
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"

# mediaset-creator

CLI-Tool und Python-Bibliothek zur Erstellung von Mediensets aus Videodateien.
Ein Medienset ist ein ULID-basiertes Verzeichnis mit statischem HTML, Vorschaubildern,
ZIP-Download und der Videodatei – bereit zum Hochladen auf einen Webserver.

---

## Voraussetzungen

- Python 3.11+
- [ffmpeg](https://ffmpeg.org/) und `ffprobe` im `$PATH`
- [kurmann-vorschaubild-manager](https://pypi.org/project/kurmann-vorschaubild-manager/) (wird als Dependency installiert)
- Ein [Anthropic API Key](https://console.anthropic.com/) für die automatische Vorschaubildauswahl
  (konfigurierbar via `vorschaubild-manager config set claude.api_key <key>`)

---

## Installation

```bash
uv pip install kurmann-mediaset-creator
```

Im Entwicklungsmodus (editierbar):

```bash
uv sync
```

---

## Verwendung (CLI)

### Einzelnes Video

```bash
mediaset-creator create /pfad/zu/video.m4v \
  --title "Familienfilme 2024" \
  --video-title "Leah Treppen-Surfen" \
  --video-description "Leah demonstriert ihre hohe Kunst des Treppen-Surfens." \
  --video-category "Familie Kurmann-Glück" \
  --video-date "2024-07-01" \
  --video-quality "Dolby Vision"
```

Das Medienset wird im Verzeichnis der Quelldatei unter einem ULID-Unterverzeichnis erstellt.
Ein anderes Ausgabeverzeichnis kann mit `--output-dir` angegeben werden:

```bash
mediaset-creator create /pfad/zu/video.m4v \
  --output-dir /tmp/mediasets \
  --video-title "Mein Film"
```

### Mehrere Videos (JSON)

Für Mediensets mit mehreren Videos wird eine JSON-Datei mit Metadaten übergeben:

```bash
mediaset-creator create --from-json metadaten.json
```

Format der JSON-Datei:

```json
{
  "title": "Familienfilme 2024",
  "videos": [
    {
      "path": "/pfad/zu/video1.m4v",
      "title": "Leah Treppen-Surfen",
      "description": "Beschreibung des Videos.",
      "category": "Familie Kurmann-Glück",
      "recording_date": "2024-07-01",
      "quality_label": "Dolby Vision"
    },
    {
      "path": "/pfad/zu/video2.m4v",
      "title": "Herbst-Spaziergang",
      "description": "Ein sonniger Herbsttag.",
      "recording_date": "2024-11-01",
      "quality_label": "4K HDR"
    }
  ]
}
```

### Optionen

| Option | Beschreibung |
|--------|--------------|
| `--title TEXT` | Übergeordneter Mediaset-Titel (h1). Bei Einzelvideo auch als Video-Titel verwendet, wenn `--video-title` fehlt. Fallback: Dateiname. |
| `--video-title TEXT` | Titel des Videos (nur bei Multi-Video nötig; bei Einzelvideo wird `--title` übernommen) |
| `--video-description TEXT` | Beschreibung des Videos |
| `--video-category TEXT` | Kategorie (z.B. «Familie Kurmann-Glück») |
| `--video-date TEXT` | Aufnahmedatum im ISO-Format (`YYYY-MM-DD`). Wird als Dateiname-Prefix und in der Anzeige als deutsches Long-Datum verwendet. |
| `--video-quality TEXT` | Qualitätsangabe (z.B. «Dolby Vision», «4K HDR») |
| `--output-dir PATH` | Basisverzeichnis für die Ausgabe (Default: Verzeichnis der Quelldatei) |
| `--from-json PATH` | JSON-Datei mit Metadaten für Multi-Video-Mediaset |
| `--no-og-tags` | OpenGraph-Tags deaktivieren |
| `--verbose`, `-v` | Zusätzliche Ablaufinformationen auf stderr ausgeben |

### Ausgabe

stdout enthält den Pfad zum erstellten ULID-Verzeichnis:

```
/pfad/zum/output/01JNXYZ.../
```

Statusmeldungen werden auf stderr ausgegeben (nur mit `--verbose`).

### Erzeugte Verzeichnisstruktur

```
<ULID>/
├── index.html              # HTML-Seite mit Vorschaubild und Video-Link
├── video.mp4               # Komprimierte MP4 (bei >4K oder >50 Mbit/s) oder Original-Kopie
├── video-landscape.jpg     # Landscape-Vorschaubild (16:9, 1920×1080)
├── video-poster.jpg        # Portrait-Vorschaubild (2:3, 1080×1620)
├── video.nfo               # Infuse/Firecore-Metadaten (Titel, Datum, Genre)
└── video.zip               # ZIP mit Original-Video, Vorschaubildern und NFO
```

---

## Konfiguration

Einstellungen werden in `~/.config/mediaset-creator/config.toml` gespeichert.

### Befehle

```bash
# Wert speichern
mediaset-creator config set <schlüssel> "<wert>"

# Einzelnen Wert lesen
mediaset-creator config get <schlüssel>

# Alle gespeicherten Werte anzeigen
mediaset-creator config list
```

### Erlaubte Schlüssel

| Schlüssel | Beschreibung | Standard |
|-----------|--------------|---------|
| `og.base_url` | Stamm-URL für OG-Tags (z.B. `https://example.com/shares/`) | *(leer)* |
| `og.enabled` | OG-Tags aktivieren (`true`/`false`) | `true` |
| `og.site_name` | OG `site_name` Metadatum | *(leer)* |
| `og.locale` | OG `locale` Metadatum | `de_CH` |
| `thumbnails.sidecar` | Sidecar-Bilder als Landscape-Quelle verwenden (`true`/`false`) | `true` |
| `title.filename_fallback` | Dateiname (ohne Erweiterung) als Titel-Fallback verwenden (`true`/`false`) | `true` |
| `filename.date_prefix` | Datum (YYYY-MM-DD) als Dateiname-Prefix verwenden (`true`/`false`) | `true` |
| `video.auto_compress` | Automatische Komprimierung bei >4K-UHD oder >50 Mbit/s (`true`/`false`) | `true` |
| `tools.ffmpeg` | Pfad zur `ffmpeg`-Binärdatei | `ffmpeg` |
| `tools.ffprobe` | Pfad zur `ffprobe`-Binärdatei | `ffprobe` |
| `tools.nice_level` | CPU-Priorität für ffmpeg via `nice` (0–19; leer = keine Drosselung) | *(leer)* |

### Beispiel `config.toml`

```toml
[og]
base_url = "https://kurmannmedia.blob.core.windows.net/kurmann-glueck/"
enabled = "true"
site_name = "Patrick Kurmann Familienfilm-Freigabe"
locale = "de_CH"

[thumbnails]
sidecar = "true"

[title]
filename_fallback = "true"

[filename]
date_prefix = "true"

[video]
auto_compress = "true"

[tools]
ffmpeg = "ffmpeg"
ffprobe = "ffprobe"
nice_level = "10"
```

### OG-Tags

Wenn `og.base_url` gesetzt ist und OG-Tags aktiviert sind, generiert das HTML OpenGraph-Metadaten
für ansprechende Link-Vorschauen in Messengern und sozialen Netzwerken. Die vollständige URL
wird aus `base_url + ULID/` zusammengesetzt.

OG-Tags lassen sich deaktivieren via:
- `mediaset-creator config set og.enabled false` (persistent)
- `mediaset-creator create --no-og-tags ...` (pro Aufruf)

### Automatische Videokompression

Wenn `video.auto_compress` aktiv ist (Standard), analysiert das Tool vor der Verarbeitung die
technischen Eigenschaften des Videos. Bei Überschreiten eines der folgenden Schwellwerte wird
automatisch eine komprimierte MP4-Version erstellt:

- **Auflösung > 4K UHD** (Pixelzahl > 3840×2160, z.B. 5K, 6K)
- **Bitrate > 50 Mbit/s** (z.B. ProRes, hochbitratige HEVC-Aufnahmen)

**Was wird wohin geschrieben:**

| Datei | Inhalt |
|---|---|
| `video.mp4` im ULID-Verzeichnis | Komprimierte MP4 zum direkten Streaming |
| `video.zip` | **Original**-Videodatei + Vorschaubilder (für Medienserver) |

Wenn keine Kompression nötig ist, wird das Original wie bisher kopiert.

**Komprimierungsparameter** (macOS, VideoToolbox):
- Codec: HEVC (`hevc_videotoolbox`), Profil main10, 10-Bit
- Auflösung: 2560×1440 (QHD), Skalierung mit Lanczos-Filter
- Audio: AAC (`aac_at`), 192 kbit/s
- Keyframe-Abstand: 30 Frames, `faststart` für sofortiges Streaming

> **Hinweis:** Die Komprimierung verwendet macOS-spezifische Hardware-Beschleunigung
> (`hevc_videotoolbox`, `aac_at`). Auf anderen Plattformen schlägt ffmpeg fehl und das
> Original wird stattdessen kopiert (Fallback).

**Komprimierung deaktivieren:**
```bash
mediaset-creator config set video.auto_compress false
```

**CPU-Drosselung** (verhindert Lüfterlärm bei lang laufenden Encodings):
```bash
mediaset-creator config set tools.nice_level 10
```

Der `nice`-Wert (0–19) steuert die Prozesspriorität von ffmpeg. Höhere Werte = geringere
Priorität. Leer lassen (Standard) bedeutet keine Drosselung.

---

## Verwendung (Python API)

Die öffentliche API kann von anderen Python-Anwendungen genutzt werden:

```python
from pathlib import Path
from mediaset_creator.api import (
    CreateMediasetRequest,
    MediaItem,
    RuntimeOptions,
    create_mediaset,
)

# Fachlicher Request
request = CreateMediasetRequest(
    items=[
        MediaItem(
            source_path=Path("/pfad/zu/video.m4v"),
            title="Leah Treppen-Surfen",
            description="Beschreibung des Videos.",
            category="Familie Kurmann-Glück",
            recording_date="1. Juli 2024",
            quality_label="Dolby Vision",
        ),
    ],
    mediaset_title="Familienfilme 2024",
    output_dir=Path("/tmp/mediasets"),
    enable_og_tags=True,
)

# Technische Laufzeitoptionen (getrennt vom fachlichen Request)
runtime = RuntimeOptions(
    base_url="https://example.com/shares/",
    ffmpeg_path="ffmpeg",
    ffprobe_path="ffprobe",
)

# Mediaset erstellen
result = create_mediaset(request, runtime)

if result.success:
    print(f"Mediaset erstellt: {result.output_dir}")
    print(f"HTML: {result.html_path}")
else:
    print(f"Fehler: {result.error_message}")
```

### Fortschritts-Events

Für lang laufende Operationen kann ein Event-Callback übergeben werden:

```python
from mediaset_creator.api import MediasetCreatorEvent

def on_event(event: MediasetCreatorEvent) -> None:
    label = f" [{event.current}/{event.total}]" if event.current is not None else ""
    print(f"  {event.message}{label}")

result = create_mediaset(request, runtime, on_event=on_event)
```

### Öffentliche API-Exporte

```python
from mediaset_creator.api import (
    create_mediaset,          # Hauptfunktion
    CreateMediasetRequest,    # Fachlicher Request
    MediaItem,                # Ein Medienelement (aktuell: Video)
    RuntimeOptions,           # Technische Laufzeitoptionen
    MediasetResult,           # Ergebnis mit Pfaden
    MediasetCreatorEvent,     # Strukturiertes Fortschritts-Event
    MediasetCreatorStage,     # Stage-IDs (StrEnum)
)
```

---

## Änderungsverlauf

### 1.2.1 – 2026-03-28

- Bugfix: Sidecar-Bilder im TIFF-Format (16-Bit) werden jetzt beim Landscape-Vorschaubild korrekt zu sRGB-JPG konvertiert (vorher wurde die Datei unverändert kopiert)

### 1.2.0 – 2026-03-28

- Verbessertes HTML-Layout: Mediathek-Header, Datenschutzhinweis (privater Link, 30-Tage-Ablauf), Videodauer unterhalb des Titels
- Download-Link zeigt ZIP-Grösse und weist auf volle Auflösung hin
- Infuse-Kompatibilität: NFO-Datei im Firecore-Format (`<media type="Other">`) wird generiert und ins ZIP gepackt (Titel, Datum, Genre)
- Grösseres Play-Icon mit Drop-Shadow für besseren Kontrast auf hellen Bildern
- Erstellungsdatum (Timestamp) wird auf der HTML-Seite angezeigt
- Videodauer wird via ffprobe extrahiert und im HTML dargestellt

### 1.1.0 – 2026-03-27

- Automatische Videokompression: Bei >4K-UHD oder >50 Mbit/s wird eine komprimierte HEVC-MP4
  (2560×1440, VideoToolbox) erstellt – das Original kommt ins ZIP für den Medienserver
- CPU-Drosselung via `tools.nice_level` (0–19) verhindert Lüfterlärm bei lang laufenden Encodings
- Graceful Fallback: Bei Analysefehler oder fehlgeschlagenem Encoding wird das Original kopiert
- Neue Config-Keys: `video.auto_compress`, `tools.nice_level`
- Neue Event-Stages: `VIDEO_ANALYSIERT`, `VIDEO_KOMPRIMIERT`

### 1.0.0 – 2026-03-26

- Erstveröffentlichung als Python CLI-Applikation
- `create`-Befehl für Einzel- und Multi-Video-Mediensets
- `config`-Befehle für persistente TOML-Konfiguration
- Öffentliche Python API mit Request/Result-Muster
- Vorschaubilder via vorschaubild-manager (Landscape + Portrait)
- Poster-Overlay: Titel, Kategorie und Datum werden ins Portrait-Bild eingebettet
- Sidecar-Bilder als Landscape-Quelle (konfigurierbar via `thumbnails.sidecar`)
- Titel-Fallback: Dateiname wird als Titel verwendet wenn keiner angegeben (konfigurierbar via `title.filename_fallback`)
- Datum-Prefix: Dateinamen erhalten `YYYY-MM-DD` als Prefix wenn `--video-date` angegeben (konfigurierbar via `filename.date_prefix`)
- Datum-Eingabe im ISO-Format (`YYYY-MM-DD`), automatische Anzeige als deutsches Long-Datum (z.B. «Sonntag, 22. März 2026»)
- Einzelvideo: `--title` wird automatisch als Video-Titel übernommen; h2-Untertitel wird nur bei Multi-Video angezeigt
- ZIP-Download mit Video und Vorschaubildern (unkomprimiert, da Video bereits komprimiert)
- ULID-basierte Ausgabeverzeichnisse
- OG-Tags konfigurierbar und abschaltbar
- Eigenständiges CSS (kein CDN, kein JavaScript)
- Dark-Theme, responsive Layout

Vollständige Historie: [CHANGELOG.md](CHANGELOG.md)

---

## Lizenz

MIT
