Radio youtube #2

Merged
D4rkst3r merged 6 commits from radio-youtube into main 2026-08-28 14:02:24 +02:00
Owner
No description provided.
D4rkst3r added 6 commits 2026-08-28 14:02:11 +02:00
Das Fundament, noch ohne Anbindung ans Radio.

yt-dlp holt selbst und schiebt rohe Bytes durch ein Rohr an ffmpeg. Der
bequemere Weg waere `-g` und die fertige Adresse -- der ist eine Falle:
googlevideo-Adressen laufen ab und haengen an der IP, die sie geholt hat.
Das schlaegt nach zehn Minuten zu und sieht dann aus wie ein Netzproblem.

Beim Stroemen nach stdout ist die Vorgabe von yt-dlp *mit* Bild; ohne ein
ausdrueckliches `-f bestaudio/best` laedt ein Tonstrom das ganze Video.
Nachgelesen im README der Fassung 2026.08.19.

stderr wird aufgehoben statt weggeworfen. Genau hier entsteht sonst der
Fehler, den niemand deuten kann: YouTube antwortet "Sign in to confirm",
yt-dlp bricht ab, der Bot sitzt still im Kanal. Die letzte ERROR-Zeile
geht ins Panel.

Gemessen am 28.08.2026 gegen echtes YouTube (yt-dlp 2026.08.19, von hier
aus, NICHT auf dem Zielhost): Einzelvideo, Suche und flache Playlist
liefern die erwarteten Felder, eine kaputte Video-ID meldet "Video
unavailable" und wird als Fehler durchgereicht statt als leere Liste.

Die Warteschlange steht in der Datenbank, nicht nur im Speicher -- ein
Deploy soll die Musik unterbrechen, nicht die Wuensche von fuenf Leuten
wegwerfen. Die YouTube-Tafel bekommt eine eigene Tabelle, weil
`radio_state` beim Stoppen geloescht wird und die Tafel das ueberleben
soll.

Nebenbei: der ffmpeg-Kommentar im Dockerfile beschrieb noch die alte
Ogg/Opus-Kette. Seit der Lautstaerkeregelung laeuft dort PCM.
Der ganze Unterschied ist einer: ein Sender endet nie, ein Titel schon.
Also verzweigt genau eine Abspielfunktion und genau ein Idle-Melder nach
der Art der Quelle, statt dass ein zweiter Pfad daneben entsteht -- zwei
Pfade, die dasselbe tun sollen, driften auseinander.

Beim Sender heisst Idle "die Leitung ist weg" (neu aufbauen), bei YouTube
"fertig, der naechste bitte". Danach: Warteschlange, sonst der Sender von
vorher, sonst raus. Das Radio ist die Grundstellung, YouTube die
Unterbrechung.

Bremse gegen das Durchrutschen: ein Eintrag ohne Ton geht sofort wieder
auf Idle. Ohne Zaehlung waere eine Liste mit einem kaputten Eintrag in
Sekundenbruchteilen leer, und niemand haette gesehen warum. Nach drei
Fehlschlaegen in Folge wird angehalten und der Grund gemeldet. Von Hand
Uebersprungenes zaehlt nicht mit.

Zwei Fehler nebenbei, beide vorher schon da:

Der Idle-Melder hielt `kanal` aus dem Abschluss des ERSTEN Aufrufs fest.
Nach einem Kanalwechsel haette der Wiederanlauf in den alten Kanal
gespielt. Er liest den Kanal jetzt frisch aus `laufend`.

`radioLautstaerke()` gab bei unbelegter Einstellung 10 zurueck statt der
50, die der Kommentar zwei Zeilen darueber als Vorgabe begruendet:
`Number(null)` ist 0 und damit endlich, die Pruefung auf "nicht endlich"
hat den unbelegten Fall nie erwischt und auf die Untergrenze geklemmt.
Eine frische Installation startete also sehr leise. Gemessen gegen eine
leere Datenbank, mit Gegenproben fuer leeren String, Unsinn, 0 und 999.
Eine eigene Nachricht statt ein paar Knoepfe mehr an der Radio-Tafel.
Discord laesst fuenf Reihen je Nachricht zu, vier davon gehoeren dort den
Sender-Menues -- fuer Ueberspringen, Einreihen, Warteschlange und Leeren
ist kein Platz, und ein Sender-Menue zu opfern hiesse, Sender aus der
Auswahl zu werfen.

Der Vorzug ist groesser als die Notloesung: /radio bleibt genau das, was
es war. Wer nie ein Video einreiht, merkt vom ganzen Umbau nichts.

Bei einem Suchbegriff wird bewusst nicht der erste Treffer genommen,
sondern die Auswahl gezeigt: "Sleeping Sun" hat drei Fassungen, und
welche gemeint war, weiss nur wer es getippt hat. Eine Adresse geht
direkt rein, eine Playlist mit allen Eintraegen auf einmal.

Die Abhaengigkeit zeigt nur in eine Richtung: radio-musik.js kennt das
Radio, das Radio kennt es nicht -- es meldet ueber beiAenderung() nur,
dass sich etwas geaendert hat. Ein gegenseitiger Import zwischen zwei
Dateien beisst beim naechsten Umbau.

Gemessen gegen echtes YouTube am 28.08.2026: Adresse landet in der Liste,
Suchbegriff liefert fuenf Treffer und reiht NICHTS ein (Liste nachweislich
unveraendert), kaputte Adresse meldet "Video unavailable" und laesst die
Liste in Ruhe. Die Tafel zeigt Dauer je Titel, Gesamtdauer, Wunschgeber
und die letzte Fehlerzeile im Klartext.

