Wie das System funktioniert
Das System ist bewusst einfach gehalten — kein n8n, kein komplexes Workflow-System.
Ein Python-Script, ein Cron-Job, eine SQLite-Datenbank. Läuft auf Server3 unter
/opt/docker/release-tracker/ als User homelab-user.
Der entscheidende Trick: YouTube bietet für jeden Kanal einen öffentlichen RSS-Feed — keine API-Keys, kein Quota, keine Authentifizierung. Einfach pollen, parsen, fertig.
Cron — täglich 08:00 + 20:00 │ ▼ RSS-Fetcher YouTube Feeds für alle 5 Kanäle abrufen URL: https://www.youtube.com/feeds/videos.xml?channel_id=UC... │ ▼ Title-Parser Regex-Patterns pro Kanal "Artist - Album (Year) [Label]" → artist, album "Artist : Album" → Only Black Metal (Sonderfall) │ ▼ SQLite-Check Video schon bekannt? → überspringen Neu → weiter │ ▼ Spotify-Suche (rapidfuzz fuzzy matching) Treffer ≥ Threshold → Track zur Jahres-Playlist hinzufügen Kein Treffer → Status "pending" — täglicher Retry Parse-Fehler → Status "skipped" │ ▼ SQLite-Update + HA-Notification (noch offen)
Überwachte YouTube-Kanäle
Channel-ID herausfinden über https://commentpicker.com/youtube-channel-id.php
oder direkt aus dem RSS-Feed:
https://www.youtube.com/feeds/videos.xml?channel_id=UCxxxxx.
Dann einfach einen neuen Block in channels.yaml kopieren und anpassen —
kein Code-Änderung nötig, kein Neustart des Systems.
Setup auf Server3
/opt/docker/release-tracker/ ├── .env ← Spotify Credentials + Refresh Token ├── channels.yaml ← Kanal-Konfiguration + Regex-Patterns ├── tracker.py ← Hauptscript ├── auth_setup.py ← Einmaliges OAuth-Setup ├── requirements.txt ├── data/ │ └── releases.db ← SQLite-Datenbank └── logs/ └── tracker.log ← Tägliche Logs
pip install feedparser requests rapidfuzz python-dotenv pyyaml
SPOTIFY_CLIENT_ID=deine_client_id_hier SPOTIFY_CLIENT_SECRET=dein_secret_hier SPOTIFY_REDIRECT_URI=http://127.0.0.1:8080/callback # SPOTIFY_REFRESH_TOKEN wird von auth_setup.py automatisch eingetragen # HA_URL=http://homeassistant.local:8123 (noch offen) # HA_TOKEN=... (noch offen)
auth_setup.py generiert die Auth-URL. Diese im Browser öffnen,
Spotify-Login durchführen, dann die Callback-URL manuell ins Terminal einfügen.
Der Refresh Token landet automatisch in der .env.
cd /opt/docker/release-tracker python3 auth_setup.py # URL im Browser öffnen → einloggen → Callback-URL einfügen # → SPOTIFY_REFRESH_TOKEN wird in .env geschrieben
homelab-user täglich um 08:00 und 20:00.# Metal Release Tracker — 2× täglich
0 8,20 * * * cd /opt/docker/release-tracker && python3 tracker.py >> logs/cron.log 2>&1
Das Verzeichnis und die .env-Datei müssen dem User homelab-user gehören.
Nach sudo-Operationen prüfen: sudo chown -R homelab-user:homelab-user /opt/docker/release-tracker.
WinSCP zeigt versteckte Dateien (wie .env) erst nach Strg+Alt+H.
Spotify Developer App anlegen & OAuth einrichten
Um die Spotify API nutzen zu können braucht man eine eigene Developer App im Spotify Developer Dashboard. Das klingt komplizierter als es ist — ein normaler Spotify-Account reicht, kein Premium nötig, und die App bleibt kostenlos solange man sie nur für sich selbst nutzt.
— App name: beliebig, z.B.
release-tracker
— App description: kurze Beschreibung, z.B. "Metal Release Tracker"
— Redirect URI:
http://127.0.0.1:8080/callback eintragen und Add klicken
— APIs used: "Web API" anhaken
Dann Save.
.env-Datei auf dem Server eintragen.
Das Secret niemals in Git einchecken oder öffentlich teilen.
auth_setup.py einen manuellen Flow:
Script generiert eine Auth-URL → diese im lokalen Browser öffnen →
Spotify-Login → nach dem Redirect die komplette URL aus der Browserzeile
kopieren und ins Terminal einfügen. Der Refresh Token wird automatisch
in die .env geschrieben.
cd /opt/docker/release-tracker python3 auth_setup.py # Ausgabe: "Öffne diese URL im Browser:" # https://accounts.spotify.com/authorize?client_id=...&scope=... # # Nach dem Login im Browser: komplette Redirect-URL kopieren # z.B. http://127.0.0.1:8080/callback?code=AQD...&state=... # → ins Terminal einfügen → Enter # # SPOTIFY_REFRESH_TOKEN wird automatisch in .env geschrieben ✓
cd /opt/docker/release-tracker python3 tracker.py # Ausgabe: "Playlist 'Kanalname 2026' angelegt: spotify:playlist:..." # Ausgabe: "X neue Releases verarbeitet, Y gematcht, Z pending"
Wer bereits eine Spotify Developer App hat (z.B. für Home Assistant),
kann diese weiterverwenden. Einfach unter Edit Settings die
Redirect URI http://127.0.0.1:8080/callback als weitere URI hinzufügen —
bestehende URIs bleiben dabei erhalten.
Der Refresh Token muss nur einmal generiert werden. Er ist zeitlich unbegrenzt gültig solange er nicht manuell im Developer Dashboard widerrufen wird. Access Tokens (kurzlebig, 1 Stunde) erneuert das Script automatisch bei jedem Lauf. Jahres-Playlists werden automatisch angelegt sobald das erste Release des neuen Jahres auftaucht — kein manueller Eingriff zum Jahreswechsel nötig.
Kanal-Konfiguration & Regex-Patterns
Jeder Kanal hat eigene Regex-Patterns weil die Titel-Formate variieren.
Das wichtigste Sonderzeichen: bei Only Black Metal
wird : als Separator verwendet statt - .
Das Regex verwendet deshalb [:\-–] als Character Class —
in YAML in einfache Anführungszeichen einschließen um den Doppelpunkt
nicht als YAML-Syntax zu interpretieren.
channels: - name: "Black Metal Promotion" channel_id: "UCzCWehBejA23yEz3zp7jlcg" handle: "@bmpromotion" priority: true title_patterns: # Pattern 1: Artist - Album (Year) [Label] - '^(?P<artist>.+?)\s*[-–]\s*(?P<album>.+?)\s*[\(\[]' # Pattern 2: Fallback — Artist - Album - '^(?P<artist>.+?)\s*[-–]\s*(?P<album>.+?)$' - name: "Only Black Metal" channel_id: "UCLUzzvPKB8YFuBc4QFHIriw" handle: "@onlyblackmetal" priority: false title_patterns: # Sonderfall: Separator ist " : " — in einfache Quotes! - '^(?P<artist>.+?)\s*[:\-–]\s*(?P<album>.+?)\s*[\(\[]' - '^(?P<artist>.+?)\s*[:\-–]\s*(?P<album>.+?)$'
Regex-Patterns mit : müssen in einfache Anführungszeichen
('...') eingeschlossen werden — nicht doppelte. YAML interpretiert
sonst den Doppelpunkt als Key-Value-Trenner und der YAML-Parser wirft einen Fehler.
Das war ein echter Fallstrick beim Setup von Only Black Metal.
SQLite — direkte Abfragen für Wartung
# DB öffnen sqlite3 /opt/docker/release-tracker/data/releases.db -- Alle pending Releases anzeigen SELECT channel, artist, album, published FROM releases WHERE status = 'pending' ORDER BY published DESC; -- Statistik pro Kanal SELECT channel, status, COUNT(*) as n FROM releases GROUP BY channel, status; -- Release manuell auf "new" zurücksetzen (z.B. nach Playlist-Duplikat) UPDATE releases SET status = 'new' WHERE channel = 'Black Metal Promotion' AND status = 'matched'; -- Playlist-Eintrag löschen (bei Duplikat — Script legt neu an) DELETE FROM playlists WHERE channel = 'Black Metal Promotion' AND year = 2026; -- Letzten Lauf prüfen SELECT MAX(last_checked) FROM releases;
Logs, Updates, Kanal hinzufügen
# Live-Log tail -f /opt/docker/release-tracker/logs/tracker.log # Script manuell ausführen (außerhalb Cron) cd /opt/docker/release-tracker && python3 tracker.py # Cron-Log prüfen tail -50 /opt/docker/release-tracker/logs/cron.log
Einfach einen neuen Block in channels.yaml einfügen —
Channel-ID aus dem RSS-Feed-URL oder via commentpicker.com.
Beim nächsten Lauf (oder manuell) erkennt das Script den neuen Kanal,
legt die Jahres-Playlist an und beginnt mit dem Tracking.
Kein Neustart, kein Code-Änderung nötig.
Was noch fehlt
HA_URL und
HA_TOKEN als Umgebungsvariablen in der .env.
Fehlt noch: der Long-Lived Access Token aus Home Assistant
(Profil → Langlebige Zugriffstoken → Token erstellen) und das Eintragen
in die .env.
channels.yaml,
da manche Kanäle konsistentere Titelnamen haben als andere.
labstuff.tibbers.de/tracker laufen
oder als kleines FastAPI-Backend auf Server3.
Was schiefgehen kann
channels.yaml enthält einen Doppelpunkt (:)
ohne einfache Anführungszeichen. YAML interpretiert den Doppelpunkt als Key-Value-Trenner.
Fix: alle Patterns mit : in einfache Quotes einschließen: '...'.
root statt homelab-user. Passiert wenn
Dateien mit sudo erstellt wurden.
Fix: sudo chown -R homelab-user:homelab-user /opt/docker/release-tracker.
playlists-Tabelle einen veralteten Eintrag enthält.
Fix: Eintrag aus der Tabelle löschen und alle zugehörigen Releases auf
status = 'new' zurücksetzen. Beim nächsten Lauf legt das Script
die Playlist neu an und befüllt sie vollständig.
:
nicht im Pattern berücksichtigt ist. In channels.yaml beim
Only Black Metal Kanal den Character Class auf [:\-–] erweitern
(in einfache Anführungszeichen). Dann betroffene Releases auf
status = 'new' setzen und erneut laufen lassen.
auth_setup.py erneut ausführen, neuen Token generieren und
in die .env schreiben.