-7

Here the Codesandbox example.

I have a list array of songs:

const tracks = [
    {
        name: "Sunny",
        src: "https://www.bensound.com/bensound-music/bensound-sunny.mp3"
    },
    ...

From that list I would like to know how to start download automatically in background the next song (not all the list, only the next) once the current has been completely downloaded.

Why?

Because it is the user's intention to listen to the next song in a selected playlist (We are talking about small files of less than 10MB).

My question is very similar to this one excepted for I'm in React JS and I'm using react-h5-audio-player.

Simon Orro
  • 184
  • 7
  • 20
  • 1
    Why do you even want to do that? The user might not even request the next song but you will load it after all. Anyway, you could use a simple hidden audio tag in the background with a source of the next song. Afterwards when your audio player will request the next song the browser will use its cache so your audio will be already loaded. Does this do the trick? – prieston Apr 12 '22 at 14:17
  • 1
    @prieston when a user hit play on a list means that wants to listen all the tracks, that's why I would like to make it faster play the next song. – Simon Orro Apr 12 '22 at 14:52

1 Answers1

1

You can insert <link rel="prefetch"> elements into the <head> of the page. This will tell the browser to go ahead and download the thing that it finds in the src property of that element so that it can be served from the cache if something else on the page (in this case, the audio player) requests it in the future (see docs).

Here's some code that should work:

const alreadyPreloaded = new Set();

export function preloadTrack({ src } = {}) {
  // We make sure not to insert duplicate <link rel="prefetch> elements
  // in case this function gets called multiple times with the same track.
  if (typeof src === "string" && !alreadyPreloaded.has(src)) {
    const head = document.getElementsByTagName("HEAD")[0];
    const link = document.createElement("link");
    link.rel = "prefetch";
    link.href = src;
    head.appendChild(link);
    alreadyPreloaded.add(src);
  }
}

Then, in your react component, you could call preloadTrack as a side-effect of when the track changes:

 useEffect(() => {
    preloadTrack(tracks[trackIndex]); // Also preload the current track
    preloadTrack(tracks[trackIndex + 1]); // tracks[trackIndex + 1] might be undefined, but we wrote the preloadTracks function to safely handle that.
  }, [trackIndex]);

See this fork of your codesandbox

You can see that it's working by checking the "network" tab in debug tools. This is what I see on a fresh page reload after clearing the cache, and before clicking on anything.

enter image description here

Another way to be sure that it is working, is to hit the "next" button once - you should see that track #2 (bensoud-tenderness.mp3) is being served from the cache with a 206 status code.

enter image description here

Andrew Stegmaier
  • 3,429
  • 2
  • 14
  • 26
  • it doesn't work at all...once the first song is completely downloaded, it must starts download the next one (only the next one). Instead in your sandbox it doesn't start to download the next song. – Simon Orro Apr 15 '22 at 18:53
  • In my tests (by examining the "network" tab of debug tools, and filtering for any network request that includes "mp3"), I see that the codesandbox example I provided does indeed download both the "next" track (see the screenshot). One thing to be aware of is that this request will be coming from "preloadTrack.js" not from the player code itself. But that's fine - when the player (later) requests the next track, it will be served (almost instantly) from the prefetch cache. Does that make sense? If not, can you clarify why you don't think it's working? – Andrew Stegmaier Apr 15 '22 at 19:06
  • As you can see from [this picture](https://ibb.co/z2FrR6N), it doesn't work as expected. – Simon Orro Apr 16 '22 at 07:50
  • The `206` responses in your screenshot mean "this request was served from disk cache" - you don't see the prefetch request for either resource (only the "real" requests from the media player) because chrome is smart enough not to "re-prefetch" something that's already in the cache (like the "next" song). IOW, what you're seeing is it working as expected for the second visit. If you want to see what it's like on the first visit (my screenshot), you need to clear your cache and refresh the page. With dev tools open, right click on the "refresh" icon and click "empty cache and hard refresh" – Andrew Stegmaier Apr 16 '22 at 12:37
  • Did you check the picture? I know what 206 is... that's not the point. The picture shows that it downloads only the 1st song, nothing else. I hard cache reload, also I tried on a different browser. It only download the first song. – Simon Orro Apr 16 '22 at 14:34
  • Looking closer at your screenshot, it looks like one difference with mine is that you've filtered on `type="Media"` instead of `type="All"` and `text="mp3"`. This will hide prefetch requests, which have `type="octet-stream"` What do you see if you change the filters to `type="All"` and `text="mp3"` (like mine) and clear the cache and refresh? Another way to verify would be to clear the cache, refresh, wait, and then hit "next track" - if it's served from the cache (206), that's another clue that it's working (see second screenshot above). – Andrew Stegmaier Apr 16 '22 at 15:16
  • it's not a problem of filtering items, I did check all elements previously as well. – Simon Orro Apr 16 '22 at 17:03
  • Alright well if you're willing to share more information - screenshots of the correctly-filtered network log, or screenshots of the network log after you hit "next track" - I'm happy to help debug. – Andrew Stegmaier Apr 16 '22 at 17:15
  • 1
    So you are seeing the prefetch requests for the "next" track? Thats an improvement from before. As far as the order of the requests in the dev tools, thats not going to slow anything down in a noticeable way because network requests are asynchronous. In other words, just because the request for track #3 is kicked off before the request for track #2, it doesn't mean that #2 will wait for #3 to complete before returning from the cache. The loading of track #2 by the player will complete almost instantly (from the cache), before the preload request for track #3 finishes. – Andrew Stegmaier Apr 17 '22 at 01:26
  • It doesn't work as expected however it seems the better solution found around. Thanks – Simon Orro Apr 27 '22 at 11:15