Initial: Pixelpöbel Discord Bot
Some checks failed
Auto Build and Push Docker Image / build (push) Failing after 8s

- Modular Discord Bot mit TypeScript und discord.js
- Grouped Commands (/admin, /owner subcommands)
- SQLite Datenbank mit Persistenz
- Twitch Monitoring mit Stream-ID Tracking
- Konfigurierbares Warn-System (Auto-Kick/Mute/Ban)
- Mute mit verschiedenen Zeiteinheiten (sec, min, hour, day, week, month, year, perm)
- Auto-Deploy beim Start (Option 3)
- Docker Support

Features:
- /ping, /help, /twitch (online, add, remove, list)
- /admin (kick, warn, unwarn, mute, unmute, ban, unban, config)
- /owner (deploy, stats, servers)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-22 16:29:30 +01:00
commit 40be1e181c
26 changed files with 3042 additions and 0 deletions

View File

@@ -0,0 +1,121 @@
import { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder } from 'discord.js';
import { Command } from '../../structures/Command.js';
import { TwitchManager } from '../../structures/TwitchManager.js';
const command: Command = {
data: new SlashCommandBuilder()
.setName('twitch')
.setDescription('Twitch-Befehle.')
.addSubcommand(subcommand =>
subcommand
.setName('online')
.setDescription('Prüft, ob ein Kanal online ist.')
.addStringOption(option =>
option.setName('channel')
.setDescription('Der Name des Twitch-Kanals')
.setRequired(true)))
.addSubcommand(subcommand =>
subcommand
.setName('add')
.setDescription('Kanal überwachen (Admin).')
.addStringOption(option =>
option.setName('channel')
.setDescription('Der Name des Twitch-Kanals')
.setRequired(true))
.addStringOption(option =>
option.setName('message')
.setDescription('Optionale Nachricht')))
.addSubcommand(subcommand =>
subcommand
.setName('remove')
.setDescription('Kanal aus Überwachung entfernen (Admin).')
.addStringOption(option =>
option.setName('channel')
.setDescription('Der Name des Twitch-Kanals')
.setRequired(true)))
.addSubcommand(subcommand =>
subcommand
.setName('list')
.setDescription('Listet überwachte Kanäle.')),
category: 'Public',
async execute(interaction: any) {
const subcommand = interaction.options.getSubcommand();
const guildId = interaction.guildId;
const isAdmin = interaction.memberPermissions?.has(PermissionFlagsBits.Administrator);
const DB = interaction.client.DB;
if (subcommand === 'online') {
const channelName = interaction.options.getString('channel')!.toLowerCase();
await interaction.deferReply();
const stream = await TwitchManager.fetchStreamData(channelName);
if (!stream) {
await interaction.editReply(`🔴 Der Kanal **${channelName}** ist offline.`);
return;
}
const thumbnailUrl = stream.thumbnail_url
.replace('{width}', '1280')
.replace('{height}', '720') + `?t=${Date.now()}`;
const embed = new EmbedBuilder()
.setTitle(`🟢 ${stream.user_name} ist ONLINE!`)
.setURL(`https://twitch.tv/${stream.user_login}`)
.setColor(0x00FF00)
.setImage(thumbnailUrl)
.addFields(
{ name: 'Titel', value: stream.title || 'Kein Titel', inline: false },
{ name: 'Kategorie', value: stream.game_name || 'Unbekannt', inline: true },
{ name: 'Zuschauer', value: stream.viewer_count.toString(), inline: true }
)
.setTimestamp();
await interaction.editReply({ embeds: [embed] });
return;
}
if (subcommand === 'list') {
const monitors: any[] = DB.all('SELECT * FROM twitch_monitors WHERE guild_id = ? AND discord_channel_id = ?', guildId, interaction.channelId);
if (monitors.length === 0) {
await interaction.reply('Keine Twitch-Kanäle überwacht.');
return;
}
const list = monitors.map((m: any) => `• **${m.channel_name}**`).join('\n');
const embed = new EmbedBuilder()
.setTitle('📺 Überwachte Twitch-Kanäle')
.setColor(0x6441a5)
.setDescription(list);
await interaction.reply({ embeds: [embed] });
return;
}
// Admin only
if (!isAdmin) {
await interaction.reply({ content: '❌ Keine Berechtigung.', ephemeral: true });
return;
}
if (subcommand === 'add') {
const channelName = interaction.options.getString('channel')!.toLowerCase();
const message = interaction.options.getString('message');
const discordChannelId = interaction.channelId;
DB.run(
'INSERT INTO twitch_monitors (guild_id, channel_name, discord_channel_id, custom_message) VALUES (?, ?, ?, ?) ON CONFLICT(guild_id, channel_name) DO UPDATE SET discord_channel_id = ?, custom_message = ?',
guildId, channelName, discordChannelId, message, discordChannelId, message
);
await interaction.reply(`✅ Kanal **${channelName}** wird überwacht.`);
}
if (subcommand === 'remove') {
const channelName = interaction.options.getString('channel')!.toLowerCase();
DB.run('DELETE FROM twitch_monitors WHERE guild_id = ? AND channel_name = ?', guildId, channelName);
await interaction.reply(`✅ Kanal **${channelName}** entfernt.`);
}
},
};
export default command;