Googleカレンダーの予定をLINE Notifyに連携する

最近、connpassのイベント参加予定など、諸々の予定をGoogleカレンダーに登録することが多くなったのですが、いちいちGoogleカレンダーに予定と時間を見に行くのが面倒臭いな、と思ったので、Google Apps Scriptを使って、登録したスケジュールをLINE Notifyで自身に配信するプログラムを作りました。

LINE Notifyに送るメッセージは、こんな感じ。

```
[予定1]
予定名：テスト1
開始日時：2023.Jun.11 20:00:00
終了日時：2023.Jun.11 21:30:00
[予定2]
予定名：テスト2
開始日時：2023.Jun.12 18:30:00
終了日時：2023.Jun.12 20:45:00
```

# 機能概要
1. Googleカレンダーに登録されている予定を実行当日〜10日後の分まで取得して、上記の形式でLINE Notifyで配信
2. 実行日時と実行結果は、Googleスプレッドシートにログとして残す
・１列目：実行日
・２列目：実行時間(時分のみ)
・３列目：実行結果(OK or NG)
・４列目：ヒットした件数

# プログラムコード
## AutoSend
メインの処理です。実際に実行するメソッドはこのメソッドです。
```CalendarAutoSend.gs
function AutoSend() {
  // 機能概要
  // Googleカレンダーから当日含め10日先までの予定を取得し、LINE Notifyに送る
  // 送るタイミングは、朝一と夕方に1回ずつ。毎日実行。

  // 定数定義
  // Googleスプレッドシート
  const fileInfo = {
    fileID : 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
    sheetName : 'ログ',
  };

  const execBook = SpreadsheetApp.openById(fileInfo.fileID);
  const execSheet = execBook.getSheetByName(fileInfo.sheetName);

  // Googleカレンダー用
  const term = 10;  // スケジュールの取得日数

  const execDateFrom = new Date();
  const execDateTo = new Date();

  // 変数定義
  let status = 'NG';

  // Googleカレンダーから実行日〜10日後までのスケジュールを取得
  execDateTo.setDate(execDateFrom.getDate() + term);

  const calender = CalendarApp.getEvents(execDateFrom, execDateTo);
  const noticeContents = GetCalenderData(calender); // 配列で取得

  // LINE Notifyで表示できるよう編集
  const dispContents = EditContents(noticeContents);
  if (dispContents) {
    SendLineNotify(dispContents);
    status = 'OK';
  }

  // スプレッドシートへのログ記載
  WriteLog(execSheet, execDateFrom, status, noticeContents.length);
}
```
## GetCalendar
CalendarApp.getEventsメソッドで取得したオブジェクトから予定タイトルと開始日時、終了日時を取得するメソッドです。
```CalendarAutoSend.gs
// スケジュールを配列データとして取得する
function GetCalenderData(calenderDatas) {
  const events = calenderDatas.map(calenderData => {
    return [
      calenderData.getTitle(),
      calenderData.getStartTime(),
      calenderData.getEndTime(),
    ]
  })

  return events;
}
```
## EditContents
GetCalendarメソッドで取得したイベント情報の配列を冒頭で記述した形式に編集するメソッドです。
```CalendarAutoSend.gs
// スケジュールの配列データをLINE Notifyで表示する形式に編集する
function EditContents(rawNoticeContents) {
  let notice = '\n';
  let lstDtSta = '';
  let lstDtEnd = '';
  for (let c = 0; c < rawNoticeContents.length; c++) {
    let title = rawNoticeContents[c][0];
    let dtSta = rawNoticeContents[c][1];
    let dtEnd = rawNoticeContents[c][2];

    // 開始日時と終了日時をYYYY/MM/DD hh:mm:ss形式に編集
    lstDtSta = String(dtSta).split(' ');
    lstDtEnd = String(dtEnd).split(' ');

    // LINE Notifyに表示する形式は以下とする
    // 予定名：タイトル
    // 開始日時：編集した開始日時
    // 終了日時：編集した終了日時
    notice = notice + '[予定' + (c + 1) + ']\n';
    notice = notice + '予定名：' + title + '\n';
    notice = notice + '開始日時：' + lstDtSta[3] + '.' + lstDtSta[1] + '.' + lstDtSta[2] + ' ' + lstDtSta[4] + '\n';
    notice = notice + '終了日時：' + lstDtEnd[3] + '.' + lstDtEnd[1] + '.' + lstDtEnd[2] + ' ' + lstDtEnd[4] + '\n';
  }
  return notice;
}
```
## SendLineNotify
LINE NotifyのAPIを使って、EditContentsメソッドで作成した文章を送信するメソッドです。
```CalendarAutoSend.gs
// LINE Notifyでの送信処理
function SendLineNotify(content) {
  const token = 'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy';
  const options = {
    "method" : "post",
    "headers" : {
      "Authorization" : "Bearer " + token
    },
    "payload" : {
      "message" : content
    }
  };

  const url = 'https://notify-api.line.me/api/notify';
  console.log(options);
  UrlFetchApp.fetch(url, options);
}
```
## WriteLog
Googleスプレッドシートにログを記載するメソッドです。
```CalendarAutoSend.gs
// スプレッドシートへのログ記載
function WriteLog(objSheet, execDate, status, contentCount) {
  const lastRow = objSheet.getLastRow();
  // 実行年月日
  objSheet.getRange(lastRow + 1, 1).setValue(Utilities.formatDate(execDate, 'Asia/Tokyo', 'yyyy/MM/dd'));
  // 実行日時
  objSheet.getRange(lastRow + 1, 2).setValue(Utilities.formatDate(execDate, 'Asia/Tokyo', 'hh:mm'));
  // 実行結果
  objSheet.getRange(lastRow + 1, 3).setValue(status);
  // 予定の件数
  objSheet.getRange(lastRow + 1, 4).setValue(contentCount);
}
```
# 最後に
LINE Notifyに送られてきたメッセージが、月だけ英語略称になっていますが、何月か分かればいいやと思い、日本語にせずに完成としました...。(笑)
しばらく、GASを書いていなかったので、書き方を忘れていた部分が多々ありました。自身が書き方を忘れないための記録用としても残しておきたいと思います。