ランダム投稿&定時に日数をカウントダウンしてくれるDiscord botの作り方解説

function morning() {
    const discordWebHookURL = "ここにdiscord botのWebhookを取ってくる";
  // 試験名
  var examName = '第58回気象予報士試験';
  // 試験日
  var examDate = new Date('2022/08/21 23:59:59');
  // 本日日付
  var today = new Date();
  // 試験日までの日数を取得
  days = Math.floor((examDate - today) / (24*60*60*1000));
  today = Utilities.formatDate(today,"JST", "yyyy/MM/dd");

  // メッセージを送信する
  if(days >= 0){

  // シートデータ取得
  var id = "参照する";
  var spreadsheet = SpreadsheetApp.openById(id);  
  var sheet = spreadsheet.getSheetByName('シート1'); 
  var lastRow = sheet.getLastRow();
  
  //2行目~最終行の間で、ランダムな行番号を算出する
  var row = Math.ceil(Math.random() * (lastRow-1)) + 1;
  
  var question = sheet.getRange(row, 2).getValue();
  var answer = sheet.getRange(row, 3).getValue();
  var citation = sheet.getRange(row, 4).getValue();
  if(citation == ""){
    title = '今日の1回目の正誤問題はこれ!'
  }else{
    title = '今日の1回目の正誤問題は __' + citation + '__ から!'
  }

    const message = {
    "content": 'おはよう!\n' + examName + 'まであと**' + days + '**日!', // チャット本文
    "tts": false,  // ロボットによる読み上げ機能を無効化
    "embeds": [
        {
          "title": title,
          "description": question +'\nこれは〇か✕か?\n\n' +'解答は  '+ '|| '+answer+' ||'+'  だよ!\n(↑クリックまたはタップしてみてね!)',
          "color": 16753920,
        }
      ]
    }

    const param = {
    "method": "POST",
    "headers": { 'Content-type': "application/json" },
    "payload": JSON.stringify(message)
     }

  UrlFetchApp.fetch(discordWebHookURL, param);
  }
}

はじめに

こんにちは、hiroです。今日は、Discordで作ったランダム投稿&定時に日数をカウントダウンをしてくれるDiscord bot(通称はれるん問題出題bot)の作り方と、プログラム全容を解説していきたいと思います。上に貼ったのがプログラムの全容です。意外と少ない???順を追って解説していきます。

作り方解説

はれるん問題出題bot

完成品は上のようになっています。やっていることとしては、

  1. 毎日定時で投稿する
  2. 気象予報士試験までの日数をカウントする
  3. 気象予報士試験の問題をランダムに投稿する

というものです。それぞれの機能について、順を追って実装方法について解説していきたいと思います。

1.毎日定時で投稿する機能の実装

毎日定時で投稿するという機能を達成するために、Google Apps Script(通称GAS)というGoogle スプレッドシート付属の機能を使っています。

GASへと

スプレッドシートからGASへ飛ぶと、以下のような画面が出てきます。

GASの体裁

ここに実行したいプログラムを書いて「実行」ボタンを押すと、プログラムを動かしてくれる仕組みになっています。GASの言語はjavascriptですので、pythonを書いたことがある方なら同じインタプリタ言語として比較的スムーズに書けるんじゃないかと思います。

トリガーの設定

GASの特色として、定時投稿をしやすいのでこのbotではGASを使っています。というのも、標準機能として左側タブから「トリガー」ボタンを押して上のような画面に飛び、多少の設定するだけで、自動で決まった時間に指定のプログラムを実行してくれるという優れものなんです。GAS以外のプラットフォームを使おうと思うと、サーバーを用意したり、定時投稿するプログラムを別途書いたりする必要があるので、今回のようなランダム投稿&日数カウントダウンの機能を持ったbotを動かしたい場合、GASを使用するのをお勧めします。
上の画像では、朝、夕方、夜、の1日に3回問題投稿がされるようトリガーを設定しています。朝しかカウントダウンをしない設定にしている為、プログラムを朝用、夕方用、夜用、と別途用意してそれぞれのプログラムを指定の時間に実行されるように設定しています。

GASとDiscord、スプレッドシートを紐づける

ここからは、GASの中のプログラム内のコードについても解説していきます。まずは、コードを書く際、このGASが指定のDiscordに投稿されるよう設定しなければなりません。また、問題を出題する際、スプレッドシートに記載されている内容からランダムに取ってくる仕様にしたいので、GASが問題スプレッドシートにアクセスできるようにする必要があります。そこの解説についてです。

Diccord Webhook URLの取得

qiita.com
詳細については上のURLを参考にしてください。DIscordの設定画面からWebhook URLを取得します。

スプレッドシートIDの取得

参照したいスプレッドシートのURLを見てください。「https://docs.google.com/spreadsheets/d/」「/edit#gid=0」で挟まれた暗号のような部分があると思うんですけど、これがスプレッドシートIDであり、スプレッドシートにアクセスする為の鍵となります。これも控えておきます。

GASに紐づける為にコード内にそれぞれのURLを記載
下ごしらえパート

