Next.js × GoogleMapsAPI × YoutubeDataAPIv3を使ったライブカメラマップ開発

# 作ったサービス
今回作ったものはこちらになります。
https://youtube-live-camera-map.vercel.app
![スクリーンショット 2021-05-16 15.42.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263328/415a7b15-727e-f4c0-f280-065ccf17570b.png)
地図上のアイコンをクリックするとYouTubeでライブ配信されている映像を視聴することができる簡単なサービスです。
PC・タブレット前提でカメラの方向がわかるような考慮はしていません。
また、Google Analyticsによる解析を行なっています。

# YouTube利用規約の確認
## 動画自体の埋め込みについて
念のためYouTubeの動画を埋め込むことは問題ないか利用規約を確認。
https://www.youtube.com/static?template=terms&hl=ja&gl=JP

> 他のユーザーへのライセンス付与

> また、お客様は、本サービスを利用する他の各ユーザーに対して、本サービスを通じてコンテンツにアクセスし、（動画の再生や埋め込みなど）本サービスの機能によってのみ可能な方法で、複製、配信、派生的著作物の作成、展示、上演などのかたちでコンテンツを使用する世界的、非独占的な無償ライセンスを付与するものとします。明確にするために付記すると、このライセンスは、本サービスから独立した方法でコンテンツを使用する権利や権限を与えるものではありません。

Webサイトへ埋め込まれたくないものは、YouTube側で設定ができます。
https://support.google.com/youtube/answer/6301625?hl=ja

今回は当然投稿者側で埋め込み拒否していないものだけが対象になっていますが、埋め込み可能でも個人宅から配信してそうなものは利用を避けています。
その上で観光名所を中心に適当にライブ配信動画を選んでいます。

## アイコンの使用について
https://www.youtube.com/intl/ja/about/brand-resources/#logos-icons-colors

> すべきでないこと
アイコンの形を横方向や縦方向に伸ばす
三角形の角度やサイズを変更する
赤、黒に近いグレー、または白以外の色を使用する
アイコンを回転させる
特殊効果を加える
アイコンに模様や画像を追加する
三角形を他の図形やアイコンに置き換える
三角形を単語に置き換える
長方形の形を変更する

全部してないから大丈夫。

# 使用技術
- 言語：TypeScript
- フレームワーク：Next.js
- CSSフレームワーク：Material-UI
- ライブラリ(主要なものだけ)
    - @react-google-maps/api・・・GoogleMap描画で使用
    - react-youtube・・・動画プレイヤー埋め込みで使用
- 使用しているAPI
    - YoutubeDataAPIv3(Search:list)
- デプロイ先：Vercel

# 作ろうと思ったきっかけ
コロナの影響で本当に人出減っているのかなーと、ぼーっとYouTubeで渋谷のスクランブル交差点のライブ配信見てた時、これ地図上で見れたら面白いかも？と思ったのがきっかけでした。

前からNext.jsにも興味あったので、勉強も兼ねて開発することにしました。
年末年始の休みの期間でとりあえず動く状態にすることができたのですが、しばらく放置しており、最近手直しを行って今回記事にしました。

# 開発苦労話
開発時の課題や工夫した点について

## 1. 動画が急に見れなくなった
最初は埋め込みたいライブ配信のvideoIdをプログラム上に定義してそれを直接react-youtubeに渡して動画プレイヤーを表示していました。

初期の頃の定義情報はこんな感じ。
locationはGoogleMapでの座標(緯度・経度)です。

```
[
  {
    videoId: 'lkIJYc4UH60', title: '渋谷スクランブル交差点', location: { lat: 35.659707, lng: 139.70046 },
  },
  {
    videoId: 'zGfw93Dqzg8', title: '公園通り商店街マルイ', location: { lat: 35.661101, lng: 139.700828 },
  },
  ...(続く)
]
```

この定義情報を使って動画プレイヤーの埋め込みはすぐにできました！超簡単！
・・・しかし、ここで2、3日ほど経ったある日想定外のことが、

**動画が見れなくなってる！？**

え、でもYouTubeだと普通にライブ配信しているな。

![スクリーンショット 2021-05-15 22.29.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263328/b013fada-1da2-8e38-2de9-d55bee5b8a56.png)

あ、videoId(vパラメータの部分)が変わってる！？

実はオンデマンド動画と違ってライブ配信動画は不定期で終了・再開を繰り返し、その度にvideoIdが変わるのでした。
なるほどvideoIdを定義する方法ではダメだ。。

そこで登場するのが、YoutubeDataAPIv3(Search:list)です。
APIの詳細はこちら
https://developers.google.com/youtube/v3/docs/search/list?hl=ja

名前から想像できる通り、パラメータに指定した条件に一致するYouTubeの動画情報(videoIdも当然込み)を取得するためのAPIです。

定義情報をvideoIdからチャンネルId(`channelId`)と検索キーワード(`q`)に変更し、

```
[
  {
    channelId: 'UCGCZAYq5Xxojl_tSXcVJhiQ', q: '渋谷スクランブル交差点', location: { lat: 35.659707, lng: 139.70046 },
  },
  {
    channelId: 'UC1LK8PM_k4Fak8v4PBtcQIQ', q: '公園通り商店街マルイ', location: { lat: 35.661101, lng: 139.700828 },
  },
  ...(続く)
]
```

