107
109

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

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

Last updated at Posted at 2020-07-22

2022/04/07 追記

Discord.pyですが、開発が再開されたとのことです。

開発を再開されたことを受け、必要に応じてこの記事の更新を再開する予定です。

Qiitaの編集リクエストをお送りいただき、ありがとうございます。この場を借りて御礼申し上げます。

まえがき

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

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

環境

1.5からの仕様変更

(2020/11/21 追記)

Discord APIの仕様変更により、Discord.py 1.5から一部機能を使うにはintentsが必要になりました。

特に、メンバーのステータスや情報を取得する場合は、Discordデベロッパーポータルで設定が必要になります。
この設定をしないとBOTが起動しなかったり、意図しない動作が発生してしまうことがあります。

Intentの設定例

規模の大きいBOTを運用する場合(参加サーバーが100を超えるBOT)は別途申請が必要になります。

intentsを設定するには

Botインスタンス作成時にintentsという引数にIntentsインスタンスを代入します。

import discord
from discord.ext import commands

# discord.Intents.all()を使用するとpresencesやmembersも有効な状態になります。
discord_intents = discord.Intents.all()
# 用途に応じて以下のように無効化することもできます。設定できる項目は、以下のURLを参照してみてください。
# https://discordpy.readthedocs.io/ja/latest/api.html#discord.Intents
# discord_intents.bans = False # on_member_banやon_member_unbanのイベントを無効化

bot = commands.Bot(
    command_prefix="!",
    intents=discord_intents
)

※intentsが指定されなかった場合、自動的にintentsが設定されます。

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)

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

(2020/11/21 追記) discord.Intents.reactionsのintentを有効にする必要があります。(ドキュメント

イベントハンドラの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製作の役に立てたら幸いです。

107
109
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
107
109

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?