Etkileşimler: slash komut, buton, menü, modal
Micup’taki her bot slash komut kaydedebilir, gizli yanıt verebilir, mesajına buton ve seçim menüsü koyabilir ve modal açabilir. Onay ya da başvuru gerekmez. Alan adları, tip numaraları ve rotalar Discord ile aynıdır; discord.js ya da discord.py ile yazdığın bot birkaç ayarla çalışır. Bot oluşturmayı bilmiyorsan önce Hızlı başlangıç sayfasını oku.
Ayrıntılı başvuru: Uygulama komutları, Etkileşimler, Mesaj bileşenleri.
Nasıl çalışır
Section titled “Nasıl çalışır”- Botun komutlarını kaydeder: tüm sunucular için global ya da tek sunucu için.
- Kullanıcı
/yazıp komutu seçer, butona basar ya da menüden seçim yapar. - Micup bunu botun tek bir gateway oturumuna
INTERACTION_CREATEolarak gönderir. Olayın içinde birtokenvardır. - Bot 3 saniye içinde ilk yanıtı verir. Uzun sürecek işte önce “düşünüyor” (defer) yanıtı ver.
- Aynı token ile 15 dakika boyunca ilk yanıtı düzenleyebilir ve en çok 20 takip mesajı gönderebilirsin.
Gizli yanıt (flags: 64) yalnız komutu kullanan kişiye görünür; kanala mesaj olarak hiç yazılmaz, aramada, bildirimde ve okunmamış sayısında yer almaz.
Kütüphane ayarları
Section titled “Kütüphane ayarları”Micup REST’te /v1, gateway’de v=1 kullanır. API adresini sabitleme; Micup’ın keşif yanıtındaki endpoints.api_public değerini oku.
| Kütüphane | Ayar |
|---|---|
| discord.js 14 | new Client({rest: {api, version: '1'}, ws: {version: 1}}); gateway adresini kendisi GET /v1/gateway/bot ile alır |
| discord.py 2 | discord.http.Route.BASE, discord.http.INTERNAL_API_VERSION = 1 ve DiscordWebSocket.DEFAULT_GATEWAY |
Kütüphanelerin gönderdiği name_localizations, description_localizations ve false değerli nsfw kabul edilir ama saklanmaz (her dilde varsayılan ad görünür); nsfw: true 400 döner. contexts Discord’daki gibi uygulanır: 0 yoksa komut sunucularda görünmez, 1 varsa genel komut botla birebir DM’de çalışır. integration_types yok sayılır.
discord.js örneği
Section titled “discord.js örneği”/yardım komutu gizli bir yanıtla kategori menüsü, bir buton ve bir bağlantı butonu gösterir. Menüden seçim mesajı günceller, buton bir modal açar, modal gönderilince bot önce “düşünüyor” yanıtı verip sonra cevabı yazar. npm install discord.js ile kur, MICUP_TOKEN ve SUNUCU_ID ortam değişkenlerini ver, node bot.mjs ile çalıştır.
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, Client, Events, GatewayIntentBits, MessageFlags, ModalBuilder, Routes, SlashCommandBuilder, StringSelectMenuBuilder, TextInputBuilder, TextInputStyle,} from 'discord.js';
const {MICUP_TOKEN, SUNUCU_ID} = process.env;const kesif = await (await fetch('https://micup.gg/.well-known/fluxer')).json();const api = kesif.endpoints.api_public.replace(/\/$/, '');
const KATEGORILER = { mod: 'Moderasyon: /uyar, /sustur, /at', seviye: 'Seviye: /seviye, /top',};
const client = new Client({ intents: [GatewayIntentBits.Guilds], rest: {api, version: '1'}, ws: {version: 1},});
client.once(Events.ClientReady, async (c) => { const komutlar = [new SlashCommandBuilder().setName('yardım').setDescription('Komut kategorilerini gösterir').toJSON()]; await c.rest.put(Routes.applicationGuildCommands(c.application.id, SUNUCU_ID), {body: komutlar}); console.log(`${c.user.username} hazır`);});
client.on(Events.InteractionCreate, async (etkilesim) => { try { if (etkilesim.isChatInputCommand() && etkilesim.commandName === 'yardım') { const menu = new StringSelectMenuBuilder() .setCustomId('yardim:kategori') .setPlaceholder('Bir kategori seçin...') .addOptions({label: 'Moderasyon', value: 'mod'}, {label: 'Seviye', value: 'seviye'}); const butonlar = new ActionRowBuilder().addComponents( new ButtonBuilder().setCustomId('yardim:oneri').setLabel('Öneri gönder').setStyle(ButtonStyle.Primary), new ButtonBuilder().setURL('https://micup.gg/docs/').setLabel('Belgeler').setStyle(ButtonStyle.Link), ); await etkilesim.reply({ content: 'Bir kategori seç:', components: [new ActionRowBuilder().addComponents(menu), butonlar], flags: MessageFlags.Ephemeral, }); } else if (etkilesim.isStringSelectMenu() && etkilesim.customId === 'yardim:kategori') { const metin = KATEGORILER[etkilesim.values[0]]; if (metin === undefined) return; await etkilesim.update({content: metin}); } else if (etkilesim.isButton() && etkilesim.customId === 'yardim:oneri') { const alan = new TextInputBuilder() .setCustomId('metin') .setLabel('Önerin') .setStyle(TextInputStyle.Paragraph) .setMaxLength(500); const modal = new ModalBuilder() .setCustomId('yardim:oneri-formu') .setTitle('Öneri') .addComponents(new ActionRowBuilder().addComponents(alan)); await etkilesim.showModal(modal); } else if (etkilesim.isModalSubmit() && etkilesim.customId === 'yardim:oneri-formu') { await etkilesim.deferReply({flags: MessageFlags.Ephemeral}); const oneri = etkilesim.fields.getTextInputValue('metin'); console.log('Yeni öneri, uzunluk:', oneri.length); await etkilesim.editReply({content: 'Teşekkürler, önerin alındı.'}); } } catch (hata) { console.error('Etkileşim yanıtlanamadı:', hata.code ?? hata.message); }});
client.login(MICUP_TOKEN);etkilesim.reply, update, showModal ve deferReply ilk yanıttır ve 3 saniye içinde gitmelidir; editReply ve followUp 15 dakika boyunca çalışır.
discord.py örneği
Section titled “discord.py örneği”Aynı akış discord.py 2 ile, kütüphanenin kendi CommandTree, View ve Modal sınıflarıyla. discord.py 2.5 ve sonrası her ilk yanıtta yanıt gövdesini ister (with_response=1); Micup bu gövdeyi Discord’daki gibi döndürür, gizli mesajdaki buton ve menü de View geri çağrısına ulaşır. pip install discord.py ile kur, python bot.py ile çalıştır.
import jsonimport osimport urllib.request
import discordimport discord.gatewayimport discord.httpimport yarlfrom discord import app_commands
TOKEN = os.environ["MICUP_TOKEN"]SUNUCU = discord.Object(id=int(os.environ["SUNUCU_ID"]))
with urllib.request.urlopen("https://micup.gg/.well-known/fluxer", timeout=15) as yanit: API = json.load(yanit)["endpoints"]["api_public"].rstrip("/")
discord.http.INTERNAL_API_VERSION = 1discord.http.Route.BASE = f"{API}/v1"istek = urllib.request.Request(f"{API}/v1/gateway/bot", headers={"Authorization": f"Bot {TOKEN}"})with urllib.request.urlopen(istek, timeout=15) as yanit: discord.gateway.DiscordWebSocket.DEFAULT_GATEWAY = yarl.URL(json.load(yanit)["url"])
KATEGORILER = {"mod": "Moderasyon: /uyar, /sustur, /at", "seviye": "Seviye: /seviye, /top"}
class OneriFormu(discord.ui.Modal, title="Öneri"): metin = discord.ui.TextInput(label="Önerin", style=discord.TextStyle.paragraph, max_length=500)
async def on_submit(self, etkilesim): await etkilesim.response.defer(ephemeral=True, thinking=True) print("Yeni öneri, uzunluk:", len(self.metin.value)) await etkilesim.edit_original_response(content="Teşekkürler, önerin alındı.")
class YardimMenusu(discord.ui.View): @discord.ui.select( custom_id="yardim:kategori", placeholder="Bir kategori seçin...", options=[ discord.SelectOption(label="Moderasyon", value="mod"), discord.SelectOption(label="Seviye", value="seviye"), ], ) async def kategori(self, etkilesim, secim): await etkilesim.response.edit_message(content=KATEGORILER[secim.values[0]])
@discord.ui.button(label="Öneri gönder", custom_id="yardim:oneri", style=discord.ButtonStyle.primary) async def oneri(self, etkilesim, buton): await etkilesim.response.send_modal(OneriFormu())
client = discord.Client(intents=discord.Intents.default())agac = app_commands.CommandTree(client)
@agac.command(name="yardım", description="Komut kategorilerini gösterir", guild=SUNUCU)async def yardim(etkilesim): gorunum = YardimMenusu(timeout=None) gorunum.add_item(discord.ui.Button(label="Belgeler", url="https://micup.gg/docs/")) await etkilesim.response.send_message("Bir kategori seç:", view=gorunum, ephemeral=True)
@client.eventasync def on_ready(): await agac.sync(guild=SUNUCU) print(f"{client.user} hazır")
client.run(TOKEN)timeout=None menüyü bot çalıştığı sürece açık tutar; discord.py’nin varsayılanı 180 saniyedir. agac.sync sunucu komutlarını yazar ve dakikada 2 yazımla sınırlıdır; komutlar değişmediyse her açılışta çağırmak gerekmez.
Yanıt tipleri: 4 mesajla yanıt, 5 “düşünüyor”, 6 bileşeni sessizce onayla, 7 bileşenin olduğu mesajı güncelle, 8 otomatik tamamlama önerileri, 9 modal aç. Tam liste.
Otomatik tamamlama
Section titled “Otomatik tamamlama”Bir STRING, INTEGER ya da NUMBER seçeneğine autocomplete: true verirsen kullanıcı yazarken tip 4 etkileşim gelir. Odaktaki seçeneğin value alanı yazılan ham metindir. 3 saniye içinde tip 8 ile en çok 25 öneri döndür; bu yanıt ertelenemez. Aynı seçenekte choices ile autocomplete birlikte kullanılamaz.
Discord’dan farklar
Section titled “Discord’dan farklar”| Konu | Micup |
|---|---|
| Sürüm | REST /v1, gateway v=1 |
| HTTP uç noktası | Yok; her etkileşim gateway’den gelir |
| Bot üyeliği | Bot sunucuda üye olmalı; herkese açık yanıt için kanalda SEND_MESSAGES gerekir |
dm_permission alanı | Varsayılanı false; DM’de yalnız kullanıcı ile bot arasındaki birebir sohbette çalışır |
| Ertelenmiş herkese açık yanıt | Kanalda yer tutucu mesaj yok; ilk @original düzenlemesi mesajı oluşturur |
| Gizli yanıt | Kanala mesaj olarak yazılmaz, yalnız kullanıcının oturumuna gider |
| Components v2 | Sunucu content alanına yedek metin koyar; bot bunu yok sayar. Bugün kapalı |
| Ek takip yolu | POST /v1/interactions/{id}/followups, bot tokenı ve Idempotency-Key ile |
| Komut yazımı | If-Match isteğe bağlı |
| Yerelleştirme | name_localizations ve description_localizations saklanmaz, her dilde varsayılan ad görünür; nsfw: true reddedilir |
| Henüz yok | Sağ tık komutları, premium buton, yanıtta dosya, modal içinde menü ve dosya |
Güvenlik
Section titled “Güvenlik”custom_idve menü değerleri güvenilmez girdidir. Micup yalnız bileşenin mesajda olduğunu ve değerin seçenekler arasında olduğunu denetler. Botun bunları her kullanıcı girdisi gibi doğrulamalı; içine gizli bilgi ya da yetki koyma.- Yetkiyi botta denetle.
default_member_permissionsyalnız komutu gizler. - Bağlantı butonu yalnız
httpvehttpsadresi alır, en çok 512 karakter, kullanıcı adı ve parola içeremez, engel listesindeki alan adları reddedilir. Kullanıcı açmadan önce dış bağlantı uyarısını görür. - Etkileşim tokenı bir kimlik bilgisidir: 15 dakika boyunca o etkileşimin yanıtlarını yazar. Loglara ve hata raporlarına yazma.
- Botlar butona tıklayamaz: tıklama rotası bot tokenıyla 403
ACCESS_DENIEDdöner. Bu, botların bileşen yazamadığı anlamına gelmez; bileşenler botun kendi mesajına yazılır.
Sık görülen hatalar
Section titled “Sık görülen hatalar”| Ne zaman | Kod |
|---|---|
| İlk yanıt 3 saniyeyi ya da token 15 dakikayı geçti | 410 INTERACTION_EXPIRED |
| Etkileşime zaten ilk yanıt verildi | 409 INTERACTION_TOKEN_CONSUMED |
| Token ya da uygulama kimliği tutmuyor | 404 UNKNOWN_WEBHOOK |
| Bot ya da kullanıcı için ilgili özellik kapalı | 403 APPLICATION_COMMAND_FEATURE_DISABLED |
If-Match ile yazarken komut seti değişmiş | 412 APPLICATION_COMMAND_VERSION_CONFLICT |
| Desteklenmeyen bileşen türü | 400 UNSUPPORTED_COMPONENT |
| Seçim değeri bileşende yok | 400 INVALID_COMPONENT_VALUE |
| Açık modal olmadan gönderim | 409 MODAL_NOT_OPEN |
Hız sınırı aşılınca 429 gelir; Retry-After kadar bekle. Hız sınırları.
Onaylı bot
Section titled “Onaylı bot”Başvuru şartları ayrıca duyurulacak.