Add: Timer and Trigger modules with help subcommands
All checks were successful
Auto Build and Push Docker Image / build (push) Successful in 6s
All checks were successful
Auto Build and Push Docker Image / build (push) Successful in 6s
- Add /timer command: add, remove, list, listall, help - Add /trigger command: add, remove, list, help - Add /admin help and /owner help subcommands - Add /twitch help subcommand - Add ReminderManager for timer notifications - Add reminders table to database - Update README.md and AGENTS-BOT.md documentation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -116,6 +116,10 @@ const command: Command = {
|
||||
option.setName('duration_value')
|
||||
.setDescription('Dauer in Sekunden')
|
||||
.setMinValue(0)))
|
||||
.addSubcommand(subcommand =>
|
||||
subcommand
|
||||
.setName('help')
|
||||
.setDescription('Zeigt Hilfe zu den Admin-Befehlen an.'))
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ModerateMembers),
|
||||
category: 'Admin',
|
||||
async execute(interaction: any) {
|
||||
@@ -124,6 +128,28 @@ const command: Command = {
|
||||
const guild = interaction.guild;
|
||||
const guildId = interaction.guildId;
|
||||
|
||||
if (subcommand === 'help') {
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle('🛡️ Admin Hilfe')
|
||||
.setColor(0xe74c3c)
|
||||
.setDescription('Moderations-Tools für Server-Verwaltung.')
|
||||
.addFields(
|
||||
{ name: '`/admin kick <nutzer> [grund]`', value: 'Kickt einen Nutzer vom Server.', inline: false },
|
||||
{ name: '`/admin warn <nutzer> <grund>`', value: 'Verwarnt einen Nutzer. Bei X Warnungen wird automatisch eine Aktion ausgeführt.', inline: false },
|
||||
{ name: '`/admin unwarn <nutzer>`', value: 'Entfernt die letzte Warnung eines Nutzers.', inline: false },
|
||||
{ name: '`/admin mute <nutzer> <dauer> <einheit> [grund]`', value: 'Muted einen Nutzer für eine bestimmte Zeit.\nEinheiten: sec, min, hour, day, week, month, year, perm', inline: false },
|
||||
{ name: '`/admin unmute <nutzer>`', value: 'Entmutet einen Nutzer.', inline: false },
|
||||
{ name: '`/admin ban <nutzer> [grund] [delete_days]`', value: 'Bannt einen Nutzer vom Server.\ndelete_days: Nachrichten der letzten X Tage löschen (0-7).', inline: false },
|
||||
{ name: '`/admin unban <id>`', value: 'Entbannt einen Nutzer (via ID oder @username).', inline: false },
|
||||
{ name: '`/admin config <setting> [wert]`', value: 'Konfiguriert das Warn-System.\nSettings: warn_threshold, warn_action, warn_mute_duration, show', inline: false },
|
||||
{ name: 'Warn-System', value: 'Automatische Aktionen bei X Warnungen:\n`/admin config warn_action kick|mute|ban`', inline: false }
|
||||
)
|
||||
.setTimestamp();
|
||||
|
||||
await interaction.reply({ embeds: [embed], flags: [MessageFlags.Ephemeral] });
|
||||
return;
|
||||
}
|
||||
|
||||
// Get or create guild settings
|
||||
let settings: any = DB.get('SELECT * FROM guild_settings WHERE guild_id = ?', guildId);
|
||||
if (!settings) {
|
||||
|
||||
@@ -18,6 +18,10 @@ const command: Command = {
|
||||
subcommand
|
||||
.setName('servers')
|
||||
.setDescription('Listet alle Server'))
|
||||
.addSubcommand(subcommand =>
|
||||
subcommand
|
||||
.setName('help')
|
||||
.setDescription('Zeigt Hilfe zu den Owner-Befehlen an.'))
|
||||
.setDMPermission(true),
|
||||
category: 'Owner',
|
||||
async execute(interaction: any, client: any) {
|
||||
@@ -30,6 +34,22 @@ const command: Command = {
|
||||
|
||||
const subcommand = interaction.options.getSubcommand();
|
||||
|
||||
if (subcommand === 'help') {
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle('🔑 Owner Hilfe')
|
||||
.setColor(0xf1c40f)
|
||||
.setDescription('Bot-Einstellungen und Statistiken.')
|
||||
.addFields(
|
||||
{ name: '`/owner deploy`', value: 'Aktualisiert alle Discord-Befehle.\nNach Code-Änderungen ausführen.', inline: false },
|
||||
{ name: '`/owner stats`', value: 'Zeigt Bot-Statistiken: Uptime, Latency, Server- und Nutzerzahl.', inline: false },
|
||||
{ name: '`/owner servers`', value: 'Listet alle Server, auf denen der Bot aktiv ist.', inline: false }
|
||||
)
|
||||
.setTimestamp();
|
||||
|
||||
await interaction.reply({ embeds: [embed], flags: [MessageFlags.Ephemeral] });
|
||||
return;
|
||||
}
|
||||
|
||||
if (subcommand === 'deploy') {
|
||||
await interaction.deferReply({ flags: [MessageFlags.Ephemeral] });
|
||||
|
||||
|
||||
347
src/commands/utility/timer.ts
Normal file
347
src/commands/utility/timer.ts
Normal file
@@ -0,0 +1,347 @@
|
||||
import { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder, MessageFlags } from 'discord.js';
|
||||
import { Command } from '../../structures/Command.js';
|
||||
|
||||
// Parse time duration strings like "30s", "2h", "1d30m"
|
||||
function parseDuration(input: string): number | null {
|
||||
const regex = /(\d+)\s*([a-z]+)/gi;
|
||||
let match;
|
||||
let totalMs = 0;
|
||||
|
||||
while ((match = regex.exec(input)) !== null) {
|
||||
const value = parseInt(match[1]);
|
||||
const unit = match[2].toLowerCase();
|
||||
const unitMs: Record<string, number> = {
|
||||
's': 1000,
|
||||
'sec': 1000,
|
||||
'sek': 1000,
|
||||
'sekunden': 1000,
|
||||
'm': 60000,
|
||||
'min': 60000,
|
||||
'minuten': 60000,
|
||||
'h': 3600000,
|
||||
'hour': 3600000,
|
||||
'std': 3600000,
|
||||
'stunden': 3600000,
|
||||
'd': 86400000,
|
||||
'day': 86400000,
|
||||
't': 86400000,
|
||||
'tage': 86400000,
|
||||
'w': 604800000,
|
||||
'week': 604800000,
|
||||
'wochen': 604800000,
|
||||
'mo': 2592000000,
|
||||
'month': 2592000000,
|
||||
'monat': 2592000000,
|
||||
'monate': 2592000000,
|
||||
'y': 31536000000,
|
||||
'year': 31536000000,
|
||||
'j': 31536000000,
|
||||
'jahr': 31536000000,
|
||||
'jahre': 31536000000
|
||||
};
|
||||
|
||||
if (unitMs[unit]) {
|
||||
totalMs += value * unitMs[unit];
|
||||
}
|
||||
}
|
||||
|
||||
return totalMs > 0 ? totalMs : null;
|
||||
}
|
||||
|
||||
// Parse date-time strings like "25.12.2024 14:30" or "tomorrow 3pm"
|
||||
function parseDateTime(input: string): Date | null {
|
||||
const now = new Date();
|
||||
|
||||
// German date format: DD.MM.YYYY or DD.MM.YYYY HH:MM
|
||||
const germanDate = /^(\d{1,2})\.(\d{1,2})\.(\d{4})(?:\s+(\d{1,2}):(\d{1,2}))?$/.exec(input);
|
||||
if (germanDate) {
|
||||
const day = parseInt(germanDate[1]);
|
||||
const month = parseInt(germanDate[2]) - 1; // Month is 0-indexed
|
||||
const year = parseInt(germanDate[3]);
|
||||
const hour = germanDate[4] ? parseInt(germanDate[4]) : 12;
|
||||
const minute = germanDate[5] ? parseInt(germanDate[5]) : 0;
|
||||
|
||||
const date = new Date(year, month, day, hour, minute);
|
||||
if (isNaN(date.getTime())) return null;
|
||||
return date;
|
||||
}
|
||||
|
||||
// ISO format: YYYY-MM-DD or YYYY-MM-DD HH:MM
|
||||
const isoDate = /^(\d{4})-(\d{1,2})-(\d{1,2})(?:[T\s](\d{1,2}):(\d{1,2}))?$/.exec(input);
|
||||
if (isoDate) {
|
||||
const year = parseInt(isoDate[1]);
|
||||
const month = parseInt(isoDate[2]) - 1;
|
||||
const day = parseInt(isoDate[3]);
|
||||
const hour = isoDate[4] ? parseInt(isoDate[4]) : 12;
|
||||
const minute = isoDate[5] ? parseInt(isoDate[5]) : 0;
|
||||
|
||||
const date = new Date(year, month, day, hour, minute);
|
||||
if (isNaN(date.getTime())) return null;
|
||||
return date;
|
||||
}
|
||||
|
||||
// Tomorrow/Nächsten Tag
|
||||
const lowerInput = input.toLowerCase();
|
||||
if (lowerInput.includes('morgen') || lowerInput.includes('tomorrow')) {
|
||||
const tomorrow = new Date(now);
|
||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||
|
||||
// Try to extract time
|
||||
const timeMatch = /(\d{1,2}):(\d{1,2})/.exec(input);
|
||||
if (timeMatch) {
|
||||
tomorrow.setHours(parseInt(timeMatch[1]), parseInt(timeMatch[2]), 0, 0);
|
||||
} else {
|
||||
tomorrow.setHours(9, 0, 0, 0); // Default 9 AM
|
||||
}
|
||||
return tomorrow;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const command: Command = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName('timer')
|
||||
.setDescription('Erinnerungen und Timer verwalten.')
|
||||
.addSubcommand(subcommand =>
|
||||
subcommand
|
||||
.setName('add')
|
||||
.setDescription('Fügt einen neuen Timer hinzu.')
|
||||
.addStringOption(option =>
|
||||
option.setName('zeit')
|
||||
.setDescription('Zeit (z.B. "30min", "2h", "25.12.2024 14:30", "morgen")')
|
||||
.setRequired(true))
|
||||
.addStringOption(option =>
|
||||
option.setName('nachricht')
|
||||
.setDescription('Die Erinnerungs-Nachricht')
|
||||
.setRequired(true)))
|
||||
.addSubcommand(subcommand =>
|
||||
subcommand
|
||||
.setName('remove')
|
||||
.setDescription('Entfernt einen Timer.')
|
||||
.addIntegerOption(option =>
|
||||
option.setName('id')
|
||||
.setDescription('Die Timer-ID (siehe /timer list)')
|
||||
.setRequired(true)))
|
||||
.addSubcommand(subcommand =>
|
||||
subcommand
|
||||
.setName('list')
|
||||
.setDescription('Zeigt alle Timer dieses Kanals an.'))
|
||||
.addSubcommand(subcommand =>
|
||||
subcommand
|
||||
.setName('listall')
|
||||
.setDescription('Zeigt alle Timer des Servers an (Nur Moderatoren).'))
|
||||
.addSubcommand(subcommand =>
|
||||
subcommand
|
||||
.setName('help')
|
||||
.setDescription('Zeigt Hilfe zu den Timer-Befehlen an.')),
|
||||
category: 'Public',
|
||||
async execute(interaction: any) {
|
||||
const subcommand = interaction.options.getSubcommand();
|
||||
const guildId = interaction.guildId;
|
||||
const channelId = interaction.channelId;
|
||||
const userId = interaction.user.id;
|
||||
const isAdmin = interaction.memberPermissions?.has(PermissionFlagsBits.ModerateMembers);
|
||||
const DB = interaction.client.DB;
|
||||
|
||||
if (subcommand === 'help') {
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle('⏰ Timer Hilfe')
|
||||
.setColor(0x3498db)
|
||||
.setDescription('Setze Erinnerungen für dich oder andere.')
|
||||
.addFields(
|
||||
{ name: '`/timer add <zeit> <nachricht>`', value: 'Fügt einen neuen Timer hinzu.\nJeder kann Timer setzen.', inline: false },
|
||||
{ name: '`/timer remove <id>`', value: 'Entfernt einen Timer (Mod).\nDie ID bekommst du über `/timer list`.', inline: false },
|
||||
{ name: '`/timer list`', value: 'Zeigt alle Timer in diesem Kanal an.', inline: false },
|
||||
{ name: '`/timer listall`', value: 'Zeigt alle Timer auf dem Server an (Mod).', inline: false },
|
||||
{ name: 'Zeitformate', value: 'Dauer: `30s`, `2h`, `1d30m`, `3wochen`, `1jahr`\nDatum: `25.12.2024 14:30` oder `morgen 15:00`', inline: false },
|
||||
{ name: 'Beispiele', value: '`/timer add 30min Meeting erinnern`\n`/timer add morgen 9 Uhr Aufstehen`\n`/timer add 25.12.2024 18:00 Weihnachtsessen`', inline: false }
|
||||
)
|
||||
.setTimestamp();
|
||||
|
||||
await interaction.reply({ embeds: [embed], flags: [MessageFlags.Ephemeral] });
|
||||
return;
|
||||
}
|
||||
|
||||
if (subcommand === 'add') {
|
||||
const timeInput = interaction.options.getString('zeit')!;
|
||||
const message = interaction.options.getString('nachricht')!;
|
||||
const now = new Date();
|
||||
|
||||
let targetTime: Date | null = null;
|
||||
|
||||
// Try duration first (e.g., "30min", "2h", "1d30m")
|
||||
const duration = parseDuration(timeInput);
|
||||
if (duration !== null) {
|
||||
targetTime = new Date(now.getTime() + duration);
|
||||
} else {
|
||||
// Try date-time parsing
|
||||
targetTime = parseDateTime(timeInput);
|
||||
}
|
||||
|
||||
if (!targetTime || targetTime <= now) {
|
||||
await interaction.reply({
|
||||
content: '❌ Ungültige Zeitangabe. Verwende z.B.: "30min", "2h30m", "25.12.2024 14:30" oder "morgen 15:00"',
|
||||
flags: [MessageFlags.Ephemeral]
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Insert reminder
|
||||
const result = DB.run(
|
||||
'INSERT INTO reminders (guild_id, channel_id, user_id, reminder_text, target_time) VALUES (?, ?, ?, ?, ?)',
|
||||
guildId,
|
||||
channelId,
|
||||
userId,
|
||||
message,
|
||||
targetTime.toISOString()
|
||||
);
|
||||
|
||||
const timeDiff = targetTime.getTime() - now.getTime();
|
||||
const minutes = Math.floor(timeDiff / 60000);
|
||||
const hours = Math.floor(minutes / 60);
|
||||
const days = Math.floor(hours / 24);
|
||||
|
||||
let timeStr = '';
|
||||
if (days > 0) timeStr += `${days}d `;
|
||||
if (hours % 24 > 0) timeStr += `${hours % 24}h `;
|
||||
if (minutes % 60 > 0) timeStr += `${minutes % 60}min`;
|
||||
|
||||
await interaction.reply({
|
||||
content: `✅ Erinnerung gesetzt (ID: ${result.lastInsertRowid}) für **${timeStr.trim()}**`,
|
||||
flags: [MessageFlags.Ephemeral]
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (subcommand === 'remove') {
|
||||
if (!isAdmin) {
|
||||
await interaction.reply({ content: '❌ Keine Berechtigung. Moderatoren erforderlich.', flags: [MessageFlags.Ephemeral] });
|
||||
return;
|
||||
}
|
||||
|
||||
const timerId = interaction.options.getInteger('id')!;
|
||||
|
||||
const result = DB.run('DELETE FROM reminders WHERE id = ? AND guild_id = ?', timerId, guildId);
|
||||
|
||||
if (result.changes === 0) {
|
||||
await interaction.reply({ content: `❌ Timer mit ID ${timerId} nicht gefunden.`, flags: [MessageFlags.Ephemeral] });
|
||||
return;
|
||||
}
|
||||
|
||||
await interaction.reply({ content: `✅ Timer mit ID ${timerId} entfernt.`, flags: [MessageFlags.Ephemeral] });
|
||||
return;
|
||||
}
|
||||
|
||||
if (subcommand === 'list') {
|
||||
const reminders: any[] = DB.all(
|
||||
'SELECT * FROM reminders WHERE guild_id = ? AND channel_id = ? ORDER BY target_time ASC',
|
||||
guildId,
|
||||
channelId
|
||||
);
|
||||
|
||||
if (reminders.length === 0) {
|
||||
await interaction.reply({ content: 'Keine Timer in diesem Kanal.', flags: [MessageFlags.Ephemeral] });
|
||||
return;
|
||||
}
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle('⏰ Timer in diesem Kanal')
|
||||
.setColor(0x3498db)
|
||||
.setTimestamp();
|
||||
|
||||
const now = new Date();
|
||||
const chunks: string[] = [];
|
||||
const chunkSize = 10;
|
||||
|
||||
for (let i = 0; i < reminders.length; i += chunkSize) {
|
||||
const chunk = reminders.slice(i, i + chunkSize).map((r: any) => {
|
||||
const targetTime = new Date(r.target_time);
|
||||
const diffMs = targetTime.getTime() - now.getTime();
|
||||
const diffMins = Math.floor(diffMs / 60000);
|
||||
const diffHours = Math.floor(diffMins / 60);
|
||||
const diffDays = Math.floor(diffHours / 24);
|
||||
|
||||
let timeLeft = '';
|
||||
if (diffDays > 0) timeLeft = `${diffDays}d ${diffHours % 24}h`;
|
||||
else if (diffHours > 0) timeLeft = `${diffHours}h ${diffMins % 60}min`;
|
||||
else if (diffMins > 0) timeLeft = `${diffMins}min`;
|
||||
else timeLeft = '< 1min';
|
||||
|
||||
const dateStr = targetTime.toLocaleString('de-DE');
|
||||
return `• **ID ${r.id}**: ${r.reminder_text}\n 🕐 ${dateStr} (in ${timeLeft})`;
|
||||
}).join('\n\n');
|
||||
chunks.push(chunk);
|
||||
}
|
||||
|
||||
embed.setDescription(chunks[0]);
|
||||
await interaction.reply({ embeds: [embed], flags: [MessageFlags.Ephemeral] });
|
||||
|
||||
for (let i = 1; i < chunks.length; i++) {
|
||||
const nextEmbed = new EmbedBuilder()
|
||||
.setColor(0x3498db)
|
||||
.setDescription(chunks[i]);
|
||||
await interaction.followUp({ embeds: [nextEmbed], flags: [MessageFlags.Ephemeral] });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (subcommand === 'listall') {
|
||||
if (!isAdmin) {
|
||||
await interaction.reply({ content: '❌ Keine Berechtigung. Moderatoren erforderlich.', flags: [MessageFlags.Ephemeral] });
|
||||
return;
|
||||
}
|
||||
|
||||
const reminders: any[] = DB.all(
|
||||
'SELECT r.*, c.name as channel_name FROM reminders r LEFT JOIN channels c ON r.channel_id = c.id WHERE r.guild_id = ? ORDER BY r.target_time ASC',
|
||||
guildId
|
||||
);
|
||||
|
||||
if (reminders.length === 0) {
|
||||
await interaction.reply({ content: 'Keine Timer auf dem Server.', flags: [MessageFlags.Ephemeral] });
|
||||
return;
|
||||
}
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle('⏰ Alle Timer auf dem Server')
|
||||
.setColor(0xe74c3c)
|
||||
.setTimestamp();
|
||||
|
||||
const now = new Date();
|
||||
const chunks: string[] = [];
|
||||
const chunkSize = 10;
|
||||
|
||||
for (let i = 0; i < reminders.length; i += chunkSize) {
|
||||
const chunk = reminders.slice(i, i + chunkSize).map((r: any) => {
|
||||
const targetTime = new Date(r.target_time);
|
||||
const diffMs = targetTime.getTime() - now.getTime();
|
||||
const diffMins = Math.floor(diffMs / 60000);
|
||||
const diffHours = Math.floor(diffMins / 60);
|
||||
const diffDays = Math.floor(diffHours / 24);
|
||||
|
||||
let timeLeft = '';
|
||||
if (diffDays > 0) timeLeft = `${diffDays}d ${diffHours % 24}h`;
|
||||
else if (diffHours > 0) timeLeft = `${diffHours}h ${diffMins % 60}min`;
|
||||
else if (diffMins > 0) timeLeft = `${diffMins}min`;
|
||||
else timeLeft = '< 1min';
|
||||
|
||||
const dateStr = targetTime.toLocaleString('de-DE');
|
||||
return `• **ID ${r.id}**: ${r.reminder_text}\n 📍 Kanal: ${r.channel_id}\n 🕐 ${dateStr} (in ${timeLeft})`;
|
||||
}).join('\n\n');
|
||||
chunks.push(chunk);
|
||||
}
|
||||
|
||||
embed.setDescription(chunks[0]);
|
||||
await interaction.reply({ embeds: [embed], flags: [MessageFlags.Ephemeral] });
|
||||
|
||||
for (let i = 1; i < chunks.length; i++) {
|
||||
const nextEmbed = new EmbedBuilder()
|
||||
.setColor(0xe74c3c)
|
||||
.setDescription(chunks[i]);
|
||||
await interaction.followUp({ embeds: [nextEmbed], flags: [MessageFlags.Ephemeral] });
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default command;
|
||||
131
src/commands/utility/trigger.ts
Normal file
131
src/commands/utility/trigger.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
import { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder, MessageFlags } from 'discord.js';
|
||||
import { Command } from '../../structures/Command.js';
|
||||
|
||||
const command: Command = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName('trigger')
|
||||
.setDescription('Auto-Antworten verwalten.')
|
||||
.addSubcommand(subcommand =>
|
||||
subcommand
|
||||
.setName('add')
|
||||
.setDescription('Fügt einen neuen Trigger hinzu.')
|
||||
.addStringOption(option =>
|
||||
option.setName('trigger')
|
||||
.setDescription('Das Trigger-Wort')
|
||||
.setRequired(true))
|
||||
.addStringOption(option =>
|
||||
option.setName('antwort')
|
||||
.setDescription('Die Antwort-Nachricht')
|
||||
.setRequired(true)))
|
||||
.addSubcommand(subcommand =>
|
||||
subcommand
|
||||
.setName('remove')
|
||||
.setDescription('Entfernt einen Trigger.')
|
||||
.addStringOption(option =>
|
||||
option.setName('trigger')
|
||||
.setDescription('Das Trigger-Wort')
|
||||
.setRequired(true)))
|
||||
.addSubcommand(subcommand =>
|
||||
subcommand
|
||||
.setName('list')
|
||||
.setDescription('Listet alle Trigger auf.'))
|
||||
.addSubcommand(subcommand =>
|
||||
subcommand
|
||||
.setName('help')
|
||||
.setDescription('Zeigt Hilfe zu den Trigger-Befehlen an.')),
|
||||
category: 'Admin',
|
||||
async execute(interaction: any) {
|
||||
const subcommand = interaction.options.getSubcommand();
|
||||
const guildId = interaction.guildId;
|
||||
const isAdmin = interaction.memberPermissions?.has(PermissionFlagsBits.ModerateMembers);
|
||||
const DB = interaction.client.DB;
|
||||
|
||||
if (subcommand === 'help') {
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle('🎯 Trigger Hilfe')
|
||||
.setColor(0x3498db)
|
||||
.setDescription('Automatische Antworten auf Trigger-Wörter.')
|
||||
.addFields(
|
||||
{ name: '`/trigger add <wort> <antwort>`', value: 'Fügt einen neuen Trigger hinzu (Mod).\nTrigger-Wörter werden automatisch klein geschrieben.', inline: false },
|
||||
{ name: '`/trigger remove <wort>`', value: 'Entfernt einen Trigger (Mod).', inline: false },
|
||||
{ name: '`/trigger list`', value: 'Zeigt alle Trigger auf diesem Server an.', inline: false },
|
||||
{ name: 'Beispiel', value: '`/trigger add hallo Hallo! Wie kann ich helfen?`', inline: false }
|
||||
)
|
||||
.setTimestamp();
|
||||
|
||||
await interaction.reply({ embeds: [embed], flags: [MessageFlags.Ephemeral] });
|
||||
return;
|
||||
}
|
||||
|
||||
if (subcommand === 'list') {
|
||||
const triggers: any[] = DB.all('SELECT * FROM auto_responses WHERE guild_id = ? ORDER BY trigger_word ASC', guildId);
|
||||
|
||||
if (triggers.length === 0) {
|
||||
await interaction.reply({ content: 'Keine Trigger konfiguriert.', flags: [MessageFlags.Ephemeral] });
|
||||
return;
|
||||
}
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle('🎯 Auto-Antworten')
|
||||
.setColor(0x3498db)
|
||||
.setTimestamp();
|
||||
|
||||
const chunks: string[] = [];
|
||||
const chunkSize = 10;
|
||||
for (let i = 0; i < triggers.length; i += chunkSize) {
|
||||
const chunk = triggers.slice(i, i + chunkSize).map((t: any) =>
|
||||
`• **${t.trigger_word}** → ${t.response_text}`
|
||||
).join('\n');
|
||||
chunks.push(chunk);
|
||||
}
|
||||
|
||||
embed.setDescription(chunks[0]);
|
||||
await interaction.reply({ embeds: [embed], flags: [MessageFlags.Ephemeral] });
|
||||
|
||||
for (let i = 1; i < chunks.length; i++) {
|
||||
const nextEmbed = new EmbedBuilder()
|
||||
.setColor(0x3498db)
|
||||
.setDescription(chunks[i]);
|
||||
await interaction.followUp({ embeds: [nextEmbed], flags: [MessageFlags.Ephemeral] });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Admin only for add/remove
|
||||
if (!isAdmin) {
|
||||
await interaction.reply({ content: '❌ Keine Berechtigung. Moderatoren erforderlich.', flags: [MessageFlags.Ephemeral] });
|
||||
return;
|
||||
}
|
||||
|
||||
if (subcommand === 'add') {
|
||||
const triggerWord = interaction.options.getString('trigger')!.toLowerCase();
|
||||
const responseText = interaction.options.getString('antwort')!;
|
||||
|
||||
DB.run(
|
||||
'INSERT INTO auto_responses (guild_id, trigger_word, response_text) VALUES (?, ?, ?) ON CONFLICT(guild_id, trigger_word) DO UPDATE SET response_text = ?',
|
||||
guildId,
|
||||
triggerWord,
|
||||
responseText,
|
||||
responseText
|
||||
);
|
||||
|
||||
await interaction.reply({ content: `✅ Trigger **${triggerWord}** hinzugefügt/aktualisiert.`, flags: [MessageFlags.Ephemeral] });
|
||||
return;
|
||||
}
|
||||
|
||||
if (subcommand === 'remove') {
|
||||
const triggerWord = interaction.options.getString('trigger')!.toLowerCase();
|
||||
|
||||
const result = DB.run('DELETE FROM auto_responses WHERE guild_id = ? AND trigger_word = ?', guildId, triggerWord);
|
||||
|
||||
if (result.changes === 0) {
|
||||
await interaction.reply({ content: `❌ Trigger **${triggerWord}** nicht gefunden.`, flags: [MessageFlags.Ephemeral] });
|
||||
return;
|
||||
}
|
||||
|
||||
await interaction.reply({ content: `✅ Trigger **${triggerWord}** entfernt.`, flags: [MessageFlags.Ephemeral] });
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default command;
|
||||
@@ -36,7 +36,11 @@ const command: Command = {
|
||||
.addSubcommand(subcommand =>
|
||||
subcommand
|
||||
.setName('list')
|
||||
.setDescription('Listet überwachte Kanäle.')),
|
||||
.setDescription('Listet überwachte Kanäle.'))
|
||||
.addSubcommand(subcommand =>
|
||||
subcommand
|
||||
.setName('help')
|
||||
.setDescription('Zeigt Hilfe zu den Twitch-Befehlen an.')),
|
||||
category: 'Public',
|
||||
async execute(interaction: any) {
|
||||
const subcommand = interaction.options.getSubcommand();
|
||||
@@ -44,6 +48,24 @@ const command: Command = {
|
||||
const isAdmin = interaction.memberPermissions?.has(PermissionFlagsBits.ModerateMembers);
|
||||
const DB = interaction.client.DB;
|
||||
|
||||
if (subcommand === 'help') {
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle('📺 Twitch Hilfe')
|
||||
.setColor(0x6441a5)
|
||||
.setDescription('Überwache Twitch-Streams und bekomme Benachrichtigungen.')
|
||||
.addFields(
|
||||
{ name: '`/twitch online <kanal>`', value: 'Prüft, ob ein Kanal gerade online ist.', inline: false },
|
||||
{ name: '`/twitch add <kanal> [nachricht]`', value: 'Überwacht einen Kanal in diesem Kanal (Mod).\nWenn der Streamer live geht, wird benachrichtigt.', inline: false },
|
||||
{ name: '`/twitch remove <kanal>`', value: 'Entfernt einen Kanal aus der Überwachung (Mod).', inline: false },
|
||||
{ name: '`/twitch list`', value: 'Zeigt alle überwachten Kanäle in diesem Kanal an.', inline: false },
|
||||
{ name: 'Beispiel', value: '`/twitch add shroud Hallo! Shroud ist live!`', inline: false }
|
||||
)
|
||||
.setTimestamp();
|
||||
|
||||
await interaction.reply({ embeds: [embed], flags: [MessageFlags.Ephemeral] });
|
||||
return;
|
||||
}
|
||||
|
||||
if (subcommand === 'online') {
|
||||
const channelName = interaction.options.getString('channel')!.toLowerCase();
|
||||
await interaction.deferReply();
|
||||
|
||||
Reference in New Issue
Block a user