虎の穴ラボ技術ブログ

虎の穴ラボ株式会社所属のエンジニアが書く技術ブログです

MENU

定期的なスケジュール調整をGAS + Discord連携で楽にしてみた

こんにちは!虎の穴ラボのH.Nです。 この記事は虎の穴ラボ 虎の穴ラボ Advent Calendar 2024の19日目の記事です。

突然ですが皆さんはプログラミング以外に何か趣味はお持ちですか?

私はFF14というオンラインゲームにハマっており、最近は高難易度コンテンツに挑戦するための固定リーダーを担当しております。

その中で固定メンバー8人の毎週の予定管理やそれに伴う活動管理を行うにあたって、これまでは日程調整用の外部サービスを利用していたのですが、

  • 毎週新規のイベントページを作成しないといけない
  • 予定入力状況を人力で確認しないといけない

という課題がありました。

そこで今回、予定管理をスプレッドシートで行い GAS + Discord連携を用いることで上記管理業務を自動化してみました! もし同じように固定活動をされていらっしゃるヒカセンの方など、是非ご参考にしていただければ幸いです!

今回作成した要件

まずはどのようなものを作成するか要件を検討します。

ひとまずはミニマム要件として以下で行くことにしました!

  • 各人の予定管理はスプレッドシートで一元管理する
  • 毎週日曜日に入力されている予定情報をもとに、翌火曜日〜月曜日の全員の都合がつく時間帯をDiscordのチャンネルに通知する

やろうと思えば予定が未入力な人に記入のリマインドを送ったりなど追加で色々開発もできそうですね。

Discord設定

Discordのチャンネルに通知するということで対応する設定を行う必要があります。

1. 通知を送信したいチャンネルの「チャンネルの編集」をクリック

2. 左タブから「連携サービス」を選択

3. ウェブフックから「ウェブフックを作成」を選択

4. 名前やアイコンを設定できるためお好きな内容を設定

5. 下部の「ウェブフックURLをコピー」を押下しURLをメモしておきます

以上でDiscord側の設定は完了です。意外とDiscordで必要な作業は少ないですね!

スプレッドシート設定

続いては各人が予定を入力するためのスプレッドシートを作成します。 今回は以下のようなイメージでスプレッドシートを用意しました。

各人の入力欄を設けた上で

  • IN時間にはそれぞれが活動開始できる時間を設定
  • OUT時間にはそれぞれが活動終了したい時間を設定
  • 各人が活動ができない日に関しては×を設定
  • C列の活動開始時間は各人のIN時間のMAX値を表示
  • D列の活動終了時間は各人のOUT時間のMIN値を表示
  • 誰かしら×がついている日に関してはC,D列共に休み表示

のような形で運用を行うことにしました! こちらに関してはスプレッドシートの関数で完結する内容なので、詳細なセルごとの設定内容に関しては割愛させていただきます。

GoogleAppsScript設定

では実際に予定入力状況を参照してDiscordに通知するGASの作成を行います!

スプレッドシートの「拡張機能」から「AppsScript」を選択します。

GASのエディタ画面が開かれると思いますので、まずは簡単なDiscord通知を送ってみましょう。

Discord通知部分の作成

// Discord設定内で取得した「ウェブフックURL」を以下に設定してください
const WEBHOOK_URL = "https://xxxx"

function sendMessageToDiscord() {
  webhookUrl = WEBHOOK_URL
  let payload = {
    "content": "hello world!"
  };

  let options = {
    "method": "post",
    "payload": payload
  };

  UrlFetchApp.fetch(webhookUrl, options);
}

エディタ上部から sendMessageToDiscord を選択し「実行」を押下します。 (Googleの認証が求められた場合は、許可します)

最終的に以下のようにDiscordにメッセージが送られてきていれば成功です!

では先程の sendMessageToDiscord 関数を修正して以下のようにします。

/**
 * Discordのウェブフックにメッセージを送信する関数
 */
function sendMessageToDiscord(message) {
  webhookUrl = WEBHOOK_URL
  let payload = {
    "content": message
  };

  let options = {
    "method": "post",
    "payload": payload
  };

  UrlFetchApp.fetch(webhookUrl, options);
}

これで引数で受け取ったメッセージをDiscordで通知する関数が作成できました!

スケジュール取得してメッセージ送信の作成

続いてはスケジュール情報を取得してメッセージ送信を行う部分を作成したいと思います。

