Date

Die Mediatheken der Öffentlich-Rechtlichen haben ja immer wieder Perlen zu bieten. Leider aber häufig nur für sehr kurze Zeit, und nicht umbedingt dann, wenn ich als Nutzer auch Zeit habe diese zu konsumieren. Und auch so manches Endgerät, wie die PlayStation, harmonieren nicht so wunderbar mit den Mediatheken. Mit MediathekView und yt-dlp gibt es aber ja zum Glück hervorragende Möglichkeiten Medien zur zeit- und gerätesouveränen Nutzung auf einen lokalen DLNA-Server oder ein Plex zu sichern.

Das Problem

Ärgerlich ist hierbei, wenn Original- und synchronisierte Version in den Mediatheken als separate Videos angeboten werden. Denn das Video ist ja in allen Versionen dasselbe. Wird es für alle Sprachversionen separat gesichert, sorgt es für doppelte Downloadgröße und doppelten Speicherbedarf. Dabei würde eine zusätzliche Tonspur nur minimalen Platz verbrauchen.

Mehrsprachige Videos herunterladen

In der Mediathek des ZDF finden sich inzwischen auch Videos bei denen allen Sprachversionen parallel ausgeliefert werden. Leider lassen sich diese nicht direkt über MediathekView herunterladen. Aber mit yt-dlp ist dies möglich. Der Magie besteht hierdrin in der Nutzung des Parameters --audio-multistream und der korrekten Auswahl der Tonspuren. Letzere lässt sich durch die Auswahl bestaudio auch automatisieren, allerdings müssen alle Sprachen explizit angegeben werden, also beispielsweise bestaudio[language=de]+bestaudio[langauge=en].

Die Arbeit an ein Skript delegieren

Um die Sprachen nicht jedes mal von Hand auswählen zu müssen hilft ein kleine Shellscript welches zuerst per yt-dlp --dump-json die Metadaten des Videos abfragt, aus diesen die Sprachen per jq extrahiert und daraus den passenden Parameter für yt-dlp baut.

#!/bin/bash

set -eu -o pipefail

echo "Lade ${1} als ${2}"

AUDIO=$(yt-dlp --dump-json "${1}" | jq -r '[[.formats[] | select(.vcodec == "none") | .language] | sort | unique[] | "+bestaudio[language=\(.)]"] | join("")')

yt-dlp --write-subs --sub-langs 'deu,eng,fra' --audio-multistreams --format "bestvideo${AUDIO}" --embed-metadata --merge-output-format 'mp4' --write-thumbnail --output "${2}.%(ext)s" "${1}"

Das Skript übernimmt die URL eines Videos als erster Parameter, und schreibt mehrsprachiges Video, Untertitel, und ein Titelbild in Dateien welche den zweiten Parameter als Namen nutzen. Das erlaubt die Dateien direkt mit den passenden Namen für die Metadatenerkennung von Plex anzulegen. Um also beispielsweise Sugar aus der ZDF-Mediathek für eine Wiedergabe an der PS5 per Plex herzunterzuladen würde das, als zdf_mt_dl.sh abgelegte, Skript wie folgt aufgerufen:

zdf_mt_dl.sh 'https://www.zdf.de/filme/spielfilm-highlights/sugar-108.html' 'Sugar (2022)'

Das Skript erklärt

Das anfängliche set -eu -o pipefail stellt sicher, dass das Skript abbricht wenn:

  • ein Aufruf im Skript einen Fehler zurückgibt (-e),
  • und zwar auch, wenn wir das Ergebnis per Pipe weitergeben (-o pipefail).
  • Auch beim Zugriff auf eine undefinierte Variable bricht das Skript ab (-u).

yt-dlp --dump-json holt die Metadaten von der übergebenen URL und gibt diese als JSON aus. Diese verarbeiter der Aufruf von jq weiter. Aus allen Formaten werden nur diese ausgewählt, bei welchen das Attribut vcoded den Wert none hat, also die reinen Audio-Stream. Von diesen lesen wir das Attribut language aus, sortieren diese, sortieren Duplicate aus, und setzen diese per \(.) jeweils in die Zeichenkette "+bestaudio[language=\(.)]" ein. Wichtig ist hier, dass wir das ganze nochmal ein eckigen Klammern haben, damit bekommen wir nicht eine Zeichenkette pro Zeile im Output von jq, sondern bekommen das ganze immer noch als JSON-Array. Damit können wir diese am Schluss noch per join("") zusammenfassen und bekommen dann so etwas wie +bestaudio[language=de]+bestaudio[langauge=en] welches wir dann anschließend über die Variable ${AUDIO} in unseren Aufruf von yt-dlp setzen können.

Beim Aufruf von yt-dlp nutzt das Skript noch ein paar weitere Parameter:

  • --write-subs holt, falls verfügbar, auch die Untertitel mit aus der Mediathek.
  • --sublangs 'deu,eng,fra' wählt die Sprachen aus die --write-subs versuchen soll.
  • --audio-multistreams sorgt dafür, dass mehrere Tonspuren in der geschriebenen Datei landen dürfen. Sonst gäbe die Auswahl mehrerer Spuren einen Fehler.
  • --format "bestvideo${AUDIO}" wählt die Spuren aus. Wir wollen die beste Videospur, und zu jeder Sprache das beste Audio. ${AUDIO} wird hier mit der Spezifikation der Tonspuren ersetzt die wir zuvor zusammegebastelt haben.
  • --embed-metadata sorgt dafür, dass die Tonspuren auch schöne Namen haben.
  • --merge-output-format sorgt dafür, dass eine mp4 statt einer mkv geschrieben wird. Das hat bei der Weitergabe an eine PlayStation den Vorteil, dass die PlayStation MP4-Dateien, anders als Matroska-Dateien direkt abspielen kann. So wird im Zweifel der Medienserver ein klein wenig entlastet.
  • --write-thumbnail sorgt dafür, dass das Titelbild zur Datei mitgesichert wird.
  • --output "${2}.%(ext)s" schließlich lässt yt-dlp unseren vorgegebenen Dateinamen übernehmen, aber für die einzelnen Dateien selbst die passende Endung auswählen. Ein deutscher Untertitel lautet beim oben genannten Beispiel also unter Sugar (2022).deu.vtt, das Video selbst unter Sugar (2022).mp4.