'How to Map the Buffer TimeRange Data From an HTML5 Video Player Ref to a Progress Bar?

I'm basically just trying to emulate the buffer bar from the default HTML5 video player or like on YouTube.

I am making a custom JSX HTML5 video player control-bar but have gotten stuck because I am not sure how to get/use the buffer progress data object from the videoRef. It seems like I am supposed to use the buffers end() function and the TimeRanges object from the video's ref, but I haven't seen any examples or documentation on how it can be used to calculate the buffer bar.

Question: How can I use the buffer object in the videoRef from the video player and map the data to my custom video control-bar's buffer progress-bar?

Youtube's buffer bar

Do I somehow detect the progress of the stream's buffer, is there some kind of event?

Example code:

export default function App() {
  const videoRef = React.useRef();
  const [videoProgress, setVideoProgress] = useState(0);
  const [videoBufferProgress, setVideoBufferProgress] = useState(0);
  const [videoTime, setVideoTime] = useState(0);

  //updates the video progress bar 1-100%, works fine
  function updateTime() {
    setVideoProgress(
      (videoRef.current.currentTime / videoRef.current.duration) * 100
    );
    setVideoTime(videoRef.current.currentTime);
  }

  //get buffer information so that I can use it to fill the buffer progress bar, it doesnt work rn
  function updateBuffer() {
    //setVideoBufferProgress()
    console.log(videoRef.current.buffered.end(0));
  }

  useEffect(() => {
    videoRef.current.addEventListener("loadeddata", () => updateBuffer());
    videoRef.current.addEventListener("timeupdate", () => updateTime());

    return () => {
      videoRef.current.removeEventListener("loadeddata", () => updateBuffer());
      videoRef.current.removeEventListener("timeupdate", () => updateTime());
    };
  }, []);

  return (
    <div>
      <video ref={videoRef}>
        <source src={`/api/video/stream/480/624593ba5a88168159a56169`} type="video/mp4"/>
      </video>
      <div>
        //video timeline bar, this works fine
        <ProgressBar
          now={videoProgress}
        />
        //video buffer bar, this doesnt work
        <ProgressBar
          now={videoBufferProgress}
        />
      </div>
    </div>
  );
}


Solution 1:[1]

I figured it out. You just listen for the progress event.

function updateBuffer() {
    setVideoBufferProgress((videoRef.current.buffered.end(0) / videoRef.current.duration) * 100); //provides the last second of the video that has been loaded/buffered
}

//use the progress event to update the buffer for when new data is loaded
useEffect(() => {
  videoRef.current &&
    videoRef.current.addEventListener("loadeddata", () => updateBuffer());
  videoRef.current &&
    videoRef.current.addEventListener("progress", () => updateBuffer());
  videoRef.current &&
    videoRef.current.addEventListener("timeupdate", () => updateTime());
}, [videoRef.current]);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1