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
All checks were successful
Auto Build and Push Docker Image / build (push) Successful in 7s
This commit is contained in:
@@ -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
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
40
src/commands/utility/cat.ts
Normal file
40
src/commands/utility/cat.ts
Normal 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;
|
||||||
31
src/commands/utility/catgif.ts
Normal file
31
src/commands/utility/catgif.ts
Normal 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;
|
||||||
26
src/structures/CatManager.ts
Normal file
26
src/structures/CatManager.ts
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user