8
6

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.js-buttonsを使ってButtonで操作出来るDiscordBotを作ってみた

Last updated at Posted at 2021-06-07

経緯

このBotを作ろうとした理由と記事を書いた理由は下記の通りです。

  • Discordに新しく追加されたインタラクションであるButtonsを使ってみたかった
  • discord.js-buttonsに関する情報がなかった

似たようなことをしたい人の参考になれば良いなと思います。
なお、discord.js-buttonsはリポジトリが削除されているため今後無くなる可能性がありますが
discord.js自体のmasterブランチにButtonsに関するソースコードが追加されている為(2021/06/08現在)  
discord.jsが今後のバージョンでButtonsに対応すると思われますのでそちらを待ってもいいかもしれません。

ソースコード

GitHubにあります。
noriokun4649/DiscordSoundEffectBot
利用してるライブラリなどの依存関係はpackage.jsonに書いてありますが下記の通りです。

  • "@discordjs/opus": "^0.5.0"
  • "opusscript": "^0.0.8"
  • "config": "^3.3.6"
  • "discord.js": "^12.5.3"
  • "discord.js-buttons": "^1.0.0"
  • "ffmpeg-static": "^4.3.0"
  • "fs": "^0.0.1-security"

discord.js-buttons の使い方

discord.js-buttons の使い方について書いていきます。

discord.js-buttonsのセットアップ

const discord = require('discord.js');
const client = new discord.Client();
const discordbtn = require('discord.js-buttons')(client);

これでdiscord.jsからButtonsを利用する準備は完了です。

##Buttonのコンポーネントを作成
上記のセットアップで定義したdiscordbtnからMessageButton()を呼びだし新しいインスタンスを作ることで作成できます。

シンプルなbuttonコンポーネント
const button = new discordbtn.MessageButton()
    .setStyle('green')
    .setLabel('ファイル更新・読込')
    .setID('scan');

シンプルな例だとこのようになり、次のようなボタンが作成されます。
image.png
そして、このボタンを押したときのButtonIDは'scan'になります。
このButtonIDは後述する「buttonのイベントを受け取る」で利用するので覚えておきましょう。
MessageButton()に設定できるパラメータは幾つかあるので例を挙げてみます。

無効化されたbuttonコンポーネント
const disabledbutton = new discordbtn.MessageButton()
    .setStyle('green')
    .setLabel('ファイル更新・読込')
    .setID('scan')
    .setDisabled(); //このボタンを無効化された状態に設定する

image.png

URLのbuttonコンポーネント
const urlbutton = new discordbtn.MessageButton()
    .setStyle('url') //ボタンのスタイルをurlにする
    .setLabel('ファイル更新・読込')
    .setURL('https://hoge.hoge');
    //スタイルがurlの場合setIDではなくsetURLを指定するので注意

image.png

指定できるスタイルに関してはDiscordのAPIドキュメントを参照してください。
setStylesetLabelsetID若しくはsetURLは必須の項目なので注意が必要です。
ボタンの無効化は既に送信済みのボタンが無効化されるわけではないため、既に送信済みのメッセージを編集して無効化したボタンに置き換える時などがユーズケースだと思われます。

##メッセージの送信時にButtonを追加する
ここでは早速メッセージ送信時にButtonを付ける方法に触れていきます。

1つのbuttonを追加
message.channel.send('1つのボタンがついてるメッセージ', button);

意外に簡単です。この例では下記のようになります。
image.png

1つのbuttonを追加(返信)
message.reply('1つのボタンがついてる返信メッセージ', button);

このように返信を送る際にも同様の方法でボタンを追加出来ます。
image.png

そして、このbuttonはDiscordAPI仕様によりメッセージと一緒に送る必要があります。
また、同じくDiscordAPI仕様によりメッセージは空にできない為buttonだけを送信する方法は今のところありません。

さて、このbuttonですが1つのメッセージに対して最大で5個まで追加する事ができます。

複数のbuttonを追加
message.reply('複数のボタンがついてる返信メッセージ', { buttons: [button, disabledbutton, urlbutton] });

image.png
discord.jsから送信したメッセージのシンタックスハイライトを有効にする際などで使う文法をそのまま使えるので第2引数の連想配列には、buttonsという名前がついたbuttonコンポーネントの配列を渡してあげれば大丈夫です。

buttonのイベントを受け取る

ここではbuttonがおされた後の処理を行います。

buttonが押された際のイベントを受け取るハンドラ
client.on('clickButton', async (button) => {

});

このように書き、discord.jsにおけるmessageイベントを受け取るときと同じ書き方が出来ます。
この時、仮引数であるbuttonにはDiscordAPIドキュメントのインタラクションに書かれているフィールドに加えて、レスポンスを返す為の関数が用意されています。

