LINE API × GAS でイベント情報を自動投稿

![1624930883795.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1552742/c5a29fba-fc28-c8a9-1dd7-72de86fc18ae.png)



# 概要
LINE公式アカウント（旧LINE＠）を使用しているお店のイベント情報を自動投稿できるようにする。

仕組みはGoogleカレンダーの予定をGASで取得し、指定の時間になったら翌日の予定（イベント情報）を、自動的に投稿する。といった流れ。

# 経緯
これまで作成した"気象に応じた"販促の自動投稿に手応えがあったため、「GASなら予定の自動投稿も簡単にできるだろう」と思い、作成してみることに。

# 使用したもの
・LINE Messaging API
・Google Apps Script (GAS)
・Googleカレンダー

# Googleカレンダーの予定日取得について
GASで予定日を取得するため以下3つの変数を宣言する。

```javascript:getEvent()
  const calendar_ID = "×××××××××××××××××@group.calendar.google.com"; 
  const calendar = CalendarApp.getCalendarById(calendar_ID);
  const events = calendar.getEventsForDay("取得したい日にち");
```
カレンダーIDは、[Googleカレンダー](https://calendar.google.com/) → 取得するカレンダーの"設定" → カレンダーの統合 にある。

なお取得するカレンダーには以下の設定が必要
・アクセス権限の「一般公開して誰でも利用できるようにする」にチェック
・「特定のユーザーとの共有」にGASを作成するアカウントを入れる

取得可能な設定になると上記の `events` に、指定した "取得したい日にち" の予定が格納される（といってもプロパティを含まないと予定は取得できない）

予定を取得するには、

```javascript:getEvent()
  var msgContent = "";
  for(const event of events){
    //var desc = event.getDescription(); /*予定の説明。今回はメッセージの体裁を考え保留に。*/
    var scheduleTitle = event.getTitle() //予定のタイトル
    var startTime = Utilities.formatDate(event.getStartTime(), 'JST', 'HH:mm'); //予定の開始日(終日のときは00:00)
    var endTime = Utilities.formatDate(event.getEndTime(), 'JST', 'HH:mm'); //予定の終了日(終日のときは00:00)
    var time = event.isAllDayEvent() ? "" : "（" + startTime + " ～ " + endTime + "）"; //開始時間～終了時間のフォーマットを生成(終日のときは空白)
    msgContent += "\n◯" + scheduleTitle + time + "\n"; //こんな形で予定を表示させる
  }
```
のように `events` の中身をfor文でまわしながら `msgContent ` という変数に格納していく。

# イベント情報をLINEに投稿
上記で使用した変数 `msgContent ` に値が入っていれば投稿処理をおこなう。
（  `header ` と `footer ` の変数については完成形を参照。）

```javascript:getEvent()
  //イベント情報が格納された時のみ投稿処理
  if(msgContent != ""){
    var postData = {
      'messages': [{
      'type': 'text',
      'text': header + msgContent + footer //ここではイベント情報に上・下部のメッセージ（header,footer）の変数を挟む *完成形を参照
      }],
    };
    broadcast_fetch_data(postData);
  }
```

```javascript:broadcast_fetch_data()
function broadcast_fetch_data(postData) {
  var options = {
    "method": "post",
    "headers": {
      "Content-Type": "application/json",
      "Authorization": "Bearer " + "LINEのアクセストークン"
    },
    "payload": JSON.stringify(postData)
  };
  UrlFetchApp.fetch("https://api.line.me/v2/bot/message/broadcast", options);
}
```

あとはGASのトリガーで毎日一定時間に作動させれば無事完了。

# 完成形はこちら
上記で説明した構文をつなげるのと、ついでにスタンプをつけてみる。（[こちらのサイト](https://developers.line.biz/en/docs/messaging-api/sticker-list/#sticker-definitions)よりIDなどをコピーして使用）

```javascript:getEvent()
function getEvent(){
  //明日の日付
  var tomorrow = new Date();
  tomorrow.setDate(tomorrow.getDate() + 1);
  var tomorrowformat = Utilities.formatDate(tomorrow, 'Asia/Tokyo', 'M/d');

  //カレンダー  
  const calendar_ID = "×××××××××××××××××@group.calendar.google.com"; 
  const calendar = CalendarApp.getCalendarById(calendar_ID);
  const events = calendar.getEventsForDay(tomorrow);

  //メッセージ　
  var msgContent = "" //ここにイベント情報を格納
  var header = "こんばんは🙂\n\n明日(" + tomorrowformat + ")のイベントのお知らせです💡\n";
  var footer = "\nお客様のご来店お待ちしております。"

  for(const event of events){
    //var desc = event.getDescription(); /*予定の説明、今回はメッセージの体裁を考え保留に。*/
    var scheduleTitle = event.getTitle() //予定のタイトル
    var startTime = Utilities.formatDate(event.getStartTime(), 'JST', 'HH:mm'); //予定の開始日(終日のときは00:00)
    var endTime = Utilities.formatDate(event.getEndTime(), 'JST', 'HH:mm'); //予定の終了日(終日のときは00:00)
    var time = event.isAllDayEvent() ? "" : "（" + startTime + " ～ " + endTime + "）"; //開始時間～終了時間のフォーマットを生成(終日のときは空白)
    msgContent += "\n◯" + scheduleTitle + time + "\n"; //こんな形で予定を表示させる
  }

  //イベント情報が格納された時のみ投稿処理
  if(msgContent != ""){
    var postData = {
      'messages': [{
      'type': 'text',
      'text': header + msgContent + footer
      },{
        "type": "sticker",
        "packageId": "1070",
        "stickerId": "17839"
      }],
    };
    broadcast_fetch_data(postData);
  }
}

function broadcast_fetch_data(postData) {
  var options = {
    "method": "post",
    "headers": {
      "Content-Type": "application/json",
      "Authorization": "Bearer " + "LINEのアクセストークン"
    },
    "payload": JSON.stringify(postData)
  };
  UrlFetchApp.fetch("https://api.line.me/v2/bot/message/broadcast", options);
}
```
上記の `getEvent()` を実行させると冒頭の画像のようなメッセージが投稿される。

# 応用編（今後の課題など）
- イベント情報に対応した画像投稿
 Googleカレンダーには添付ファイルの項目があるものの、GASでは取得できない（らしい）ので、説明文に画像のURLを貼り付けて、それをLINE APIで使用するといったやり方で運用中。説明文なので簡単に編集できてしまうため代替策を試案中。

- LINE botでイベント情報を返す
 特定のメッセージに対して単純に上記の `getEvent()` を流せばOK。

- 複数のイベント情報の処理
例えば営業時間を流したいときや、セール情報を流したいときなど幾つか状況が考えられるが、個々にカレンダーを作成して適宜処理をおこなうことで対応。

- 投稿のタイミングについて
「週末のイベント情報は、前日ではなく週始めにも投稿したい」という声を頂いたので、該当のカレンダーは5日前と1日前に投稿するという仕様に変更。こういった様に「投稿する〇日前に投稿する」という設定機能は必要なのかなと考え中。

# 備考
Googleカレンダーにイベント情報などを作成するだけで自動的に販促投稿するシステムはそこそこ需要があると思いつつ、上記で示したような個々の仕様（画像の設定、投稿するタイミングの拡張性など）が今後の課題。