▶️
iframe APIを使って、Youtubeの同時再生をを止める方法
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').
-
エラーについての記事
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