Help us understand the problem. What is going on with this article?

Discord.pyで、あれこれをやりたいためのサンプルコード集

まえがき

この記事はDiscord.pyを使用してBOTを作る際に役立つかもしれないサンプルソースコードを掲載しています。

いずれもベストプラクティスであるとは限りませんが、DiscordのBOT作りの参考になればいいなという思いで、記事にしました。

環境

BOTが反応する頭文字を変えたい

Botインスタンス作成時にcommand_prefixという引数に頭文字を指定します。

from discord.ext import commands

bot = commands.Bot(
    command_prefix="!"
)

メンションにも反応させたい

commands.when_mentioned_orを使用するとメンションでも、頭文字でも反応するようになります。

from discord.ext import commands

bot = commands.Bot(
    command_prefix=commands.when_mentioned_or("!")
)

コマンドの大文字小文字を気にしないようにしたい

Botインスタンス作成時にcase_insensitiveTrueにすると大文字小文字の区別をせず、反応するようになります。

from discord.ext import commands

bot = commands.Bot(
    command_prefix="!",
    case_insensitive=True
)

標準搭載のヘルプ機能を無効にしたい

Botインスタンス作成時にhelp_commandという引数をNoneにします。

from discord.ext import commands

bot = commands.Bot(
    command_prefix="!",
    help_command=None
)

Botアカウントに「~をプレイ中」と表示したい

commands.Botインスタンスを作成時にactivity引数にdiscord.Gameインスタンスを代入します。

import discord
from discord.ext import commands

bot = commands.Bot(
    command_prefix="!",
    activity=discord.Game("Qiita") # Qiitaをプレイ中
)

もしくは、discord.Gameインスタンスを作成し、Botの接続完了時にchange_presenceで変更します。

import discord
from discord.ext import commands

bot = commands.Bot(
    command_prefix="!"
)

presence = discord.Game("Qiita") # Qiitaをプレイ中

@bot.event
async def on_ready():
    await bot.change_presence(activity=presence)

特定のリアクションをしたらロールを付与、解除したら剥奪する

イベントハンドラのon_raw_reaction_addon_raw_reaction_removeを使用してロールの付与・剥奪を処理します。

on_raw_reaction_removeでは、memberが代入されないので、
get_guildを使ってギルド(サーバー)情報を取得してから、get_memberでユーザー情報を取得する必要があります。

from discord.ext import commands

class RoleCog(commands.Cog):
    def __init__(self, bot):
        self.bot = bot # commands.Botインスタンスを代入

    @commands.Cog.listener()
    async def on_raw_reaction_add(self, payload):
        if payload.member.bot: # BOTアカウントは無視する
            return

        if payload.channel_id != 123456789123: # 特定のチャンネル以外でリアクションした場合は無視する
            return

        if payload.emoji.name == "👍": # 特定の絵文字
            await payload.member.add_roles(
                payload.member.guild.get_role(123456789123) # ロールID
            )

    @commands.Cog.listener()
    async def on_raw_reaction_remove(self, payload):
        guild = self.bot.get_guild(payload.guild_id)
        member = guild.get_member(payload.user_id)
        if guild is None or member is None: # サーバーやメンバー情報が読めなかったら無視
            return

        if member.bot: # BOTアカウントは無視する
            return

        if payload.channel_id != 123456789123: # 特定のチャンネル以外でリアクションを解除した場合は無視する
            return

        if payload.emoji.name == "👍": # 特定の絵文字
            await payload.member.remove_roles(
                payload.member.guild.get_role(123456789123) # ロールID
            )

「~が入力中」と表示させる

async with ctx.typing():(ctxはテキストチャンネル)を使用することで入力中のサインを表示できます。

import asyncio
from discord.ext import commands

class TypingCog(commands.Cog):
    @commands.command()
    async def delay_send(self, ctx):
        async with ctx.typing(): # 送られてきたチャンネルで入力中と表示させる
            await asyncio.sleep(5) # 重い処理をwith内で書く。(一例)
            await ctx.send("処理完了")

カテゴリを取得したい

テキストチャンネル等と同様に、get_channel関数でカテゴリを取得することができます。

from discord.ext import commands

bot = commands.Bot()

@bot.event
async def on_ready():
    category = bot.get_channel(123456789123) # カテゴリのID

コマンドにDiscordのメンバーが予め入ったものを使用したい

メンバーを入れる引数の後にdiscord.Memberを指定すると、Memberインスタンスとして代入されます。
なお、メンバーが見つからなかった場合は例外commands.BadArgumentが送出されます。
エラーハンドリングは後述にて説明します。

import discord
from discord.ext import commands

class CommandArgCog(commands.Cog):
    @commands.command()
    async def say_hello(self, ctx, target: discord.Member): # targetにメンバー指定する
        await ctx.send(f"Hello, {target.mention}!")

各コマンドのエラーハンドリングを行いたい

@{コマンドの関数名}.errorというデコレータ付け、引数にctxerrorを定義します。
ちなみに、コマンド処理内でエラーが発生すると、commands.CommandInvokeErrorが送出されます。

import discord
from discord.ext import commands

class ErrorHandlingCog(commands.Cog):
    @commands.command()
    async def say_hello(self, ctx, target: discord.Member):
        await ctx.send(f"Hello, {target.mention}!")

    @say_hello.error
    async def say_hello_error(self, ctx, error):
        if isinstance(error, commands.BadArgument): # errorはBadArgumentか
            await ctx.send(f"{ctx.message.author.mention} ターゲットを指定して下さい。もしくはユーザーが見つかりませんでした。")
            return

実行しているBotが所属しているどのギルド(サーバー)に入ってないユーザー情報を取得したい

fetch_userを使うとBotが所属しているギルドに入ってないユーザー情報を取得することができます。

fetch_userはユーザーが見つからなかった場合に例外が出されるため、tryで囲むべきです。

import discord
from discord.ext import commands

class FetchUser(commands.Cog):
    def __init__(self, bot):
        self.bot = bot # commands.Botインスタンスを代入

    @commands.command()
    async def fetch_user(self, target_id: int):
        try:
            target = await self.bot.fetch_user(target_id)
        except discord.NotFound:
            # ユーザーが見つからなかった場合の処理(以下は一例)
            await ctx.send("ユーザーが見つかりませんでした。")
            return

        await ctx.send(str(target)) # Username#0000

あとがき

紹介したのは一例でしたが、BOT製作の役に立てたら幸いです。

気が向いたらまたこの記事を更新するかもしれません。

2020/08/08 追記: たくさんのLGTMとストックありがとうございます。

YuzuRyo61
"Hello World!"と書き続けているだけの人。 Pythonが主成分。 ウェブアプリ好き。それ系書き書きしてます。
https://yuzulia.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした