bluprince13
bluprince13

Reputation: 5011

How to prefetch video in a react application?

I have a React app with a component that loads different videos depending on user input. There are only 4 or 5 small videos, so I'd like to pre-fetch all of them when the browser is inactive.

Within my component, I have:

<video src={this.props.video} type="video/mp4" />

In my index.html, I have a line in the head for a video:

<link rel="prefetch" as="video/mp4" href="link/to/my/video.mp4">

However, this doesn't work. Looking at the console, I can see that the video is fetched (with a 200 status) but not stored in the cache (size is 5 Mb for the response, 0 Mb for on disk). When I provide user input and the component needs to display that video, it is fetched again which takes a few seconds.

PS - The reason I'm not trying to use preload on the video element is because preload only works if the page you are looking at has the video in it. In my case, I want to load the videos even if they are not required for the current page.

Update: I made a pen where you can see that the video isn't pre-fetched despite the use of a link tag in the head.

Upvotes: 12

Views: 16261

Answers (2)

Julia Melo
Julia Melo

Reputation: 9

Is it really necessary to prefetch all the videos before loading the screen? Even though they are small videos, to preload information that not necessarily will be used is not the only option. Imagine if the user only watch one of the five videos, it means that 80% of all data preloaded was never used. An alternative would be showing a component while you're loading the video, like Netflix does when is searching for options.

Upvotes: 0

Tu Tran
Tu Tran

Reputation: 458

In your situation, you can make an AJAX request and create blob URL from the response of that request.

You can see from my code pen

function playVideo() {
    var video = document.getElementById('video')

    if (video) {
        video.play().then(_ => {
            console.log('played!')
        });
    }
}

function onSuccess(url) {
    console.log(url);
    var video = document.createElement('VIDEO')
    if (!video.src) {
        video.id = 'video';
        document.body.appendChild(video);
        video.src = url
    }
}

function onProgress() {

}

function onError() {

}

prefetch_file('https://raw.githubusercontent.com/FilePlayer/test/gh-pages/sw_360_lq.mp4', onSuccess, onProgress, onError)

function prefetch_file(url,
                       fetched_callback,
                       progress_callback,
                       error_callback) {
    var xhr = new XMLHttpRequest();
    xhr.open("GET", url, true);
    xhr.responseType = "blob";

    xhr.addEventListener("load", function () {
        if (xhr.status === 200) {
            var URL = window.URL || window.webkitURL;
            var blob_url = URL.createObjectURL(xhr.response);
            fetched_callback(blob_url);
        } else {
            error_callback();
        }
    }, false);

    var prev_pc = 0;
    xhr.addEventListener("progress", function (event) {
        if (event.lengthComputable) {
            var pc = Math.round((event.loaded / event.total) * 100);
            if (pc != prev_pc) {
                prev_pc = pc;
                progress_callback(pc);
            }
        }
    });
    xhr.send();
}

The disadvantage of this approach is that it will not work if the video doesn't allow CORS for your site.

Upvotes: 8

Related Questions