それでは、先ほど取得したURLをコード内に記入していきましょう。DIscord Webhook URLが2行目、スプレッドシートIDが17行目に記載されています。これで、DiscordとGASとスプレッドシートが繋がりました。

2.気象予報士試験までの日数をカウントする機能の実装

ここで、コードの初めの部分が出てきたので、ここのプログラムの解説について行いたいと思います。この部分は、プログラムの核となる部分を書くための下ごしらえパートとなっています。この部分で、気象予報士試験までの日数を計算しています。それでは見ていきましょう。
1行目では「morning」という関数を定義しています。実行するときは、GASの「実行する関数を選択」ボタンから「morning」を選択してください。
4行目、6行目、8行目ではそれぞれ試験名、試験日、本日の日付を定義しています。
10行目ではMath.floor関数を使い、試験日と本日の日付の差分(ミリセカンドで出力される)を日付に直し、小数点以下は切り捨てることで試験までの日数を「days」に格納しています。
11行目では、本日の日付のフォーマットを日本時間の「西暦/月/日」の形式に変換しています。
14行目では、if関数を用いてdaysが0以上、すなわち気象予報士試験に到達するまでの期間に、それ以下のプログラムを実行するよう定めています。
17,18,19行目では指定のスプレッドシートの「シート1」を参照するように言っています。以下、「sheet」の後にコマンドを入力することでこのシートを操作することが出来るようになっています。
ここまでが下ごしらえパートです!10行目で、気象予報士試験までの日数カウントダウン部分が計算されました。

3.気象予報士試験の問題をランダムに投稿する機能の実装

本体パート

それでは、20行目以降のプログラムの根幹に関わる部分の解説を進めます。ここで問題をランダムに投稿する部分のコードが書かれています。前から順番に解説していきましょう。

20行目では、スプレッドシートの書き込みがある部分(問題が書かれている部分)の最終行を「lastrow」として保存しています。
23行目では、Math.randomで0~1の中で乱数を取得し、全行となる「lastlow -1」を掛け合わせ、Math.ceilでその値を切り上げた後、1を足しています。これにより、2行目から最終行目までの無作為な行数について抽出しています。これを「row」として保存しています。

スプレッドシート内の構成

スプレッドシート内では、上図のようにB列に問題、C列に〇か✕の答え、D列に引用元の試験回を記録しています。25,26,27行目では、「question」「answer」「citation」に、23行目でランダムに選んだ行のB列、C列、D列の値を格納しています。
28行目~32行目では、もし引用元があればそれを示し、無ければそれを含まないような「title」を格納しています。「title」は「message」としてDiscordに投稿する際の重要な引数となっています。
それでは、以下はDiscordに投稿する際の内容です。
34行目で、以下の行で「message」を定義すると宣言しています。メッセージは、「おはよう!試験まであと○○日!」という内容になっています。○○のところには10行目で計算した日数が入ります。また、Discordの中でロボットが読み上げる機能を無効化しています。それが35行目、36行目の内容です。
37行目~43行目では「embeds」を定義しています。これは、Discord特有の投稿装飾機能です。

embeds(オレンジの枠内)

太字部分が先ほど定義した「title」、細字部分が「discription」、「color」は左側の装飾色で、カラーコードで指定しています。DIscordの規則として、「**」で囲むとアンダーライン、「||」で囲むとブラインド(クリック又はタップで表示)、「\n」で改行となっています。
46行目~50行目は投稿に関わる形式を指定している部分です。「param」に「message」の形式を格納しています。
52行目で、指定のDiscordチャンネルに「param」を実際に投稿しています。

プログラムは以上のようになっています。

このプログラムを活用すると…

気象庁HPbot
試験までの日数を管理してくれる秘書bot

このはれるん問題出題botのプログラムを利用して、私は2つの派生botを作りました。
1つ目は、気象庁のHPから予め重要な部分を抽出しておいて無作為にHPへのリンクを教えてくれる「気象庁bot」です。私は、気象予報士専門試験対策の為に、気象庁のHPを毎日読めるようなbotがあれば良いな~と思いこのbotを作成しました。春ちゃんが季節の挨拶と共に気象庁HPへの案内をしてくれます。
2つ目は、試験までの日数を毎日カウントダウンしてくれる「秘書bot」です。「計画的に頑張ってくださいね!」という励ましとともに、推しキャラが受ける予定である試験までのカウントダウンを毎日早朝に行ってくれます。毎日、私はこれを見て「今日も頑張ろう!」という気持ちで出勤しています。

使い方は色々あると思います。皆さんそれぞれに自分に役立つDIscord botを作成されては如何でしょうか?

おわりに

今回初めての試みでDiscord botの中身について紹介しました。需要があるようであれば、他のDiscord botの裏側についても紹介する予定です。気軽に身近に役立つ自動化を行うことが出来るDiscord bot、皆さんもプログラミングスキルの向上という目的で作成してみては如何でしょうか?

2023/3/6追記

qiita.com
Discord自習室の作り方の記事もQiitaにupしましたので、ご参照ください。
随時他のDiscord botの裏側も紹介していく予定です。