Discord.jsでWebhookを利用したグローバルチャットの作り方

# はじめに

この記事では、webhookを利用したグローバルチャットのサンプルコードを書きます。
投稿するのは、初めてなので何か間違っていたら、教えてください。

### 追記
この記事のコードは最新のdiscord.jsには対応していません。
暇があればdiscord.js v13向けのものを書きます(その頃には既にほかの人が書いてるかも)

# 必要なもの
- fs
- discord.js v12.3.0
- Botアカウント

(Botアカウントの設定や、Discord.js、fsのインストールなどはすでに済ませている前提で書きます。)

# コード
```js
const Discord = require("discord.js")
const client = new Discord.Client()
const fs = require("fs")
const prefix = "?"

client.on("ready", () => {
  console.log(client.user.tag + "でログイン中")
});
client.on("message", message => {
  if (message.author.bot) {
    return;
  }
  if (message.channel.type == "dm") {
    return;
  }
  if (message.content == prefix+"globalchatjoin") {
    if (!message.channel.permissionsFor(message.guild.me).has("MANAGE_WEBHOOKS")) {
      message.channel.send("Webhookを作成する権限がありません。")
      return;
    }
    message.channel.createWebhook('グローバルチャット用webhook').then(webhook => {
      var webhookinfo = {
        "id": webhook.id,
        "token": webhook.token,
        "channel": message.channel.id
      }
      var savedata = JSON.stringify(webhookinfo);
      try {
        fs.mkdirSync(`globalchatfiles/${message.guild.id}/`, { recursive: true });
        fs.writeFileSync(`globalchatfiles/${message.guild.id}/webhook.json`, savedata);
        //成功すれば、Webhookが保存されます。
      }
      catch (error) {
        message.channel.send("参加できませんでした。")
        return;
      }
      var sentchannelid = webhook.channel
      const webhooks = new Discord.WebhookClient(webhook.id, webhook.token)
      webhooks.send("グローバルチャットに参加しました。")
      //ほかのサーバーに参加通知を送る
      //サーバーごとにファイルを読み込んで、webhookで送信する。
      client.guilds.cache.forEach(guild => {
        try {
          var webhookjoined = JSON.parse(fs.readFileSync(`globalchatfiles/${guild.id}/webhook.json`))
        } catch (err) {
          return;
          //参加していなければ、そのサーバーはパスする。
        }
        var channelid = webhookjoined.channel
        try {
          client.channels.cache.get(channelid).id
        }
        catch (error) {
          return;
          //チャンネルが削除されていたら、動作をキャンセルするコード。
        }
        var webhookid = webhookjoined.id
        var webhooktoken = webhookjoined.token
        if (message.channel.id == sentchannelid) return;
        if (message.guild.id == guild.id) return;
        try {
          new Discord.WebhookClient(webhookid, webhooktoken).send(message.guild.name + "が、グローバルチャットに参加しました。", { username: "グローバルチャットマネージャー", disableMentions: "all"})
        } catch (error) {

        }
      })
      //webhookは、チャンネルごとに10個までしか作れないので、作成できなかった場合には、参加成功メッセージが来ない仕組み。
    }).catch(console.error);
  } 
});
client.on("message", message => {
  if (message.author.bot) {
    return;
  }
  if (message.channel.type == "dm") {
    return;
  }
  try {
    const guild_webhook = JSON.parse(fs.readFileSync(`globalchatfiles/${message.guild.id}/webhook.json`))
    var sentchannelid = guild_webhook.channel
  } catch (error) {
    return;
    //読み取れなかった場合、ほとんどの場合は参加していないのでリターンする。
  }
  if (message.channel.id == sentchannelid) {
    //サーバーごとにファイルを読み込んで、webhookで送信する。
    client.guilds.cache.forEach(guild => {
      try {
        var webhook = JSON.parse(fs.readFileSync(`globalchatfiles/${guild.id}/webhook.json`))
      } catch (err) {
        return;
        //参加していなければ、そのサーバーはパスする。
      }
      var channelid = webhook.channel
      try {
        client.channels.cache.get(channelid).id
      }
      catch (error) {
        return;
        //チャンネルが削除されていたら、動作をキャンセルするコード。
      }
      var webhookid = webhook.id
      var webhooktoken = webhook.token
      const serverwebhook = new Discord.WebhookClient(webhookid, webhooktoken)
      if (message.channel.id == channelid) return;
      if (message.guild.id == guild.id) return;
      try {
        serverwebhook.send(message.content, { username: message.author.tag, avatarURL: `https://cdn.discordapp.com/avatars/${message.author.id}/${message.author.avatar}.png`, disableMentions: "all"})
      } catch (error) {
      }
    })
  }
});

client.login("トークンをここに記述")
```

これ単体でも、Botは動くと思うので、お試しください。



# 説明

## 権限不足時
```js
if (!message.channel.permissionsFor(message.guild.me).has("MANAGE_WEBHOOKS")) {
  message.channel.send("Webhookを作成する権限がありません。")
  return;
}
```
このコードは、webhookを作る権限がBotに与えられていないときにキャンセルするためのコード



## disableMentions

webhookで送信するときのコードに書かれている `disableMentions: "all"` は、@everyoneや、ユーザーに対するメンションを無効化するためのコード
(ユーザーに対するメンションを許可するには、everyoneに設定する。)

# 参考サイト
[公式ドキュメント](https://discord.js.org/#/docs/main/stable/general/welcome)