/**
 * 翌週の活動予定日をアナウンスします
 * 毎週日曜日に実行
 */
function announcementSchedule() {
  //  スプレッドシートの読み込み
  const spreadsheet = SpreadsheetApp.getActiveSpreadsheet()
  //  シートの選択
  const sheet = spreadsheet.getSheetByName('日程表')

  // 翌火曜日の日付を取得
  let now = new Date();
  let targetDate = now
  for (let i = 0; i < 7; i++){
    var checkDate = new Date(now.getFullYear(), now.getMonth(), now.getDate() + i)
    // 火曜日であるかチェック
    if (checkDate.getDay() === 2) {
      targetDate = checkDate
      break
    }
  }

  // 起点となるセルの行番号を取得
  let baseRowNum = searchBaseRowNum(sheet, targetDate)
  // 見つからなかったケースの考慮
  if (baseRowNum === 0) {
    console.log("実行対象の日付が見つからなかったのでスキップします。")
    return
  }

  // 送信メッセージ内容の取得
  let sendMessage = getMessage(sheet, baseRowNum) 
  
  sendMessageToDiscord(sendMessage)
}

/**
 * 起点となるセルの行番号を検索
 */
function searchBaseRowNum(sheet, targetDate) {
  let resultNum = 0;
  // 対象の日付が見つからないことを考慮し、一旦200行までを対象に
  for (let i = 5; i < 200; i++) {
    // 選択セルの日付を取得
    let itrDate = sheet.getRange(i,1).getValue()
    if (itrDate === '') {
      continue
    }
    if (Utilities.formatDate(targetDate,'JST','yyyyMMdd') === Utilities.formatDate(itrDate,'JST','yyyyMMdd')) {
      resultNum = i
      break
    }
  }
  return resultNum
}

/**
 * 送信するメッセージ内容を取得する関数
 */
function getMessage(sheet, baseRowNum) {
  let resultMessage = "";
  // 7日分の探索
  for (let i = baseRowNum; i < baseRowNum + 7; i++) {
    // 選択セルの日付を取得
    let itrDate = sheet.getRange(i,1).getValue()
    let month = itrDate.getMonth() + 1
    let day = itrDate.getDate()
    let dayOfWeek = sheet.getRange(i,2).getValue()
    let startTime = sheet.getRange(i,3).getValue()
    let endTime = sheet.getRange(i,4).getValue()

    let itrMessage = month + "/" + day + " (" + dayOfWeek + ") "
    if (startTime === "未入力あり") {
      itrMessage += "未入力予定があります。"
    } else if (startTime === "休み") {
      itrMessage += "休み"
    }else{
      // HH:MM形式への整形
      let startStr = ('0' + startTime.getHours()).slice(-2) + ":" + ('0' + startTime.getMinutes()).slice(-2)
      let endStr = ('0' + endTime.getHours()).slice(-2) + ":" + ('0' + endTime.getMinutes()).slice(-2)
      itrMessage += startStr + " 〜 " + endStr
    }
    resultMessage += itrMessage + "\n"
  }
  return resultMessage
}

GASではスプレッドシート操作用の関数が SpreadsheetApp に用意されております。 その上で searchBaseRowNum でセルを探索し、 getMessage にて次回通知対象の日付となるセル情報を取得して活動時間を文字列として整形しております。

これでDiscordへ連携するGASのコードが出来上がりました!

スケジュール設定

最後に毎週日曜日に先程のGASが実行されるように設定を行います。

1. 左タブから「トリガー」を選択

2. 「トリガーを追加」を押下

3. 以下内容を設定

  • 実行する関数:announcementSchedule
  • イベントのソース:時間手動型
  • 時間ベースのトリガーのタイプ:週ベース
  • 曜日:日曜日
  • 時刻:お好きな時間帯

これで毎週日曜日に活動スケジュールがDiscordに通知されるようになりました!

最後に

意外と簡単にスケジュール管理の簡易化ができたのではないかと思います。

ぜひ皆様も普段のちょっとした手間の自動化を検討してみてはいかがでしょうか?

ちなみに今回例示したアプリは以下のような形で運用されてます(笑)

Fantia開発採用情報

虎の穴ラボでは現在、一緒にFantiaを開発していく仲間を積極募集中です!
多くのユーザーに使っていただけるtoCサービスの開発をやってみたい方は、ぜひ弊社の採用情報をご覧ください。
toranoana-lab.co.jp