Een Discord tijdelijk spraakkanaal (temp voice) systeem ruimt de tientallen lege, vaste spraakkamers op die zich op drukke servers opstapelen: een gebruiker komt in één "kamer aanmaken"-kanaal, de bot bouwt direct een privé-spraakkanaal voor hem en verplaatst hem ernaartoe, en het kanaal verwijdert zichzelf zodra het leeg is. In deze gids bouwen we dat systeem vanaf nul met discord.js v14. Alles draait eigenlijk om één gebeurtenis: voiceStateUpdate.
Hoe het systeem werkt
Het idee is simpel, maar het helpt om de flow expliciet te maken:
- De server heeft één "lobby"-spraakkanaal (bijv. "➕ Kamer aanmaken"). Niemand blijft hier; het is slechts een trigger.
- Wanneer een gebruiker dat kanaal binnenkomt, maakt de bot een nieuw spraakkanaal voor hem aan onder dezelfde categorie en verplaatst de gebruiker erin.
- De kamereigenaar krijgt beheerrechten over het kanaal (hernoemen, kicken, een limiet instellen).
- Als de laatste persoon vertrekt, verwijdert de bot het kanaal, zodat er geen rommelkanalen achterblijven.
Vereisten en intents
Om spraakstatus-gebeurtenissen te ontvangen heeft de bot de GuildVoiceStates-intent nodig. Om kanalen te maken en leden te verplaatsen, moet de rol van de bot de rechten Kanalen beheren en Leden verplaatsen hebben. Laten we eerst de client opzetten:
// index.js
const {
Client, GatewayIntentBits, ChannelType, PermissionFlagsBits,
} = require('discord.js');
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildVoiceStates,
],
});
// ID van het "Kamer aanmaken"-lobbykanaal
const LOBBY_ID = '123456789012345678';
// Tijdelijke kanalen die we maakten: channelId -> ownerId
const tempChannels = new Map();
client.login(process.env.TOKEN);
De tempChannels-map is cruciaal: de bot mag alleen kanalen verwijderen die hij zelf heeft gemaakt. Dit register voorkomt dat hij andere spraakkanalen op de server aanraakt.
Een kamer aanmaken bij binnenkomst
De gebeurtenis voiceStateUpdate wordt bij elke spraakstatuswijziging geactiveerd met twee parameters: oldState (de vorige status) en newState (de nieuwe). We weten dat een gebruiker de lobby is binnengekomen wanneer newState.channelId gelijk is aan de lobby-ID:
client.on('voiceStateUpdate', async (oldState, newState) => {
// Is de gebruiker het lobbykanaal binnengekomen?
if (newState.channelId !== LOBBY_ID) return;
const { guild, member } = newState;
const channel = await guild.channels.create({
name: `Kamer van ${member.displayName}`,
type: ChannelType.GuildVoice,
parent: newState.channel.parentId, // zelfde categorie als de lobby
permissionOverwrites: [
{
id: member.id,
allow: [
PermissionFlagsBits.ManageChannels,
PermissionFlagsBits.MoveMembers,
],
},
],
});
tempChannels.set(channel.id, member.id);
await member.voice.setChannel(channel);
});
Hier geven we de categorie van de lobby door als parent, zodat de nieuwe kamers netjes gegroepeerd blijven onder dezelfde map. Met permissionOverwrites geven we de eigenaar het recht om zijn eigen kanaal te beheren. De laatste regel, member.voice.setChannel, trekt de gebruiker de nieuwe kamer in.
De lege kamer automatisch verwijderen
Een tweede voiceStateUpdate-listener vangt het moment waarop iemand een kanaal verlaat. Als oldState.channel bestaat en er niemand meer in zit (members.size === 0) en dat kanaal een van onze bijgehouden tijdelijke kanalen is, verwijderen we het:
client.on('voiceStateUpdate', async (oldState) => {
const left = oldState.channel;
if (!left) return;
// Is het er een van ons en nu leeg?
if (tempChannels.has(left.id) && left.members.size === 0) {
await left.delete().catch(() => {});
tempChannels.delete(left.id);
}
});
De .catch(() => {}) is belangrijk: als het kanaal om een andere reden al weg is (handmatig verwijderd, een rechtenwijziging), voorkomt het dat de bot crasht. De tempChannels.delete-aanroep houdt de map schoon.
Afwerking en robuustheid
Het basissysteem werkt; een paar toevoegingen die het bruikbaar maken op een echte server:
- Gebruikerslimiet: voeg
userLimit: 5toe aancreateom kamers klein te houden. - Spambescherming: als een gebruiker snel in- en uitloopt, kunnen er veel kanalen ontstaan. Voeg een cooldown per gebruiker toe.
- Herstarts: bij een herstart van de bot wordt de
tempChannels-map gereset. Het is verstandig om bij het opstarten de categorie te scannen en achtergebleven lege tijdelijke kanalen op te ruimen. - Naam-/limietcommando's: met slash-commando's kun je de eigenaar zijn kanaal laten hernoemen of vergrendelen.
Veelgestelde vragen
De bot maakt geen kanalen aan, waarom?
De twee meest voorkomende oorzaken: de rol van de bot mist Kanalen beheren en Leden verplaatsen, of je bent vergeten de GuildVoiceStates-intent toe te voegen. Bovendien moet de rol van de bot in die categorie kanalen mogen aanmaken volgens de permissie-overschrijvingen.
Wordt prestatie een probleem op een server met honderden leden?
Nee. Omdat het event-gedreven is, wordt het alleen geactiveerd als iemand de lobby binnenkomt of een kanaal verlaat. De aanmaak-/verwijderverzoeken vallen onder de rate limits van de Discord-API, maar normaal gebruik blijft daar ruim binnen.
Heb ik een database nodig?
Voor kleine servers niet — een Map in het geheugen volstaat. Voor zeer grote of multi-bot-opstellingen zorgt het opslaan van de tijdelijke kanaal-ID's in een lichte database zoals SQLite ervoor dat het systeem herstarts overleeft.
Wil je een kant-en-klaar, robuust temp voice-systeem voor je community? Ik bouw Discord-bots op maat met tijdelijke spraakkanalen, een kamerbeheerpaneel en moderatie-integratie — neem contact op.