📅 February 01, 2022
•⏱️8 min read
主にゲームで利用されるコミュニティアプリは様々あります。
一昔前はMSNメッセンジャーやSkypeとかでした。(ん?同じ?w
んで、今の主流はというと「Discord」です。
メッセージを飛ばしたり、ボイスチャット(通話)したり、配信なんかもできます。
個々でやり取りをするのはもちろん、グループでも可能となっていて、使い勝手はすごくいいです。
そんなDiscordをNodeで扱えるようにした便利なライブラリが「Discord.js」です。
DiscordAPIと簡単に接続できます。
DiscordでBOTを作成したかったので、その過程を本記事にまとめていきます。
Discord用のBOTは事前に登録しておきます。
https://discordjs.guide/preparations/setting-up-a-bot-application.html#creating-your-bot
こちらを参考に、各種トークンがCopyできるようにしておきましょう。
この辺はDiscord.jsとはあまり関係ありません。
BOT開発用のディレクトリを作成します。
mkdir test-bot
cd test-bot
npm init
まーテンプレ通り。。。
まずは、本題でもあるDiscord.jsをインストールします。
npm install discord.js
※ --save
は不要です。npm v5 以降はインストール時にデフォルトで package.json
の dependencies
に追加してくれるようになりました。
本来、環境変数や .envファイル
等から読み込むほうが良い気がします。
今回はGithubでも管理しないような個人のBOTなので設定ファイルを作ります。
config.json
{
"clientId": "${Developer Potakで取得したclientId}",
"guildId": "${BOTを動かしたいサーバのID(Discordを開発者モードにして、サーバ名を右クリックしたら取得できます)}",
"token": "${Developer Potakで取得したtoken}"
}
以前までは「チャットの内容をリッスンして、とある文言だったらBOTが反応する〜」みたいなBOTの作りだったような気がするのですが、現在は「予め決められたコマンドを作成しておいて、それに対応するBOTを作る」みたいな作りが仕様になっていました。
v13の新機能なのかな?
https://scrapbox.io/discordjs-japan/Discord.js_v13%E3%81%AE%E6%96%B0%E6%A9%9F%E8%83%BD
ということで、まずは /ping
に対応するBOTを作成します。
deploy-commands.js
const { SlashCommandBuilder } = require('@discordjs/builders');
const { REST } = require('@discordjs/rest');
const { Routes } = require('discord-api-types/v9');
const { clientId, guildId, token } = require('./config.json');
const commands = [
new SlashCommandBuilder().setName('ping').setDescription('Replies with pong!')
]
.map(command => command.toJSON());
const rest = new REST({ version: '9' }).setToken(token);
rest.put(Routes.applicationGuildCommands(clientId, guildId), { body: commands })
.then(() => console.log('Successfully registered application commands.'))
.catch(console.error);
こちらを実行すると、Discordの指定サーバ内でコマンドが有効になります。
【画像】
今回は、ギルドコマンドと呼ばれる特定のサーバで有効になるコマンドを作成しました。
どのサーバでも使えるようなグローバルコマンドも作れるようですが、めんどくさそうなので。。。
2でBotを呼び出すための準備が整いました。実際にレスポンス用のコードを書いていきます。
index.js
// Require the necessary discord.js classes
const { Client, Intents } = require('discord.js');
const { token } = require('./config.json');
// Create a new client instance
const client = new Client({ intents: [Intents.FLAGS.GUILDS] });
// When the client is ready, run this code (only once)
client.once('ready', () => {
console.log('Ready!');
});
// ココがメイン
client.on('interactionCreate', async interaction => {
if (!interaction.isCommand()) return;
const { commandName } = interaction;
if (commandName === 'ping') {
await interaction.reply('Pong!');
}
});
// Login to Discord with your client's token
client.login(token);
interactionCreate
イベントに対応するコードを書きます。
interactionのcommandNameがpingだった場合、replyを利用して「Pong!」と返します。
(そのままw)
node deploy-commands.js
node index.js
このように順に実行してもOKです。
私は、毎回2つ呼ぶのが面倒くさいので、npmのプロジェクトとして実行しました。
package.json
・・・,
"scripts": {
"prestart": "node deploy-commands.js",
"start": "node index.js"
},
・・・
上記のように package.json
を書いた上で、ターミナルで
npm run start
すると、startコマンドに対応する prestart が直前に自動実行されます。
https://docs.npmjs.com/cli/v8/using-npm/scripts
準備完了です。
サーバ上のBOTはオンラインになりましたか?
オフラインの方は、コンソールのエラーログを見て解決してあげてください。
オンラインになった方はPingしてみましょう。
/ping
【画像】
Pong
【画像】
完璧です。
後は、想像力を働かせてBOTのコマンドを増やしていくだけです。
コマンドに引数がほしいときは、SlashCommandBuilderを用いてサブコマンドを登録していきます。
const commands = [
new SlashCommandBuilder().setName('ping').setDescription('Replies with pong!').
new SlashCommandBuilder().setName('echo').addStringOption(option =>
option.setName('input').setDescription('The input to echo back').setRequired(true))
]
.map(command => command.toJSON());
このように登録すると、echoコマンドのサブコマンドとして、inputの入力を求めるようになります。
応答する側は、
const string = interaction.options.getString('input');
とすることで、inputとして入力された値を取得することができます。
私が作成したBOTは、入力された値を元に他の外部APIを呼び出して処理を行います。
よって、処理に少し時間がかかります。
何も対策せずに実行すると、、、
【画像】
このようにエラーとなってしまいます。たしか3秒。
そんなときは、Deferred responsesを使いましょう。
https://discordjs.guide/interactions/slash-commands.html#deferred-responses
if (interaction.commandName === 'ping') {
await interaction.deferReply();
await wait(4000);
await interaction.editReply('Pong!');
}
deferReplyを呼び出すことで、タイムアウト時間を伸ばす事ができます。(15分?
editReplyで結果を返してあげましょう。
以上。
便利じゃの!!