aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Discord Botları

discord.py Slash Komut: app_commands ve Cog Rehberi

Modern bir Discord botu yazıyorsan discordpy slash komut yapısını öğrenmek artık seçim değil, zorunluluk. Eski !komut tarzı metin tabanlı (prefix) komutlar yerini, Discord'un kullanıcıya yazarken otomatik tamamlama ve parametre ipuçları sunduğu slash komutlarına bıraktı. discord.py 2.x ile birlikte gelen app_commands modülü bu işin resmi yoludur ve doğru kurulduğunda hem temiz hem de bakımı kolay bir kod tabanı verir.

Bu rehberde sıfırdan başlayıp parametreli komutlara, Cog'larla modüler yapıya ve hata yönetimine kadar ilerleyeceğiz. Tüm örnekler discord.py 2.x ve Python 3.9+ ile çalışır.

Ortam ve temel bot iskeleti

Önce kütüphaneyi güncel sürümle kuralım. Eski sürümlerde app_commands bulunmaz, bu yüzden 2.x şart:

pip install -U "discord.py>=2.3"

Şimdi minimal bir bot. commands.Bot sınıfı, slash komutları tutan bir CommandTree nesnesini bot.tree üzerinden otomatik sağlar:

import discord
from discord import app_commands
from discord.ext import commands

intents = discord.Intents.default()
bot = commands.Bot(command_prefix="!", intents=intents)

@bot.event
async def on_ready():
    print(f"{bot.user} olarak giriş yapıldı")

bot.run("TOKEN")

Slash komutları için message_content intent'ine ihtiyacın yok; bu, prefix komutlarına özgüdür. Token'ı asla koda gömme, bir ortam değişkeninden oku.

İlk slash komutun ve senkronizasyon

En sade slash komut bot.tree.command dekoratörüyle tanımlanır. İlk parametre her zaman discord.Interaction tipindedir:

@bot.tree.command(name="selam", description="Selam verir")
async def selam(interaction: discord.Interaction):
    await interaction.response.send_message(
        f"Selam, {interaction.user.mention}!"
    )

Burada kritik nokta şudur: komutu tanımlamak yetmez, Discord'a senkronize etmen gerekir. Global senkronizasyon (await bot.tree.sync()) tüm sunucularda çalışır ama yayılması bir saate kadar sürebilir. Geliştirme sırasında bu çok yavaştır; bu yüzden tek bir test sunucusuna senkronize et — bu anında olur:

GUILD = discord.Object(id=123456789012345678)  # test sunucu ID'si

@bot.event
async def on_ready():
    bot.tree.copy_global_to(guild=GUILD)
    await bot.tree.sync(guild=GUILD)
    print("Komutlar sunucuya senkronize edildi")

Uyarı: sync() bir API çağrısıdır ve sınırlıdır. Botu her başlattığında körü körüne sync() çağırma; sadece komutlar gerçekten değiştiğinde çalıştır. Yaygın bir desen, senkronizasyonu yalnızca sahibin tetikleyebileceği gizli bir prefix komutuna bağlamaktır.

Parametreler, açıklamalar ve seçenekler

Slash komutların gücü tip belirteçli (type-hinted) parametrelerden gelir. discord.py, Python tip ipuçlarını okur ve doğru giriş alanını üretir: int sayı, discord.Member kullanıcı seçici, bool aç/kapa olur.

@bot.tree.command(name="topla", description="İki sayıyı toplar")
@app_commands.describe(a="Birinci sayı", b="İkinci sayı")
async def topla(interaction: discord.Interaction, a: int, b: int):
    await interaction.response.send_message(f"{a} + {b} = {a + b}")

@app_commands.describe her parametrenin yanında görünen açıklamayı belirler — kullanıcı deneyimi için önemlidir. Sabit seçenekler sunmak istersen Choice kullan:

@bot.tree.command(name="zorluk", description="Zorluk seç")
@app_commands.describe(seviye="Oynanış zorluğu")
@app_commands.choices(seviye=[
    app_commands.Choice(name="Kolay", value="easy"),
    app_commands.Choice(name="Zor", value="hard"),
])
async def zorluk(interaction: discord.Interaction,
                 seviye: app_commands.Choice[str]):
    await interaction.response.send_message(
        f"Seçilen: {seviye.name} ({seviye.value})"
    )

