Files
d4rkbot/Dockerfile
D4rkst3r af16bc1b18 YouTube als zweite Tonquelle: yt-dlp, Warteschlange, Abbild
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.
2026-08-28 13:26:05 +02:00

67 lines
2.9 KiB
Docker

# EcoBot — Discord-Bot + Webinterface
# Stage 1: React-Frontend bauen
FROM node:22-slim AS frontend
WORKDIR /build
COPY frontend/package.json frontend/package-lock.json ./
RUN npm ci
COPY frontend ./
RUN npm run build
# Stage 2: Runtime (slim statt alpine: better-sqlite3 liefert glibc-Prebuilds)
FROM node:22-slim
# Fonts für die Willkommens-Karten (sharp/librsvg braucht installierte Schriften),
# git für die Repo-Backups (git clone --mirror + bundle),
# ffmpeg fürs Radio: es holt den Strom und gibt rohe Abtastwerte (PCM) aus, an
# denen die Sprachbibliothek die Lautstärke regelt, bevor sie nach Opus packt.
# Bis zur Lautstärkeregelung lief hier Ogg/Opus unverändert durch — an fertigen
# Opus-Paketen lässt sich die Lautstärke nicht drehen.
RUN apt-get update && apt-get install -y --no-install-recommends fonts-dejavu-core git ffmpeg \
&& rm -rf /var/lib/apt/lists/*
# yt-dlp fürs YouTube-Einreihen im Radio.
#
# Die eigenständige Binärdatei statt `pip install`: sie bringt ihr eigenes
# Python mit, also kein python3-pip im Abbild und kein Compiler. `yt-dlp_linux`
# verlangt glibc 2.17+, node:22-slim (bookworm) hat 2.36.
#
# Bewusst die *jeweils neueste* Fassung und keine feste: YouTube ändert seine
# Sperren schneller, als hier jemand eine Versionsnummer nachzieht, und ein
# veraltetes yt-dlp ist die häufigste Ursache für „geht plötzlich nicht mehr".
# Damit hängt der Bau an GitHub — dieselbe Abhängigkeit, die `apt-get` und
# `npm ci` schon haben.
#
# Der `--version`-Aufruf am Ende ist kein Beiwerk: ohne ihn fällt ein kaputter
# Download erst im Betrieb auf, als stiller Sprachkanal statt als Baufehler.
ADD https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_linux /usr/local/bin/yt-dlp
RUN chmod 0755 /usr/local/bin/yt-dlp && /usr/local/bin/yt-dlp --version
WORKDIR /app
# Erst nur Manifest kopieren → Docker-Layer-Cache für npm ci
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY src ./src
# Die Prüfwerkzeuge müssen dort laufen, wo der Fehler auftritt — im Container.
# Ohne diese Zeile lief `docker exec … node tools/udp-pruefen.mjs` ins Leere,
# obwohl genau das im Kopf des Skripts steht.
COPY tools ./tools
COPY --from=frontend /build/dist ./frontend/dist
# Laufzeitdaten (SQLite) landen in /app/data → Volume
RUN mkdir -p /app/data
ENV NODE_ENV=production
# Ohne diese Zeile weiss Docker nur, DASS der Prozess laeuft — nicht, ob der
# Bot noch mit Discord verbunden ist. Genau das beantwortet /health.
#
# `curl` und `wget` fehlen im slim-Abbild (nachgemessen), also Node selbst.
# Die Schonfrist ist grosszuegig: der Anmeldevorgang bei Discord dauert, und
# ein Neustart soll nicht als Ausfall gelten.
HEALTHCHECK --interval=30s --timeout=5s --start-period=45s --retries=3 \
CMD node -e "fetch('http://127.0.0.1:'+(process.env.HTTP_PORT||3080)+'/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
CMD ["node", "src/index.js"]