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.
90 lines
3.1 KiB
JavaScript
90 lines
3.1 KiB
JavaScript
// Einstiegspunkt — startet Discord-Bot, Webserver und den Wochen-Rückblick-Scheduler
|
|
import { startBot } from './bot/client.js';
|
|
import { startWebServer } from './web/server.js';
|
|
import { scheduleWeeklyRecap } from './bot/weekly-recap.js';
|
|
import { startWatchdog } from './bot/watchdog.js';
|
|
import { scheduleBackups } from './backup.js';
|
|
import { startServerMonitor } from './bot/server-monitor.js';
|
|
import { startLsFarm } from './bot/ls-farm.js';
|
|
import { startRadio, radioBeenden } from './bot/radio.js';
|
|
import { startMusik } from './bot/radio-musik.js';
|
|
import { startGiveaways } from './bot/giveaways.js';
|
|
import { startScheduledPosts } from './web/scheduled-posts.js';
|
|
import { startSocialNotify } from './bot/social-notify.js';
|
|
import { startBirthdays } from './bot/birthdays.js';
|
|
import { scheduleRepoBackups } from './repo-backup.js';
|
|
|
|
process.on('unhandledRejection', (error) => {
|
|
console.error('[main] Unhandled Rejection:', error);
|
|
});
|
|
|
|
let client = null;
|
|
let app = null;
|
|
|
|
/**
|
|
* Geordnet herunterfahren.
|
|
*
|
|
* Ohne das räumt `docker stop` den Prozess nach der Schonfrist einfach ab.
|
|
* Zwei Dinge geben dann falsche Auskunft: der Bot steht in Discord noch eine
|
|
* Weile als online, und die Statuszeile am Sprachkanal behauptet weiter, es
|
|
* liefe Musik. Beides überlebt den Container, der es geschrieben hat.
|
|
*
|
|
* Reihenfolge ist wichtig: erst das Radio, denn zum Abräumen der Statuszeile
|
|
* braucht es die Verbindung zu Discord noch.
|
|
*/
|
|
let laeuftAus = false;
|
|
async function beenden(signal) {
|
|
if (laeuftAus) return; // zweites SIGTERM nicht doppelt abarbeiten
|
|
laeuftAus = true;
|
|
console.log(`[main] ${signal} — fahre herunter`);
|
|
|
|
// Docker wartet vorgabemässig zehn Sekunden und schiesst dann. Lieber
|
|
// vorher selbst aufhören, als mitten im Aufräumen abgeschossen zu werden.
|
|
const frist = setTimeout(() => {
|
|
console.error('[main] Herunterfahren dauert zu lange — breche ab');
|
|
process.exit(1);
|
|
}, 8000);
|
|
frist.unref?.();
|
|
|
|
for (const [was, tun] of [
|
|
['Radio', () => radioBeenden()],
|
|
['Webserver', () => app?.close()],
|
|
['Discord', () => client?.destroy()],
|
|
]) {
|
|
try {
|
|
await tun();
|
|
} catch (error) {
|
|
// Ein Fehler beim Aufräumen darf das restliche Aufräumen nicht
|
|
// verhindern — sonst bleibt wegen der Statuszeile der Bot online.
|
|
console.error(`[main] ${was} beim Herunterfahren:`, error.message);
|
|
}
|
|
}
|
|
|
|
clearTimeout(frist);
|
|
console.log('[main] beendet');
|
|
process.exit(0);
|
|
}
|
|
|
|
process.on('SIGTERM', () => beenden('SIGTERM'));
|
|
process.on('SIGINT', () => beenden('SIGINT'));
|
|
|
|
try {
|
|
client = await startBot();
|
|
app = await startWebServer(client);
|
|
scheduleWeeklyRecap(client);
|
|
startWatchdog(client);
|
|
scheduleBackups(client);
|
|
startServerMonitor(client);
|
|
startLsFarm(client);
|
|
startRadio(client);
|
|
startMusik();
|
|
startGiveaways(client);
|
|
startScheduledPosts(client);
|
|
startSocialNotify(client);
|
|
startBirthdays(client);
|
|
scheduleRepoBackups();
|
|
} catch (error) {
|
|
console.error('[main] Start fehlgeschlagen:', error);
|
|
process.exit(1);
|
|
}
|