[JS] YouTube iFrame Player APIの同時再生は規約違反な件

1つのWebページ内に複数のYouTubeプレーヤーを配置する場合、
常に再生されるのは1つのプレイヤーに限定しなければ利用規約違反になるそうで。

※なお、iOSやAndroidでも同時再生が規約違反なのは同じ。

ぶっちゃけ注意のメールが来るまで知らなかった🙄

WordPressでembedしたやつとか普通に同時再生なるし、今更?と思ったが
3営以内にどうにかしろと大本営に言われたらやるしかないので、
対策がてらサンプルを作ってみた。

Vue.jsで管理するサンプル

妹が好きなバンドのPVを1個だけ再生するぞ。

See the Pen Example of YouTube component playing only one video at a time by Tenderfeel (@Tenderfeel) on CodePen.

YouTubeのiFrame Player APIそのものは変わってないので、昔書いた記事とやり方は同じ。

コンソール見るとpostMessageのエラー出てますが、

Failed to execute ‘postMessage’ on ‘DOMWindow’: The target origin provided (‘https://www.youtube.com’) does not match the recipient window’s origin

console.error

originを設定したり色々試したけど消せなかったんで諦めた。

embedUrl() {
  return `//www.youtube.com/embed/${this.data.id}?rel=0&playsinline=1&enablejsapi=1&origin=${window.location.origin}`;
}

確認中iOS12系だとインライン再生できない不具合があった。(バッファリングで勝手に止まる)iOS13はなんともない。

以下要点の説明

Appコンポーネント

App.created

APIのスクリプトタグ追加してイベントハンドラ設定している。
イベントハンドラでは dataのyoutubeApiReady を変更する。

  created() {
    const tag = window.document.createElement('script');
    tag.src = '//www.youtube.com/iframe_api';
    tag.async = true;
    const firstScriptTag = document.querySelector('script');
    firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
    window.onYouTubeIframeAPIReady = () => {
      console.log('YouTube API Ready')
      this.youtubeApiReady = true;
    };
  },

App.methods.onYouTubeStateChange

Youtubeコンポーネントのchangeイベントに渡すイベントハンドラ。
新しいプレイヤーの再生が始まった時、すでに再生中のプレイヤーがあれば停止する。

methods: {
    onYouTubeStateChange({ player, status }) {
      if (status !== window.YT.PlayerState.PLAYING) {
        return;
      }
      if (playingVideo === null) {
        playingVideo = player;
        return;
      }
      if (playingVideo.getVideoUrl() !== player.getVideoUrl()) {
        try {
          playingVideo.stopVideo();
        } catch (e) {
          //
        }
        playingVideo = player;
      }
    }
  }

YouTubeコンポーネント

YouTube.mounted

親の youtubeApiReady を監視する。trueになったらPlayer作る。
Propsで渡してwatchで監視するでも良い。

mounted() {
    this.$watch('$parent.youtubeApiReady', val => {
      if (val === true) {
        this.createPlayer();
      }
    })
},

YouTube.methods.createPlayer

iFrame要素を渡す場合でURLにパラメーターを設定しているならプレイヤー作成時のオプションを省略できる。
コールバックでカスタムイベントを$emitする。

  methods: {
   createPlayer() {
      this.player = new window.YT.Player(this.$refs.iframe, {
        events: {
          onReady: event => {
            this.$emit('ready', { player: event.target });
          },
          onStateChange: event => {
            this.$emit('change', {
              player: event.target,
              status: event.data
            });
          }
        }
      });
    }
  }

YouTube.beforeDestroy

コンポーネント破棄前にplayer.destroy()する。

  beforeDestroy() {
    try {
      if (this.player) {
        this.player.destroy();
      }
    } catch (e) {
      //
    }
  },

lazysizesに対応させる場合

YouTubeプレイヤーコンポーネントに遅延読み込みのライブラリlazysizesを使うサンプル。

div.lazyloadな要素にlazybeforeunveilイベントハンドラを設定する。
子のdivにref="player"を設定しておく。(iFrameでもおk)

<div class="lazyload" @lazybeforeunveil="onLazybeforeunveil">
    <div ref="player" />
</div>

あとはイベントハンドラの方でプレイヤー作成するだけ。

methods: {
  onLazybeforeunveil() {
    this.player = new window.YT.Player(this.$refs.player, {
       // ここにプレイヤーの設定
    })
  }
}
 

注意文面

どうやらYouTube使ってるサービスへ一斉に注意がきたそうな。
不正な再生数稼ぎ対策の一環らしい。

Policy #: III.C 1

Violation: API Client is allowing multiple players playing parallel in a web page.
Proposed Solution: As per YouTube terms of services & policies in a page only one video should be played at a time. In case there are multiple videos on that page make sure that only one player must be active at a time in each and every page of your website wherever applicable.

YouTube API Services Form

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください