いーじすの戯言

戯言を書く予定です。しょうもなさ全開

Discord.jsのBotでみまもり君を作る&絵文字を送る

動機とか

新型コロナウイルスのおかげて友人とdiscordで通話しながら作業する機会が増えたので、誰かが通話し始めたら通知が行くと嬉しいな。みたいな感じで作りはじめた。

と言ってもそんなに真面目な目的ではなく、まあdicordのapiとか触ってみたいと思っていたし〜みたいなかるーいノリ
pythonかjsが主流(C#とかもあるらしい)ぽいので、とりあえずjsで書いてみた。
あと、そのサーバでカスタム絵文字で遊ぶ文化があるので、絵文字も送ろうと思ったがちょっと一手間必要で調べてもイマイチぴんと来る資料が見つからなかったので、合わせてまとめて書いた

内輪向けのコードがほぼそのまま乗っているので、一部の人にしか通じないネタがあるが理解できなくてもbotは作れるのでご安心を。気づいたら適当にツイートでもしてくだされ。

前提環境

ssh クライアント

  • MacBook Pro 13-inch Mojave
  • Visual Studio Code
  • サーバー

  • Raspberry Pi 3 Model B+
  • Rasbian 10.3
  • 環境構築

    サーバの設定

    npmとか色々入れる

    sudo apt-get update
    sudo apt-get upgrade
    sudo apt-get install -y nodejs npm
    sudo npm cache clean
    sudo npm install n -g
    sudo n stable
    sudo ln -sf /usr/local/bin/node /usr/bin/node

    serverの適当なところにフォルダを用意し、Erisを入れる

    mkdir discordBot
    cd discordBot
    mkdir watchingBot
    sudo npm install eris
    discordの設定

    サーバーの作成を先にしておいてください ここにアクセス
    左上のNew Applicationを押してBotを作成
    NAMEやアイコンを適当に決め、OAuthのタブに移動
    BOTにチェックを入れ、下のAdministratorにチェック
    Adminにしなくてもいい場合もあるが、後から直すのも面倒なのでこのままで
    この状態でhttps://discordapp.com/api/oauth2/authorize?client_id=〜の形で表示されているurlをコピーし、開くとサーバに追加する画面が表示される
    作成した任意のサーバを選択し、認証
    Botのタブに移動し、TOKENをコピーのボタンを押してTOKENを取得
    あとで使うのでタブを開けておくか、適当に貼っておくかする

    このTOKENは絶対に公開してはいけません

    大荒れしたこともあるらしい。なむなむ。
    githubとかにこのTOKENが上がると自動でdiscordがTOKENを更新して事故(事件)を防ぐらしいけど、気をつけようね。

    本編

    やっていきます
    Visual Studio Code(以後vscode)で新規ファイル index.jsを作成
    vscodesshをしてコーディングをする方法があります。ググってみて

    動作テスト

    まずはEris公式にあるサンプルコードをコピペ

    var bot = new Eris("BOT_TOKEN");
    bot.on("ready", () => {
        console.log("Ready!");
    });
    bot.on("messageCreate", (msg) => {
        if(msg.content === "!ping") {
            bot.createMessage(msg.channel.id, "Pong!");
        }
    });
    bot.connect();
    

    !pingというメッセージを送信するとPong!と返すだけのプログラム
    保存したらindex.jsがあるディレクトリで

    npm index.js

    Botが動きます
    起動前はbotはオフライン表示になっていますが、起動するとちゃんとオンラインになってるはず
    そして!pingと送るとPongと返ることも確認できます

    そしたらカスタマイズして行く

    abal.moe ここの公式サイトを見れば大体のことはできる

    みまもり君のコーディング

    ここでは監視君(?)に必要そうな動作として

  • voice channelに人が来たら指定のtext channelで通知
  • voice channelから人が抜けたら指定のtext channelで通知
  • を実装する

    
    const TOKEN = "??????";
    const Eris = require("eris"); 
     
    //Eriisを作る
    var bot = new Eris(TOKEN); 
    
    var guildId = '000000000000000"';
    var channelId = "000000000000000";
    
    var emojiArray={};
     
    bot.on("ready", () => { 
      console.log("ready"); 
      bot.createMessage(channelId, "進捗みまもり隊が起動しました。進捗どうですか?");
      emojiLoad();
    });
    
     
    bot.on("voiceChannelJoin", (member, newChannel) => { 
      //入室処理
      let ch = newChannel.guild.defaultChannel; 
      
      var reply =  member.username + "さんが チャンネル[" + newChannel.name + "] に入室しました" + emojiArray['sintyoku_dodesuka'];
      bot.createMessage(channelId, reply); 
    }); 
    
    bot.on("voiceChannelSwitch", (member, newChannel, oldChannel) => { 
      //入室処理
      let ch = newChannel.guild.defaultChannel; 
      
      var reply =  member.username + "さんが チャンネル[" + newChannel.name + "] に移動しました";
      bot.createMessage(channelId, reply); 
    }); 
     
    bot.on("voiceChannelLeave", (member, oldChannel) => { 
      // 退室処理 
      let ch = oldChannel.guild.defaultChannel; 
      console.log("%s さんが チャンネル %s を退室しました。:oyasumi:", member.username, oldChannel.name); 
      var reply =  member.username + "さんが チャンネル[" + oldChannel.name + "] を退室しました。"+emojiArray['oyasumi']
      bot.createMessage(channelId,reply);
    }); 
    
    bot.on("messageCreate", (msg) => {
      //Botの投稿を無視する
      //自分自身だけでなく、他のBotも無視する
      if(msg.author.bot)return
      console.log(emojiArray['dame']);
    
      if(msg.content === emojiArray['iidesuyo']) {
          //iidesuyoの絵文字を受け取るとgood_poemの絵文字を返す
          bot.createMessage(msg.channel.id,emojiArray['good_poem']);
          console.log("ok");
      } else if(msg.content === emojiArray['dame']) { 
          //dameの絵文字を受け取るとdamekaの絵文字を返す
          bot.createMessage(msg.channel.id,emojiArray['dameka']);
          console.log("not ok");
      }
    });
     
    //Discordに接続
    bot.connect(); 
    
    function emojiLoad(){
      //serverを特定
     
      var guild = bot.guilds.find(guild => guild.id == guildId);
      console.log(guild.emojis);
      makeEmoji(guild,'sintyoku_dodesuka');
      makeEmoji(guild,'oyasumi');
      makeEmoji(guild,'iidesuyo');
      makeEmoji(guild,'dame');
      makeEmoji(guild,'dameka');
    }
    
    //絵文字の文字列
    function makeEmoji(guild,_name){
      emojiArray[_name]= "<:"+_name+":"+guild.emojis.find(emoji => emoji.name == _name).id +">";
    }
    
    コードの解説
    var guildId = '000000000000000"';
    var channelId = "000000000000000";
    

    もちろん000000〜はダミー
    channelIdはテキストチャンネルのIdで、discordアプリ内でチャンネルを右クリックするとIDをコピーというのがある
    ない場合はユーザー設定->テーマ->開発者モードをオンにすると見れる
    guildIdはサーバ名を右クリックで見れる。guildとはこの場合Discordの各サーバのこと

    bot.on("ready", () => { 
      console.log("ready"); 
      bot.createMessage(channelId, "進捗みまもり隊が起動しました。進捗どうですか?");
      emojiLoad();
    });
    

    botが実行された時に一度だけ実行される
    bot.createMessage(channelId, "進捗みまもり隊が起動しました。進捗どうですか?"); のように、createMessagenにチャンネルIDと発言内容を渡してやるだけで送ることができる

    bot.on("voiceChannelJoin", (member, newChannel) => { 
      //入室処理
      let ch = newChannel.guild.defaultChannel; 
      
      var reply =  member.username + "さんが チャンネル[" + newChannel.name + "] に入室しました" + emojiArray['sintyoku_dodesuka'];
      bot.createMessage(channelId, reply); 
    }); 
    

    voiceChannelJoinnは誰かがvoiceチャンネルに入った時に実行されるイベントになる
    voiceChannelLeaveはいなくなった時、Switchは移動した時に実行
    member.usernameのから名前も取れるのでメンションも簡単につけられる

    bot.on("messageCreate", (msg) => {
      //Botの投稿を無視する
      //自分自身だけでなく、他のBotも無視する
      if(msg.author.bot)return
      console.log(emojiArray['dame']);
    
      if(msg.content === emojiArray['iidesuyo']) {
          //iidesuyoの絵文字を受け取るとgood_poemの絵文字を返す
          bot.createMessage(msg.channel.id,emojiArray['good_poem']);
          console.log("ok");
      } else if(msg.content === emojiArray['dame']) { 
          //dameの絵文字を受け取るとdamekaの絵文字を返す
          bot.createMessage(msg.channel.id,emojiArray['dameka']);
          console.log("not ok");
      }
    });
    

    messageCreateは誰かがmessageを送った時に実行される
    bot自身の送信を拾わないようにしている(無限ループは起こる可能性がある)
    あとはそのまま。簡単だね

    //Discordに接続
    bot.connect(); 

    繋ごう。

    function emojiLoad(){
      //serverを特定
     
      var guild = bot.guilds.find(guild => guild.id == guildId);
      console.log(guild.emojis);
      makeEmoji(guild,'sintyoku_dodesuka');
      makeEmoji(guild,'oyasumi');
      makeEmoji(guild,'iidesuyo');
      makeEmoji(guild,'dame');
      makeEmoji(guild,'dameka');
    }
    

    bot.guilds.findでサーバ名を確かめる
    makeEmojiでemojiArrayに絵文字の文字列を追加
    botで絵文字を送るときは :thinking_face: のように送ってもただの文字列になってしまうので、

    //絵文字の文字列
    function makeEmoji(guild,_name){
      emojiArray[_name]= "<:"+_name+":"+guild.emojis.find(emoji => emoji.name == _name).id +">";
    }
    

    これで <:thinking_face:123456789>みたいにしてやる
    これでサーバに追加したカスタム絵文字が使える。
    nitro課金をしていないのでgifでもできるかは不明。できそうだけど

    終わり

    こんな感じでdiscordとjavascriptで簡単にbotが作れる
    今回はサーバマシンを別に用意したが、macとかでも常駐させればいいし、glitch みたいなサービスを使ってもいい



    …個人的にGASに拡張してみたい
    それでは。