Feat: Multi-bot support - separate Discord bot per plugin

Each plugin gets its own Discord client and token:
- DISCORD_TOKEN_JUKEBOX (fallback: DISCORD_TOKEN) → Soundboard
- DISCORD_TOKEN_RADIO → Radio

discord.ts: factory createClient() instead of singleton
plugin.ts: per-plugin context storage via registerPlugin(p, ctx)
index.ts: creates/logins/shutdowns multiple bots independently

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Daniel 2026-03-06 10:56:22 +01:00
parent fd0a95be8e
commit 3cd9f6f169
3 changed files with 78 additions and 44 deletions

View file

@ -1,13 +1,14 @@
import { Client, GatewayIntentBits, Partials } from 'discord.js';
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildVoiceStates,
GatewayIntentBits.DirectMessages,
GatewayIntentBits.MessageContent,
],
partials: [Partials.Channel],
});
export default client;
/** Create a new Discord client instance (one per bot token). */
export function createClient(): Client {
return new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildVoiceStates,
GatewayIntentBits.DirectMessages,
GatewayIntentBits.MessageContent,
],
partials: [Partials.Channel],
});
}

View file

@ -30,9 +30,11 @@ export interface PluginContext {
}
const loadedPlugins: Plugin[] = [];
const pluginContexts = new Map<string, PluginContext>();
export function registerPlugin(plugin: Plugin): void {
export function registerPlugin(plugin: Plugin, ctx: PluginContext): void {
loadedPlugins.push(plugin);
pluginContexts.set(plugin.name, ctx);
console.log(`[Plugin] Registered: ${plugin.name} v${plugin.version}`);
}
@ -40,6 +42,10 @@ export function getPlugins(): Plugin[] {
return [...loadedPlugins];
}
export function getPluginCtx(pluginName: string): PluginContext | undefined {
return pluginContexts.get(pluginName);
}
// ── Voice claim system ──
// Only one plugin can use voice per guild. When a new plugin claims voice,
// the previous claimant's cleanup callback is invoked automatically.