見出し画像

Youtube iframe APIを活用した同時再生防止のテクニック


Youtubeの規約では同時再生は規約違反

同時再生は規約違反になるので、一つしか再生されないようにする方法を記載していきます。
下記参考

まずは、youtube iframe apiのjsを読み込む

scriptタグに下記のsrcを読み込む
この時点でconsoleに`YT`と打って存在すれば読み込めています

<script src="https://www.youtube.com/iframe_api"></script>

iframeでYouTubeを読み込む

`?enablejsapi=1`のqueryはapiを使う上で必須です。
styleはいい感じに調整してください

    <div>
      <iframe width="50%" height="315" src="https://www.youtube.com/embed/eB0arUZ-63I?enablejsapi=1" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
      <iframe width="50%" height="315" src="https://www.youtube.com/embed/eB0arUZ-63I?enablejsapi=1" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
      <iframe width="50%" height="315" src="https://www.youtube.com/embed/eB0arUZ-63I?enablejsapi=1" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
      <iframe width="50%" height="315" src="https://www.youtube.com/embed/eB0arUZ-63I?enablejsapi=1" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
    </div>

playerのinstanceを生成する

  • `querySelectorAll`でiframeを取得する

  • mapでinstanceを生成して、instanceの配列を生成

    • 第一引数にはiframeのdomかidを入れる

  • `onStateChange`のeventに関数を登録する

    • `onStateChange`とはyoutubeの状態に変更があった場合にtriggerされるeventです。

    • 今回は`再生`をtriggerしたいので使用しています。

  // domを取得(取得方法は自由でOK)
  var iframes = Array.from(document.querySelectorAll('iframe'));
  
  var players = iframes.map((iframe) => {
      // 第一引数にはiframeのdomかidを入れる(下記はdomの例)
     return new YT.Player(iframe , {
        events: {
                        // ↓ここにステータスが変わった時に発火して欲しい関数を入れる
          'onStateChange': onPlayerStateChange,
        },
      });
  });

再生されていたら、他を止める処理

  • 先ほど`onStateChange`に登録した関数に処理を書いていく

  • 引数には、`data`(status そのプレイヤーの状態)と`target`(player そのもの)が入っています。

  • 今回は`target`のみを使用するので、引数で受け取る。

  • triggerとなった再生を開始した、playerは再生を停止したくないので、ループして、同一のplayerだった場合returnする。

  • `player.getPlayerState()`でplayerの状態を取得(再生中は1が入る)※状態一覧は下記記載

  • `player.stopVideo()`で他の再生中の動画を止める。

  const onPlayerStateChange = ({ target }) => {
    // ループしてplay中の動画があるかチェック
    players.forEach((player, index) => {
      // targetと同じ場合はreturn
      if (target === player) return ;

      // プレイヤーのステータスを取得
      let state = player.getPlayerState();

      // プレイ中のものは再生を止める
      if (state === YT.PlayerState.PLAYING) {
        player.stopVideo();
      }
    });
  };

`YT.PlayerState`の中身は下記のような定数

BUFFERING: 3 CUED: 5 ENDED: 0 PAUSED: 2 PLAYING: 1 UNSTARTED: -1

登録したeventとinstanceの破棄

ページを離れた時に破棄しましょう
destroyはeventのremoveとinstanceの破棄も兼ねていますs

players.forEach((player) => {
  player.destroy();
});

デモ

これで下記のように再生中に他の動画を再生したら、元々再生されていた動画が止まっていますね

エラーが出た場合の対策

  • エラー内容

Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('https://www.youtube.com') does not match the recipient window's origin ('http://localhost').
  • このエラーは、originが違うよーと言うエラーです(httpsとhttp)
    起きる例としてiframeに`loading="lazy"`がついていると画面外にあるまだロードしていない、iframeに対して、instanceを生成しようすると起こるエラーです。

エラーについての記事は下記をご参考にしてくください

対策としてloadした時に、instanceを生成してあげる

iframeのload eventに関数を登録

iframes.forEach((iframe) => {
  iframe.addEventListener('load', onLoad);
});

loadしたタイミングでinstanceを生成する

// loadが完了したらinstanceを生成
  let onLoad = (e) => {
    // loadが終わっているものは弾く
    if (e.currentTarget.dataset.loaded === 'true') return ;
    // loadしたらloadedにtrueを入れておく
    e.currentTarget.dataset.loaded = 'true';
    // playerのinstanceを生成
    player = new YT.Player(iframe , {
      events: {
        'onStateChange': onPlayerStateChange,
      },
    });
  }

まとめ

同時再生対策する際にぜひ参考にしてみてください!

この記事が気に入ったらサポートをしてみませんか?