Files
d4rkbot/src/bot/commands/umfrage.js
T
D4rkst3randClaude Opus 5 4d71122820
Deploy / check (push) Canceled after 0s
Deploy / deploy (push) Canceled after 0s
Radio: Schalter dorthin, wo man ihn sucht — und Stille sagt jetzt warum
Drei Sachen, alle vom selben Bericht ausgeloest.

1. Der Schalter war nur im Modul-Reiter zu finden, die Meldung schickte aber
   nach "Community". Beim Nachsehen kam heraus: Modul-Schalter haben in
   /api/settings gar keinen Weg — jeder stand von Hand in api.js, und fuenf
   fehlten dort (radio, automod, anti_raid, linked_roles, ls_farm). Die
   liessen sich nur ueber den Modulreiter umlegen. Jetzt kommen sie wie
   Kanaele, Rollen und Texte aus dem Register; jeder neue ist damit von
   allein speicherbar. Dazu steht der Haken jetzt oben im Radio-Abschnitt,
   wo auch die Sender stehen.

2. Der Bot sass im Sprachkanal und schwieg. Ursache im Code: nach
   joinVoiceChannel wurde sofort losgespielt. Der Aufruf kommt zurueck,
   sobald der Bot sichtbar im Kanal steht — der UDP-Weg wird danach erst
   ausgehandelt. Wer vorher sendet, sendet ins Leere. Jetzt wird auf
   VoiceConnectionStatus.Ready gewartet, und schlaegt das fehl, sagt der
   Befehl es statt still dazustehen.

3. Stille erklaert sich. Fehlt ffmpeg im Container, setzte sich der Bot
   bisher hin und schwieg — nichts stuerzte ab, nichts fehlte sichtbar.
   ffmpeg wird jetzt beim Start geprueft, /radio verweigert mit klarer
   Ansage, und kommt binnen acht Sekunden kein Ton, steht der Grund in der
   Tafel: fehlendes ffmpeg oder ein Sender, der nichts liefert.

Nebenbei: -analyzeduration stand hinter -i und wurde damit als
Ausgabe-Option gelesen, also ignoriert.

Geprueft: die Tonkette laeuft lokal gegen einen echten Sender durch bis zum
Abspieler (4,1 s Ton in 6 s Laufzeit, Status bleibt playing). Alle 16
Modul-Schalter gehen angemeldet durch /api/settings hin und zurueck.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 11:54:49 +02:00

88 lines
3.8 KiB
JavaScript

// /umfrage — native Discord-Umfrage starten.
//
// Bewusst Discords eigenes Poll-Objekt statt einer Nachbildung mit Knöpfen:
// die Oberfläche, das Auszählen und die Ergebnisanzeige macht Discord dann
// selbst, auch auf dem Handy. Wir bauen nur die Frage zusammen.
//
// Nicht zu verwechseln mit /wunsch — das sammelt Feature-Wünsche dauerhaft
// und zeigt sie auf der Roadmap. Diese hier ist für die schnelle Frage
// zwischendurch und läuft nach der eingestellten Zeit von selbst ab.
import { SlashCommandBuilder, PermissionFlagsBits, MessageFlags, PollLayoutType } from 'discord.js';
import { moduleEnabled } from '../../modules.js';
// Discord erlaubt bis zu 10 Antworten; vier reichen für den Alltag und halten
// den Befehl übersichtlich. Die ersten beiden sind Pflicht.
const ANTWORT_FELDER = ['a', 'b', 'c', 'd'];
const DAUER = [
{ name: '1 Stunde', value: 1 },
{ name: '4 Stunden', value: 4 },
{ name: '1 Tag', value: 24 },
{ name: '3 Tage', value: 72 },
{ name: '1 Woche', value: 168 },
];
export const data = new SlashCommandBuilder()
.setName('umfrage')
.setDescription('Startet eine Umfrage in diesem Kanal')
.setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages)
.addStringOption((o) => o.setName('frage').setDescription('Worum geht es?').setRequired(true).setMaxLength(300))
.addStringOption((o) => o.setName('a').setDescription('Erste Antwort').setRequired(true).setMaxLength(55))
.addStringOption((o) => o.setName('b').setDescription('Zweite Antwort').setRequired(true).setMaxLength(55))
.addStringOption((o) => o.setName('c').setDescription('Dritte Antwort').setMaxLength(55))
.addStringOption((o) => o.setName('d').setDescription('Vierte Antwort').setMaxLength(55))
.addIntegerOption((o) => o.setName('dauer').setDescription('Wie lange offen? (Standard: 1 Tag)').addChoices(...DAUER))
.addBooleanOption((o) => o.setName('mehrfach').setDescription('Mehrere Antworten erlaubt? (Standard: nein)'));
export async function execute(interaction) {
if (!moduleEnabled('polls')) {
await interaction.reply({
content: '❌ Umfragen sind ausgeschaltet — im Panel unter **Module → Community** einschalten.',
flags: MessageFlags.Ephemeral,
});
return;
}
const frage = interaction.options.getString('frage').trim();
const antworten = ANTWORT_FELDER
.map((feld) => interaction.options.getString(feld)?.trim())
.filter(Boolean)
.map((text) => ({ text }));
// Zwei gleiche Antworten sind kein Fehler für Discord, aber Unsinn für die
// Auswertung — hier abfangen statt eine kaputte Umfrage zu posten.
const einmalig = new Set(antworten.map((a) => a.text.toLowerCase()));
if (einmalig.size !== antworten.length) {
await interaction.reply({
content: '❌ Zwei Antworten sind gleich — dann kann niemand sinnvoll abstimmen.',
flags: MessageFlags.Ephemeral,
});
return;
}
try {
await interaction.channel.send({
poll: {
question: { text: frage },
answers: antworten,
duration: interaction.options.getInteger('dauer') ?? 24,
allowMultiselect: interaction.options.getBoolean('mehrfach') ?? false,
layoutType: PollLayoutType.Default,
},
});
} catch (error) {
console.error('[umfrage]', error);
await interaction.reply({
content: '❌ Umfrage konnte nicht gepostet werden — darf der Bot hier schreiben?',
flags: MessageFlags.Ephemeral,
});
return;
}
// Die Umfrage selbst ist die sichtbare Antwort; die Bestätigung bleibt still
await interaction.reply({
content: `✅ Umfrage läuft — ${antworten.length} Antworten.`,
flags: MessageFlags.Ephemeral,
});
}