Nicht geprueft, weil es dafuer eine echte Discord-Sprachverbindung
braucht: die Darstellung waehrend etwas laeuft, und das Weiterschalten.
Neun Endpunkte unter /api/radio: Stand, Steuern, Warteschlange (einreihen,
entfernen, leeren, sortieren), Suche und der yt-dlp-Block.

Alles geht durch dieselben Funktionen wie die Discord-Tafeln. Eine zweite
Abspiellogik neben radio.js waere eine zweite Gelegenheit, sich anders zu
verhalten als die erste.

Start, Stopp, Skip, Sender und Lautstaerke liegen als Aktionen auf einem
Endpunkt statt auf fuenf: alle brauchen dieselbe Server-Aufloesung,
dieselbe Rechtepruefung und antworten mit demselben Stand. Fuenf Geruest-
Kopien waeren fuenf Gelegenheiten, eine davon zu vergessen.

Ein Suchbegriff wird auch hier nicht geraten -- die Treffer gehen zurueck,
gewaehlt wird im Panel. Genau wie in Discord.

Die cookies.txt bekommt einen eigenen Endpunkt statt eines Feldes in den
Einstellungen: der Inhalt ist mehrzeilig und enthaelt Sitzungsschluessel
eines echten Kontos. Er gehoert in eine Datei mit 0600 neben die Datenbank,
und zurueck kommt nie der Inhalt, nur Groesse und Datum. Nur der Owner
darf ihn setzen, nicht das Team.

listVoiceChannels() prueft die Rechte mit: ein Kanal, den das Panel
anbietet und in den der Bot dann nicht darf, sieht aus wie ein kaputter
Knopf.

Beim Schreiben aufgefallen und behoben: radioState() wurde benutzt, aber
nicht importiert -- das haette beim ersten Senderwechsel aus dem Panel
geknallt. Der Syntaxcheck sieht so etwas nicht, das Laden des Moduls schon.

Geprueft mit echtem Fastify, signiertem Sitzungs-Cookie und gefaelschtem
Discord-Client: 24 Faelle, davon acht Gegenproben, die fehlschlagen
muessen (ohne Anmeldung 401, unbekannte Aktion, Sender ohne ID, Skip ohne
Kanal, leere Eingabe, kaputte Adresse, Sortieren ohne Angabe, Cookies ohne
Netscape-Kennzeile). Alle 24 wie erwartet.
Was laeuft, wo, aus welcher Quelle, mit Fortschrittsbalken. Sprachkanal
waehlen, Sender abspielen, Ueberspringen, Zum Radio, Stopp,
Lautstaerke-Schieber. Einreihen per Link oder Suchbegriff, Warteschlange
mit Hoch/Runter/Weg und Leeren. Darunter ein aufklappbarer yt-dlp-Block:
Zustand, Fassung, cookies.txt, eigene Argumente, Aktualisieren -- und die
letzte Fehlerzeile im Klartext.

Steht ueber der Senderliste, weil man oefter etwas abspielt als die Liste
pflegt.

Die Abfrage laeuft nur, solange der Community-Reiter offen ist. Sonst
ginge alle fuenf Sekunden eine Anfrage gegen eine Ansicht raus, die
niemand ansieht.

Der Balken erscheint nur bei bekannter Dauer. Bei einem Livestream gaebe
er einen Stand vor, den niemand kennt -- dort steht stattdessen "live".

Die Kanalauswahl graut aus, wo der Bot nicht rein darf. Ein Kanal, den das
Panel anbietet und in den der Bot dann nicht kommt, sieht aus wie ein
kaputter Knopf.

Geprueft: der Vite-Build laeuft durch, und ein Abgleich stellt alle 30
Feldpfade, die die Oberflaeche vom Stand liest, gegen die echte
API-Antwort -- 0 fehlen. Der Abgleich hat eine Gegenprobe mit bekanntem
Ausgang (ein Feld, das es nicht gibt, muss als fehlend erkannt werden) und
prueft vorher, ob die sonst leeren Zweige (Warteschlange, Cookies, letzter
Fehler) ueberhaupt besetzt sind -- sonst meldet er "ungueltig" statt "in
Ordnung". Seine erste Fassung hatte Fehlalarm geschlagen (?. und .map als
fehlende Felder gelesen); das ist behoben.

NICHT geprueft: das tatsaechliche Rendern im Browser -- hier ist weder
Browser noch DOM-Werkzeug vorhanden.
Der README behauptete an prominenter Stelle "bewusst kein YouTube".
Das stimmt seit vier Commits nicht mehr, und ein Satz, der das Gegenteil
des Codes sagt, wird geglaubt. Ersetzt samt der PO-Token-Lage und dem
Hinweis auf Cookies und eigene Argumente.

.env.example kennt jetzt FFMPEG_PATH und YTDLP_PATH -- mit dem Hinweis,
dass YTDLP_PATH=/bin/false der Weg ist, den Fehlerpfad zu pruefen.

Beim letzten Durchlesen aufgefallen: `weiter()` holt den naechsten Titel
aus der Liste, BEVOR `spielen()` laeuft. Scheitert der Beitritt in den
Sprachkanal -- fehlendes Recht, voller Kanal, DAVE --, war der Eintrag
weg. Genau im haeufigsten Fall: jemand reiht etwas ein, waehrend der Bot
noch gar nicht im Kanal sitzt, der erste Beitritt ist der, der scheitern
kann, und der Wunsch verschwindet wortlos.

Jetzt wird er wieder ganz vorn eingereiht und der Fehler weitergereicht.
Gegenprobe mit einem Kanal, dessen Beitritt garantiert wirft: drei Titel
vorher, drei Titel nachher, "Erster" wieder an erster Stelle.
D4rkst3r merged commit c46581a548 into main 2026-08-28 14:02:24 +02:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: D4rkst3r/d4rkbot#2