4

I want to keep track of the seeks performed in an HTML5 video. For this, I need to know the seek-from and seek-to positions. While getting the second is trivial (one only has to listen to the seeked event), I am unable to figure how to get the first.

In the past, I've used custom controls, so I could save currentTime just before manually changing it to perform the seek, when listening to the mousedown event of the progress bar or whatever I had rendered.

Now, I wanted to do it with the standard controls, but I am unable to capture this last played position.

I even tried to listen the mousedown event on the video element, but it only fires when selecting outside the control area...

let video = document.getElementsByTagName('video')[0];
let list = document.getElementsByTagName('ul')[0];


function log(name, time) {
  let li = document.createElement('li');
  li.textContent = name + ': ' + time;
  list.appendChild(li);
}

video.addEventListener('seeked', e => {
  log('seeked', e.target.currentTime);
});

video.addEventListener('mousedown', e => {
  log('mousedown', e.target.currentTime);
});
<video width="300" src="http://distribution.bbb3d.renderfarming.net/video/mp4/bbb_sunflower_1080p_30fps_normal.mp4" controls></video>
<ul>
</ul>

Thank you!

cristiancajiaos
  • 948
  • 1
  • 8
  • 16
nerestaren
  • 156
  • 1
  • 12

4 Answers4

3

You could use thetimeupdate event to keep track of current time, then when a seeked event occurs you know the last known current time.

Only problem here is that at least Chrome triggers an timeupdate just before triggering seeked what would break this approach. But then we can use seeking event to know when it should stop keeping track of current time.

The only downside of this is that if user do multiples seeks to points where video has not loaded yet you'll just get the first seek start position.

let currentVideoTime = 0;
let saveCurrentTime = true;

video.addEventListener('seeked', e => {
  log('seeked (started at ' + currentVideoTime + ')', e.target.currentTime);
  saveCurrentTime = true;
});

video.addEventListener('seeking', e => {
  log('seeking', e.target.currentTime);
  saveCurrentTime = false;
});

video.addEventListener('timeupdate', e => {
  log('timeupdate', e.target.currentTime);
  if(saveCurrentTime)
    currentVideoTime = e.target.currentTime;
});
Luizgrs
  • 4,765
  • 1
  • 22
  • 28
  • Thanks for your answer. Unfortunately, I had already tried something very similar to that before and it didn't work. Your idea does not work either, at least on Chrome 58. Why? `currentTime` is updated before either the `seeking` event is fired or the `seeking` property is set to true. https://jsfiddle.net/94st7zzm/1/ – nerestaren Jun 09 '17 at 15:50
  • to me it works, this is what I get in the logs: "(multiples seeking).. | seeking: 149.301882 | timeupdate: 149.301882 | seeked (**started at 0**): 149.301882 | timeupdate: 149.301882", if I try again it works again: "seeking: 286.161941 | timeupdate: 286.161941 | seeked (**started at 149.301882**): 286.161941 | timeupdate: 286.161941" – Luizgrs Jun 09 '17 at 19:17
  • I see... are you **playing** the video or are you doing this with the video **paused**? – nerestaren Jun 09 '17 at 19:46
  • I just tried to seek with the video playing. `seeked` event is triggered everytime you stop the progress range in a section which has already been downloaded, it does not matter if you're still holding the range marker, and that breaks my approach :( – Luizgrs Jun 10 '17 at 01:09
2

I have been facing this problem myself, and I was able to make it work using the following trick:

var timing = 0;    
video.addEventListener('timeupdate', function () {
    var previousTime = timing;
    var currentTime = Math.round(this.currentTime);
    if (currentTime > previousTime + 1 || currentTime < previousTime - 1) {
        console.log('Video ' + this.id + ' was skipped from ' + previousTime + ' to ' + currentTime + ' sec.');
    }
    timing = currentTime;
});

Using the timeupdate event, I check for a difference of more than 1 second between the previousTime and the currentTime". Tested on Chrome, FF and Safari with success.

fleveillee
  • 55
  • 1
  • 6
0

My problem is that seeking even, when it's fired, video_element.currentTime is already the updated "seek to" time.

The way I do it is basically by tracking only timeupdate (except that timeupdate doesn't fire often enough [sometimes 20s? sometimes 1ms? maybe depends on load?] so I just set a timer for 100 fps and poll the currentTime. If it has changed "significantly" since last time, I assume a seek. FWIW.

It does seem that timeupdate "sometimes" fires before the seeking event does (bummer). Might make a difference whether it's forward vs. backward seek or some odd.

rogerdpack
  • 62,887
  • 36
  • 269
  • 388
0

Take a look to video played property.

To get the seek-from position i'm using next code

const vid = document.getElementById("video1");
vid.onseeking = function() {
    let seekStartTime = 0;
    if (vid.played.length >= 1) {
      seekStartTime = vid.played.end(vid.played.length - 1);
    }
    document.getElementById('videoSeekedFrom').innerHTML = "Video seeked from - " + seekStartTime + " seconds";
};
vid.onseeked = function() {
    let seekEndTime = vid.currentTime;
    document.getElementById('videoSeekedTo').innerHTML = "Video seeked to - " + seekEndTime + " seconds";
};
AndrewS
  • 1
  • 2