LoginSignup
0
0

video.jsでendedイベントが発火されない

Posted at

はじめに

以前、業務でvideo.jsを触っていた時にendedイベントが発火せず苦戦したので、その時に調査した内容と解決策をここにまとめます。

発生していた問題

動画がplayした時間、stopした時間、endedした時間をサーバに返す必要があり、それぞれのイベントリスナーが発火した時間を取得しようとしていましたが、endedイベントのみが発火しませんでした

原因

video.jsでは、videoのloop再生をONにしているとendedイベントが発火されずにループする挙動になります。業務で用いているvideo.jsでは、loopをONにしていたためにendedイベントが発生しませんでした。

解決策1 loopをOFFにする

loopがONだとendedイベントが発生しないので単純にloopをOFFにすれば解決することはできます。

しかし、業務では諸事情でloop再生をOFFにすることはできなかったので、なんとかして動画の終了イベントを検知する必要がありました。

解決策2 timeupdateイベントから擬似的なendedイベントを発火させる

video.jsのイベントには、動画の現在時刻が更新されたときに発生するtimeupdateイベントがあります。このtimeupdateが発火した時のcurrentTimeの値を変数に持っておき、動画の終了時刻から開始時刻に変化したタイミングを擬似的にendedイベントとすることができます。

例(React)

const prevTimeRef = useRef<number>(0); // ループを検知するためにtimeupdateイベントの直前の時間を保持

const onReady = useCallback(
  (player: videojs.Player) => {
    // ループを検知してendedイベントを発火させる
    player.on('timeupdate', () => {
      if (
        prevTimeRef.current - player.currentTime() >
        player.duration() - 1
      ) {
        console.log('ended')
      }
      prevTimeRef.current = player.currentTime();
    });
  },
  []
);

ただし、timeupdateイベントの頻度はシステムの負荷に依存するため、正確な終了時刻を取ることはできないという課題があるため注意が必要です。今回は1秒以内に収まっていればループしたと判断しました。

最後に

loop時にloopイベントなるものが標準で用意されてくれていればこんな回りくどいことする必要ないんですけどね。。。
今回はloopをOFFにできなかったので苦肉の策でしたしより良い方法もあると思います。もしより良い方法があればコメントで教えてくださるとありがたいです!

ご覧いただきありがとうございました!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0