みかづきブログ・カスタム

基本的にはちょちょいのほいです。

YouTube IFrame Player APIで読み込んだ動画を自動で再生してループさせる 🎥

f:id:kimizuka:20201102125631p:plain

公式ドキュメントをざっと読むと、autoplayというパラメータも、loopというオプションも見つかるので、その2つを使って

const player = new YT.Player('player', {
  width: '320',
  height: '180',
  videoId: '1g0ebPju_eE',
  playerVars: {
    autoplay: 1,
    playsinline: 1,
    loop: 1
  }
});

と書きたくなりますが、残念ながらこれだと動きません。
先にざっくり正解のコードを書くと、

const player = new YT.Player(playerTag, {
  width: '320',
  height: '180',
  videoId: '1g0ebPju_eE',
  events: {
    'onReady': function(evt) {
      evt.target.mute();
      evt.target.playVideo();
    },
    'onStateChange': function(evt) {
      switch (evt.data) {
        case YT.PlayerState.ENDED:
          evt.target.playVideo();
          break;
      }
    }
  },
  playerVars: {
    playsinline: 1,
  }
});

という感じで書けば、PCでもスマホでも、自動再生とループが両立できます。

自動再生

前提として昨今のブラウザ事情としては、音がある動画を自動再生することはできません。
ページを開いたときにいきなり音が流れるとびっくりしちゃいますからね。

なので、

const player = new YT.Player('player', {
  width: '320',
  height: '180',
  videoId: '1g0ebPju_eE',
  playerVars: {
    autoplay: 1,
    playsinline: 1
  }
});

では動かないのは、火を見るよりも明らかで、

const player = new YT.Player('player', {
  width: '320',
  height: '180',
  videoId: '1g0ebPju_eE',
  events: {
    'onReady': function(evt) {
      evt.target.mute(); // ミュートにする
    },
  playerVars: {
    autoplay: 1,
    playsinline: 1
  }
});

という感じで、プレイヤーの準備が完了した時点で無音に設定する必要があります。

が。

この設定だとPCではうまくいくのですが、スマホではなぜかうまくいきません。原因は謎です。

ただ、プレイヤー準備完了のコールバックイベントを設定しているので、そこでビデオの再生も行ってしまえばスマホでも動きます。

const player = new YT.Player('player', {
  width: '320',
  height: '180',
  videoId: '1g0ebPju_eE',
  events: {
    'onReady': function(evt) {
      evt.target.mute(); // ミュートにする
      evt.target.playVideo(); // 再生
    },
  playerVars: {
    playsinline: 1
  }
});


ループ再生

autoplayの項目を良く読むと、playlistに設定可能なオプションということがわかります。
playlistには単一の動画も渡せるので、

const player = new YT.Player('player', {
  width: '320',
  height: '180',
  playerVars: {
    playlist: '1g0ebPju_eE', // プレイリストに動画のIDを渡す
    playsinline: 1,
    loop: 1 // ループ
  }
});

という感じで設定すれば、ループが設定できます。

が。

この設定だと自動再生と組み合わせるとうまくいきません。
なので、プレイヤーの状態が変化した際のコールバックでplayVideoを叩き直すことでループを実装しましょう。

const player = new YT.Player('player', {
  width: '320',
  height: '180',
  videoId: '1g0ebPju_eE',
  events: {
    'onStateChange': function(evt) {
      switch (evt.data) {
        case YT.PlayerState.ENDED: // ビデオの終了時
          evt.target.playVideo(); // ビデオの再生
          break;
      }
    },
  playerVars: {
    playsinline: 1
  }
});


自動再生かつループ再生

自動再生とループ再生を組み合わせるとこんな感じになります。

const tag = document.createElement('script');
const firstScriptTag = document.getElementsByTagName('script')[0];
const playerTag = document.createElement('div');

tag.src = 'https://www.youtube.com/iframe_api';

firstScriptTag.parentNode.insertBefore(playerTag, firstScriptTag);
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

window.onYouTubeIframeAPIReady = onYouTubeIframeAPIReady;

function onYouTubeIframeAPIReady() {
  const player = new YT.Player(playerTag, {
    width: '320',
    height: '180',
    videoId: '1g0ebPju_eE',
    events: {
      'onReady': onPlayerReady,
      'onStateChange': onPlayerStateChange
    },
    playerVars: {
      playsinline: 1,
    }
  });
}

function onPlayerReady(evt) {
  evt.target.mute();
  evt.target.playVideo();
}

function onPlayerStateChange(evt) {
  switch (evt.data) {
    case YT.PlayerState.ENDED:
      evt.target.playVideo();
      break;
  }
}

結局、オプションとしては、autoplayも、loopも使ってません。すごく初見殺しだと思います。