// /radio — Steuertafel im Kanal öffnen. // // Der Befehl nimmt bewusst keinen Sendernamen entgegen: getippt werden müsste // er auf dem Handy erst recht, und die Auswahl steht ohnehin im Menü. Ein // Aufruf, eine Tafel, umschalten per Klick. import { SlashCommandBuilder, MessageFlags } from 'discord.js'; import { moduleEnabled } from '../../modules.js'; import { listStations, getStation, setRadioState } from '../../db.js'; import { spielen, laeuft, tafelEmbed, tafelKomponenten, titelHolen, ffmpegVorhanden } from '../radio.js'; export const data = new SlashCommandBuilder() .setName('radio') .setDescription('Radio im Sprachkanal — Sender wählen und umschalten'); export async function execute(interaction) { if (!moduleEnabled('radio')) { await interaction.reply({ content: '❌ Radio ist ausgeschaltet — im Panel unter **Community → Radio** einschalten.', flags: MessageFlags.Ephemeral, }); return; } const stationen = listStations(); if (stationen.length === 0) { await interaction.reply({ content: '❌ Es sind noch keine Sender eingetragen — im Panel unter **Community → Radio**.', flags: MessageFlags.Ephemeral, }); return; } const kanal = interaction.member?.voice?.channel; const schonAn = laeuft(interaction.guild.id); if (!kanal && !schonAn) { await interaction.reply({ content: '❌ Geh erst in einen Sprachkanal.', flags: MessageFlags.Ephemeral, }); return; } // Darf der Bot da überhaupt rein? Sonst hängt der Verbindungsaufbau, bis // die Interaktion abgelaufen ist, und der Nutzer sieht nur „Fehler". if (kanal) { const rechte = kanal.permissionsFor(interaction.guild.members.me); if (!rechte?.has('Connect') || !rechte?.has('Speak')) { await interaction.reply({ content: `❌ Ich darf in <#${kanal.id}> nicht rein oder nicht sprechen.`, flags: MessageFlags.Ephemeral, }); return; } // Ein voller Kanal sieht aus wie ein Rechteproblem: Discord nimmt die // Beitrittsanfrage entgegen und antwortet einfach nicht mehr. Nur wer // Mitglieder verschieben darf, kommt am Limit vorbei. if (kanal.userLimit > 0 && kanal.members.size >= kanal.userLimit && !rechte.has('MoveMembers')) { await interaction.reply({ content: `❌ <#${kanal.id}> ist voll (${kanal.members.size}/${kanal.userLimit}). ` + 'Entweder Platz machen oder mir das Recht **Mitglieder verschieben** geben.', flags: MessageFlags.Ephemeral, }); return; } } // Ohne ffmpeg wuerde der Bot sich hinsetzen und schweigen. Lieber gleich // sagen, woran es liegt, als jemanden im stillen Kanal warten lassen. if (ffmpegVorhanden() === false) { await interaction.reply({ content: '❌ Auf dem Server fehlt **ffmpeg** — ohne das kann der Bot keinen Ton ' + 'umwandeln. Das Image muss neu gebaut werden.', flags: MessageFlags.Ephemeral, }); return; } // Verbinden dauert länger als die drei Sekunden, die Discord gibt await interaction.deferReply(); let station = schonAn ? getStation(schonAn.stationId) : null; let titel = schonAn?.titel ?? null; if (!schonAn) { station = stationen[0]; try { await spielen(kanal, station); } catch (error) { console.error('[radio]', error); await interaction.editReply(`❌ ${error.message || 'Verbindung in den Sprachkanal fehlgeschlagen.'}`); return; } ({ titel } = await titelHolen(station.url)); const s = laeuft(interaction.guild.id); if (s) s.titel = titel; } const jetzt = laeuft(interaction.guild.id); const nachricht = await interaction.editReply({ embeds: [tafelEmbed(interaction.client, station, titel, kanal?.id ?? schonAn?.channelId, { tonLaeuft: jetzt?.tonLaeuft, ffmpeg: ffmpegVorhanden() })], components: tafelKomponenten(stationen, station?.id), }); // Die Tafel merken, damit der Titel-Melder sie später bearbeiten kann setRadioState({ guildId: interaction.guild.id, channelId: kanal?.id ?? schonAn.channelId, stationId: station?.id ?? null, panelChannelId: nachricht.channelId ?? interaction.channelId, panelMessageId: nachricht.id, }); }