仮引数(button)に用意されてるフィールドと関数
    client: Client;
    id: string;
    version: number;
    token: string;
    discordID: Snowflake;
    applicationID: Snowflake;
    guild: Guild;
    channel: Channel;
    clicker: {};
    message: Message;
    webhook: WebhookClient;
    replied: boolean;
    deferred: boolean;
    defer(ephemeral: boolean): Promise<void>;
    think(ephemeral: boolean): Promise<void>;
    get reply(): {
        send: (content: string, options?: object) => Promise<void>;
        fetch: () => Promise<string>;
        edit: (content: any, options?: object) => Promise<any>;
        delete: () => Promise<void>;
    };

フィールドについて

フィールドについては特筆すべきことは無いと思いますがあるとすればid: stringです。
これはbuttonコンポーネントが押されたときの押されたbuttonと紐付くButtonIDの文字列が入っています。
あとはclicker: {}ですが、これにはbuttonをおしたユーザーの情報が入っています。

clickerフィールドの利用例
const guild = button.guild;
const member = guild.member(button.clicker.user);

このように使うことで、buttonをおしたユーザのGuildMemberインスタンスを取得できます。
replieddeferredフィールドに関しては次の「関数について」で触れる関数が既に使われているかどうかを判定します。これは関数を使った後にすぐ状態が変化するわけではなく、もう一度buttonがおされた際に変化するので注意が必要です。

関数について

このときthink(boolean)関数はユーザに処理中若しくは考え中を表示させる関数です。defer(boolean)関数はユーザに処理を先延ばしにする旨を伝える関数です。先延ばしに関する処理はデスクトップ版Discordがバグっているのかわかりませんが、モバイル版のDiscordのみボタンが押せない状態で処理が先延ばしされます。
この2つの関数において引数になるbooleanはこの考え中や先延ばしというBot側のメッセージをbuttonを押したユーザーだけに伝えるかどうかを指定できます。trueの場合はbuttonを押したユーザーだけに伝えます。  
reply.send()ではbuttonのついたメッセージへ返信出来ます。
reply.delete()では返信を削除できます。これはthink(boolean)によって送信された「考え中・・・」というメッセージも対処です。
reply.edit()では返信を編集出来ます。
reply.fetch()では返信されているメッセージを取得出来ます。

そして注意が必要なのは、これらの関数のうちいずれかを利用しないと、Discord上で「インタラクションに失敗しました」というメッセージが表示される事です。そのため、buttonが押され正常な処理が出来る場合にはいずれかの関数を使いレスポンスを返してあげましょう。

では早速、具体的に機能を書いていきます。

const listButton = new disbut.MessageButton() //buttonコンポーネントを定義しておく
    .setStyle('green')
    .setLabel('再生可能ファイル一覧を表示')
    .setID('list');

client.on('clickButton', async (button) => { //button押された時に実行される
    await button.think(false); //botが考え中ということを全員にしらせる
    if (button.id === 'scan') { //ButtonIDがscanの場合
        const fileList = readfile(); //ファイル読み込み関数を呼ぶ(buttonには関係ない処理)
        if (fileList.length > 0) { //ファイルが1以上だったら
            btn = createButtns(fileList);
            button.reply.edit('ファイル更新・読込に成功しました。', { code: true, buttons: [listButton]         }); 
            //考え中の返信を「ファイル更新・読込に成功しました。」というメッセージに編集する。
        } else {
            button.reply.edit('ファイル更新・読込に失敗しました。', { code: true });
            //考え中の返信を「ファイル更新・読込に失敗しました。」というメッセージに編集する。
        }
});

GIF 2021-06-08 5-42-58.gifGIF 2021-06-08 5-39-27.gif

このようになります。わかりづらいかも知れませんが「考え中・・・」と出た後に書き換えられてるかと思います。
因みに上記プログラムのbutton.think(false);button.think(true);に変更すると
GIF 2021-06-08 5-45-49.gif
こうなります。「これらはあなただけに表示されています」という風になりますね。

discord.js-buttonsの使い方おわり

以上がdiscord.js-buttonsを使ったButtonsの使い方です。使いこなせるようになると非常にUXに優れたBotが作成できると思います。
Buttonsを多用しすぎてメッセージチャンネルをあらさないような配慮も考えつつ活用して頂ければ幸いです。

最後に

最後に、私が今回作ったBotについて軽く触れて終わりにします。

今回作ったのはDiscordのボイスチャンネル上でサウンドエフェクトを再生できるBotです。
Buttonsを多用して非常に使いやすくできたと思っていますのでよろしければ使ってみてください。
ソースコードに飛ぶ

リンク

8
6
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
8
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?