YouTube.js
Guide
Discord
❤️ Sponsor
GitHub
Guide
Discord
❤️ Sponsor
GitHub

GoogleVideo

A collection of modules for working with YouTube's proprietary video streaming protocols (UMP/SABR). It can be used to build clients or to integrate with existing media players (e.g., Shaka Player).

API Reference →

Repository

Installation

# NPM
npm install googlevideo

# JSR / Deno
npx jsr add @luanrt/googlevideo
deno add jsr:@luanrt/googlevideo

# GitHub
npm install LuanRT/googlevideo

Basic Usage

Below is a basic example using the UMP modules to create a buffer, write parts, and process them:

import { CompositeBuffer, UmpReader, UmpWriter } from 'googlevideo/ump';
import { MediaHeader, UMPPartId } from 'googlevideo/protos';
import { concatenateChunks } from 'googlevideo/utils';
import { Part } from 'googlevideo/shared-types';

function handleMediaHeader(part: Part) {
  const mediaHeader = MediaHeader.decode(concatenateChunks(part.data.chunks));
  console.log('Media Header:', mediaHeader);
}

function handleMedia(part: Part) {
  const headerId = part.data.getUint8(0);
  console.log(`Media Part (Associated Header ID: ${headerId}):`, part.data.split(1).remainingBuffer.getLength(), 'bytes');
}

function handleMediaEnd(part: Part) {
  const headerId = part.data.getUint8(0);
  console.log(`Media End Part (Associated Header ID: ${headerId}):`, part.data.split(1).remainingBuffer.getLength(), 'bytes');
}

const umpPartHandlers = new Map<UMPPartId, (part: Part) => void>([
  [ UMPPartId.MEDIA_HEADER, handleMediaHeader ],
  [ UMPPartId.MEDIA, handleMedia ],
  [ UMPPartId.MEDIA_END, handleMediaEnd ]
]);

const buffer = mockUmpData();
const reader = new UmpReader(buffer);

reader.read((part) => {
  const handler = umpPartHandlers.get(part.type);
  if (handler) {
    handler(part);
  } else {
    console.warn(`No handler for part type: ${part.type}`);
  }
});

/**
 * Generates a mock UMP data buffer containing a MEDIA_HEADER, and respective MEDIA and MEDIA_END parts.
 * This group represents a single audio segment, which is what you would typically see
 * in a real UMP stream.
 */
function mockUmpData(): CompositeBuffer {
  const buffer = new CompositeBuffer();
  const writer = new UmpWriter(buffer);

  const audioHeaderId = 0;

  const partsToWrite: [UMPPartId, Uint8Array][] = [
    [
      UMPPartId.MEDIA_HEADER,
      MediaHeader.encode({
        headerId: audioHeaderId,
        videoId: "sOa4VVlI9tE",
        itag: 141,
        lmt: 1645502668395260,
        xtags: "",
        startRange: 5463800,
        isInitSeg: false,
        sequenceNumber: 0,
        durationMs: 0,
        formatId: {
          itag: 141,
          lastModified: 1645502668395260,
          xtags: ""
        },
        contentLength: 963966,
      }).finish()
    ],
    [ UMPPartId.MEDIA, new Uint8Array([ audioHeaderId, ...new Uint8Array(827609).fill(0) ]) ],
    [ UMPPartId.MEDIA, new Uint8Array([ audioHeaderId, ...new Uint8Array(136357).fill(0) ]) ],
    [ UMPPartId.MEDIA_END, new Uint8Array([ audioHeaderId ]) ]
  ];

  for (const [type, data] of partsToWrite) {
    writer.write(type, data);
  }

  return buffer;
}

Expected output:

Media Header: { ... }
Media Part (Associated Header ID: 0): 827609 bytes
Media Part (Associated Header ID: 0): 136357 bytes
Media End Part (Associated Header ID: 0): 0 bytes

More advanced usage examples can be found in the examples directory.

Edit this page
Last Updated: 7/24/25, 1:11 PM