25
14

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 3 years have passed since last update.

Discord BotAdvent Calendar 2020

Day 19

DiscordAPIの新機能 Slash Commandを試す

Last updated at Posted at 2020-12-18

はじめに

この記事はDiscordBotアドベントカレンダー2020の19日目の記事です。

こんにちは。この記事では、つい先日オープンベータになった、スラッシュコマンドを試してみたいと思います。

スラッシュコマンドは、公式にサポートされたコマンド機能です。組み込みのコマンドもいくつかあり、例えば /tableflip おりゃーと送信すると、おりゃー (╯°□°)╯︵ ┻━┻と変換してくれるコマンドなどがあります。

スラッシュコマンドは利用するユーザーにやさしいのが特徴です。/を打てば、コマンドの名前と機能の説明が表示されるだけでなく、コマンドをTabで補完したり、引数をユーザー型やチャンネル型などに限定することも出来ます。

image.png

なお、この機能はベータ版であり、今後動かなくなる可能性があることに注意してください。

コマンドの登録

Botの権限を変更する

まず、コマンドを追加するためにBotに権限が必要なので、Discord Developer Portal — My Applicationsから新しくサーバーへの招待リンクを作り直します。

アプリケーションを選択👉OAuth2👉OAuth2 URL Generator

からapplications.commandsにチェックを入れ、生成されたURLを踏んで、Botのサーバー権限を上書きします。

コマンドを追加する

いよいよ、コマンドを追加していきます。コマンドの追加は、以下のURLにPOSTでリクエストすることで可能です。

https://discord.com/api/v8/applications/{application.id}/commands

公式チュートリアルを少し弄ったものをリクエストします。例はPythonです。

import requests

url = "https://discord.com/api/v8/applications/<APPLICATION_ID>/commands"

json = {
    "name": "blep",
    "description": "Send a random adorable animal photo",
    "options": [
        {
            "name": "animal",
            "description": "The type of animal",
            "type": 3,
            "required": True,
            "choices": [
                {
                    "name": "Dog",
                    "value": "animal_dog"
                },
                {
                    "name": "Cat",
                    "value": "animal_cat"
                },
                {
                    "name": "Penguin",
                    "value": "animal_penguin"
                }
            ]
        },
        {
            "name": "only_smol",
            "description": "Whether to show only baby animals",
            "type": 5,
            "required": False
        }
    ]
}

# For authorization, you can use either your bot token 
headers = {
    "Authorization": "Bot <BOT_TOKEN>"
}

r = requests.post(url, headers=headers, json=json)
print(r.json())

レスポンスに登録したコマンドの情報に加えて、IDなどが帰ってきていれば登録成功です。

ここまで上手くいっていれば/blepでコマンドが表示されるはずです。ただし、この時点では送信しても特に何も起こりません。

image.png

コマンドに返信する

方法は二つあります。一つはGateway EventのInteractionEventをキャッチする方法。もう一つはwebhookを用意する方法です。今回は一つ目で行きます。

新しい機能なのでどのフレームワークにも当然実装されていません。ということで、生のDiscord Gatewayを触る...のは流石に面倒なのでdiscordpyを拡張しながら実装していきます。

コマンドをキャッチする


from discord.ext import commands
from pprint import pprint

TOKEN = "<BOT TOKEN>"

class MyBot(commands.Bot):

    def __init__(self,**kwargs):
        super().__init__(**kwargs)
        self.add_listener(self.on_socket_response)

    async def on_socket_response(self,msg):
        if msg["t"] != "INTERACTION_CREATE":
            return

        pprint(msg)

if __name__ == '__main__':
    bot = MyBot(command_prefix='!',
                   description='slash test')
    bot.run(TOKEN)

これで、スラッシュコマンドのEventにのみ反応し、Eventの内容は以下のような辞書で手に入ります。

{'d': {'channel_id': '<CHANNEL ID>',
       'data': {'id': '<COMMAND ID>',
                'name': 'blep',
                'options': [{'name': 'animal', 'value': 'animal_dog'},
                            {'name': 'only_smol', 'value': True}]},
       'guild_id': '<GUILD ID>',
       'id': '<COMMAND INTERACTION ID>',
       'member': {'deaf': False,
                  'is_pending': False,
                  'joined_at': '2020-01-13T14:08:23.570000+00:00',
                  'mute': False,
                  'nick': None,
                  'pending': False,
                  'permissions': '11111111',
                  'premium_since': None,
                  'roles': [],
                  'user': {'avatar': '1111111111111111111111',
                           'discriminator': '1111',
                           'id': '11111111111111',
                           'public_flags': 111,
                           'username': 'Pishiko'}},
       'token': '<COMMAND INTERACTION TOKEN>',
       'type': 2,
       'version': 1},
 'op': 0,
 's': 3,
 't': 'INTERACTION_CREATE'}

コマンドに返信する

これで、返信するのに必要なコマンドのアクション(=Interaction)のIDとトークンが分かったので、以下のURLにPOSTでリクエストします。

https://discord.com/api/v8/interactions/{interaction.id}/{interaction.token}/callback

discordpyでリクエストするにはaiohttpモジュールを利用します。以下のような関数を用意して返信します。

async def reply(id,token,content):
        url = "https://discord.com/api/v8/interactions/{0}/{1}/callback".format(
            id, token)
        
        json = {
            "type":4,
            "data":{
                "content":content
            }
        }
        
        async with aiohttp.ClientSession() as s:
            async with s.post(url,json=json) as r:
                if 200 <= r.status < 300:
                    return

最終的に以下のようなコードになりました。

from discord.ext import commands
from pprint import pprint
import aiohttp

TOKEN = "<BOT TOKEN>"

class MyBot(commands.Bot):

    def __init__(self,**kwargs):
        super().__init__(**kwargs)
        self.add_listener(self.on_socket_response)

    async def on_socket_response(self,msg):
        if msg["t"] != "INTERACTION_CREATE":
            return

        await reply(msg["d"]["id"], msg["d"]["token"],str(msg["d"]["data"]["options"]))

async def reply(id, token, content):

    url = "https://discord.com/api/v8/interactions/{0}/{1}/callback".format(
        id, token)

    json = {
        "type": 4,
        "data": {
            "content": content
        }
    }

    async with aiohttp.ClientSession() as s:
        async with s.post(url, json=json) as r:
            if 200 <= r.status < 300:
                return

if __name__ == '__main__':
    bot = MyBot(command_prefix='!',
                   description='slash test')
    bot.run(TOKEN)

うまくいけば、このように表示されるはずです。

image.png

おわりに

この他にも、サブコマンド、ユーザーやチャンネルの指定、返信の編集や表示の変更など、出来ることはまだあるので、以下を参考にしながらいろいろ遊んでみてください。

Discord Developer Portal — Documentation — Slash Commands

25
14
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
25
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?