▶️

iframe APIを使って、Youtubeの同時再生をを止める方法

2022/06/08に公開

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

同時再生は規約違反になるので、一つしか再生されないようにする方法を記載していきます。
下記参考
https://developers.google.com/youtube/terms/developer-policies#iii.-general-developer-policies

まずは、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();
});

デモ

https://runstant.com/kinchan/projects/fe66ccb7
これで下記のように再生中に他の動画を再生したら、元々再生されていた動画が止まっていますね
Image from Gyazo

エラーが出た場合の対策

  • エラー内容
Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('https://www.youtube.com') does not match the recipient window's origin ('http://localhost').
  • エラーについての記事
    https://teratail.com/questions/119741

  • このエラーは、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,
      },
    });
  }

まとめ

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

Discussion