Programování

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.

12. 10. 2026 · 4 min čtení

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

  1. Otevřete Discord Developer Portal a klikněte na New Application.
  2. V sekci Bot zkopírujte token (tlačítko Reset Token). Token je heslo – nikdy ho necommitujte.
  3. 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.
  4. V OAuth2 → URL Generator zaškrtněte scopes bot a applications.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.commands v pozvánce, nebo neproběhl sync. Zkuste restartovat Discord klienta (Ctrl+R).
  • PrivilegedIntentsRequired – v kódu žádáte intent (např. message_content nebo members), který není zapnutý v Developer Portalu.
  • Blokující kód – requests nebo time.sleep v příkazu zablokuje celého bota. Používejte aiohttp/httpx.AsyncClient a asyncio.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.