DEV Community

Cover image for How YouTube Downloads Videos and Plays Them Offline with Javascript?
Hiếu Cao Khả
Hiếu Cao Khả

Posted on

How YouTube Downloads Videos and Plays Them Offline with Javascript?

Introduction

Have you ever wondered how YouTube allows you to download videos and watch them offline? It's not just about saving a file to your device. YouTube employs a sophisticated mechanism involving **HLS streaming, IndexedDB storage and Uint8Array for binary handling. Let’s dive into the technical magic behind this feature! 🚀


Understanding HLS Streaming

Many video on the interneet uses HTTP Live Streaming (HLS) to deliver video content efficiently. Unlike traditional downloads, HLS breaks videos into small .ts segments and provides a manifest file (.m3u8) that guides playback. This approach allows for:

  • Adaptive streaming, where video quality adjusts based on network speed.
  • Efficient loading, as only required segments are fetched, reducing bandwidth usage.
  • Smooth seeking, since video chunks are separate, allowing fast-forwarding without preloading the entire video.

Example: HLS manifest file (.m3u8)

#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=640x360
video_360p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1400000,RESOLUTION=1280x720
video_720p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2800000,RESOLUTION=1920x1080
video_1080p.m3u8
Enter fullscreen mode Exit fullscreen mode

💡 Now that we understand how YouTube streams videos, where does it store them for offline viewing?


Where Does YouTube Store Downloaded Videos? IndexedDB

When you download a video on YouTube, it doesn’t get saved as a simple .mp4 file. Instead, YouTube uses IndexedDB, a built-in browser database, to store video data efficiently. Here's why:

  • IndexedDB allows storage of large binary files, making it perfect for video chunks.
  • It supports structured data storage, which helps manage video metadata, resolutions, and playback positions.
  • Unlike localStorage or sessionStorage, IndexedDB has no strict size limitations, making it suitable for offline video caching.

Example: Storing video chunks in IndexedDB

const request = indexedDB.open("YouTubeCache", 1);
request.onupgradeneeded = event => {
  const db = event.target.result;
  db.createObjectStore("videos", { keyPath: "id" });
};
Enter fullscreen mode Exit fullscreen mode

💡 Great! Now we know where the data is stored. But what format does YouTube use to save these video segments?


Uint8Array: Handling Video Data in the Browser

Instead of saving video files as-is, YouTube stores them as Uint8Array, a special typed array in JavaScript designed for handling raw binary data. Why Uint8Array?

  • Compact and efficient storage: Stores video as byte sequences without unnecessary overhead.
  • Fast retrieval and manipulation: Allows quick access and processing before playback.
  • Ideal for streaming: Works well with Media Source Extensions (MSE) to reconstruct videos dynamically.

Example: Converting a Blob to Uint8Array

fetch("video-segment.ts")
  .then(response => response.arrayBuffer())
  .then(buffer => {
    const uint8Array = new Uint8Array(buffer);
    console.log("Video chunk as Uint8Array:", uint8Array);
  });
Enter fullscreen mode Exit fullscreen mode

💡 Now that YouTube has downloaded the video data, how does it actually play the video from IndexedDB?


Loading and Playing Video from Uint8Array using mux.js

I don't know how YouTube plays videos offline, but I uses mux.js, a JavaScript library designed for working with media container formats like MP4 and TS, to reconstruct and play stored videos. Here's how it works:

🔗 Check it out on GitHub: mux.js

  1. Retrieving stored video data: YouTube fetches Uint8Array chunks from IndexedDB.
  2. Repackaging with mux.js: The extracted data is converted into a playable MP4 format.
  3. Streaming to HTML5 video player:
    • Uses Media Source Extensions (MSE) to append processed video chunks.
    • The <video> tag dynamically loads and plays the reconstructed video.

Example: Playing a video from Uint8Array with mux.js

const muxjs = require("mux.js");
const transmuxer = new muxjs.mp4.Transmuxer();

fetch("video-segment.ts")
  .then(response => response.arrayBuffer())
  .then(buffer => {
    transmuxer.push(new Uint8Array(buffer));
    transmuxer.flush();
  });
Enter fullscreen mode Exit fullscreen mode

💡 We’ve now completed the journey from downloading a video to playing it back offline! 🎬


My Library for Supporting Download and Offline Playback

To help developers implement a similar offline video solution, I created a library called hls-downloader. This library makes it easy to download HLS video segments and store them for offline playback.

🔗 Check it out on GitHub: hls-downloader

🔗 Check it out on NPM: hls-downloader

With this library, you can efficiently download HLS streams, store them in IndexedDB, and play them back seamlessly.


Conclusion: The Magic Behind YouTube’s Offline Mode

YouTube’s offline video playback relies on a combination of **HLS streaming, IndexedDB for storage and Uint8Array for efficient binary handling. Each of these components plays a crucial role in ensuring smooth, high-quality offline video experiences.

Understanding this process can help developers create similar offline video applications or optimize video playback on the web.

🚀 Inspired to build something similar? Dive into these technologies and start experimenting!

Top comments (0)