Bir Discord geçici ses kanalı (temp voice) sistemi, kalabalık sunucularda boş duran onlarca sabit ses odasını ortadan kaldırır: kullanıcı tek bir "oda aç" kanalına girer, bot anında ona özel bir ses kanalı oluşturur ve içine taşır; oda boşalınca da kendiliğinden silinir. Bu rehberde bu sistemi discord.js v14 ile sıfırdan kuracağız. Mantık aslında tek bir olaya dayanır: voiceStateUpdate.
Sistem nasıl çalışır?
Fikir basit ama akışı netleştirmek önemli:
- Sunucuda bir "lobi" ses kanalı bulunur (örn. "➕ Oda Aç"). Kimse burada kalmaz; burası sadece bir tetikleyicidir.
- Bir kullanıcı bu kanala girince bot, aynı kategorinin altında ona ait yeni bir ses kanalı oluşturur ve kullanıcıyı oraya taşır.
- Oda sahibine, kanal üzerinde yönetim yetkisi verilir (yeniden adlandırma, kişi atma, limit koyma).
- Odadaki son kişi de ayrılınca bot kanalı siler, böylece arkada çöp kanal birikmez.
Gereksinimler ve intent'ler
Ses durumu olaylarını alabilmek için botun GuildVoiceStates intent'ine ihtiyacı var. Kanal oluşturma ve üyeyi taşıma için botun rolü Kanalları Yönet ve Üyeleri Taşı yetkilerine sahip olmalı. Önce istemciyi kuralım:
// index.js
const {
Client, GatewayIntentBits, ChannelType, PermissionFlagsBits,
} = require('discord.js');
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildVoiceStates,
],
});
// "Oda Aç" lobi kanalinin ID'si
const LOBBY_ID = '123456789012345678';
// Olusturdugumuz gecici kanallar: channelId -> ownerId
const tempChannels = new Map();
client.login(process.env.TOKEN);
tempChannels haritası kritik: bot, yalnızca kendi oluşturduğu kanalları silmeli. Sunucudaki diğer ses kanallarına dokunmamak için bu kayıt şart.
Kanala girince oda açmak
voiceStateUpdate olayı her ses durumu değişiminde iki parametre verir: oldState (önceki durum) ve newState (yeni durum). Kullanıcının lobiye girdiğini, newState.channelId'nin lobi ID'sine eşit olmasından anlarız:
client.on('voiceStateUpdate', async (oldState, newState) => {
// Kullanici lobi kanalina girdi mi?
if (newState.channelId !== LOBBY_ID) return;
const { guild, member } = newState;
const channel = await guild.channels.create({
name: `${member.displayName} odasi`,
type: ChannelType.GuildVoice,
parent: newState.channel.parentId, // lobi ile ayni kategori
permissionOverwrites: [
{
id: member.id,
allow: [
PermissionFlagsBits.ManageChannels,
PermissionFlagsBits.MoveMembers,
],
},
],
});
tempChannels.set(channel.id, member.id);
await member.voice.setChannel(channel);
});
Burada parent olarak lobinin kategorisini verdik; böylece yeni odalar düzenli biçimde aynı klasörün altında toplanır. permissionOverwrites ile de oda sahibine kendi kanalını yönetme yetkisi tanıdık. Son satırda member.voice.setChannel kullanıcıyı yeni odaya çeker.
Boş odayı otomatik silmek
İkinci bir voiceStateUpdate dinleyicisi, bir kanaldan ayrılma anını yakalar. oldState.channel dolu ve içinde kimse kalmadıysa (members.size === 0) ve bu kanal bizim kayıtlı geçici kanallarımızdan biriyse, siliyoruz:
client.on('voiceStateUpdate', async (oldState) => {
const left = oldState.channel;
if (!left) return;
// Bizim olusturdugumuz bir kanal mi ve artik bos mu?
if (tempChannels.has(left.id) && left.members.size === 0) {
await left.delete().catch(() => {});
tempChannels.delete(left.id);
}
});
.catch(() => {}) önemli: kanal başka bir nedenle (manuel silme, izin değişikliği) zaten yok olmuşsa botun çökmesini önler. tempChannels.delete ile de haritayı temiz tutarız.
İnce ayarlar ve dayanıklılık
Temel sistem çalışıyor; gerçek bir sunucuda işe yarayan birkaç ekleme:
- Kullanıcı limiti:
createiçineuserLimit: 5ekleyerek odaları küçük tutabilirsin. - Spam koruması: Kullanıcı odalar arasında hızlıca girip çıkarsa çok kanal açılabilir. Kişi başına bekleme (cooldown) ekle.
- Yeniden başlatma: Bot kapanıp açıldığında
tempChannelsharitası sıfırlanır. Kategoriyi tarayıp boş kalmış eski geçici kanalları açılışta temizleyen bir kontrol koymak iyi olur. - İsim/limit komutu: Slash komutlarıyla oda sahibine kanalını yeniden adlandırma veya kilitleme imkânı verebilirsin.
Sık Sorulan Sorular
Bot kanalları açmıyor, neden?
En sık iki sebep: botun rolünde Kanalları Yönet ve Üyeleri Taşı yetkisinin olmaması, ya da GuildVoiceStates intent'ini eklemeyi unutmak. Ayrıca botun rolü, kategori izinlerine göre o kategoride kanal oluşturabilmeli.
Yüzlerce kişilik sunucuda performans sorun olur mu?
Hayır. Olay tabanlı çalıştığı için yalnızca biri lobiye girince veya bir kanaldan çıkınca tetiklenir. Kanal oluşturma/silme istekleri Discord API rate limitlerine tabidir ama normal kullanımı rahat karşılar.
Veritabanına gerek var mı?
Küçük sunucular için hayır, bellekteki Map yeterli. Çok büyük veya çok botlu kurulumlarda, yeniden başlatmaya dayanıklılık için geçici kanal ID'lerini SQLite gibi hafif bir veritabanında tutmak mantıklıdır.
Topluluğun için hazır ve dayanıklı bir temp voice sistemi mi istiyorsun? Geçici ses kanalları, oda paneli ve moderasyon entegrasyonuyla birlikte özel Discord botları yazıyorum — benimle iletişime geç.