feat: add Cat module with /cat and /catgif commands using TheCatAPI
All checks were successful
Auto Build and Push Docker Image / build (push) Successful in 7s

This commit is contained in:
sarah
2026-08-02 23:08:29 +02:00
parent 5c40faa5c9
commit ddfc82e1c5
6 changed files with 105 additions and 1 deletions

View File

@@ -6,5 +6,8 @@ TWITCH_USERNAME=dein_twitch_username
TWITCH_OAUTH_TOKEN=oauth:xxxxxxxxxxxxxxxxxx TWITCH_OAUTH_TOKEN=oauth:xxxxxxxxxxxxxxxxxx
BOT_OWNER_ID=deine_discord_user_id BOT_OWNER_ID=deine_discord_user_id
# Optional: TheCatAPI Key für höheres Ratenlimit (default: leer / kostenlos)
THECATAPI_KEY=
# Optional: Automatische Slash-Command Registrierung bei Bot-Start (default: true) # Optional: Automatische Slash-Command Registrierung bei Bot-Start (default: true)
AUTO_DEPLOY=true AUTO_DEPLOY=true

View File

@@ -19,7 +19,8 @@ The bot uses a **Modular Command & Event Loading** pattern with **ESM (ECMAScrip
10. **Welcome/Goodbye System:** Guild member add/remove events with customizable messages. 10. **Welcome/Goodbye System:** Guild member add/remove events with customizable messages.
11. **Logging System:** Configurable event logging (messages, roles, moderation, etc.) via centralized `EventLogger`. 11. **Logging System:** Configurable event logging (messages, roles, moderation, etc.) via centralized `EventLogger`.
12. **Role Selection System:** Self-service role assignment via select menus with support for exclusive categories and max-role limits. 12. **Role Selection System:** Self-service role assignment via select menus with support for exclusive categories and max-role limits.
13. **Centralized Event Logger:** Kapsel event logs into `EventLogger.sendLog()` to eliminate duplicated logging logic across event files. 13. **Cat & CatGIF System:** TheCatAPI integration for random cat images and GIFs (`CatManager`).
14. **Centralized Event Logger:** Kapsel event logs into `EventLogger.sendLog()` to eliminate duplicated logging logic across event files.
## 📁 Project Structure ## 📁 Project Structure
@@ -37,6 +38,7 @@ pixelpoebel/
│ ├── Command.ts │ ├── Command.ts
│ ├── Database.ts # Database with Transaction, Indexes & Surgical Caching │ ├── Database.ts # Database with Transaction, Indexes & Surgical Caching
│ ├── EventLogger.ts # Centralized event logging helper │ ├── EventLogger.ts # Centralized event logging helper
│ ├── CatManager.ts # TheCatAPI HTTP request helper
│ ├── TwitchManager.ts # Batch Polling & Transaction logic │ ├── TwitchManager.ts # Batch Polling & Transaction logic
│ ├── TwitchMonitor.ts # IRC Monitoring & Webhook reuse │ ├── TwitchMonitor.ts # IRC Monitoring & Webhook reuse
│ ├── TwitchCache.ts # IRC Message FIFO Cache │ ├── TwitchCache.ts # IRC Message FIFO Cache

View File

@@ -72,6 +72,8 @@ npm run deploy
### Öffentlich ### Öffentlich
- `/ping` Latenz test - `/ping` Latenz test
- `/help` Alle Befehle - `/help` Alle Befehle
- `/cat [typ]` Zufälliges Katzenbild oder Katzen-GIF (Auswahl: Bild / GIF)
- `/catgif` Zufälliges Katzen-GIF direkt posten
- `/twitch online <channel>` Twitch-Status - `/twitch online <channel>` Twitch-Status
- `/twitch list` Überwachte Kanäle - `/twitch list` Überwachte Kanäle
- `/twitch help` Twitch-Hilfe - `/twitch help` Twitch-Hilfe

View File

@@ -0,0 +1,40 @@
import { SlashCommandBuilder, EmbedBuilder } from 'discord.js';
import { Command } from '../../structures/Command.js';
import { CatManager } from '../../structures/CatManager.js';
const command: Command = {
data: new SlashCommandBuilder()
.setName('cat')
.setDescription('Postet ein zufälliges Katzenbild oder Katzen-GIF.')
.addStringOption(option =>
option.setName('typ')
.setDescription('Wähle zwischen Bild oder GIF')
.setRequired(false)
.addChoices(
{ name: 'Bild', value: 'image' },
{ name: 'GIF', value: 'gif' }
))
.setDMPermission(true),
category: 'Public',
async execute(interaction: any) {
const type = (interaction.options.getString('typ') as 'image' | 'gif') || 'image';
await interaction.deferReply();
const imageUrl = await CatManager.fetchCatImage(type);
if (!imageUrl) {
await interaction.editReply('❌ Konnte kein Katzenbild laden. Bitte versuche es später erneut.');
return;
}
const embed = new EmbedBuilder()
.setTitle(type === 'gif' ? '🐱 Zufälliges Katzen-GIF' : '🐱 Zufälliges Katzenbild')
.setURL(imageUrl)
.setImage(imageUrl)
.setColor(0xf39c12)
.setTimestamp();
await interaction.editReply({ embeds: [embed] });
},
};
export default command;

View File

@@ -0,0 +1,31 @@
import { SlashCommandBuilder, EmbedBuilder } from 'discord.js';
import { Command } from '../../structures/Command.js';
import { CatManager } from '../../structures/CatManager.js';
const command: Command = {
data: new SlashCommandBuilder()
.setName('catgif')
.setDescription('Postet direkt ein zufälliges Katzen-GIF.')
.setDMPermission(true),
category: 'Public',
async execute(interaction: any) {
await interaction.deferReply();
const imageUrl = await CatManager.fetchCatImage('gif');
if (!imageUrl) {
await interaction.editReply('❌ Konnte kein Katzen-GIF laden. Bitte versuche es später erneut.');
return;
}
const embed = new EmbedBuilder()
.setTitle('🐱 Zufälliges Katzen-GIF')
.setURL(imageUrl)
.setImage(imageUrl)
.setColor(0xf39c12)
.setTimestamp();
await interaction.editReply({ embeds: [embed] });
},
};
export default command;

View File

@@ -0,0 +1,26 @@
export class CatManager {
static async fetchCatImage(type: 'image' | 'gif' = 'image'): Promise<string | null> {
const apiKey = process.env.THECATAPI_KEY || '';
const mimeTypes = type === 'gif' ? 'gif' : 'jpg,png';
const url = `https://api.thecatapi.com/v1/images/search?mime_types=${mimeTypes}`;
try {
const headers: Record<string, string> = {};
if (apiKey) {
headers['x-api-key'] = apiKey;
}
const response = await fetch(url, { headers });
if (!response.ok) return null;
const data: any = await response.json();
if (Array.isArray(data) && data.length > 0 && data[0].url) {
return data[0].url;
}
return null;
} catch (error) {
console.error('[CAT] Error fetching cat image:', error);
return null;
}
}
}