marukot-chの日記

弱小SEの雑記です

discord.pyはまだスラッシュコマンドを実装しないが、他ライブラリを使用すれば使える

あらすじ

  • Community UpdatesでDiscordにスラッシュコマンド実装されたことを知る
  • Qiitaにある記事はいいものだった
  • Pythonの使い方がわかってなくてClassの場合のスラッシュコマンドライブラリの使い方に手間取ったが動くようにできた

目次

前置き

誰も人はいないけれど、コミュニティサーバーを運営してる。

そこで、スラッシュコマンドが使えるようになった旨のメッセージがDiscordのCommunity Updatesとして来ていた(コミュニティサーバーにするとその辺の情報を得ることができる)。

discord.pyはまだ対応しないつもりに見える(2021/09/04追記あり)

  • よくわからないが、正式版になってから対応するぞ!と言っている気がする...
  • ちょっと残念
  • 2021/09/04追記
    • discord.pyは開発凍結されたため、フォークされたプロジェクト等による実装を待つしか無い状況になってしまいました
    • 他のライブラリを使うなりすれば、普通に動くので、そのまま使っていても良いとは思います
    • ただ、Discord側に大きな変更があった際の対応がどうなるかが心配ではあります...

github.com

Qiitaの記事

Googleで調べてみると、Qiitaの記事が検索された。ほぼ、公式ページのquickstart*1を日本語化したような記事かと思ったが、制限事項などをきちんと盛り込んでありとても良い。

qiita.com

公式の記事

Discordの公式の制限事項も分かりやすいけれども、英語だからなぁ。グローバルコマンド、ギルドコマンドの50個制限は、グローバルコマンドが50個、ギルドごとに各50個ずつって意味らしい。

discord.com

An app can have up to 50 top-level global commands (50 commands with unique names) An app can have up to an additional 50 guild commands per guild An app can have up to 10 subcommand groups on a top-level command An app can have up to 10 subcommands within a subcommand group choices can have up to 10 values per option commands can have up to 10 options per command Limitations on command names Limitations on nesting subcommands and groups

グローバルコマンドは1時間程度登録に時間がかかり、ギルドコマンドは即時反映というのはThis command will be available on all your app's guilds.*2のあたりに書いてあるやつかな。

 

使うにあたり悩んだこと

今回使ってみるにあたり悩んだことがあって、こういう単純なタイプなら動くけれど(cogでの使い方はpypiが詳しい*3

from discord.ext import commands
from discord_slash import SlashCommand
from logging import basicConfig, getLogger

import discord

basicConfig(level=setting.LOG_LEVEL)
LOG = getLogger(__name__)

# 読み込むCogの名前を格納しておく。
INITIAL_EXTENSIONS = [
    'cogs.testcog'
    , 'cogs.slashcog'
]

async def on_ready(self):
    LOG.info('We have logged in as {0.user}'.format(self))

intents = discord.Intents.all()
intents.typing = False

bot = commands.Bot(command_prefix='/', intents=intents, case_insensitive=True)
slash = SlashCommand(bot, sync_commands=True)

for cog in INITIAL_EXTENSIONS:
    bot.load_extension(cog)
bot.run'__DISCORD_TOKEN__')

Classとかでやっているタイプは動かなくて。試行錯誤して、ちゃんとcommands.BotでSlashCommandを作れば良いと分かった(Pythonオブジェクト指向がちゃんと分かっている人は多分quickstartを見ただけでわかるんだろうな...)。

ダメだったやつ
from discord.ext import commands
from discord_slash import SlashCommand
from logging import basicConfig, getLogger

import discord

basicConfig(level=setting.LOG_LEVEL)
LOG = getLogger(__name__)

# 読み込むCogの名前を格納しておく。
INITIAL_EXTENSIONS = [
    'cogs.testcog'
    ,'cogs.slashcog'
]

class DiscordReminderBot(commands.Bot):
    # MyBotのコンストラクタ。
    def __init__(self, command_prefix, intents):
        # スーパークラスのコンストラクタに値を渡して実行。
        super().__init__(command_prefix, case_insensitive=True, intents=intents)

        # INITIAL_EXTENSIONSに格納されている名前から、コグを読み込む。
        for cog in INITIAL_EXTENSIONS:
            self.load_extension(cog)

     async def on_ready(self):
         LOG.info('We have logged in as {0.user}'.format(self))

# discord-reminderbotbのインスタンス化、および、起動処理
if __name__ == '__main__':
    intents = discord.Intents.all()
    intents.typing = False
    intents.members = False
    intents.presences = False

    bot = DiscordReminderBot(command_prefix='/', intents=intents)
    slash = SlashCommand(bot, sync_commands=True) #ここはダメ

    bot.run(setting.DISCORD_TOKEN)
うまく動いたやつ
from discord.ext import commands
from discord_slash import SlashCommand
from logging import basicConfig, getLogger

import discord

basicConfig(level=setting.LOG_LEVEL)
LOG = getLogger(__name__)

# 読み込むCogの名前を格納しておく。
INITIAL_EXTENSIONS = [
    'cogs.testcog'
    ,'cogs.slashcog'
]

class DiscordReminderBot(commands.Bot):
    # MyBotのコンストラクタ。
    def __init__(self, command_prefix, intents):
        # スーパークラスのコンストラクタに値を渡して実行。
        super().__init__(command_prefix, case_insensitive=True, intents=intents)
        slash = SlashCommand(self, sync_commands=True) # ココにslashをおこう!(第一引数はself)

        # INITIAL_EXTENSIONSに格納されている名前から、コグを読み込む。
        for cog in INITIAL_EXTENSIONS:
            self.load_extension(cog)

     async def on_ready(self):
        LOG.info('We have logged in as {0.user}'.format(self))

# discord-reminderbotbのインスタンス化、および、起動処理
if __name__ == '__main__':
    intents = discord.Intents.all()
    intents.typing = False
    intents.members = False
    intents.presences = False

    bot = DiscordReminderBot(command_prefix='/', intents=intents)
    bot.run(setting.DISCORD_TOKEN)

追記(2021/05/16)

  • v2.0でdiscord.pyはスラッシュコマンドをサポートするらしい(Twitterでそんな話を見かけつつも確認していなかった)

github.com

  • いくつかのパターンの最小限のBot(discord.py)を下記に書いてみたので、もし参考になる人がいれば確認してほしい(そしてScrapboxプロジェクトに参加して記事を充実してほしい/プロジェクトに参加するとメンバーにメールアドレスが知られてしまうのでその点は注意)

scrapbox.io

追記(2021/09/04)

note.com

qiita.com

smhn.info