0

I'm having a problem with HTML Video and JavaScript so have written some simple code to demonstrate. There is one video which contains three "clips" all five seconds long (obviously, real-world, they are a lot longer). One at 25 - 30 seconds, one at 55 - 60 seconds and the last at 85 - 90 seconds. I want the user to be able to click the relevant button for each five second clip.

There are two issues:

  1. The Chrome currenttimer() bug which doesn't seem to let you change the start time of an external video (The video will be stored on an Azure Blob). There appear to be a number of posts on this but no fix.
  2. When you play the first clip and then try and play the second clip, because the start time of clip 2 is after the end time for clip 1, it doesn't play because the AddEventListener is still in effect. Is there a way to drop the original EventListener or replace it with the new end time?

Here is the code being used:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    <div style="width: 700px; height: 400px; margin: auto; text-align: center;">
        <video id="video1" width="620" controls>
            <source type="video/mp4" src="external video link here" />
            Your browser does not support HTML5 video.
        </video>

        <input type="button" value="Play Clip 1 (25 - 30 seconds" onclick="javascript: showvid(25);" /><br />
        <input type="button" value="Play Clip 2 (55 - 60 seconds" onclick="javascript: showvid(55);" /><br />
        <input type="button" value="Play Clip 3 (85 - 90 seconds" onclick="javascript: showvid(85);" /><br />
    </div>

    <script type="text/javascript">
        function showvid(timer) {
            var myVideo = document.getElementById("video1");
            myVideo.currentTime = timer;
            myVideo.play();

            myVideo.addEventListener("timeupdate", function () {
                if (this.currentTime >= (timer + 5)) {
                    this.pause();
                }
            });
        }
    </script>
</body>
</html>

UPDATE 1

I've changed the event listener check to pause the video only if the currenttime is within a second of the end time. SO if the next clip is more than a second away, they listener won't stop the clip before it starts.

Still looking into the Chrome issue.

IanTrem
  • 25
  • 1
  • 7
  • take a look at this answer to a similar challenge https://stackoverflow.com/questions/16459470/jump-around-in-a-video-to-times-from-an-array/16474484#16474484 – Offbeatmammal Dec 17 '18 at 10:04
  • Fixes neither problem. Chrome still starts at 0 (when I want it to start at 25) and whilst it pauses once it reaches 30 seconds, when you click button two to start at 55 seconds, it does nothing as the listener is still set at 30 seconds. – IanTrem Dec 17 '18 at 18:45

1 Answers1

1

I don't know what Chrome bug you are talking about, but for cleaner code, you might be interested in the #t=start[,end] Media Fragment, which will allow you to set a time range directly as the source of your <video>:

onclick =e=> {
  const data = e.target.dataset;
  if(!data.start) return;
  vid.src = vid.src.split('#')[0] +
    '#t=' + data.start + ',' + data.end;
  // url.vid#t=start,end
  vid.play();
}
<button data-start="5" data-end="10">play [5,10]</button>
<button data-start="35" data-end="40">play [35,40]</button>
<button data-start="00:01:25" data-end="00:01:30">play [00:01:25,00:01:30]</button>
<video id="vid" src="https://upload.wikimedia.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm" muted></video>

Now if you really wish to go the way you were going, then you'll have change your code a bit.

Never add a new event listener from an user-generated event.

Add it once, and only trigger semaphores / update variables from user events.

So we first add the timeupdate event on our <video>, then if no user generated event did happen, we exit early. Otherwise, we check for a variable that is accessible to both our event listeners (here called next_stop) if we should pause or not.

Then, in the buttons event listeners, we update the <video>'scurrentTime, request it to play and update next_stop.

The two event listeners can interact thanks to the shared next_stop variable, but no more conflicts.

let next_stop = Infinity; // a variable shared by both event listeners

// add the event listeners only once
vid.addEventListener('timeupdate', handleTimeupdate, {passive: true});
document.addEventListener('click', handleClick);

function handleTimeupdate(evt) {
  // not set? exit early
  if(!isFinite(next_stop)) return;
  // a single action
  if(this.currentTime > next_stop) {
    this.pause();
    // if you want to disable the range once it's done
    // e.g to allow default controls interactions
//    next_stop = Infinity;
  }
}

function handleClick(evt) {
  const times = parseTime(evt.target);
  if(!times) return;
  // update the video's current time  
  vid.currentTime = times.start;
  // update the shared variable
  next_stop = times.end;
  // start playing if needed
  if(vid.paused) {
    vid.play();
  }
}

function parseTime(target) {
  const data = target.dataset;
  if(!data || !data.start) return null;
  return {start: +data.start, end: +data.end};
}
<button data-start="5" data-end="10">play [5,10]</button>
<button data-start="35" data-end="40">play [35,40]</button>
<button data-start="85" data-end="90">play [00:01:25,00:01:30]</button>
<video id="vid" src="https://upload.wikimedia.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm" controls></video>
Community
  • 1
  • 1
Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • The media fragment code works great with your video (on Chrome and other browsers) but doesn't work with the video I'm using on Azure Blob so I'm assuming there's an issue. there. Thanks for the info though, I can definitely use this. – IanTrem Dec 18 '18 at 10:39