自宅筋トレのすゝめ【GAS×Youtube Data API×Slack bot】

本記事は、[ハンズラボ Advent Calendar 2022](https://qiita.com/advent-calendar/2022/handslab) 13日目の記事です。

ドキドキしながらのQiita初投稿です。よろしくお願いいたします。

# はじめに
みなさん、リモートワーク中に運動不足になっていませんか？
今回は、運動不足解消の一助となるべく、Google Apps Scripts(GAS)を利用して**自宅でもできる筋トレ動画を垂れ流すSlack bot**を作ってみました。

# 作ったもの
なかやまきんに君さんの再生リスト「自宅で筋トレ」の動画の中から、ランダムで一つの動画を、毎朝Slackの特定のチャンネルに通知します。
![スクリーンショット 2022-11-28 17.18.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317864/cb6ef631-43e7-b890-2026-a0f6fab1ffc6.png)

# やったこと
1. Slack botを作成するために、Slackアプリを新規作成する。
1. 筋トレ動画をSlackへ通知するために、GASのプログラムを作成する。
1. GASのプログラムを定期実行するために、トリガーを設定する。

## Slack botの作成準備
https://api.slack.com/ にアクセスし、「**Create an app**」をクリックしてSlackアプリを新規作成します。
![スクリーンショット 2022-12-06 18.10.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317864/e9dd97ed-cddd-5d03-3db7-67f7e4bdd3d5.png)
「From scratch」をクリックします。
![スクリーンショット 2022-12-07 17.09.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317864/9dc959f4-3d60-cf81-267c-2212049a8c28.png)
App Nameにはアプリ名(任意・後から変更可)を入力します。Pick a workspace to develop your app in:ではワークスペース名を選択します。
![スクリーンショット 2022-12-07 17.09.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317864/018adedc-10c1-bc0a-b026-f8c59713adc9.png)
左サイドメニューの「OAuth & Permissions」を選択して、実装に使う[Web API methods](https://api.slack.com/methods)に応じて必要な権限を付与します。今回は、**Bot Token Scopes**に`chat:write`の権限を付与します。
![スクリーンショット 2022-11-28 17.07.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317864/63c6c1b7-1399-adec-c7e3-867755fa9691.png)
左サイドメニューの「Install App」を選択して、「Install to Workspace」をクリックします。Slack APIを利用するのに必要なので、**Bot User OAuth Token**が発行されたらコピーしておきます。
![スクリーンショット 2022-12-02 14.32.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317864/052c78bd-c90e-999c-a4eb-6fb68edfdd87.png)
Slackのチャンネルにアプリを追加していないと、Slack botからメッセージを投稿することができません。チャンネル詳細画面の「**インテグレーション**」からアプリを追加することができます。私はこの操作をすっかり忘れていて、地味にハマりました。
![スクリーンショット 2022-12-02 14.40.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317864/b4e22361-46ec-b432-2627-bace178f2124.png)
これでSlack側の準備は完了です。

## YouTube Data APIを利用するための準備
[YouTube Data API](https://developers.google.com/youtube/v3/docs)を利用すると、動画や再生リスト、登録チャンネルなどに関する情報を取得することができます。
このAPI、利用するためにはGoogle Cloud Platform(GCP)への登録やAPIキーが必要…という記事を何度か見かけましたが、GASを利用する場合はそういった手順は不要だそうです。**GASで「サービス」を追加するだけ**で、YouTube Data APIを利用することができます。

GASのエディタにて、「サービス」の十字マークを選択します。
![スクリーンショット 2022-12-02 11.24.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317864/cce07327-4d30-9928-0fcd-764a089e6f01.png)
一覧の中から**Youtube Data API v3**を選択し、「追加」ボタンをクリックします。
![スクリーンショット 2022-12-02 11.25.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317864/f77d8966-634e-3676-26a5-6c8005b162dd.png)
「サービス」の下にYouTubeが追加されていれば、こちらも準備完了です。
![スクリーンショット 2022-12-02 11.44.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317864/8c89173f-2a8a-9e4f-989b-a9ce8fb93712.png)

## GASのプログラムを作成する
### YouTubeの再生リストの情報を取得し、スプレッドシートに書き込む
```javascript
// 再生リストID
const PLAYLIST_ID = '<再生リストID>';
// 書き込み対象のシート情報
const SHEET_NAME = 'シート1';

/**
 * スプレッドシートに動画情報を書き込む
 */
function updateSheet() {
  // スプレッドシートを取得
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME);

  // 指定の再生リストから動画情報を取得
  const items = getPlaylistItems(PLAYLIST_ID);

  // シートを一括クリア
  sheet.clear();

  // スプレッドシートに書き込む
  sheet.getRange(1, 1, items.length, items[0].length).setValues(items);
}

/**
 * 指定した再生リストの動画に関する情報を、配列として返す
 */
function getPlaylistItems(playlistId) {
  const playlistItems = YouTube.PlaylistItems.list(
    'snippet',  // 再生リストのアイテムに関する基本情報(タイトル、再生リスト内の位置など)
    {
      playlistId: playlistId, // 再生リストID
      maxResults: 50  // アイテムの最大数
    }
  );

  // 返却用の配列
  const playlistData = [];
  for (const item of playlistItems.items) {
    const title = item.snippet.title;
    const url = 'https://www.youtube.com/watch?v=' + item.snippet.resourceId.videoId
      + '&list=' + item.snippet.playlistId;

    playlistData.push([title, url]);
  }

  return playlistData;
}
```
「再生リストID」には、お好みの再生リストIDを指定してみてください。YouTubeの再生リストのURLは`https://www.youtube.com/playlist?list=XXXX`のようになっており、`XXXX`の部分が「再生リストID」です。
```javascript
// 再生リストID
const PLAYLIST_ID = '<再生リストID>';
```
YouTube Data APIの`PlaylistItems.list`メソッドの公式リファレンスはこちらです。

https://developers.google.com/youtube/v3/docs/playlistItems

### スプレッドシートのデータを取得し、Slackに通知する
```javascript
// SlackAPIで設定したトークン
const TOKEN = '<Bot User OAuth Token>';
// Slackチャンネル
const CHANNEL_ID = '<チャンネルID>';

/**
 * Slackチャンネル宛にメッセージを送信する
 */
function postMessageToRecommendHomeWorkout() {
  // スプレッドシートからデータを取得
  const data = readSheet();

  // メッセージを作成
  const di = Math.floor(Math.random() * data.length);
  const words = ['パワー！', 'ヤー！', 'ハッ(笑顔)'];
  const wi = Math.floor(Math.random() * words.length);
  const message = words[wi] + '\n\n*' + data[di][0] + '*\n' + data[di][1];
  console.log(message);

  // 送信内容
  const params = {
    'method' : 'post',
    'payload' : {
      'token': TOKEN,
      'channel': CHANNEL_ID,
      'username': '自宅筋トレのすゝめ',
      'icon_emoji': ':nakayamakinnikun:',
      'text': message
    }
  };

  // slackにメッセージを送信
  const url = 'https://slack.com/api/chat.postMessage';
  UrlFetchApp.fetch(url, params);
}

/**
 * スプレッドシートから動画情報を読み込む
 */
function readSheet() {
  // スプレッドシートを取得
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME);

  // シート内の全データを取得
  const values = sheet.getDataRange().getValues();

  return values;
}
```
「チャンネルID」には、メッセージの送信先となるSlackのチャンネルのものを指定してください。アプリ版Slackを使用している場合は、該当のチャンネル名を右クリックして「リンクをコピー」してみてください。コピーされたURLは`https://YYYY.slack.com/archives/ZZZZ`のようになっており、`ZZZZ`の部分が「チャンネルID」です。
```javascript
// slackチャンネル
const CHANNEL_ID = '<チャンネルID>';
```
Slack APIの`chat.postMessage`メソッドの公式リファレンスはこちらです。

https://api.slack.com/methods/chat.postMessage

## 動作確認
`updateSheet`を実行すると、「シート1」に動画のタイトルとURLが書き込まれます。
![スクリーンショット 2022-12-02 17.29.57 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317864/3783a4a0-eaa9-3209-e3ef-576ef99a5661.png)
![スクリーンショット 2022-12-02 16.33.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317864/0297ac83-c332-9481-a269-bb4889dbb539.png)
`postMessageToRecommendHomeWorkout`を実行すると、指定したSlackのチャンネルにメッセージを投稿します。
![スクリーンショット 2022-12-02 17.29.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317864/75ce420e-bbf5-1193-4037-a49ded54724e.png)
![スクリーンショット 2022-12-02 18.43.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317864/f97273c9-da90-7f3a-52e0-04531e0b71ac.png)

## トリガーを設定する
トリガーを追加して、作成したGASのプログラムを定期実行させます。
![スクリーンショット 2022-12-02 13.46.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317864/02945c83-4187-c867-4b0c-bb85cf98d795.png)
Slackにメッセージを投稿する`postMessageToRecommendHomeWorkout`関数を選択し、任意の設定をします。今回は、「時間主導型」「日付ベースのタイマー」「午前7時〜8時」にトリガーを設定してみます。
![スクリーンショット 2022-12-06 10.28.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317864/0d8085e3-3baa-4917-91e1-bd7ecba36a19.png)
設定した時間にSlackのチャンネルへメッセージが届いたら、成功です。

# おわり
お疲れさまでした。
ここまで読んでくださり、ありがとうございました。
このSlack botのおかげで、1日1回の筋トレを継続することができています。

余談になりますが、現職のSlackには、分報や多種多様なカスタム絵文字があります。私は筋トレ動画の通知先を自分の分報にしており、筋トレが完了したら「済」の絵文字を押しています。また、分報チャンネルを見ている社員の方から、「応援しています」や「えらい」などの絵文字を押していただくことがあり、モチベーションにつながっています。
筋トレは一人でも行えるものですが、Slackを通じてお互いに応援し合うことで、日々の筋トレが楽しくなるかもしれません。
![スクリーンショット 2022-12-02 12.28.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317864/37dacb62-aa7a-3c73-277e-3e605d768dfc.png)
![スクリーンショット 2022-12-02 12.29.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317864/5e006bc3-738d-537d-9417-35028e08cda9.png)

# 参考
https://zenn.dev/mokomoka/articles/6d281d27aa344e

https://zenn.dev/sungvalley/articles/ccce17e076984f

https://www.youtube.com/playlist?list=PLTaUg3YsjO7QVCtTd1VyxE3hxZdMHEAYl