Discord.js でボットを作る ～発言させるまで～

！この記事は前に書いた記事の続きです。環境構築まだ・Node.js LTS (14 だっけ) を使ってる(ここのコードなんか動かん)人はぜひ！

https://qiita.com/yuto0214w/items/432c9f702b3d1067a29c

# このページでやること
1. アカウント・サーバー作成
2. ボットの作成からトークンの取得まで
3. コードを書く

## 目次みたいなの
Discord アカウントを持っていない ー＞　アカウントを作る
サーバーを作っていない、または入っていない　－＞　サーバーを作る
ボットを作っていない　－＞　ボットを作る
準備が整っている　－＞　コードを書く

|Go to...|ボットを作る|コードを書く|
|:-:|:-:|:-:|
|Select|[██████](#ボットを作る)|[██████](#コードを書く)|

:::note info
アカウント作成からサーバー作成までは Discord の基本なのでまとめました。
基本的には権限さえ持っていれば問題ないです。
:::

<details><summary>アカウント作成からサーバー作成まで</summary><h2>アカウントを作る</h2><p>まずは、このURLにアクセスして、アカウントの登録をします。

https://discord.com/register

それだけです。
次に行きましょう。</p><h2>サーバーを作る</h2><p>既にサーバーがある人は飛ばしちゃってください。</p><h3>1. サーバーに入れてもらう</h3><p>友達とかに招待してもらう方法です。
画面左にある「＋」をクリックします。
そしたら「サーバーに参加」をクリック、
教えてもらったコードを入力し、参加をクリックします。
ただ、ボットを作成するにあたって権限を与えてもらう必要があります。
僕も友達のサーバーに入れてもらうことにしようとしましたが...
\> ん？サーバーがないぞ？あれ？あ、そうか！
友達いないんだっけ (´・ω・`)</p><h3>2. サーバーを作る</h3><p>サーバーを作る方法です。
まず画面左にある「＋」をクリックします。
そしたら「サーバーを作成」をクリックします。
サーバー名入力して、新規作成をクリックします。
これでOKです。次へ行きましょう。</p></details>

## ボットを作る
びゅーん
では早速作っていきましょう。
まずは Developer Portals にアクセスします。

https://discord.com/developers/applications

そして、右上の方にある `New Application` をクリックします。
そしたら `NAME` にボットの名前を入力して `Create` を押します。
するとなんか出てきます(語彙力) 簡単に説明すると、

- `APP ICON` = ボットのアイコン。
- `NAME` = ボットの名前。
- `DESCRIPTION (MAXIMUM 400 CHARACTERS)` = 説明。400字までで、ボットの About Me になる。
- `TAGS (MAXIMUM 5)` = ボットのタグ...？5つまで。多分なんか新しい機能を作っているんでしょう(知らんけど)
- `APPLICATION ID` = ボットの ID
- `PUBLIC KEY` = Discord Interactions で使われる認証鍵。`PUBLIC` だからといって、周りに公開するものではないです

...という様な感じです。
では左側の `SETTINGS` を見てください。
今は `General Information`を選択しています。`Bot` をクリック。
すると画面は変わって真ん中に `Build-A-Bot` と表示されます。横の `Add Bot` をクリック。
そしたら確認が出てくるので `Yes, do it!` を押しましょう。

|`A wild bot has appeared!`|
|:-:|

と出たら成功です。これでボットができます！
でももし、

|`Too many users have this username, please try another.`|
|:-:|

と言われてしまった人は残念ながらその名前は使えないので、他の名前にする様にしましょう。
わるい例: `test` や `bot` など

---

ではここに表示されている項目について簡単に説明します。

- `ICON` = ボットのアイコン。
- `USERNAME` = ボットの名前。
- `TOKEN` = トークン。ボットの中で一番大事なやつ。**決してインターネットで晒すことをしてはいけない。**
- `PUBLIC BOT` = オンならそのボットの `APPLICATION ID` が分かっててかつ権限を持っていればだれでもそのボットをサーバーに招き入れることができます。逆にオフにすれば自分しか追加できなくなります。
- `REQUIRES OAUTH2 CODE GRANT` = オフのままにしときましょう。

:::note warn
<strong>Privileged Gateway Intents</strong>
「PRESENCE INTENT」と「SERVER MEMBERS INTENT」「MESSAGE INTENT」すべてオンにしといたほうがいいです。
これがないと割と何もできないので...
:::

---

`TOKEN` 近くの `Reset Token` を押すことで、新しいトークンを生成できます。トークンお漏らししてハックされた時でも、ここからリセットすれば案外なんとかなります。(管理を怠れといういみではないです)
後で使うので、メモ帳なりなんなりにコピーしときましょう。

では次です。サーバーに追加します。
左側の `SETTINGS` から `OAuth2` をクリックし、その下の `URL Generator` をクリック。
するとたくさんのチェックボックスが見えると思います。
「bot」と「application.commands」を選んでください。
そしたら使いたい権限を選びましょう。自分用なら `Administrator` (管理者権限) でもいいかも。

最低でも

- `Read Messages/View Channels` (メッセージを読む/チャンネルを見る)
- `Send Messages` (メッセージを送信)
- `Read Message History` (メッセージ履歴を読む)

は欲しいかもしれません。

すると下にURLが出ていると思います。そのURLに飛びましょう。
すると、ボットをサーバーに追加するページに飛びます。
「サーバーを選択」とあるので、ここで作った・または入ったサーバーを選びましょう。

:::note warn
ここでサーバーが表示されない人は、おそらく権限がないです。
「サーバーの管理」権限をもらうか、サーバーを作りましょう。
:::

サーバーで確認してみて、ボットが表示されていれば成功です。次へ行きましょう。

## コードを書く
今度はディレクトリ(フォルダのことです)を用意します。
僕の場合 `Daikichi` というディレクトリを作りました。
空白さえ入っていなければ大丈夫そうです。
そしたらそこでターミナルを開きます。(Bash や PowerShell、Termux のことです)
そして `npm init -y` を入力します。

:::note info
ターミナルの開き方はOSによって異なります。
<details><summary>Windows</summary>Windows であれば、ボットのフォルダを開いたエクスプローラーの上で Shift + 右クリックをし、「PowerShell (コマンド ウィンドウ)をここで開く」をクリックすることでできます。</details>
<details><summary>Mac</summary>Mac では <code>command+スペース</code> を押し、<code>terminal</code> と入力するとターミナルが開けます。そうしたら <code>cd</code> と入力し <code>スペース</code>、そしたら Finder でさっき用意したディレクトリを開き、ターミナルに<a href="https://www.howtogeek.com/wp-content/uploads/2021/07/folder_drag.mov.gif?format=mp4">このようにドラッグします</a>。(出典: <a href="https://www.howtogeek.com/742518/use-drag-and-drop-to-speed-up-mac-terminal-commands">HowToGeek</a>)</details>
<details><summary>Linux</summary>Ubuntu ではそのままエクスプローｒ<br>ファイルマネージャー上でそのまま右クリックし、「ターミナル(端末)を開く」をクリックすることでできます。<br>別のディストリビューションや、GUIインターフェースでも似たようなことができるものが多いです。<br>もしCUIであったり、GUIでできなければ <code>cd</code> コマンドで導いてあげましょう。</details>
<details><summary>Termux (Android)</summary>Termux も <code>cd</code> コマンドで導いてあげればよいですが、少し<a href="https://wiki.termux.com/wiki/FAQ#:~:text=How%20can%20I%20access%20device%20storage%20with%20Termux">設定が必要</a>かもしれません。Android のダウンロードフォルダに作ったなら <code>cd storage/downloads</code>、ストレージのどこかに作ったらなら <code>cd storage/shared/どこか</code> とすればよいです。</details>
:::

Yarn が入ってる人は `yarn init -y` です。
すると、package.json ができます。

```json:package.json
{
  "name": "Daikichi",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "MIT"
}
```

大体こんな感じに編集します。

```json:package.json
{
  "name": "名前",
  "version": "1.0.0",
  "description": "説明",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "author": "自身の名前",
  "license": "MIT"
}
```

(GitHub にあげたりとかする必要がなければこれで十分です)

```json:package.json
{
  "name": "名前",
  "version": "1.0.0",
  "scripts": {
    "start": "node index.js"
  }
}
```

そこで今度はターミナルの方で `npm install discord.js` を入力します。(Yarn なら `yarn add discord.js`)
無事終われば早速ボットのコードを書いていきましょう！
ディレクトリに `index.js` というファイルを作ります。

:::note warn
Windows の場合「新しいテキスト ドキュメント」の後に「.txt」がついていなければ拡張子が表示されていません。
はまりポイントでもあります。
そういう場合、ファイルオプションなどから拡張子を表示する設定にするのが一番相応しいですが、コマンドプロンプトなどから <code>echo c>index.js</code> などとすることでも作成することできます。
:::

そうして出来た「index.js」に早速記述していきましょう！

:::note warn
今日はやたらと黄色いのが多いですね。
ですがこれは v1**4** のコードです！2022/7/18 以前にインストールされた Discord.js (v13.9.0) では動かないです。
v13 用のコードは下にあります。あまり変わらないようにみえますが一部変わっています。
:::

```javascript:index.js
const { Client, GatewayIntentBits } = require("discord.js");
const client = new Client({
  intents: Object.values(GatewayIntentBits).reduce((a, b) => a | b)
});

client.on("ready", () => {
  console.log(`${client.user.tag} でログインしています。`);
});

client.on("messageCreate", async msg => {
  if (msg.content === "!ping") {
    msg.reply("Pong!");
  }
});

client.login("トークン");
```

<details><summary>Discord.js v13 のコード</summary><div>

```javascript:index.js
const { Client, Intents } = require("discord.js");
const client = new Client({
  intents: Object.values(Intents.FLAGS).reduce((a, b) => a | b)
});

client.on("ready", () => {
  console.log(`${client.user.tag} でログインしています。`);
});

client.on("messageCreate", async msg => {
  if (msg.content === "!ping") {
    msg.reply("Pong!");
  }
});

client.login("トークン");
```

</div></details>

取りあえずはこれでOK。最後の `トークン` にはさっきコピーした TOKEN をペーストします。
そしたらターミナルに戻ってください。
そこで `node index.js` と打ってみてください。

```
Name#0000 でログインしています。
```

の様に表示されて Discord を開くとボットがオンラインになっています！
`!ping` と入力してみてください。
するとボットが「Pong!」と返してくれます！

:::note info
上手くいかない時はインターネットの問題または上で Privileged Intents をオンにしていない可能性が高いです。
一度確認してみてください。
分からないことがあれば気軽に <a href="https://twitter.com/yuto0214w">Twitter</a> でDMください。
:::

では仕組みを説明していきます。まずはこれ。

```javascript:index.js 1ー4 行目
const { Client, Intents } = require("discord.js");
const client = new Client({
  intents: Object.values(Intents.FLAGS).reduce((a, b) => a | b)
});
```

ここでは定義をしています。さっき `npm install...` で追加したやつですね。
`discord.js` から `Client` と `GatewayIntentBits` を取り出す...？？
`Client` を `client` として初期化する...おぶじぇくとばりゅー...？？？
私は Privileged Intents が好きじゃないです。ボット作成を少しはまりやすくしたなぁという感想があります。
一言でいえば「ボットは何ができるか」というフラグが `GatewayIntentBits` にあり、それらすべてを使っています。

```javascript:index.js 6ー8 行目
client.on("ready", () => {
  console.log(`${client.user.tag} でログインしています。`);
});
```

これは準備が出来たらプロンプトに「～でログインしています。」と表示させるやつです。
JavaScript は `console.log("メッセージ")` がターミナルにメッセージを表示させる基本形です。
エラーがどこで起きているかとかの確認によく使うので、覚えておきましょう。
では次。

```javascript:index.js 10ー14 行目
client.on("messageCreate", async msg => {
  if (msg.content === "!ping") {
    msg.reply("Pong!");
  }
});
```

これはそのまま日本語に訳してしまった方がきっと分かりやすいです...

```text:日本語訳
クライアント.が(イベント "messageCreate" を受信したら, それを msg とする => {
  もし (msg.の内容 が "!ping" なら) {
    msg.に返信する("Pong!");
  }
});
```

こんな感じです。
では最後。

```javascript:index.js 16 行目
client.login("トークン");
```

これはボットでログインするためのやつ。

# その他
## 豆知識1: JavaScript の == と ===
ちなみに、

```javascript
if (msg.content === "!ping") {
  msg.reply("Pong!");
}
```

の最初の行、

```javascript
if (msg.content === "!ping") {
```

`===` のところを、

```javascript
if (msg.content == "!ping") {
```

と書いても動くには動きますが、そうすると後々大変なことになってしまうケースもあるので、やめた方がいいでしょう。
これを `eqeqeq` と `eqeq` の違いと言います。
`厳密等価演算子` と `等価演算子` の違いと言ったりもします。 
`eqeq` を使ってしまうと型を考慮しないので、

```javascript
'1' == 1 // true
```

となってしまいます。

## 豆知識2: TypeScript
TypeScript という言語をご存じでしょうか？
TypeScript は一言で説明すると JavaScript の強化版といったところでしょうか？
「型」というものが厳密になって正しく使えばバグを減らせるというもの。
「型」について知ると Discord.js のドキュメンテーションが読めるようになってさらに世界が広がると思います...
でもいきなりやれというのもかなり難しい言語です。
JavaScript についてある程度理解出来たら　挑戦してみるといいかもです

## ネタ
IRL Example (かつて Developer Portals に存在したフィールド) を再現！

> 名前
>
> **PERMISSIONS**
> &#x2705; Bake a cake
> &#x2705; Buy you a nice seafood dinner
> &#x2705; Have an existential crisis
> &#x2705; Microbrew some local kombucha
> &#x2705; Record a new mixtape.

# 終わりに
作ってみてどうでした？楽しかったり嬉しかったりしてくれたら幸いです。
次からはボットのコマンドを作っていきましょう。