CLI-Tool zur Erstellung von Mediensets (statisches HTML mit OG-Tags, Vorschaubildern und ZIP-Download) aus Videodateien.
Project description
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 und
ffprobeim$PATH - kurmann-vorschaubild-manager (wird als Dependency installiert)
- Ein Anthropic API Key für die automatische Vorschaubildauswahl
(konfigurierbar via
vorschaubild-manager config set claude.api_key <key>)
Installation
uv pip install kurmann-mediaset-creator
Im Entwicklungsmodus (editierbar):
uv sync
Verwendung (CLI)
Einzelnes Video
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:
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:
mediaset-creator create --from-json metadaten.json
Format der JSON-Datei:
{
"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",
"frame_number": 500,
"crop_position": "center-left"
},
{
"path": "/pfad/zu/video2.m4v",
"title": "Herbst-Spaziergang",
"description": "Ein sonniger Herbsttag.",
"recording_date": "2024-11-01",
"quality_label": "4K HDR",
"timestamp_seconds": 45.0
}
]
}
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 |
--ulid TEXT |
Bestehende ULID verwenden (überschreibt ein vorhandenes Medienset) |
--poster-frame N |
Video-Framenummer für Vorschaubild (überspringt KI-Auswahl) |
--poster-at SEKUNDEN |
Zeitpunkt in Sekunden für Vorschaubild-Frame (z.B. 90 oder 1.5) |
--poster-crop POS |
Bildausschnitt für Poster (left/center-left/center/center-right/right) |
--force |
Erzwingt Neuerstellung aller Dateien, auch wenn Video bereits vorhanden ist |
--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 # Video (komprimiert oder Original-Kopie)
├── video.jpg # Vorschaubild (16:9, 1920×1080)
└── video.zip # ZIP für Infuse (Video, -fanart.jpg, -poster.jpg, .nfo)
Konfiguration
Einstellungen werden in ~/.config/mediaset-creator/config.toml gespeichert.
Befehle
# 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.portrait_suffix |
Suffix für Hochformat-Vorschaubilder (Infuse: -poster) |
-poster |
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 >40 Mbit/s (true/false) |
true |
video.crf |
CRF-Wert für libx265 (0–51, tiefer = bessere Qualität) | 20 |
video.max_bitrate |
Maximale Bitrate in Mbit/s – darüber wird komprimiert/nachkomprimiert | 40 |
video.preset |
libx265-Preset (ultrafast/fast/medium/slow/veryslow) |
slow |
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
[og]
base_url = "https://kurmannmedia.blob.core.windows.net/kurmann-glueck/"
enabled = "true"
site_name = "Patrick Kurmann Familienfilm-Freigabe"
locale = "de_CH"
[thumbnails]
portrait_suffix = "-poster"
sidecar = "true"
[title]
filename_fallback = "true"
[filename]
date_prefix = "true"
[video]
auto_compress = "true"
crf = "20"
max_bitrate = "40"
preset = "slow"
[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 > 40 Mbit/s (konfigurierbar via
video.max_bitrate)
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.
Warum Software-Encoding statt Hardware-Encoding?
Die komprimierte MP4-Datei dient dem Streaming via HTML über einen geheimen Link. Hier zählt
bestmögliche Qualität pro Bit, nicht Encoding-Geschwindigkeit. libx265 (Software) erreicht
bei gleicher Bitrate ca. 20–30% bessere Qualität als VideoToolbox (Hardware), insbesondere
bei Szenen mit viel Bewegung (z.B. Schneefall, Regen, wehende Blätter). Der CRF-Modus
(Constant Rate Factor) gewährleistet konstante visuelle Qualität über das gesamte Video –
einfache Szenen werden kleiner, komplexe Szenen bekommen mehr Bitrate.
Das Original-Video bleibt unverändert im ZIP für den Download (z.B. für Infuse/Medienserver). Durch die Skalierung von z.B. 4K auf 2560×1440 ist die Encoding-Geschwindigkeit trotz Software-Encoding akzeptabel (~0.5–0.7x Echtzeit).
Komprimierungsparameter:
| Parameter | Wert | Konfigurierbar |
|---|---|---|
| Codec | HEVC (libx265), 10-Bit (yuv420p10le) |
– |
| Qualität | CRF 20 (visuell verlustfrei) | video.crf |
| Preset | slow (beste Qualität/Grösse) |
video.preset |
| Auflösung | 2560×1440 (QHD), Lanczos-Skalierung | – |
| Audio | AAC, 192 kbit/s | – |
| Streaming | faststart (Moov-Atom am Dateianfang) |
– |
| HDR | Farbmetadaten (BT.2020, SMPTE 2084) werden durchgereicht | – |
Nachkomprimierung bei hoher Bitrate:
Wenn die Bitrate nach der initialen Komprimierung noch über 40 Mbit/s liegt (z.B. bei Videos mit viel Bewegung wie Schneefall), wird automatisch erneut vom Original komprimiert – mit schrittweise erhöhtem CRF (20 → 22 → 24 → ...) bis die Bitrate unter dem Schwellwert liegt oder die CRF-Obergrenze von 28 erreicht ist.
Fallback: Falls libx265 nicht verfügbar ist (z.B. bei einer ffmpeg-Installation ohne
--enable-libx265), wird automatisch auf VideoToolbox (macOS Hardware-Encoding) zurückgefallen.
Prüfen ob libx265 verfügbar ist: ffmpeg -encoders 2>&1 | grep libx265
Komprimierung deaktivieren:
mediaset-creator config set video.auto_compress false
CPU-Drosselung (verhindert Lüfterlärm bei lang laufenden Encodings):
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:
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. Events sind
strukturierte Datenstrukturen (nicht Freitext) mit stabilen stage_id-Strings, die eine
Host-Applikation maschinell auswerten kann.
from mediaset_creator.api import MediasetCreatorEvent, MediasetCreatorStage
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)
Event-Reihenfolge pro Video:
| Stage-ID | Beschreibung | Wann |
|---|---|---|
mediaset_gestartet |
Mediaset-Erstellung beginnt | Einmal zu Beginn |
video_analysiert |
Videoanalyse (Auflösung, Bitrate, Codec) | Pro Video |
thumbnails_erstellt |
Breitbild- und Poster-Vorschaubilder erstellt | Pro Video |
nfo_erstellt |
Infuse/Firecore-Metadatei erstellt | Pro Video |
video_komprimiert |
Komprimierung abgeschlossen (mit CRF, Bitrate, Encoder) | Pro Video (wenn nötig) |
video_kopiert |
Original kopiert (keine Komprimierung nötig) | Pro Video (alternativ) |
video_nachkomprimiert |
Nachkomprimierung läuft (Bitrate noch zu hoch) | 0–n mal pro Video |
zip_erstellt |
ZIP-Archiv mit Original + Vorschaubilder erstellt | Pro Video |
html_generiert |
HTML-Seite mit OG-Tags generiert | Einmal am Ende |
mediaset_abgeschlossen |
Alle Dateien erstellt | Einmal am Ende |
Hinweis zur Reihenfolge: Thumbnails und NFO werden bewusst vor der Videokomprimierung
erstellt. So kann eine Host-Applikation nach thumbnails_erstellt + nfo_erstellt bereits
mit dem Infuse-Deployment beginnen (Original-Video + Vorschaubilder + NFO auf den
Medienserver kopieren), während die langsame Software-Komprimierung noch läuft.
Komprimierungs-Zusammenfassung (video_komprimiert) wird in der CLI immer auf stderr
angezeigt (auch ohne --verbose), z.B.:
Video komprimiert: video.mp4 | CRF=20 | 35 Mbit/s [1/1]
Öffentliche API-Exporte
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
Beinhaltet die letzten drei Minorversionen.
1.4.0 – 2026-03-29
- Software-Encoding: libx265 mit CRF-Modus statt VideoToolbox Hardware-Encoding für bessere Qualität pro Bit. Automatischer Fallback auf VideoToolbox wenn libx265 nicht verfügbar.
- Vereinfachte Bildnamen: Vorschaubild heisst
<stem>.jpgohne Suffix, Portrait + NFO nur noch im ZIP - Reihenfolge optimiert: Thumbnails + NFO vor Videokomprimierung (ermöglicht frühes Infuse-Deployment durch Host-Applikation)
- Neue Config-Keys:
video.crf,video.preset,thumbnails.portrait_suffix - Neue Event-Stage:
NFO_ERSTELLT - Standard-Bitrate-Schwellwert von 50 auf 40 Mbit/s gesenkt
- Frame-Auswahl:
--poster-frame,--poster-at,--poster-cropfür manuelle Vorschaubild-Steuerung - Inkrementelle Verarbeitung: Vorhandene Videos werden übersprungen wenn Quelle nicht neuer (
--forcezum Übersteuern)
1.3.0 – 2026-03-28
- Internet-freundliche Dateinamen: Umlaute transliteriert (ö→oe), Leerzeichen → Bindestriche, nur ASCII-Zeichen. Verhindert 404-Fehler durch Unicode-Normalisierungs-Unterschiede (macOS NFD vs. Server NFC).
- ZIP-Inhalte behalten originale Dateinamen (Infuse-freundlich)
- Neue Option
--ulidzum Überschreiben bestehender Mediensets - Automatische Nachkomprimierung bei zu hoher Bitrate
1.2.0 – 2026-03-28
- Verbessertes HTML-Layout: Mediathek-Header, Datenschutzhinweis, Videodauer
- Infuse-Kompatibilität: NFO-Datei im Firecore-Format
- Grösseres Play-Icon mit Drop-Shadow
- 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
Vollständige Historie: CHANGELOG.md
Lizenz
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kurmann_mediaset_creator-1.4.0.tar.gz.
File metadata
- Download URL: kurmann_mediaset_creator-1.4.0.tar.gz
- Upload date:
- Size: 23.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
64bcf9be60a04b4a518ea701671dd07d132b04e09e1e6dce43a86cdc33209e29
|
|
| MD5 |
991049e7fd4ccc65ad093c7735cd6ff9
|
|
| BLAKE2b-256 |
52d4cd6b8b2ba2873ea624801cf66c3a85ff25b55067c428c029a43750729a1a
|
Provenance
The following attestation bundles were made for kurmann_mediaset_creator-1.4.0.tar.gz:
Publisher:
publish.yml on kurmann/mediaset-creator
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kurmann_mediaset_creator-1.4.0.tar.gz -
Subject digest:
64bcf9be60a04b4a518ea701671dd07d132b04e09e1e6dce43a86cdc33209e29 - Sigstore transparency entry: 1194598405
- Sigstore integration time:
-
Permalink:
kurmann/mediaset-creator@f5f9b433ebc1f2351aacc4cc608a3c1a25374b87 -
Branch / Tag:
refs/tags/v1.4.0 - Owner: https://github.com/kurmann
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f5f9b433ebc1f2351aacc4cc608a3c1a25374b87 -
Trigger Event:
release
-
Statement type:
File details
Details for the file kurmann_mediaset_creator-1.4.0-py3-none-any.whl.
File metadata
- Download URL: kurmann_mediaset_creator-1.4.0-py3-none-any.whl
- Upload date:
- Size: 27.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d6ab574fb23617e5eb483b18c2fd4d5230ba01d725dd171e0c18e0c6bb5f5c29
|
|
| MD5 |
33b0a163e3a00826b854c43c92e6e8d4
|
|
| BLAKE2b-256 |
0b78edb4191a1df677ab89eae40fbae026ae53f793adb70559fcac00e30484b2
|
Provenance
The following attestation bundles were made for kurmann_mediaset_creator-1.4.0-py3-none-any.whl:
Publisher:
publish.yml on kurmann/mediaset-creator
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kurmann_mediaset_creator-1.4.0-py3-none-any.whl -
Subject digest:
d6ab574fb23617e5eb483b18c2fd4d5230ba01d725dd171e0c18e0c6bb5f5c29 - Sigstore transparency entry: 1194598409
- Sigstore integration time:
-
Permalink:
kurmann/mediaset-creator@f5f9b433ebc1f2351aacc4cc608a3c1a25374b87 -
Branch / Tag:
refs/tags/v1.4.0 - Owner: https://github.com/kurmann
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f5f9b433ebc1f2351aacc4cc608a3c1a25374b87 -
Trigger Event:
release
-
Statement type: