diff --git a/.env.example b/.env.example index 4bee08b..9f6659c 100644 --- a/.env.example +++ b/.env.example @@ -62,3 +62,13 @@ GITEA_API_TOKEN= # Optional: Pfad zur SQLite-Datei (Default: ./data/ecobot.db) # DB_PATH=./data/ecobot.db + +# Optional: Pfade zu ffmpeg und yt-dlp fuers Radio (Default: im PATH suchen). +# Beide stecken im Docker-Abbild und muessen dort nicht gesetzt werden. Lokal +# ohne Docker ist das der Ort, an dem man sie bekannt macht. +# +# Zum Pruefen der Fehlerwege taugt ein Pfad, der nicht abspielt: +# YTDLP_PATH=/bin/false laesst die Radiosender weiterlaufen und muss im Panel +# als "yt-dlp fehlt" erscheinen -- nicht als Stille im Sprachkanal. +# FFMPEG_PATH=ffmpeg +# YTDLP_PATH=yt-dlp diff --git a/README.md b/README.md index 676e745..d925867 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,8 @@ auf nichts mehr: keine Posts, keine Hintergrund-Prüfungen. | 📸 **Screenshot-Galerie** | Bilder aus dem Screenshot-Kanal → öffentliche Galerie (lokal gespeichert, weil Discord-CDN-Links ablaufen) | | 💡 **Feature-Voting** | `/wunsch-setup` postet den Ideen-Aufruf: Bereich wählen, Formular ausfüllen → Voting-Post mit 👍 und **Thread zum Reden**. Wünsche haben einen **Stand** (wird geprüft · geplant · in Arbeit · umgesetzt · nicht geplant) samt Begründung — auf der Roadmap und im Discord-Post. Wer gestimmt hat, bekommt eine DM, sobald es umgesetzt ist. Die Roadmap filtert nach Stand und Bereich, sortiert nach Top / Bewegung / Neu und zeigt die Zahl der Beiträge im Thread. Ein Klick öffnet die **eigene Seite der Idee** mit der Unterhaltung aus dem Discord-Thread — gespiegelt samt Screenshots, geschrieben wird weiter dort. Fehlende Forum-Tags legt das Panel auf Knopfdruck an. Ist der Voting-Kanal ein **Forum**, wird jeder Wunsch ein Forums-Beitrag mit **Tags** für Bereich und Stand — der Stand zieht beim Ändern automatisch mit. Eine Stimme je Person, egal ob 👍 oder Web-Knopf; Doppler lassen sich zusammenführen | | 🗳️ **Umfragen** | `/umfrage` erzeugt eine **native Discord-Poll** — keine Reaktions-Bastelei, Discord zählt selbst | -| 📻 **Radio** | `/radio` holt den Bot in deinen Sprachkanal und öffnet eine Tafel mit Sender-Auswahl zum Durchschalten; der laufende Titel steht im Embed und aktualisiert sich selbst. **44 RauteMusik-Sender** sind ab Werk eingetragen — dieselben, die im LS25 und ETS als Bordradio laufen —, eigene lassen sich im Panel ergänzen. Der Bot geht von selbst wieder raus, wenn der Kanal leer ist, und kommt nach einem Neustart zurück. Bewusst **kein YouTube**: daran sind Groovy und Rythm gestorben | +| 📻 **Radio** | `/radio` holt den Bot in deinen Sprachkanal und öffnet eine Tafel mit Sender-Auswahl zum Durchschalten; der laufende Titel steht im Embed und aktualisiert sich selbst. **44 RauteMusik-Sender** sind ab Werk eingetragen — dieselben, die im LS25 und ETS als Bordradio laufen —, eigene lassen sich im Panel ergänzen. Der Bot geht von selbst wieder raus, wenn der Kanal leer ist, und kommt nach einem Neustart zurück | +| ▶️ **YouTube** | `/musik` öffnet eine zweite Tafel: Link oder Suchbegriff einreihen, Warteschlange umsortieren, überspringen. Ist die Liste leer, kommt der Sender zurück, der vorher lief — das Radio ist die Grundstellung, YouTube die Unterbrechung. Steuern lässt sich alles auch **komplett im Panel** unter *Community → Radio*, inklusive Live-Ansicht. Braucht `yt-dlp` auf dem Server (steckt im Image). ⚠️ YouTube sperrt Server-Adressen inzwischen häufig — dagegen gibt es im Panel ein Feld für eine `cookies.txt` und eines für eigene yt-dlp-Argumente, beides ohne neues Image. Schlägt es fehl, steht der Grund im Klartext im Panel und in der Tafel, statt als Stille im Sprachkanal | | 🎉 **Giveaways** | `/giveaway` (Admin): Teilnahme-Button, automatische Ziehung; am Gewinner-Post 🔁 Neu auslosen + 👥 Teilnehmerliste | | 🎂 **Geburtstage** | `/geburtstag` zum Eintragen; morgens Gratulation im Kanal + Tages-Rolle | | 📅 **Events** | Neue Discord-Events werden angekündigt + öffentliche Events-Seite | diff --git a/src/bot/radio.js b/src/bot/radio.js index 358db18..6fd63ff 100644 --- a/src/bot/radio.js +++ b/src/bot/radio.js @@ -51,7 +51,7 @@ import { import { moduleEnabled } from '../modules.js'; import { listStations, getStation, radioState, radioStates, setRadioState, clearRadioState, setSetting, - queueNext, + queueNext, queueAdd, queueVor, } from '../db.js'; import { senderGrundstock } from './radio-sender.js'; import { tonstrom, ytdlpPruefen, ytdlpVorhanden } from './youtube.js'; @@ -801,13 +801,27 @@ export async function weiter(client, guildId, { erzwungen = false, kanalId: star return null; } - await spielen(kanal, quelle); + try { + await spielen(kanal, quelle); + } catch (error) { + // Der Eintrag ist oben schon aus der Liste geholt worden. Kommt + // die Sprachverbindung nicht zustande, waere er damit weg — + // jemand reiht etwas ein, der Beitritt scheitert an einem Recht, + // und der Wunsch ist verschwunden. Also zurück an dieselbe + // Stelle: anhängen und nach vorn holen. + if (naechster) { + const neu = queueAdd(guildId, naechster); + queueVor(guildId, neu); + } + throw error; + } + const tafel = radioState(guildId); setRadioState({ guildId, channelId: kanalId, stationId: laufend.get(guildId)?.heimStationId ?? null, - panelChannelId: radioState(guildId)?.panel_channel_id, - panelMessageId: radioState(guildId)?.panel_message_id, + panelChannelId: tafel?.panel_channel_id, + panelMessageId: tafel?.panel_message_id, }); // Beim Rückfall auf den Sender steht sonst noch der letzte Liedtitel // in der Statuszeile und behauptet, er liefe.