Home > Net >  Prefetch / download video and save in javascript for later use
Prefetch / download video and save in javascript for later use

Time:06-20

I'm trying to build a hero banner that starts playing one random video out of four and continues on the playlist. However from what I understand, my current code, whenever a new video needs to be played, and it had already been loaded and played once, uses internet for the same data again.

From what I've google so far, and I might be wrong since I'm still a newbie, it's possible to prefetch before playing that video so that there wouldn't be any stuttering or etc. How can I load once and reuse the video data later again? Right now my only option is to create objects / HTML elements, assign and load videos to them, append whenever a certain video needs to be played, remove it and append next one, basically like a playlist. However I'm bothered that this logic, if it works, wouldn't be performance friendly, because I'm trying to get better at JS whilst also knowing great optimization practices for all aspects.

Here is the current code:

      <img
        src="image.jpg"
        id="noscript-img"
        width="100%"
        heigh="100%"
        loading="lazy"
      />
      <video id="hero-banner" muted="" playsinline disablePictureInPicture>
        <source src="" type="video/mp4" id="hero-banner-src" />
      </video>
      <div ></div>
      <h1 >{{ collection.title }}</h1>
    </div>
    <script defer type="text/javascript">
      var heroBanner;
      var heroBannerSrc;
      var sources;
      var startWith;
      var curDuration;
      var curtains;
      function fadeAnim() {
        var opacity = 0.1;
        var anim = setInterval(function () {
          if (opacity >= 1) {
            clearInterval(anim);
          }
          curtains.style.opacity = opacity;
          opacity  = opacity * 0.1;
        }, 10);
      }
      function fadeOutAnim() {
        var opacity = 1;
        var anim1 = setInterval(function () {
          if (opacity <= 0.1) {
            clearInterval(anim1);
          }
          curtains.style.opacity = opacity;
          opacity -= opacity * 0.1;
        }, 50);
      }
      window.addEventListener("load", (event) => {
        heroBanner = document.getElementById("hero-banner");
        heroBanner.style.visibility = "visible";
        document.getElementById("noscript-img").remove();
        heroBannerSrc = document.getElementById("hero-banner-src");
        sources = [
          "video1.mp4",
          "video2.mp4",
          "video3.mp4",
          "video4.mp4",
        ];
        startWith = Math.floor(Math.random() * 4);
        heroBannerSrc.setAttribute("src", sources[startWith]);
        heroBanner.load();
        curtains = document.querySelector(".curtains");
        heroBanner.addEventListener("loadeddata", (event) => {
          curDuration = heroBanner.duration * 1000;
          setTimeout(fadeAnim, curDuration - 800);
        });
        heroBanner.play();
        heroBanner.addEventListener("ended", (event) => {
          if (startWith < 3 && startWith >= 0) {
            startWith  ;
          } else if (startWith >= 3 || startWith <= 0) {
            startWith = 0;
          }
          heroBannerSrc.setAttribute("src", sources[startWith]);
          heroBanner.load();
          heroBanner.addEventListener("loadeddata", (event) => {
            curDuration = heroBanner.duration * 1000;
            setTimeout(fadeOutAnim, 0);
            setTimeout(fadeAnim, curDuration - 800);
          });
          heroBanner.play();
        });
      });
    </script>

Any help is greatly appreciated.

CodePudding user response:

Alright using XMLHttpRequest() to save loaded videos into an array resolves my question.

If anyone else who's still learning JavaScript and is looking for a method to do what I was trying to do here is what it would look like:

var preVideos = new Array("", "", "", "");
//since I start a random video from my playlist
//and continue the query from there this is why
//I pre add four elements to the Array

function preLoad(fadeOutState) {
        //'fadeOutState' is plainly for the transition animation
        if (preVideos.at(startWith) != "") {
          heroBannerSrc.src = preVideos.at(startWith);
          heroBanner.load();
          //the video element in my case has <source> as a child
          //heroBannerSrc points to the <source> element
          //heroBanner points to the <video> element
          heroBanner.addEventListener("loadeddata", (event) => {
            curDuration = heroBanner.duration * 1000;
            setTimeout(fadeOutAnim, 0);
            setTimeout(fadeAnim, curDuration - 800);
            //this event is plainly for a transition between videos animation 
          });
          heroBanner.play();
          return;
          //overall this 'if' is to stop HTTP requests from happening below,
          //after all of the videos have already been loaded and stored
        }
        let req = new XMLHttpRequest();
        req.open("GET", sources[startWith], true);
        req.responseType = "blob";
        req.onload = function () {
          if (req.readyState !== XMLHttpRequest.DONE && status != 200) {
            console.log(
              "Status does not equal to 200 or HTTP request hasn't finished 
              yet"
            );
            return;
          }
          var blob = URL.createObjectURL(this.response);
          switch (startWith) {
            case 0:
              preVideos.splice(0, 1, blob);
              //if I didn't need to preadd elements to the
              //array I'd use '.push(blob)' instead of '.splice'
              //and I wouldn't need the 'switch case' for that matter too
              heroBannerSrc.src = blob;
              break;
            case 1:
              preVideos.splice(1, 1, blob);
              heroBannerSrc.src = blob;
              break;
            case 2:
              preVideos.splice(2, 1, blob);
              heroBannerSrc.src = blob;
              break;
            case 3:
              preVideos.splice(3, 1, blob);
              heroBannerSrc.src = blob;
              break;
            default:
              heroBannerSrc.src = blob;
          }
          heroBanner.load();
          switch (fadeOutState) {
            case false:
              heroBanner.addEventListener("loadeddata", (event) => {
                curDuration = heroBanner.duration * 1000;
                setTimeout(fadeAnim, curDuration - 800);
                heroBanner.play();
                //event for the anim.
              });
            case true:
              heroBanner.addEventListener("loadeddata", (event) => {
                curDuration = heroBanner.duration * 1000;
                setTimeout(fadeOutAnim, 0);
                setTimeout(fadeAnim, curDuration - 800);
                heroBanner.play();
                //event for the anim.
              });
          }
        };
        req.send();
      }

However, there may be a more performance-friendly way to approach this, and caching videos is also a great idea if you're also looking to implement all of the 'core' (I think?) requirements.

  • Related