Fix: Voice claim system - radio stops when soundboard plays

Plugins now claim voice per guild via claimVoice(). When soundboard
plays a sound, radio's cleanup runs automatically (kills ffmpeg,
broadcasts SSE stop event). Fixes stale "now playing" UI on tab switch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Daniel 2026-03-06 10:21:11 +01:00
parent e0635b30ef
commit 1e4ccfb1f1
3 changed files with 30 additions and 0 deletions

View file

@ -39,3 +39,25 @@ export function registerPlugin(plugin: Plugin): void {
export function getPlugins(): Plugin[] {
return [...loadedPlugins];
}
// ── 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.
type VoiceClaimCleanup = () => void;
const voiceClaims = new Map<string, { plugin: string; cleanup: VoiceClaimCleanup }>();
export function claimVoice(guildId: string, pluginName: string, cleanup: VoiceClaimCleanup): void {
const existing = voiceClaims.get(guildId);
if (existing && existing.plugin !== pluginName) {
console.log(`[Voice] ${pluginName} claims guild ${guildId}, releasing ${existing.plugin}`);
existing.cleanup();
}
voiceClaims.set(guildId, { plugin: pluginName, cleanup });
}
export function releaseVoice(guildId: string, pluginName: string): void {
const claim = voiceClaims.get(guildId);
if (claim?.plugin === pluginName) {
voiceClaims.delete(guildId);
}
}