Discord bot v Pythonu: discord.py se slash příkazy krok za krokem
Vytvořte Discord bota v discord.py 2.x – registrace aplikace, intenty, slash příkazy, embedy, cogs a bezpečné uložení tokenu. Funkční kód od nuly.
Discord bot v Pythonu se dá rozběhnout za půl hodiny. Knihovna discord.py ve verzi 2.x podporuje slash příkazy, tlačítka i modální okna. Postavíme bota s několika příkazy a ukážeme, jak ho udržet přehledný, když poroste.
1. Registrace aplikace
- Otevřete Discord Developer Portal a klikněte na New Application.
- V sekci Bot zkopírujte token (tlačítko Reset Token). Token je heslo – nikdy ho necommitujte.
- Ve stejné sekci zapněte Message Content Intent, pokud bot bude číst text běžných zpráv. Pro čisté slash příkazy ho nepotřebujete.
- V OAuth2 → URL Generator zaškrtněte scopes
botaapplications.commands, vyberte oprávnění (např. Send Messages) a vygenerovaným odkazem bota pozvěte na svůj server.
2. Instalace
python3 -m venv .venv
source .venv/bin/activate
pip install "discord.py>=2.3" python-dotenv
Soubor .env (přidejte ho do .gitignore):
DISCORD_TOKEN=vas_token
GUILD_ID=123456789012345678
ID serveru získáte po zapnutí Developer Mode v nastavení Discordu (Pokročilé) a kliknutí pravým tlačítkem na server → Kopírovat ID serveru.
3. Minimální bot se slash příkazem
import os
import discord
from discord import app_commands
from dotenv import load_dotenv
load_dotenv()
TOKEN = os.environ["DISCORD_TOKEN"]
GUILD = discord.Object(id=int(os.environ["GUILD_ID"]))
class Bot(discord.Client):
def __init__(self):
super().__init__(intents=discord.Intents.default())
self.tree = app_commands.CommandTree(self)
async def setup_hook(self):
# Synchronizace na jeden server je okamžitá.
self.tree.copy_global_to(guild=GUILD)
await self.tree.sync(guild=GUILD)
bot = Bot()
@bot.event
async def on_ready():
print(f"Přihlášen jako {bot.user} (ID {bot.user.id})")
@bot.tree.command(description="Odpoví pong a změří latenci")
async def ping(interaction: discord.Interaction):
await interaction.response.send_message(
f"Pong! {round(bot.latency * 1000)} ms"
)
@bot.tree.command(description="Hodí kostkou")
@app_commands.describe(stran="Počet stran kostky")
async def kostka(interaction: discord.Interaction, stran: app_commands.Range[int, 2, 100] = 6):
import random
await interaction.response.send_message(f"🎲 Padlo: {random.randint(1, stran)}")
bot.run(TOKEN)
Spusťte python bot.py. Na serveru napište / a uvidíte své příkazy.
Proč synchronizovat na konkrétní server
Globální příkazy (await tree.sync() bez argumentu) se propagují na všechny servery, ale Discord je omezuje rate limitem a změny se nemusí projevit hned. Při vývoji synchronizujte na testovací server, globálně až při nasazení. A nevolejte sync() v on_ready – ten se spouští i při každém znovupřipojení.
4. Typy parametrů a volby
Typ parametru určuje, co Discord uživateli nabídne:
@bot.tree.command(description="Info o uživateli")
async def kdo(interaction: discord.Interaction, clen: discord.Member):
embed = discord.Embed(title=clen.display_name, color=discord.Color.blurple())
embed.set_thumbnail(url=clen.display_avatar.url)
embed.add_field(name="Na serveru od", value=discord.utils.format_dt(clen.joined_at, "D"))
await interaction.response.send_message(embed=embed)
@bot.tree.command(description="Nastaví jazyk")
@app_commands.choices(jazyk=[
app_commands.Choice(name="Čeština", value="cs"),
app_commands.Choice(name="English", value="en"),
])
async def jazyk(interaction: discord.Interaction, jazyk: app_commands.Choice[str]):
await interaction.response.send_message(f"Jazyk: {jazyk.name}", ephemeral=True)
ephemeral=True zobrazí odpověď jen volajícímu.
5. Pomalé operace: defer
Na interakci musíte odpovědět do 3 sekund, jinak uživatel uvidí „Aplikace nereagovala“. U pomalých úloh nejdřív odpověď odložte:
@bot.tree.command(description="Pomalý výpočet")
async def report(interaction: discord.Interaction):
await interaction.response.defer(thinking=True)
vysledek = await nejaka_pomala_async_funkce()
await interaction.followup.send(vysledek)
Po defer máte na odpověď 15 minut.
6. Oprávnění
@bot.tree.command(description="Smaže zprávy")
@app_commands.default_permissions(manage_messages=True)
@app_commands.checks.has_permissions(manage_messages=True)
async def smaz(interaction: discord.Interaction, pocet: app_commands.Range[int, 1, 100]):
await interaction.response.defer(ephemeral=True)
smazano = await interaction.channel.purge(limit=pocet)
await interaction.followup.send(f"Smazáno {len(smazano)} zpráv.")
default_permissions skryje příkaz v UI, checks.has_permissions ho skutečně ověří na straně bota.
7. Struktura většího bota
S rostoucím počtem příkazů přejděte na commands.Bot a rozdělte kód do cogs – tříd s příkazy v samostatných souborech, které načtete přes await bot.load_extension("cogs.moderace") v setup_hook. Každý soubor s cogem pak exportuje async def setup(bot), která cog přidá voláním await bot.add_cog(...).
Časté problémy
- Příkazy se nezobrazují – chybí scope
applications.commandsv pozvánce, nebo neproběhlsync. Zkuste restartovat Discord klienta (Ctrl+R). PrivilegedIntentsRequired– v kódu žádáte intent (např.message_contentnebomembers), který není zapnutý v Developer Portalu.- Blokující kód –
requestsnebotime.sleepv příkazu zablokuje celého bota. Používejteaiohttp/httpx.AsyncClientaasyncio.sleep.
Provoz 24/7
Bot musí běžet nepřetržitě, takže ho dejte na VPS jako službu systemd s Restart=always a token předávejte přes EnvironmentFile. Pokud server připojíte k ColdHost AI přes SSH, AI vám službu navrhne a každý příkaz před spuštěním schválíte jedním kliknutím.