Youtube Player APIで埋め込んだ複数の動画を1つだけ再生させる制御

Carview Advent Calender 3日目の記事を担当する@yamaberoです。
Qiitaデビューです。緊張します。笑

#前提
業務でYoutube動画の埋め込みをすることは、まぁ、よくあることかなと思います。

私も先日ありました。

で、いつものように[Youtube Player API](https://developers.google.com/youtube/iframe_api_reference?hl=ja)で動画の埋め込みをしてました。
ただその時は画面内に複数のYoutube動画埋め込みが必要でした。

#Youtubeの利用規約

調べてみると埋め込みしたYoutubeって同じページ内に1つまでしか動画を再生してはいけないらしんですよ。->[利用規約III - C -1（英語）](https://developers.google.com/youtube/terms/developer-policies#c.-implementing-youtube-features)
どっちかっていうとIII - C - 1に書かれてる[ミニマムリクワイアメント](https://developers.google.com/youtube/terms/required-minimum-functionality#autoplay-and-scripted-playbacks)の方が良いか。

> A page or screen must not have more than one YouTube player that automatically plays content simultaneously.
> 1つのページまたは画面に、コンテンツを自動的に同時に再生する複数のYouTubeプレーヤーを含めることはできません。(google翻訳)


**自動再生**でかつ**同時再生**を複数のプレーヤーでしてはいけないって感じですが、手動再生も念の為同時には再生できない仕組みにしておいた方が良さそうです。


#ソースコード
というわけで以下の様な感じのJavaScriptにしました。
参考にしたのは https://www.neko-it.com/blog/4536.html です。
まるっと一緒にするわけには行かないので、ちょいちょい変更はしてます。





```html:htmlサンプル
<div class="wrapper">
  <div class="movie--node">
    <div id="movie01"></div>
  </div>

  <div class="movie--node">
    <div id="movie02"></div>
  </div>

  <div class="movie--node">
    <div id="movie03"></div>
  </div>
</div>
```
htmlは、まぁ、テキトーです。
どうせ埋め込みするだけなので。


```JavaScript:Javascriptサンプル
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/player_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

// 各プレーヤーの格納配列準備
const ytPlayer = [];

// Youtube再生判定用
let ytPlaying, ytStop, ytPlay;

// 各動画情報
const ytData = [
  {
    id: "duFiiDPiwjc", // youtube動画のID
    area: 'movie01', // youtube動画を埋め込む場所
    pWidth: '560', // 動画の幅
    pHeight: '315' // 動画の高さ設定用
  },
  {
    id: "0XmIVbmeZ-I", // youtube動画のID
    area: 'movie02', // youtube動画を埋め込む場所
    pWidth: '560', // 動画の幅
    pHeight: '315' // 動画の高さ設定用
  },
  {
    id: "GBdDJHknrBQ", // youtube動画のID
    area: 'movie03', // youtube動画を埋め込む場所
    pWidth: '560', // 動画の幅
    pHeight: '315' // 動画の高さ設定用
  }
];

// 各プレーヤーの埋め込み
function onYouTubeIframeAPIReady() {
  for (let n = 0; n < ytData.length; n++) {
    ytPlayer[n] = new YT.Player(ytData[n]['area'], {
      width: ytData[n]['pWidth'],
      height: ytData[n]['pHeight'],
      videoId: ytData[n]['id'],
      playerVars: {
        rel: 0,
        playsinline: 1
      },
      events: {
        onReady: function(evt) { // ここに動画再生の準備ができた時に実行したいscriptを記述
        },
        onStateChange: function(evt) { // ここに動画のステータスが変わった時に実行したいscriptを記述
          /* 複数再生させない制御 */
          // 各プレーヤーの状態確認
          let thisState = ytPlayer[n].getPlayerState();

          if (thisState === 1 && typeof ytPlaying === 'undefined') { // 初回再生時
            ytPlaying = n;
          } else if (thisState === 1 && ytPlaying !== n) { // 他が再生されてる時
            ytStop = ytPlaying;
            ytPlay = n;
          }

          // 同時再生があった場合、元々再生していた方を停止する
          if (typeof ytStop !== 'undefined' && ytStop !== '') {
            ytPlayer[ytStop].pauseVideo();
            ytStop = '';
          }

          // 現在再生中のプレーヤー番号を保存しておく
          if (typeof ytPlay !== 'undefined' && ytPlay !== '') {
            ytPlaying = ytPlay;
            ytPlay = '';
          }
        }
      }
    });
  }
}
```

JavaScriptがキモなので、分割してちょっと説明します。


##各プレーヤーの状態確認
```JavaScript:各プレーヤーの状態確認
let thisState = ytPlayer[n].getPlayerState();
```
Youtube Player APIの説明ページにある[イベント](https://developers.google.com/youtube/iframe_api_reference?hl=ja#Retrieving_video_information)の中に「onStateChange」の説明があります。
> このイベントは、プレーヤーの状態が変わると起動します。 API がイベント リスナー関数に渡すイベント オブジェクトの data プロパティにより、プレーヤーの新しい状態に対応する整数が指定されます。 有効な値は次のとおりです。
-1（未開始）
0（終了）
1（再生中）
2（停止）
3（バッファリング中）
5（頭出し済み）

なので埋め込まれている動画の状態を「getPlayerState()」で取得します。
それをthisStateへと格納します。
再生中であれば「1」になるので、以下の様にして再生してることをif文に記載してます。

```JavaScript:再生時
if (thisState === 1 && typeof ytPlaying === 'undefined') { // 初回再生時
  ytPlaying = n;
} else if (thisState === 1 && ytPlaying !== n) { // 他が再生されてる時
  ytStop = ytPlaying;
  ytPlay = n;
}
```

あとは状態を判別して、動画再生ボタンが押された時に

- 再生ボタンを押した動画を再生開始
- もともと再生されてた動画ストップと番号の保存

という処理を行なっています。

```JavaScript:再生中の停止と再生中の動画の保存
// 同時再生があった場合、元々再生していた方を停止する
if (typeof ytStop !== 'undefined' && ytStop !== '') {
  ytPlayer[ytStop].pauseVideo();
  ytStop = '';
}

// 現在再生中のプレーヤー番号を保存しておく
if (typeof ytPlay !== 'undefined' && ytPlay !== '') {
  ytPlaying = ytPlay;
  ytPlay = '';
}
```

参考にしたブログ記事と明確に変えたところは厳密等価演算子に変えたってとこですかね。

#実行結果
最後にCodePenで上記コードを記載して実行したものを入れておきます。

<p class="codepen" data-height="500" data-theme-id="light" data-default-tab="js,result" data-user="yamabero" data-slug-hash="gOwbZog" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="youtube multiple embed">
  <span>See the Pen <a href="https://codepen.io/yamabero/pen/gOwbZog">
  youtube multiple embed</a> by yamabero (<a href="https://codepen.io/yamabero">@yamabero</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>


#参考
- https://www.neko-it.com/blog/4536.html
- https://tenderfeel.xsrv.jp/javascript/5168/