javascripthtmlvideo-streaminghtml5-videopreload

Reacting when N videos have preloaded a given time interval?


I was watching a youtube where the content creator used GSAP to animate the switching between videos, which was very smooth, and I'd like to create something similar, but with a spinner that is shown until 2 seconds of each video has been loaded, that way the experience is smooth. How would we go about reacting once 2 seconds of N videos has been preloaded?


Solution

  • You can tell when a single video have been preloaded 2 seconds using the progress event and the buffered property.

    Example:

    const video = document.getElementById('myVideo');
    
    function checkForBuffer(seconds) {
      if (video.buffered.length > 0) {
        const bufferedEnd = video.buffered.end(video.buffered.length - 1);
        if (bufferedEnd >= seconds) {
          console.log(`Video has preloaded at least ${seconds} seconds.`);
          video.removeEventListener('progress', foo);
        }
      }
    };
    
    const foo = () => checkForBuffer(2);
    
    video.addEventListener('progress', foo);
    <video id="myVideo" src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" preload="auto" controls width="200"></video>

    In order to identify when N videos have been preloaded, you can use a Promise approach.

    Let's write a simple Promise.

    function getVideoPreloadChecker(videoElement, secondsToBuffer) {
      return new Promise((resolve, reject) => {
        const progressHandler = () => {
          if (videoElement.buffered.length > 0) {
            const bufferedEnd = videoElement.buffered.end(videoElement.buffered.length - 1);
            if (bufferedEnd >= secondsToBuffer) {
              videoElement.removeEventListener('progress', progressHandler);
              resolve();
            }
          }
        };
    
        videoElement.addEventListener('progress', progressHandler);
        progressHandler();
      });
    }
    
    async function main() {
      var video = document.getElementById("myVideo");
      var seconds = 2
      await getVideoPreloadChecker(video, seconds)
      console.log(`been preloaded ${seconds} seconds`)
    }
    
    main();
    <video id="myVideo" src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" preload="auto" controls width="200"></video>

    And for the case of N:

    function getVideoPreloadChecker(videoElement, secondsToBuffer) {
      return new Promise((resolve, reject) => {
        const progressHandler = () => {
          if (videoElement.buffered.length > 0) {
            const bufferedEnd = videoElement.buffered.end(videoElement.buffered.length - 1);
            if (bufferedEnd >= secondsToBuffer) {
              videoElement.removeEventListener('progress', progressHandler);
              resolve();
            }
          }
        };
        videoElement.addEventListener('progress', progressHandler);
        progressHandler();
      });
    }
    
    async function main() {
      var videos = document.querySelectorAll(".video");
      var seconds = 2
      var promises = [...videos].map(video => getVideoPreloadChecker(video, seconds))
    
      await Promise.all(promises)
      console.log(`all videos been preloaded ${seconds} seconds`)
    }
    
    main();
    <video class="video" src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" preload="auto" controls width="200"></video>
    <video class="video" src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4" preload="auto" controls width="200"></video>