Video-jsを利用して動画をループ再生させる際、2回目の再生以降に「再生ボタン」が表示されたままになる問題を修正する方法

HTML5のVideoプレイヤーとFlashのビデオプレイヤーを併用し、いろいろな環境に合わせて動画再生を行える非常に便利なスクリプト「Video-js」。

私も多々利用させて頂いて居るのですが、ここにきてタイトル通りのバグ「ループ再生の2回目以降で、再生ボタンが表示されっぱなしになる」に遭遇し、解決したのでその方法を記載します。

まず、バグが発生する環境は下記の通り。

  • Video-jsのFlashプレイヤーで再生をしている
  • autoplayオプションをON
  • loopオプションをON
  • controlsオプションをON

HTML5のプレイヤーでも発生するかは未検証です。

原因

Video.jsでは動画の再生・停止などに合わせイベントを発行しており、内部の動作についてもそのイベントに依存して制御を行っているようです。

今回の問題はループ再生の場合にのみ発生するのですが、その発生機序としては下記のようなものでした。

  1. 1回目の動画再生が開始:playイベントが発生
  2. playコールバックの処理(1):「再生ボタン」が「display:none」になる
  3. 1回目の動画再生が終了:endedイベントが発生
  4. endedコールバックの処理(1):「ループ再生なら、再度最初から再生」という処理が実行される
  5. 2回目の動画再生が開始:playイベントが発生
  6. playコールバックの処理(1):「再生ボタン」が「display:none」になる
  7. endedイベントに登録された2つめ以降のコールバックが発生
  8. endedコールバックの処理(2):「再生ボタン」を再表示させる

要はコールバックの登録の順番が悪いというもので、endedイベントの最初のコールバックで再生処理を行ってしまっているものだから、endedイベントに登録された2個目以降のコールバックが、なぜかplayイベントの次に実行されるという訳のわからない状態に。

というわけで、このあたりのコードをさくっと修正すればバグも解消します。

コード修正

video.js(version 3.2.0現在)の926行目付近:

  init: function(player, options){
    this._super(player, options);

    player.addEvent("play", _V_.proxy(this, this.hide));
    player.addEvent("ended", _V_.proxy(this, this.show));
  },

下記のように改善します。

  init: function(player, options){
    this._super(player, options);

    player.addEvent("play", _V_.proxy(this, this.hide));
    
    if (!player.options.loop) {
      player.addEvent("ended", _V_.proxy(this, this.show));
    }
  },

要は「ループ指定がされていない場合のみ、再生終了時にボタンを再表示してねん」という処理に変更をかけます。

これで晴れて2回目以降の再生でも、再生ボタンがしっかり消えたままになります。