Repl.itでBotの機能を開発しまくったお話

##:star:まずは皆様にご挨拶
**皆様、初めまして!!**:tada:
Repl.itでDiscordBotを開発している『**`姉だぁぁぁぁ`**』と申します。
私は、まだプログラミングを始めたばかりの学生で、このサイトを利用して投稿したりするのは**本当に初めてですが、**
**良い記事の発行や、Botのプログラミング能力を高めたら**と思い、このアカウントを作りました。よろしくお願いします。:bow:

では、本編に参りまっす！
#:star:JSで覚醒した沢山の機能を作ってみる
###:one:リアクションを使って、ページネーションを作成する。
ページネーションを早く、簡単に作成したい場合は**下記のリンクを参照してください。**
（InkoHXさん、ありがとうございます！）
> [**リアクションを使って簡単にページネーションを作成する Discord.js 専用のパッケージ**](https://scrapbox.io/discordjs-japan/%E3%83%AA%E3%82%A2%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E7%B0%A1%E5%8D%98%E3%81%AB%E3%83%9A%E3%83%BC%E3%82%B8%E3%83%8D%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B_Discord.js_%E5%B0%82%E7%94%A8%E3%81%AE%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8)

↑このパッケージを使用することによって、Botのメッセージをリアクションのリアクションで、**簡単にページネーションを作成する事ができます。**

しかし、私は『**できれば自分でページネーションを作成したい**』と思ったので、数か月前にダウンロードしたソースコードを利用して、**ようやくページネーションを作成することができました。**
:star:▽▽▽そのソースコードは以下の通りです。▽▽▽

```js
//ページネーションを作成
client.on('message',async message => {
   if (message.author.bot) { return; }
  if (message.content ===('!help')) {
  const pages = {
//埋め込みでページネーションを作る時に形式を[Java]にしました。
    1: new discord.MessageEmbed()
           .setTitle('(1/2)Title')
           .setDescription("Helpコマンドっす")
           .setAuthor(message.author.tag + 'が実行したな！！', message.author.avatarURL())
           .setColor(16719653)
           .setTimestamp(),
    2: new discord.MessageEmbed()
           .setTitle('(2/2)Title')
           .setDescription("EMBEDを作るのも https://leovoel.github.io/embed-visualizer/ を参照するといいと思う（多分）")
           .setAuthor(message.author.tag + 'が実行したな！！', message.author.avatarURL())
           .setColor(16719653)
           .setTimestamp()
         };
    const options = {
      limit: 15 * 1000,
      min: 1,
      max: 2,
      page: 1,
      pages: pages,
    };
   const awaitReactions = async (msg, m, options, filter) => {
  await m
    .awaitReactions(filter, { max: 1, time: 360000, errors: ["time"] })
    .then(async (collected) => {
//各リアクションをクリックした時の処理を作る↓↓↓
        const reaction = collected.first();
          if (reaction.emoji.name === "◀") {
            await removeReaction(m, msg, "◀");
            if (options.page != options.min) {
              options.page = options.page - 1;
              await m.edit(options.pages[options.page]);
            }
            await awaitReactions(msg, m, options, filter);
          } else if (reaction.emoji.name === "▶") {
            await removeReaction(m, msg, "▶");
            if (options.page != options.max) {
              options.page = options.page + 1;
              await m.edit(options.pages[options.page]);
            }
            await awaitReactions(msg, m, options, filter);
          } else {
            await awaitReactions(msg, m, options, filter);
          }
        })
        .catch((e) => console.log(e));
    };

    const removeReaction = async (m, msg, emoji) => {
      try {
        await m.reactions.cache
          .find((r) => r.emoji.name == emoji)
          .users.remove(msg.author.id);
      } catch (err) {
        console.log(err);
      }
    };
//メッセージを送信↓↓↓
    const m = await message.channel.send(options.pages[options.page]);
//リアクションの並び順を作る↓↓↓
    await m.react("◀");
    await m.react("▶");
//送信したメッセージにリアクション追加↓↓↓
    const filter = (reaction, user) =>
      ["◀",  "▶"].includes(reaction.emoji.name) &&
      user.id == message.author.id;
    await awaitReactions(message, m, options, filter);
  }
});
//ここまで
```

結構長いソースコードです…。
ですが、このソースコードを利用して任意のチャンネルにコマンドを実行すると、**ちゃんと動いているんですよね…**
> ![実験画像](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1034619/88955ecf-9824-4476-3713-782ced6c0240.png "例１")
![実験画像](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1034619/ea498074-c30d-4f22-f6b5-819a6129f1bc.png "例２")
この通りです♪

そんな感じですかね…
**このソースコードを色んな風に使うと、様々な埋め込みをシンプルっぽくデザインすることができまっす。**
リアクションが追加されない場合は、**Botの権限の『リアクションの追加』をONにして下さい。**
***
###:two:YouTube検索機能を作成する。
:star:`!youtube [検索ワード]`**でYouTubeにある動画を検索できるソースコードは、以下の通りです。**

```js
//ようつべ検索
const yts = require('yt-search');//npmをインストール

client.on('message', async message => {
    if (message.content.startsWith("!youtube")) {
    if (message.author.bot) { return; }
  const AKB = message.content.split(" ").slice(1).join(" ")
//調べたい用語を入れなかった時のメッセージ↓↓↓
    if (!AKB) return message.channel.send({embed: {
        color: 16719653,
        description: '**調べたい用語を入れてね！**\n```使用例　：　!youtube Discord```'
      }
    })
//YouTubeで検索中の時のメッセージ↓↓↓
    const msg = await message.channel.send({embed: {
        color: 16719653,
        author: {
          name: "Youtube内で検索中なんだ！！ちょっとまてよぉぉ！！",
        },
      }
    });
    yts(AKB, function(err, r) {
      const videos = r.videos
      const playlists = r.playlists || r.lists
      const channels = r.channels || r.accounts
//メッセージを編集して動画URLをうｐ↓↓↓
      msg.edit('✅動画が見つかったよぉぉぉ！！！', {
        embed: {
          color: 16719653,
          timestamp: new Date(),
          author: {
            name: message.author.tag + 'が実行したな！！',
            icon_url: message.author.avatarURL(),
          },
          title: videos[0].title,//動画のタイトル
          description: '**動画URL**\n> ' + videos[0].url + '\n\n**　　そうかそういう動画か**'
        }
      })
    })
  }
});
//ここまで
```
そんな感じですね。
**埋め込みで動画URLとかを貼り付けるので、おしゃれにできるはずです。**
わざわざYoutube.comに飛んで検索しなくて済むから、便利と言えば便利かも知れないね…
**※`yt-search`は必ずインストールしないと、このソースコードは使えません！**
***
###:three:確認画面有りのKickコマンドを作る。
私が、Bot作る中で一番苦労したのは**『確認画面が有るKickコマンド』を作る事**でしたね…。
良いコマンドにしたくて色んなソースコードを組み合わせたものの、Runボタンを押したら…沢山の所からエラー吐いて来たので始末することに**かなり時間が掛かりました。（）**
:star:▽▽▽そのソースコードは以下の通りです。▽▽▽

```js
//Kickコマンド
client.on('message', async message => {
  if (message.author.bot) { return; }
  if (message.content.startsWith('!kick') && message.guild) {
//コマンドを実行したユーザーの権限を確認↓↓↓
  if (!message.member.hasPermission('KICK_MEMBERS')) {
//Kickする権限が無ければメッセージを↓↓↓
      return message.channel.send({embed: {
          color: 16719653,
          description: '**Kickする権限ないよ！！**',
        }
      })
    }
    const user = message.mentions.users.first();
    if (user) {
      const member = message.guild.member(user);
//権限を持っている人がKickコマンドを実行したら確認画面を↓↓↓
      const msg = await message.channel.send({
        embed: {
          color: 16719653,
          timestamp: new Date(),
          author: {
            name: message.author.tag + 'が実行したな！！',
            icon_url: message.author.avatarURL(),
          },
          description: '**本当にこれでいいのかよ！？**\n```diff\n+ [ok],[no]のどれかを送信してクレメンス\n+ ok → mentionしたメンバーをKick。\n+ no → mentionしたメンバーをKickせず、処理を停止するぜ。```'
        }
      });
//回答による処理を作る↓↓↓
      const filter = msg => msg.author.id === message.author.id
      const collected = await message.channel.awaitMessages(filter, { max: 1, time: 300000 })
      const response = collected.first()
      if (!response) return message.channel.send('> **応答はやくしてよぉぉぉ！！！**')
      if (!['ok', 'no'].includes(response.content)) { return; }
//noを送信したら↓↓↓
      if (response.content === 'no') return msg.edit({embed: {
          color: 16719653,
          author: {
            name: 'Kickの処理を止めたよ！！',
          },
        }
      });
//okを送信したらKick!!↓↓↓
      if (response.content === 'ok') {
        if (member) {
          member
            .kick('監査ログに出されるやつ')
            .then(() => {
              msg.edit({embed: {
                  color: 16719653,
                  timestamp: new Date(),
                  author: {
                    name: message.author.tag + 'が実行したな！！',
                    icon_url: message.author.avatarURL(),
                  },
                  description: '**ｷｨｨｨｨｯｸ!!!**\n**' + `${user.tag}` + '**をKickしたよ！！',
                }
              })
            })
//エラーメッセージ↓↓↓
            .catch(err => {
              msg.edit({embed: {
                  color: 16719653,
                  description: 'Kickできなかったよ！！権限確認してよぉぉ！！'
                }
              });
              console.error(err);
            });
        } else {
//メンションされたユーザーがサーバーにいない時↓↓↓
          message.channel.send({embed: {
              color: 16719653,
              description: 'そいつここのサーバーにいないよぉぉ！！'
            }
          })
        };
      }
    } else {
//対象を指定していない時↓↓↓
      message.channel.send({embed: {
          color: 16719653,
          description: '**Kickしたいメンバーをメンションしてね！！**```使用例　：　!#kick [@mention]```'
        }
      });
    }
  }
});
//ここまで
```
そんな感じですね。
これで、**確認画面有りのKickコマンドが作れます。**
確認画面の下の方のこれ↓↓↓

```js
      const filter = msg => msg.author.id === message.author.id
      const collected = await message.channel.awaitMessages(filter, { max: 1, time: 300000 })
      const response = collected.first()
      if (!response) return message.channel.send('> **応答はやくしてよぉぉぉ！！！**')
      if (!['ok', 'no'].includes(response.content)) { return; }
      if (response.content === 'no') return messsage.channel.send('なんでnoだにゃーん');
      if (response.content === 'ok') { message.channel.send('んにゃ')}