このチャンネルId(`channelId`)と検索キーワード(`q`)とその他パラメータを指定してAPIを実行し、常に最新の(有効な)videoIdをreact-youtubeに渡す作りに変えることで解決することができました！

ちなみにこの方法は動画の投稿者がタイトルや説明文を変えたりすると多分ヒットしなくなるので、完璧な方法ではありません。チャンネルIdの方は多分変わらないと思いますが。
趣味で作ったサービスってことでまぁいいか。

## 2. 開発してたらYoutubeDataAPIv3(Search:list)が使えなくなった
今度は開発中にYoutubeDataAPIv3(Search:list)が急に実行できなくなるという問題が発生しました。

これは無料枠で利用できる上限10,000を超えてしまったことが原因でした。
![スクリーンショット 2021-05-15 23.14.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263328/c6a0518f-5ece-945f-f77f-7811598b7178.png)

え、1日10,000。。リクエスト数か？流石にそんなに使用していないはず。

利用制限が解除された翌日、APIリクエスト直後にGCPの管理コンソールを確認して分かったのですが、**YoutubeDataAPIv3(Search:list)は1回のリクエストでこの数値を100消費していたのです。**

あれでもNext.jsでビルド時に(getStaticPropsで)API叩いているし、100回もビルドしていないよなぁ。。

**・・・実は開発時(next dev使ってると)getStaticPropsはページアクセスごとに動く(SSRに等しい)のでした。**

公式サイトにもちゃんと書いてました。
https://nextjs.org/docs/basic-features/data-fetching#runs-on-every-request-in-development

そりゃあっという間に10,000到達するわけだ、、

とりあえず定義情報に現時点のvideoId含めて、開発時にはAPI実行しないでこれを直接使おう！
API叩いてvideoIdの取得からプレイヤー表示までは確認できてるし、開発するときはカメラ位置だけ見れればいいか！ってことで定義情報に再び現時点でのvideoIdを追加。

```
[
  {
    channelId: 'UCGCZAYq5Xxojl_tSXcVJhiQ', q: '渋谷スクランブル交差点', location: { lat: 35.659707, lng: 139.70046 }, videoId: 'HpdO5Kq3o7Y',
  },
  {
    channelId: 'UC1LK8PM_k4Fak8v4PBtcQIQ', q: '公園通り商店街マルイ', location: { lat: 35.661101, lng: 139.700828 }, videoId: 'zGfw93Dqzg8',
  },
  ...(続く)
]
```
定義自体はこちらが完成形となります。

## 3. ビルドの自動化
videoIdが変わり見れなくなった動画がある度ビルドしてあげるのは流石に辛い。
1日1回ビルドするようスケジューリングしてあげれば、次の日には見れるようになるはず！ってことでVercelとGitHubActionsを使って自動ビルドの設定をしました。

### まずはVercelでWebHookURLを発行

Vercel公式の以下の手順に従ってWebHookURLを発行するだけ
https://vercel.com/docs/more/deploy-hooks

### あとはGitHubActionsで発行したWebHookURLを叩くだけ

今回はこんな感じにしています。

```yml:cron.yml
name: Scheduled build

on:
  schedule:
    # 毎日03:01にビルド(UTCで18:01)
    - cron: '01 18 * * *'

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Vercel Deploy
        run: |
          curl --request POST \
          --url "${{ secrets.BUILD_HOOK_URL }}"
```

`BUILD_HOOK_URL`の部分はGitHubのSecretsに発行したWebHookURLを設定しています。
これで毎日03:01にビルドするようスケジューリングできました。

## 4. location情報をどうやって集めるのか？
Webサイトに埋め込み可能なYouTubeのライブ配信動画自体は、YoutubeDataAPIv3(Search:list)使えばいいので、問題はカメラのlocation情報との紐付けですが、**これはもうひたすらYouTubeの映像とGoogleMapでストリートビュー見比べて紐付けましたw**
そのためカメラ座標が多少ずれている可能性があります。
ちなみに明らかにこのカメラだ！を見つけられた時は謎の達成感がありました。

# まとめ
開発を通してNext.jsについての理解向上、サービス公開実績を1つ追加することができたので、当初の目的は果たせました。
また、VercelとGitHubActionsを使った自動ビルド方法について知見を得ることができました。

特に工夫できたかなと思うのは以下2点です。

- Next.jsのSSGを活用(getStaticPropsでAPI実行)することでYoutubeDataAPIv3(Search:list)の利用制限の突破を防げた点
- (videoIdが変わり)サービス上でライブ配信が見れなくなっても翌日自動で見れるようになる(はず)の仕組みを構築できた点

今後は気が向いたらカメラの追加やアップデートをしていこうと思います。
ライブカメラの最大数は単純計算で100(APIの1日当たり上限10,000 ÷ 1回の実行で100消費)だけどそこまでは流石に増やせないかな。。日本だけでなく海外の映像も対象にしてみるのもありかも。
以上、適度に妥協を交えた個人開発でした！