🍭

初めてDiscordBotを作った話[discord.js V14]

2022/12/26に公開

はじめまして、プログラマーの卵の白兎しょう(@yasapuro_syo)です。

普段遊んでいるとあるDiscordのゲームコミュニティで、DiscordのBotがあると便利だねというノリと勢いで作った過程をまとめたものになります。

環境や使用したサービス

  • node.js V16.17.1

  • Discord.js V14

  • Docker for windows

  • Replit

  • UptimeRobot

目標

趣味的に作るので無料で以下の機能を作ること。

  • マップ抽選

  • 武器抽選

  • VCにいるメンバーを2チームに分ける

  • VCの入退室通知

どうやって作るか

パッと調べて一番上に出てきたのがHerokuというサービス。
制作したBotを常時動かしてくれるので便利なのですが、2022年11月28日[1]から無料での利用ができなくなるということで利用を見送りました。

Glitchというサービスもあるそうなのですが、プロジェクトの稼働時間が制限されたらしく、Botの常時稼働ができなくなった[2]とかなんとか。

ということで、利用しようとしたサービスがReplit
ブラウザだけでコーディングと常時稼働ができる神サービスです。楽チンだなと思ったのでこれを使うことにしました。
(後々欠点が見つかったので最終的に利用はやめました。絶対に常時稼働してないと嫌なんだ!という方以外はこのサービスがおすすめです。)

使用する言語は何でもよかったので、適当に調べて詳しく解説されてそうな言語を使って作っていきます。↓の記事を参考にさせていただきました。

https://ayutsuki.net/introduction/discord-js-v13-replit/

Replitで開発

最初は先述の記事だけを見ながら開発を進めていました。
必要なパッケージのインストールは何事もなく終わり、コードを書いているとやたらエラーが出てきました。

どうやらdiscord.jsのv13とv14で書き方が結構ちがうっぽいです。
というわけで公式ガイドをちゃんと読みました。

https://discordjs.guide/

ちなみに、20時間くらいで目指していた目標の8割が完成しました。
苦戦しながらもなんとかできましたが、特に苦戦した部分を備忘録を兼ねて残しておきます。

VCの情報を取得するには

intentsにGatewayIntentBits.GuildVoiceStatesを追加しないとVC関連の情報の取得が出来ないらしいです。

(全然理解してないけど、C#でいうところのusingやpythonでいうところのimportみたいなもの?)
記事にするのでちゃんと調べました。

Intentsはdiscord.py1.5の新機能です。
これを用いると、「一部のイベントを受け取り、一部のイベントは受け取らない」という選択ができ、
通信量やメモリの使用量を削減することができます。

引用:猿でもわかる!discord.pyのIntentsについて!

他にもintentsに追加しないとできないことがいくつもあるようなので、Botを作る際はこのことを頭の片隅に置いておきたいです。
intentsの一覧 → Discord Developer Portal

入退室時の名前の取得

client.on('voiceStateUpdate', async(oldState, newState) => {
  const channel = oldState.member.guild.channels.cache.find(ch => ch.name === config.sendCh);
  if (oldState.channelId === null && newState.channelId !== null) {
    if (oldState.member.nickname !== null) {
      return channel.send(`${oldState.member.nickname}さんが入室しました。`);
    } else {
      return channel.send(`${oldState.member.user.tag.slice(0, -5)}さんが入室しました。`);
    }
  }
} else if (oldState.channelId !== null && newState.channelId === null) {
  if (newState.member.nickname !== null) {
    return channel.send(`${newState.member.nickname}さんが退出しました。`);
  } else {
    return channel.send(`${newState.member.user.tag.slice(0, -5)}さんが退出しました。`);
  }
});ました。`);
    }
  }
});

このときmember.nicknameはそのサーバーでニックネームを設定していないとnullになります。
member.user.tagだけだと、名前の後ろに#xxxxが入るようです。

Botが起動しなくなる

翌日DiscordBotの様子を見てみるとオフラインになっていました。
ReplitでBotを起動させるコマンドを打っても何も表示されません。

Discord APIにレート制限がかかった時の調査法 - みっくすくらっぷブログ

どうやらレート制限というものがあるようです。
このままでは開発ができないので、とりあえず新しくプロジェクトを作り直したところ、15~18時間くらいでレート制限に引っかかっていました。

作り直してもレート制限にかかるのでは常時稼働はおろか、レート制限に引っかかっている間は起動できません。

Dockerの設定

せっかくの機会なので、Dockerの勉強を兼ねて自分のPCで動かすことにしました。

手順としては

  1. WSL2をインストール

  2. Docker Desktop for Windows

  3. Dockerfileとdocker-compose.ymlの作成

↓の記事を参考にDockerfileを作りました

https://qiita.com/suzuki0430/items/fcf57968365d15419601
https://blog.shinonome.io/nodejs-docker/

完成したコード

https://github.com/syo144/discordbot_v14

終わりに

自分のアウトプット力を鍛える練習を兼ねて書きました。思っていたよりまとめて書くのが難しいですね。誰かの開発のヒントになれば幸いです。
なにかあれば、コメントやTwitterのDMまでお願いします!

脚注
  1. 「Heroku」の無償プランが廃止へ ~Webアプリを開発・運用できるプラットフォーム - 窓の杜 ↩︎

  2. 【初心者向け】Repl.itでDiscordのBotを作る|鮎月さんの日常 ↩︎

Discussion