```
**結構色んなコマンドの所で使えるので、是非試してみて下さい！**
***
###:four:ステータスを変える方法
Botのステータス（カスタムステータス含む）を変えるには、**下記のリンクを参照にするといいです。**
（作成者様、ありがとうございます！）
> [**Discord.js 例文 (v12.2.0)**](https://bindle29.hatenablog.com/entry/2018/02/16/111623)

:star:カスタムステータスの所のソースコードは、以下の通りです。

```js
client.on('ready', message => {
  console.log('準備完了っす！');
  client.user.setActivity('にゃーん', { type: "PLAYING" });
       /*
        typeの値:
            https://discord.js.org/#/docs/main/stable/class/ClientUser?scrollTo=setActivity
                'PLAYING': 〇〇 をプレイ中
                'STREAMING': 〇〇 を配信中
                'WATCHING': 〇〇 を視聴中
                'LISTENING': 〇〇 を再生中
        */
});
```
カスタムステータスの所はこの通りに簡単に変えることができますが、『じゃあ、退席中等のステータスの所は？』と言いますと…それは、**`status値`を使って変える事ができます。**

```js
  status: "online"
       /*
                'online': オンライン
                'idle': 退席中
                'dnd': 邪魔しないで下さい
                'offline': オフライン
         ただしスマホステータスにしたい場合は別になる。
        */
```
これを入れればできると思います。
**スマホステータスに変えたい場合は、クライアントを作るところをいじればできるはず。**
:star:ソースコードは以下の通りです。

```js
const client = new discord.Client({ ws: { properties: { $browser: "Discord iOS" } } });
```

これでしばらくすると、**ステータスがスマホマークになります。**
#:star:最後に
結構沢山の所のねたばらしみたいな感じになってしまいましたが…私は、まだDiscord.jsのことをまだ完全に理解しているという訳ではないので**できれば大目に見てくれると幸いです。**
そして、こんなjsのソースコードだらけの記事を最後まで見て下さり、**誠にありがとうございました。**

**もし、最後まで見て「あれ？」と思う事がございましたら、この記事にコメントをするか、
Discordの[`姉だぁぁぁぁ#1985`]にDMを下さい。**
できる限りの事はお答えします！
ありがとうございました。