Cevabın hesaplanması uzun sürecekse (örneğin bir API çağrısı), 3 saniyelik yanıt süresini aşmamak için önce await interaction.response.defer() çağır, ardından await interaction.followup.send(...) ile sonucu gönder.

Cog'larla modüler yapı

Tek dosyada onlarca komut yönetmek hızla dağılır. commands.Cog, ilgili komutları sınıf halinde gruplayıp ayrı dosyalara (extension) bölmeni sağlar. Bir Cog içinde @app_commands.command dekoratörünü kullanırsın ve ilk parametre self olur:

# cogs/araclar.py
import discord
from discord import app_commands
from discord.ext import commands

class Araclar(commands.Cog):
    def __init__(self, bot: commands.Bot):
        self.bot = bot

    @app_commands.command(name="ping", description="Gecikmeyi gösterir")
    async def ping(self, interaction: discord.Interaction):
        gecikme = round(self.bot.latency * 1000)
        await interaction.response.send_message(f"Pong! {gecikme}ms")

async def setup(bot: commands.Bot):
    await bot.add_cog(Araclar(bot))

Extension'ları yüklemenin doğru yeri setup_hook'tur; bot bağlanmadan önce çalışır. Botu bir alt sınıfa taşımak en temiz yaklaşımdır:

class Bot(commands.Bot):
    async def setup_hook(self):
        await self.load_extension("cogs.araclar")
        await self.tree.sync()  # geliştirmede guild'e senkronize et

intents = discord.Intents.default()
bot = Bot(command_prefix="!", intents=intents)
bot.run("TOKEN")

Birden çok komutu ortak bir ad altında toplamak için app_commands.Group kullanabilirsin; böylece /ayar dil ve /ayar bildirim gibi alt komutlar oluşur.

Hata yönetimi

Komut içinde bir istisna oluşursa kullanıcı sessizce başarısızlığı görür. Tüm slash komutları için merkezi bir hata işleyici tanımlamak en iyisidir. CommandTree bunun için bir error dekoratörü sunar:

@bot.tree.error
async def on_app_command_error(
    interaction: discord.Interaction,
    error: app_commands.AppCommandError,
):
    if isinstance(error, app_commands.MissingPermissions):
        mesaj = "Bu komut için yetkin yok."
    else:
        mesaj = "Bir hata oluştu, tekrar dene."
    # Yanıt henüz gönderilmediyse response, gönderildiyse followup
    if interaction.response.is_done():
        await interaction.followup.send(mesaj, ephemeral=True)
    else:
        await interaction.response.send_message(mesaj, ephemeral=True)

ephemeral=True mesajı yalnızca komutu çalıştıran kişiye gösterir; hata bildirimleri için idealdir. Yetki kontrolünü komuta @app_commands.checks.has_permissions(...) ile ekleyebilir, kontrol başarısız olunca yukarıdaki işleyicide yakalayabilirsin.

Sık Sorulan Sorular

Slash komutlarım Discord'da neden görünmüyor?

Neredeyse her zaman senkronizasyon sorunudur. Global sync() yayılması zaman alır; geliştirmede komutları doğrudan test sunucuna (guild=...) senkronize et, anında görünürler. Ayrıca botun uygulamasında applications.commands kapsamıyla davet edildiğinden emin ol.

app_commands ile eski commands.command arasındaki fark nedir?

commands.command prefix tabanlı metin komutlarıdır (!komut). app_commands ise Discord'un yerel slash komutlarıdır: otomatik tamamlama, tip doğrulama ve görsel parametre alanları sunar. Yeni botlarda slash komutları tercih edilir.

Her açılışta sync çağırmalı mıyım?

Hayır. sync() hız sınırlıdır ve gereksiz çağrılar engellenmene yol açabilir. Yalnızca komut tanımları değiştiğinde senkronize et; üretimde bunu manuel bir sahip komutuna bağlamak yaygın bir pratiktir.

Botunu bir üst seviyeye taşımak mı istiyorsun? Slash komutlardan moderasyon sistemlerine, müzik altyapısına ve özel panel entegrasyonlarına kadar discord.py projelerinde yardımcı olabilirim. Fikrini paylaş, birlikte hayata geçirelim: benimle iletişime geç.

Bu kategorideki tüm yazılar →

Devamı için