/radio holt den Bot in den Sprachkanal und postet eine Tafel: Auswahlmenue
mit allen Sendern, Stopp, und ein Embed mit dem laufenden Titel, das sich
alle 30 Sekunden selbst nachfuehrt.
Der Titel kommt aus dem Icecast-Strom selbst (Icy-MetaData). Bewusst so und
nicht ueber eine Sender-API: das funktioniert bei jedem Strom, den jemand
eintraegt, und nicht nur bei den drei, die ich kenne. Leere Titel-Bloecke
heissen "unveraendert", deshalb werden bis zu drei gelesen.
Die Tonkette braucht keine Opus-Bibliothek: ffmpeg holt das MP3 und gibt
direkt Ogg/Opus aus, prism-media packt nur noch aus. Gemessen: 600 Pakete in
fuenf Sekunden. Sonst muesste @discordjs/opus mit ins Image, und das will
gebaut werden. Neu im Image ist nur ffmpeg.
44 RauteMusik-Sender sind ab Werk eingetragen — dieselben, die im LS25 und
ETS als Bordradio laufen. Die Liste ist nicht abgeschrieben, sondern
gemessen: jede Adresse einzeln angefragt, der Name kommt aus icy-name.
Doppelgaenger sind raus (deutschrap-charts und wackenradio liefern denselben
Strom wie deutschrap und metal). Eingetragen wird einmal, solange die Liste
leer ist — wer loescht, behaelt es geloescht.
Ein Auswahlmenue fasst nur 25 Eintraege. Bei 44 Sendern haette ein Deckel
die letzten 19 stillschweigend verschluckt; stattdessen mehrere Menues,
benannt nach ihrem ersten und letzten Sender.
Der Bot geht raus, wenn der Kanal leer ist, und kommt nach einem Neustart in
den Kanal zurueck — sonst beendet jeder Deploy die Musik endgueltig.
Kein YouTube. Genau daran sind Groovy und Rythm gestorben, und was davon
uebrig ist, ist ein Dauerlauf gegen kaputte Extraktoren.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Feed eines LS-Servers gibt viel mehr her als die Spielerzahl, die der
Monitor bisher davon benutzt hat: in denselben 49 KB stehen 163 Parzellen mit
Besitzer und Hektar, 130 Felder, jedes Fahrzeug samt Ladung und die Position
jedes Spielers. Und das Luftbild liefert der Server auch, in jeder Groesse bis
4096.
Also eine Karte: gekaufte Parzellen nach Hof eingefaerbt, Kreisflaeche gleich
Hektar, Fahrzeuge und Spieler live, dazu eine Hof-Uebersicht mit Flaeche und
Wert. Wechselt Land den Besitzer, kommt eine Meldung — beim allerersten
Durchlauf bewusst nicht, sonst haette der Botstart eine Meldung pro bereits
gekaufter Parzelle abgesetzt.
Dazu die Preiskurven aus der economy.xml: je Fruchtart, was sie in welcher der
zwoelf Perioden bringt, als Balkenzeile mit "jetzt verkaufen" oder "+43 Prozent
im Hochwinter".
Was NICHT geht, und zwar grundsaetzlich: welche Frucht auf welchem Feld steht
und wie weit sie ist. Das liegt in einer binaeren Density-Map, die kein
Endpunkt herausgibt. Ich habe 18 Dateinamen durchprobiert, es gibt genau drei.
Die Mods, die das anzeigen, sind reine HUD-Overlays ohne Ausgang. Und keiner
der fuenf anderen LS-Bots kann es, obwohl einer davon Geld kostet. Das steht
mit allen Belegen in docs/ls-feed.md, damit die Frage nicht dreimal kommt.
Beim Bauen aufgefallen:
- istLsServer() gab den Zugangs-Code zurueck statt true — die &&-Kette liefert
den letzten wahren Wert. Beim ersten Log-Aufruf haette der Code im Klartext
im Protokoll gestanden.
- Die Karte als PNG war 2,5 MB, als JPEG 268 KB. Es ist ein Luftbild.
- Nach Preisschwankung sortiert gewinnt Spargel: 26 bis 7540 Euro, und Weizen
taucht gar nicht mehr auf. Die Liste arbeitet jetzt mit einer Auswahl.
- Die Jahreszeit steht in keinem Endpunkt. Schaetzbar waere sie, aber nur
solange niemand die Zeitskala aendert — also eine Einstellung.
Geprueft gegen echte Serverdaten: Zerlegen der Statusabfrage inklusive
Vollstaendigkeit aller 163 Parzellen, Ladung ohne Diesel und leere Slots,
Hof-Uebersicht ohne verlorene Parzellen, Preiskurve mit vollem und leerem
Balken an der richtigen Stelle, flache Kurve ohne Division durch Null,
Besitzwechsel inklusive Erstlauf und neu hinzugekommener Parzelle,
Hof-Namen aus der Einstellung, SVG ohne NaN und mit maskierten Namen, und der
Merker in der Datenbank inklusive kaputtem JSON.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Repo-Backups: nachts um 04:00 werden alle Gitea-Repos als git-Bundle
gesichert — eine Datei pro Repo mit kompletter Historie, aus der sich
direkt wieder klonen lässt. 14 Tage Rotation wie beim DB-Backup,
Schalter und "Repos jetzt sichern" im System-Tab. Nutzt den bereits
vorhandenen Gitea-Token; Dockerfile installiert dafür git mit.
- Gitea-Theme im D4RKST3R-Look (docs/gitea-theme/): Neon-Gelb/Orange auf
Schwarz, gebaut gegen die Variablen von Gitea 1.26, Diff-Farben bleiben
lesbar. Einbau-Anleitung liegt daneben.
- Auto-Deploy statt manuellem "Pull and redeploy": Workflow für Gitea
Actions (prüft Server-Syntax und Frontend-Build, bevor deployed wird)
plus dokumentierter Runner-loser Weg über den Portainer-Webhook.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Willkommens-Karten: gerendertes PNG (SVG → sharp) mit Avatar im
Neon-Ring, Willkommens-Schriftzug und Member-Nummer; Fallback aufs
bisherige Embed wenn das Rendering scheitert; Dockerfile installiert
fonts-dejavu-core für die Text-Darstellung
- Geburtstags-System: /geburtstag setzen|entfernen (birthdays-Tabelle),
tägliche Runde ab 09:00 Europe/Berlin (Doppel-Post-Schutz über
last_birthday_run), Gratulations-Embed + Tages-Rolle (wird am
nächsten Morgen wieder abgeräumt); Kanal + Rolle im Community-Tab
- Devlog-Permalinks: /devlogs/:id als eigene Seite (GET /api/devlogs/:id),
Link-Symbol an jeder Karte, Link-kopieren-Button; der Server injiziert
Open-Graph-Tags ins SPA-HTML — Devlog-Links zeigen Titel, Anriss und
Bild, alle anderen Seiten bekommen Default-Tags (auch die Startseite)
- Auto-Publish: maybeCrosspost() veröffentlicht Devlog-, Release-,
Composer- und geplante Posts automatisch in Ankündigungs-Kanälen
- brandEmbed: leere Avatar-URL crasht nicht mehr die Footer-Validierung
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Alpha-Keys: Pool im Community-Tab, Ein-Klick-Verteilung per DM an alle Playtester
(Key bleibt frei, wenn die DM geblockt wird)
- Bewerbungs-Formulare: Builder im neuen Bewerbungen-Tab (bis 5 Fragen),
Button → Discord-Modal → Review-Embed mit ✅/❌, Rolle + DM bei Entscheidung
- Events: GuildScheduledEventCreate → Announce-Embed; öffentliche /events-Seite
aus den Discord-Events (5-min-Cache)
- Server-Stats: activity_daily (Nachrichten/Joins/Leaves) → Balken-Chart auf /level
- Triggers (Auto-Antworten, 30s-Cooldown), /remind (DM-Scheduler),
Twitch-Live (Helix, App-Creds write-only) + YouTube-RSS-Announcements,
Temp-Voice (Join to Create, Cleanup bei Leerstand + Start)
- Brand-Tab: MEE6-Style Bot-Identity-Karte (Avatar-Vorschau mit Status-Dot,
Bot-Name via setUsername, Presence online/idle/dnd, Aktivität)
- Neue Intents: GuildVoiceStates, GuildScheduledEvents; alles smoke-getestet
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- /wunsch: Voting-Embed mit 👍, Reaction-Tracking (add/remove) in SQLite,
Top-20-Rangliste öffentlich auf der Roadmap-Seite
- /giveaway (Admin): Preis/Dauer/Gewinnerzahl, 🎉-Teilnahme-Button (toggle),
Minuten-Scheduler zieht Gewinner, schließt das Embed ab und pingt sie
- Contribution-Heatmap: 52-Wochen-Grid in Brand-Gelb aus dem Commit-Archiv
(/api/heatmap) auf der Roadmap-Seite
- Setting voting_channel_id auf der Setup-Seite
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Modmail: DMs an den Bot landen als Threads im privaten Staff-Kanal,
Thread-Antworten gehen als DM zurück (Zustell-Feedback per Reaktion)
- Willkommens-Embed für neue Member (GuildMemberAdd; Server-Members-Intent nötig)
- Mod-Log: gelöschte/bearbeitete User-Nachrichten in privaten Log-Kanal
- Server-Monitor: FiveM-kompatible Endpoints (/dynamic.json) alle 2 min,
persistentes Status-Embed (edit in place) + Spielerzahl als Bot-Presence
- Neue Intents: DirectMessages, GuildMembers; Partials.Channel
- Setup-Seite: Sektionen // Moderation & Kontakt und // Game-Server
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- SQLite-Online-Backup (WAL-sicher) täglich 03:00 → data/backups/*.db.gz, 14 Tage Rotation
- Optional Offsite-Kopie als Upload in einen privaten Discord-Kanal (Setting)
- Setup-Seite: Toggle, Upload-Kanal, 'Backup jetzt'-Button; letztes Backup im Status-Panel
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- /bug (alle Member): erstellt Gitea-Issue inkl. Screenshot-Upload als Asset;
bug_reports-Tabelle für den Rückkanal — Issue geschlossen (issues-Webhook)
→ DM an den Reporter
- Auto-Thread '💬 Devlog <Datum>' unter jedem Devlog-Post (Setting, Default an)
- Watchdog: prüft Setting watchdog_urls alle 2 min, DM an Admin nach 2 Fails
in Folge + Entwarnung mit Downtime-Dauer
- Setup-Seite: Bug-Repo, Threads-Toggle, Watchdog-URLs; Env GITEA_API_TOKEN/GITEA_URL
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Scheduler (5-Minuten-Check, dedupe über last_weekly_recap-Setting)
- Embed: Commits pro Tag als Balken-Grafik, Commit-/Devlog-Zahlen, Top-Projekte
- Setting weekly_recap_enabled + 'Rückblick jetzt testen'-Button auf der Setup-Seite
- TZ Europe/Berlin im Compose (Scheduler + Datumsformate)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Fastify-Webserver mit /health und /webhooks/gitea (HMAC-SHA256-Signaturprüfung, timing-safe)
- Push-Commits werden in SQLite gespeichert (Dedupe per SHA) und als Embed gepostet
- Dockerfile auf node:22-slim (glibc-Prebuilds für better-sqlite3), Port 3080 published
- README: Anleitung für Cloudflare-DNS, Nginx Proxy Manager (bot.d4rkst3r.de) und Gitea-Webhook
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- discord.js v14 Bot mit Slash-Command-Registry (Guild oder global)
- Konfiguration über .env mit Validierung (config.js)
- Dockerfile + docker-compose.yml für Portainer-Deployment
- README mit Schritt-für-Schritt-Anleitung (Discord Developer Portal)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>