LoginSignup
3
3

More than 3 years have passed since last update.

Discord BOTにライブラリ非依存で返信機能を持たせる

Last updated at Posted at 2020-12-11

Advent Calendar 12日目の記事です。

初めての参加となります。よろしくお願いします。

現地時間11月16日より、Discordで返信機能が実装されました。

さぞかしBOTに「返信機能を付けてみたい!」と思う方もいるかと思います。

今回はそれについて書いていきます。

返信機能は特別なものではない

Discordの公式APIリファレンスを見ると、新しくmessage_referenceという項目ができているのが分かります。

ここにメッセージIDを指定してやればあっという間に返信が実現できます。

ライブラリを使わずにどうやるか?

私達は普段直接APIを触ることなく、それぞれの言語に用意されたフレームワーク(Discord.pyやDiscord.jsなど)を使いプログラミングしています。しかし、実際はAPIを扱いやすくしたに過ぎないため、素の状態(APIを直接触ること)でやり取りすることもできます。

この記事を書いた時点ではまだ返信機能をサポートしていないライブラリが大半です。ここでは、直接APIとやり取りしてメッセージを送信する方法を解説します。

エンドポイント

まず、メッセージを送信するためのエンドポイントは

https://discord.com/api/channels/[チャンネルID]/messages

となっているので、そんなに難しくありません。メッセージオブジェクトのチャンネルIDを当てはめればURLは完成です。

ヘッダーとデータ

APIとはJSONを使ってやり取りします。

そのため、ヘッダのContent-TypeはContent-Type: application/jsonとする必要があります。

APIを使うにあたって、ヘッダ部分に認証情報を記載する必要があります。

「え、これはどうすれば…」と思った方。もちろんBOTのトークンが使えるので大丈夫です。

言語別に記載しませんが、リクエストヘッダに書くときは

Authorization: Bot [G6WtkBk9nHW4AlhB3wbCBSzx.nDUuhSMp02k9Okjs5DwRn4QRt9SvFo36m5]

となります。トークンは適宜ご自身のものに変えてください。[ ]で囲んだ部分にトークンを入れます。

次に送信するデータです。

基本形は

{
 "content": "Hello world"
}

です。contentにメッセージを入れます。
Webhookみたいにとてもシンプルですね。

ここに、message_referenceプロパティを追加して「返信だよ!」という情報を追加します。

公式リファレンスには

FIELD DESCRIPTION (和訳)
message_id 元のメッセージのID
channel_id? 元のメッセージのチャンネルID
guild_id? 元のメッセージのサーバーID

と書かれています。FIELDの最後についている?は「パラメータは必須ではない、省略可」という意になっているので、message_idだけ渡せばよいということが分かります。

message_idには、メッセージオブジェクトのメッセージIDを渡せばいいのです。

ここまでのをまとめると、送信するJSONはこうなります。

{
 "content": "Hello world!",
 "message_reference": {
  "message_id": 1234567890123456
 }
}

となります。

これらをヘッダと組み合わせて送信してやれば、返信機能が実現できます!
試しに実験サーバーで何かメッセージを送信してみて、チャンネルIDをURLにセットして、message_idのところを送信したメッセージIDに書き換えて

curl -X POST -H "Content-Type: application/json" -H "Authorization: Bot YourToken.PUT.Here" -d "{\"content\":\"Reply\" , \"message_reference\":{\"message_id\":YOUR_MESSAGE_ID}}" https://discord.com/api/channels/YOUR_CHANNEL_ID/messages

を端末で実行して

Screenshot_20201122-205144~2.png

というふうになったことを確認できれば、完了です。

メンションOFFにする

ただ、このままだと相手にメンションが飛んでしまいます。
メンションするか、しないかは通常だとアプリの設定で変えられます。

APIも同様で「メンションしないで」という情報を送ればよいのです。

先程のJSONに付け足して

{
 "content": "Hello world!",
 "message_reference": {
  "message_id": 1234567890123456
 },
 "allowed_mentions": {
  "replied_user": false
 }
}

というふうになります。

詳しくはAllowed mentions objectを参照してください。

これのデータを先程のcurlで送るとメンションなしで返信できるのを確認できると思います。

関数化させよう

ここまでcurlを使いましたが、プログラムで使うのにはとても不都合です。

関数化させて、比較的便利に使えるようにしましょう。

Python用にあらかじめ用意した関数を貼っておきます。
使いやすいようにアレンジしてお使いください。

async def reply(basemsg, message, send_mention, **kwargs):
   url = f'https://discord.com/api/channels/{basemsg.channel.id}/messages'
   heads = {"Content-Type":"application/json", "Authorization":f"Bot {TOKEN}"}
   data = {"content":message, "message_reference": {"message_id":basemsg.id}, "allowed_mentions": {"replied_user":send_mention}}
   if kwargs.get('embed'):
      data['embed']=kwargs.get('embed').to_dict()
   async with aiohttp.ClientSession() as session:
     async with session.post(url, data=json.dumps(data), headers=heads) as req:
        if req.status!=200:
           raise Exception(f'Gateway returned an error')
           return False
   return True

使い方は

await reply(message, '返信した!', False)

となります。左から1番目にはメッセージオブジェクトを、2番目には送信したいテキスト、3番目は相手にメンションするかどうかをTrue or Falseで指定します。

また、任意でembedというキーワード付き引数にdiscord.Embedのオブジェクトを渡すと埋め込みも送信できます。

em = discord.Embed(title='埋め込みもできるよ')
await reply(message, '返信した!', False, embed=em)

なお、この関数はrequests、json、aiohttpモジュールを使用します。事前にインポートしてください。

まとめ

返信をするときはmessage_referencemessage_idプロパティに返信先メッセージIDを指定する
@メンションをしないときはallowed_mentionsreplied_userをFalseにする

本当であればライブラリのアップデートを待つのが一番だし、一番簡単です。

あくまでも参考として、早く使ってみたい方向けです。

その点についてご理解ください。

3
3
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
3
3