Wiedergabe von Playlisten, die auch YouTube enthalten
mpv als plattformübergreifende Grundlage für das Abspielen gemischter Playlisten
Discovery bei Musik bedeutet: Abspielen, was ich nicht kenne. Dummerweise bedeutet das bei lokaler Musik aber auch: Abspielen, was ich nicht habe. Deshalb mischen meine Skripte lokale Dateien und YouTube-URLs miteinander.
Damit das wie ein durchgehender Stream läuft, brauche ich einen Player, der beide Quellen abspielt, beim Wechsel nicht in der Lautstärke springt und am Ende alles bei Last.fm einträgt. Auf dem Mac macht das IINA, das im Kern nur eine Oberfläche für mpv ist. Fast alles Folgende ist deshalb mpv-Konfiguration, nicht IINA-spezifisch.
IINA, und darunter mpv#
IINA ist ein moderner macOS-Player, der intern den Medienkern von mpv nutzt. Eine .m3u mit gemischten Einträgen spielt er ohne Umweg: Lokale Pfade dekodiert mpv direkt, YouTube-URLs reicht IINA an sein io.iina.ytdl-Plugin weiter, das yt-dlp aufruft und den Stream auflöst. In den Playlists stehen dafür bereits fertige youtube.com/watch?v=…-Adressen, denn ytsearch1:-Suchanfragen versteht IINA in einer m3u nicht, diese werden stillschweigend übersprungen.
flowchart LR
M3U[".m3u<br/>FLAC-Pfade + YouTube-URLs"] --> IINA["IINA"]
IINA --> LOCAL["lokale FLAC<br/>direkt dekodiert"]
IINA --> YT["YouTube-URL<br/>ytdl-Plugin → yt-dlp (bestaudio)"]
LOCAL --> MPV["mpv-Kern<br/>Volume-Profil: Streams +10 %"]
YT --> MPV
MPV --> OUT["Audioausgabe"]
IINA -. file-loaded .-> SCR["on-change.lua → scrobble.sh"]
SCR --> LFM["Last.fm"]
classDef src fill:#e8f0fe,stroke:#3367d6,color:#000;
classDef engine fill:#e6f4ea,stroke:#1e8e3e,color:#000,stroke-width:2px;
classDef out fill:#f3e8fd,stroke:#7b2ff7,color:#000;
class M3U src;
class IINA,MPV,SCR engine;
class OUT,LFM out;
Die mit IINA gebündelte youtube-dl-Version ist seit etwa 2021 ohne Updates und scheitert an heutigem YouTube. IINA zeigt deshalb auf eine frische Homebrew-Installation, und das ytdl-Plugin wird aktiviert:
brew install yt-dlp
ln -s /opt/homebrew/bin/yt-dlp /opt/homebrew/bin/youtube-dl # Legacy-Name
defaults write com.colliderli.iina ytdlSearchPath -string "/opt/homebrew/bin"
defaults write com.colliderli.iina PluginEnabled.io.iina.ytdl -bool truebashDamit bei einem YouTube-Track kein Videofenster aufspringt, ist in IINA unter Settings → Network die yt-dlp-Formatvorgabe auf bestaudio gesetzt. Das wirkt nur über IINAs internes ytdl-Plugin, ein globales ~/.config/yt-dlp/config ignoriert IINA dagegen.
Lautstärke: YouTube an die FLACs angleichen#
Beim Wechsel von einem lokalen Track auf einen YouTube-Stream fällt die Lautstärke hörbar ab. Der Grund ist die Loudness-Normalisierung: YouTube liefert um die -14 LUFS, meine FLACs liegen oft bei -10 bis -8 LUFS. Damit der Stream nicht leiser wirkt als der Rest, hebt ein Protokoll-Profil in der mpv-Konfiguration nur HTTP(S)-Quellen um zehn Prozent an, lokale Dateien bleiben unberührt:
volume-max=150
[protocol.https]
volume=110
[protocol.http]
volume=110iniDass diese Datei überhaupt greift, liegt daran, dass IINA das Standard-mpv-Verzeichnis (~/.config/mpv/) mitliest. Darüber läuft auch das Scrobbling.
Scrobbling beider Quellen#
Fürs Scrobbeln sorgt iina-lastfm ↗. Angestoßen wird es über einen winzigen mpv-Hook: Ein Lua-Script registriert das file-loaded-Ereignis und ruft bei jedem Trackwechsel das eigentliche Scrobble-Script auf.
function track_load()
os.execute("/usr/bin/env bash ~/.config/mpv/lastfmscrobbler/scrobble.sh")
end
mp.register_event("file-loaded", track_load)luascrobble.sh fragt den laufenden Track über mpvs IPC-Socket (/tmp/mpv-socket) ab: Künstler, Titel und Dauer. Für lokale FLACs steht das alles in den eingebetteten Tags und landet sauber bei Last.fm. YouTube-Streams haben dieses Problem: yt-dlp füllt keine strukturierten artist/title-Felder, sondern nur den freien Video-Titel im Format Artist - Track [Official Music Video]. Das Originalskript findet dort keinen Künstler und bricht ab.
Gelöst ist das mit einem lokalen Patch am Skript (einsatzbereit unter scripts/scrobble.sh). Fehlt der Künstler-Tag, greift ein Fallback auf media-title: Diese Zeichenkette kommt bei den generierten Playlists aus der #EXTINF-Zeile der m3u (dort steht bereits sauberes Artist - Track), sonst aus dem YouTube-Titel. Sie wird an " - " gesplittet, und Marketing-Suffixe wie [Official Music Video] oder (Lyric Video) werden vom Track-Teil entfernt. Lokale FLACs mit echten Tags lösen den Fallback nie aus.
| Quelle | Künstler-Tag? | media-title | Ergebnis |
|---|---|---|---|
| Lokales FLAC mit Tags | ja | (Fallback feuert nicht) | gescrobbelt mit Tag-Werten |
discovery-yt.m3u, EXTINF Maisie Peters - Lost the Breakup | nein | Maisie Peters - Lost the Breakup | artist='Maisie Peters' title='Lost the Breakup' |
| YouTube-Direktlink ohne EXTINF | nein | Maisie Peters - Lost The Breakup [Official Music Video] | artist='Maisie Peters' title='Lost The Breakup' (Suffix gestrippt) |
YouTube mit Track (feat. X) [Official Music Video] | nein | Artist - Track (feat. X) [Official Music Video] | artist='Artist' title='Track (feat. X)' |
YouTube ohne " - " (Channel-Eigen-Upload) | nein | My Song Title HD | nicht gescrobbelt, Regex matcht nicht |
| YouTube-Mix oder DJ-Set | nein | 1 hour relaxing mix | nicht gescrobbelt |
Auf andere Plattformen übertragen#
Der Aufbau ist kaum an IINA gebunden, und das ist beabsichtigt. Die drei tragenden Teile sind reines mpv: Das Lautstärke-Profil ist mpv-Konfiguration, der Scrobble-Hook ist ein mpv-Lua-Script plus ein Shell-Skript am IPC-Socket, und die YouTube-Auflösung erledigt mpvs eingebauter ytdl_hook ebenfalls über yt-dlp. IINAs ytdl-Plugin ist nur die macOS-Verpackung desselben Mechanismus.
mpv-Konfiguration ohne IINA:
# Global options — keep these ABOVE the [protocol.*] profiles. Anything placed
# after a profile header belongs to THAT profile, not the global scope, so
# global options at the bottom of the file silently do nothing.
ytdl-format=bestaudio # YouTube: fetch the audio stream only
vo=null # audio-only, no video window
volume-max=150
input-ipc-server=/tmp/mpv-socket # IPC socket the Last.fm scrobble script reads
# Boost HTTP(S) streams (e.g. YouTube) to match the louder local FLAC library.
# Local files stay at default volume.
[protocol.https]
volume=110
[protocol.http]
volume=110plaintextAufruf per Kommandozeile für eine gemischte Playlist FLAC und YouTube-URLs, YouTube als audio-only und Scrobbling per lua/sh-Skript somit:
mpv Radio_against_the_current.m3u
Damit ließe sich das Setup auf jeden mpv-basierten Player übertragen: Auf mpv selbst (jedes OS), auf Celluloid unter GNOME, auf mpv.net unter Windows, auf SMPlayer oder Haruna unter KDE. Statt der IINA-Oberfläche kämen dieselbe mpv.conf und dasselbe Script ins mpv-Konfigurationsverzeichnis.
Grenzen#
Das Scrobbeln aus YouTube-Titeln ist ein Kompromiss. Tracks ohne " - " im Titel werden bewusst nicht gescrobbelt, weil die Alternative wäre, den ganzen String zu raten und unbrauchbare Scrobbles zu erzeugen. DJ-Mixes laufen als ein einziger Track durch, und Album-Informationen fehlen bei YouTube-Scrobbles ganz, weil sie im Titel-String selten stehen, der Track erscheint bei Last.fm dann ohne Cover. Auch die Lautstärke-Angleichung ist eine Pauschale: Feste zehn Prozent auf alle Streams treffen den Schnitt, ersetzen aber keine echte Per-Track-Normalisierung, weil mpv die Loudness der Quelle hier nicht einzeln misst.