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 repräsentiert genau ein Video und kann als Infuse-Medienset (Original-Video + Artworks + Metadaten) und/oder Web-Medienset (HTML-Seite + komprimiertes Video + ZIP) in separate Verzeichnisse ausgegeben werden.
Voraussetzungen
- Python 3.11+
- ffmpeg und
ffprobeim$PATH - kurmann-vorschaubild-manager (wird als Dependency installiert)
- Ein Anthropic API Key für die automatische Vorschaubildauswahl (siehe API-Keys)
Installation
uv pip install kurmann-mediaset-creator
Im Entwicklungsmodus (editierbar):
uv sync
Konzept: Profile
Ein Medienset kann in zwei Profilen ausgegeben werden:
| Profil | Zweck | Inhalt |
|---|---|---|
| Infuse | Medienserver (Infuse/Firecore) | Original-Video, Landscape (-fanart), Portrait (-poster), NFO |
| Web | Streaming via Hidden Link | HTML-Seite, komprimiertes Video, Landscape, optional ZIP |
Jedes Profil schreibt in ein eigenes Verzeichnis. Beide Profile sind unabhängig aktivierbar – mindestens eines muss angegeben werden.
Ausgabestruktur
infuse_dir/ web_dir/{ULID}/
├── Leah Treppen-Surfen.m4v ├── index.html
├── Leah Treppen-Surfen-fanart.jpg ├── leah-treppen-surfen.jpg
├── Leah Treppen-Surfen-poster.jpg ├── leah-treppen-surfen.mp4 (komprimiert)
└── Leah Treppen-Surfen.nfo └── leah-treppen-surfen.zip (optional)
- Infuse: Dateien mit Original-Dateinamen (inkl. Umlaute, Leerzeichen)
- Web: Dateien mit sanitisierten ASCII-Dateinamen, ULID-Unterverzeichnis für Hidden Links
Verwendung (CLI)
# Einfachster Aufruf – Web-Medienset im Quellverzeichnis
mediaset-creator create /pfad/zu/video.m4v \
--title "Leah Treppen-Surfen" \
--date "2024-07-01"
# Mit expliziten Profilen
mediaset-creator create /pfad/zu/video.m4v \
--title "Leah Treppen-Surfen" \
--category "Familie Kurmann-Glück" \
--date "2024-07-01" \
--infuse-dir /nas/infuse/familienfilme \
--web-dir /nas/shares
Ohne --infuse-dir oder --web-dir wird automatisch ein Web-Medienset im Verzeichnis
der Quelldatei erstellt (Web-ID-Unterordner).
Optionen
| Option | Profil | Beschreibung |
|---|---|---|
VIDEO (Argument) |
Pflicht | Pfad zur Videodatei |
--title TEXT |
Gemeinsam | Titel des Videos (auch H1-Überschrift). Fallback: Dateiname. |
--mediaset-title TEXT |
Gemeinsam | Optionaler H1-Titel, falls abweichend vom Video-Titel |
--description TEXT |
Gemeinsam | Beschreibung des Videos |
--category TEXT |
Gemeinsam | Kategorie (z.B. «Familie Kurmann-Glück») |
--date TEXT |
Gemeinsam | Aufnahmedatum im ISO-Format (YYYY-MM-DD) |
--max-luminance N |
Gemeinsam | Peak-Leuchtdichte in nits für HDR-Metadaten (Default: 1000) |
--poster-frame N |
Gemeinsam | Video-Framenummer für Vorschaubild |
--poster-at SEKUNDEN |
Gemeinsam | Zeitpunkt in Sekunden für Vorschaubild-Frame |
--poster-crop POS |
Gemeinsam | Bildausschnitt für Poster (left/center/right/...) |
--work-dir PATH |
Gemeinsam | Arbeitsverzeichnis für temporäre Dateien. Default: Quellverzeichnis |
--force |
Gemeinsam | Erzwingt Neuerstellung aller Dateien |
--verbose, -v |
Gemeinsam | Zusätzliche Ablaufinformationen auf stderr |
--infuse-dir PATH |
Infuse | Aktiviert Infuse-Profil, Zielverzeichnis |
--web-dir PATH |
Web | Web-Profil Basisverzeichnis (+ Web-ID). Default: Quellverzeichnis |
--web-id TEXT |
Web | Web-ID übersteuern (12 Zeichen, a-z 0-9). Default: auto-generiert |
--no-zip |
Web | Kein ZIP im Web-Profil |
--no-og-tags |
Web | OpenGraph-Tags deaktivieren |
Ausgabe (stdout)
- Nur Infuse: Pfad zum Infuse-Verzeichnis
- Nur Web (oder Default): Pfad zum ULID-Verzeichnis
- Beide: JSON
{"infuse": "/pfad/...", "web": "/pfad/.../ULID"}
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 |
|---|---|---|
branding.base_url |
Stamm-URL für Web-Mediasets und OG-Tags (z.B. https://mediathek.example.com/) |
(leer) |
branding.enabled |
OpenGraph-Meta-Tags rendern (true/false) |
true |
branding.site_name |
Site-Name (sichtbar im Header + OG-Meta) | (leer) |
branding.locale |
OG locale Metadatum (z.B. de_CH) |
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 als Titel-Fallback (true/false) |
true |
filename.date_prefix |
Datum (YYYY-MM-DD) als Dateiname-Prefix (true/false) |
true |
video.auto_compress |
Automatische Komprimierung bei >4K 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 | 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) |
Automatische Videokompression
Wenn video.auto_compress aktiv ist (Standard), analysiert das Tool die technischen Eigenschaften
des Videos. Bei Überschreiten eines der folgenden Schwellwerte wird automatisch eine komprimierte
MP4-Version für das Web-Profil erstellt:
- Auflösung > 4K UHD (> 3840×2160)
- Bitrate > 40 Mbit/s (konfigurierbar via
video.max_bitrate)
Das Infuse-Profil erhält immer das Original-Video – Komprimierung betrifft nur das Web-Profil.
| Parameter | Wert | Konfigurierbar |
|---|---|---|
| Codec | HEVC (libx265), 10-Bit |
– |
| Qualität | CRF 20 | video.crf |
| Preset | slow |
video.preset |
| Auflösung | 2560×1440 (QHD), Lanczos | – |
| Audio | AAC, 192 kbit/s | – |
Fallback: Falls libx265 nicht verfügbar, wird auf VideoToolbox (macOS) zurückgefallen.
API-Keys (KI-Funktionen)
Der Mediaset-Creator selbst spricht nicht mit Claude. Wenn ein
PosterSpec ohne frame_number/timestamp_seconds (oder ganz None)
übergeben wird, ruft er den
vorschaubild-manager
auf, der die Frame-Auswahl und/oder den Crop-Vorschlag via Claude erledigt.
Empfohlenes Setup: ANTHROPIC_API_KEY als Umgebungsvariable
# In ~/.zshenv eintragen (gilt für interaktive UND non-interaktive Shells,
# also auch für launchd / cron / Tool-Subprozesse via uv tool):
echo 'export ANTHROPIC_API_KEY="sk-ant-..."' >> ~/.zshenv
# Für laufende launchd-Jobs zusätzlich (einmalig, persistiert über Reboots):
launchctl setenv ANTHROPIC_API_KEY "sk-ant-..."
ANTHROPIC_API_KEY ist der offizielle Variablenname des Anthropic-SDK
und wird vom Vorschaubild-Manager bevorzugt gelesen. Der historische Name
CLAUDE_API_KEY bleibt als Fallback unterstützt.
Wer liest den Key wann?
| Tool | Liest Key? | Wann |
|---|---|---|
| Mediaset-Creator (dieses Tool) | ❌ nein | Pass-Through, KI greift implizit auf das Prozess-ENV zu |
| Vorschaubild-Manager | ✅ ja | beim Mosaic-Auto-Frame und beim Crop-Auto-Wahl |
Alternative: lokale Config-Datei
vorschaubild-manager config set claude.api_key "sk-ant-..."
# → schreibt nach ~/.config/vorschaubild-manager/config.toml
Ohne API-Key
Wenn weder ENV noch Config gesetzt sind und kein expliziter
PosterSpec.frame_number/timestamp_seconds übergeben wurde, schlägt
die Mediaset-Erstellung mit einer Fehlermeldung aus dem Vorschaubild-Manager
fehl.
Verwendung (Python API)
from pathlib import Path
from mediaset_creator.api import (
CreateMediasetRequest,
InfuseProfile,
PosterSpec,
WebProfile,
RuntimeOptions,
create_mediaset,
)
request = CreateMediasetRequest(
source_path=Path("/pfad/zu/video.m4v"),
title="Leah Treppen-Surfen",
description="Beschreibung des Videos.",
category="Familie Kurmann-Glück",
recording_date="2024-07-01",
poster=PosterSpec(timestamp_seconds=5.0),
mediaset_title="Familienfilme 2024",
work_dir=Path("/tmp/mediaset-work"), # Optional: Arbeitsverzeichnis für temporäre Dateien
infuse=InfuseProfile(output_dir=Path("/nas/infuse/familienfilme")),
web=WebProfile(
output_dir=Path("/nas/shares"),
include_zip=True,
enable_og_tags=True,
),
)
runtime = RuntimeOptions(
base_url="https://mediathek.example.com/",
)
result = create_mediaset(request, runtime)
if result.success:
if result.infuse:
print(f"Infuse: {result.infuse.output_dir}")
if result.web:
print(f"Web: {result.web.output_dir} (Web-ID: {result.web.web_id})")
else:
print(f"Fehler: {result.error_message}")
Fortschritts-Events
Events sind strukturierte Datenstrukturen mit stabilen stage_id-Strings.
Milestone-Events (INFUSE_READY, WEB_READY) enthalten ein paths-Dict mit den erzeugten
Dateipfaden, sodass Host-Applikationen sofort mit dem Deployment beginnen können.
from mediaset_creator.api import MediasetCreatorEvent, MediasetCreatorStage
def on_event(event: MediasetCreatorEvent) -> None:
print(f" {event.message}")
if event.stage_id == MediasetCreatorStage.INFUSE_READY:
# Medienserver-Deployment starten
deploy_to_infuse(event.paths)
elif event.stage_id == MediasetCreatorStage.WEB_READY:
# Web-Deployment starten
deploy_to_web(event.paths)
result = create_mediaset(request, runtime, on_event=on_event)
Event-Phasen
| Phase | Stage-ID | Beschreibung |
|---|---|---|
| – | mediaset_started |
Mediaset-Erstellung beginnt |
| 1 | video_analyzed |
Videoanalyse (Auflösung, Bitrate, Codec) |
| 1 | thumbnails_created |
Landscape- und Portrait-Vorschaubilder erstellt |
| 1 | nfo_created |
Infuse/Firecore-Metadatei erstellt |
| 2 | ⭐ infuse_ready |
Infuse-Medienset komplett (mit paths) |
| 3 | video_copied |
Original kopiert (keine Komprimierung nötig) |
| 3 | video_skipped |
Video unverändert, übersprungen |
| 3 | zip_created |
ZIP-Archiv erstellt |
| 3 | html_generated |
HTML-Seite generiert |
| 4 | video_recompressed |
Nachkomprimierung läuft (Bitrate zu hoch) |
| 4 | video_compressed |
Komprimierung abgeschlossen |
| 5 | ⭐ web_ready |
Web-Medienset komplett (mit paths) |
| 5 | mediaset_completed |
Alle Profile fertig |
MediasetResult
@dataclass
class MediasetResult:
success: bool
infuse: InfuseResult | None # Infuse-Profil Ergebnis
web: WebResult | None # Web-Profil Ergebnis
error_message: str | None
@dataclass
class InfuseResult:
output_dir: Path
video_path: Path
landscape_path: Path
portrait_path: Path
nfo_path: Path
@dataclass
class WebResult:
output_dir: Path # Web-ID-Verzeichnis
web_id: str # 12 Zeichen, a-z 0-9 (Lowercase Base36)
html_path: Path
video_path: Path
landscape_path: Path
zip_path: Path | None # None wenn include_zip=False
Öffentliche API-Exporte
from mediaset_creator.api import (
create_mediaset, # Hauptfunktion
CreateMediasetRequest, # Fachlicher Request
InfuseProfile, # Infuse-Profil Konfiguration
WebProfile, # Web-Profil Konfiguration
PosterSpec, # Vorschaubild-Parameter
RuntimeOptions, # Technische Laufzeitoptionen
MediasetResult, # Ergebnis (profil-basiert)
InfuseResult, # Infuse-Ergebnis
WebResult, # Web-Ergebnis
MediasetCreatorEvent, # Strukturiertes Fortschritts-Event
MediasetCreatorStage, # Stage-IDs (StrEnum)
)
Änderungsverlauf
Beinhaltet die letzten drei Versionen.
3.0.0 – 2026-04-17
- Web-ID statt ULID: Web-Mediasets bekommen 12-stellige Lowercase-IDs (a-z, 0-9) statt 26-stellige ULIDs. Kürzere URLs (
/a3xk9mn2pqrw/statt/01KPCZDEZVQ0PDNAJKB6V5RTXV/) - Dolby Vision-Erkennung: Wird automatisch erkannt und im
color_space_labelausgegeben (Vorrang vor "BT.2020 PQ") - HTML-Title mit Kategorie:
<title>Familie Kurmann-Glück – Heubürzel Ann-Sophie</title> - Technische Specs im HTML: Stream + Original/ZIP mit Farbraum, Auflösung, fps, Bitrate
VideoInfo.frame_rate+bit_depth+color_space_label+is_dolby_vision: Neue PropertiesVideoSpecsDataclass: Neue View-Modell-Klasse mitformat_compact()OgConfig→BrandingConfig: Klarerer Name, gleiche Felder (+web_idstattulid)- Config-Keys:
og.X→branding.X quality_labelentfernt: Durch Tech-Specs überflüssig (Dolby Vision wird automatisch erkannt)- Breaking: HTML-Generierung läuft jetzt nach der Komprimierung.
HTML_GENERATEDEvent kommt nachVIDEO_COMPRESSED.WEB_READYbleibt unverändert als zentraler Milestone. - Dependency:
python-ulidentfernt
2.1.0 – 2026-04-16
- HDR-Metadaten-Einbettung: MaxCLL, MaxFALL und Mastering Display Metadaten werden automatisch in HDR-Videos eingebettet, damit Geräte die Peak-Leuchtdichte korrekt interpretieren
--max-luminance: Peak-Leuchtdichte in nits übersteuern (Default: 1000)- HDR-Erkennung:
VideoInfo.is_hdrvia ffprobe (PQ/HLG/BT.2020) - AudioToolbox-Encoder:
aac_at(macOS) für bessere Audioqualität
2.0.1 – 2026-04-09
- HTML-Template als Python-String eingebettet statt aus Dateisystem laden
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-3.1.0.tar.gz.
File metadata
- Download URL: kurmann_mediaset_creator-3.1.0.tar.gz
- Upload date:
- Size: 31.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3bb332c759ceedca2d337d1e3fd1e080cb0e70cabe4538a71e23290ebf5c5d86
|
|
| MD5 |
270426cd901fb1fd34783c6a4904c47d
|
|
| BLAKE2b-256 |
5567ec81dc1f55b70c2fdd3e056a7a78a36b91fe66627543525ef94ad4a0b625
|
Provenance
The following attestation bundles were made for kurmann_mediaset_creator-3.1.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-3.1.0.tar.gz -
Subject digest:
3bb332c759ceedca2d337d1e3fd1e080cb0e70cabe4538a71e23290ebf5c5d86 - Sigstore transparency entry: 1399149152
- Sigstore integration time:
-
Permalink:
kurmann/mediaset-creator@abc19724d57fd46a55973ee1e1a8adfa8b2c535d -
Branch / Tag:
refs/tags/v3.1.0 - Owner: https://github.com/kurmann
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@abc19724d57fd46a55973ee1e1a8adfa8b2c535d -
Trigger Event:
release
-
Statement type:
File details
Details for the file kurmann_mediaset_creator-3.1.0-py3-none-any.whl.
File metadata
- Download URL: kurmann_mediaset_creator-3.1.0-py3-none-any.whl
- Upload date:
- Size: 36.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a4beeee5ffb527692b5e9d6899e59bd39cad5cff46510037404b5e3c658d5236
|
|
| MD5 |
244e097763b0aceda1695f449dabb23f
|
|
| BLAKE2b-256 |
74439c35391e96eaac7c707b579ef4c934f652f62e0b1e4b3698e04701fcf1be
|
Provenance
The following attestation bundles were made for kurmann_mediaset_creator-3.1.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-3.1.0-py3-none-any.whl -
Subject digest:
a4beeee5ffb527692b5e9d6899e59bd39cad5cff46510037404b5e3c658d5236 - Sigstore transparency entry: 1399149206
- Sigstore integration time:
-
Permalink:
kurmann/mediaset-creator@abc19724d57fd46a55973ee1e1a8adfa8b2c535d -
Branch / Tag:
refs/tags/v3.1.0 - Owner: https://github.com/kurmann
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@abc19724d57fd46a55973ee1e1a8adfa8b2c535d -
Trigger Event:
release
-
Statement type: