Skip to main content
The M3U8 parser service provides comprehensive parsing of HLS (HTTP Live Streaming) playlists, including master playlists with multiple quality levels and media playlists with fragment information.

Overview

This service implements the IParser interface from @hls-downloader/core and wraps the m3u8-parser library to:
  • Parse master playlists to extract available quality levels and media groups
  • Parse media playlists to extract fragment URIs and encryption keys
  • Inspect encryption metadata including AES-128 keys and initialization vectors
  • Convert relative URLs to absolute URLs using the playlist base URL

Interface: IParser

The M3U8 parser implements three core methods:

parseMasterPlaylist

Parses a master playlist to extract video streams, audio tracks, subtitles, and closed captions.
parseMasterPlaylist(manifestText: string, baseurl: string): Level[]

Parameters

manifestText
string
required
Raw M3U8 master playlist content
baseurl
string
required
Base URL for resolving relative playlist URIs

Returns

Level[]
Array of level objects representing all available streams, audio tracks, subtitles, and closed captions

Level types

The returned array contains different level types: Stream levels (type: "stream"):
id
string
Unique identifier (UUID v4)
playlistID
string
Base URL of the master playlist
uri
string
Absolute URL to the media playlist
bitrate
number | undefined
Bandwidth in bits per second (from BANDWIDTH attribute)
fps
number | undefined
Frame rate (from FRAME-RATE attribute)
width
number | undefined
Video width in pixels
height
number | undefined
Video height in pixels
audioGroupId
string | undefined
Audio group ID that this stream is associated with
Audio levels (type: "audio"):
id
string
Unique identifier combining label and group ID
uri
string
Absolute URL to the audio playlist
language
string | undefined
ISO 639 language code
name
string
Human-readable track name
channels
string | undefined
Audio channel configuration (e.g., “2”, “6”)
characteristics
string | undefined
Additional track characteristics
isDefault
boolean | undefined
Whether this is the default audio track
autoSelect
boolean | undefined
Whether this track should be auto-selected
groupId
string
Audio group identifier
Subtitle levels (type: "subtitle"):
id
string
Unique identifier combining label and group ID
uri
string
Absolute URL to the subtitle playlist
language
string | undefined
ISO 639 language code
name
string
Human-readable subtitle name
forced
boolean | undefined
Whether this is a forced subtitle track
characteristics
string | undefined
Additional track characteristics
isDefault
boolean | undefined
Whether this is the default subtitle track
autoSelect
boolean | undefined
Whether this track should be auto-selected
groupId
string
Subtitle group identifier
instreamId
string | undefined
In-stream identifier for closed captions

Example

import { M3u8Parser } from "./m3u8-parser";

const masterPlaylist = `#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=1280000,RESOLUTION=640x360
low.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2560000,RESOLUTION=1280x720
high.m3u8`;

const levels = M3u8Parser.parseMasterPlaylist(
  masterPlaylist,
  "https://example.com/playlist.m3u8"
);

console.log(levels);
// [
//   {
//     type: "stream",
//     id: "uuid...",
//     uri: "https://example.com/low.m3u8",
//     bitrate: 1280000,
//     width: 640,
//     height: 360
//   },
//   ...
// ]

parseLevelPlaylist

Parses a media playlist to extract individual fragment URIs and encryption metadata.
parseLevelPlaylist(string: string, baseurl: string): Fragment[]

Parameters

string
string
required
Raw M3U8 media playlist content
baseurl
string
required
Base URL for resolving relative fragment URIs

Returns

Fragment[]
Array of fragment objects representing downloadable media segments

Fragment structure

index
number
Sequential index of the fragment (starting at 0)
uri
string
Absolute URL to the fragment file
key
object
Encryption key information:
  • uri: Absolute URL to the encryption key (or null if not encrypted)
  • iv: Initialization vector as a hex string (or null if not specified)

Behavior

  • Init segments: If a segment has a #EXT-X-MAP tag, the parser inserts a separate fragment entry for the initialization segment before the media segment
  • Encryption: Each fragment includes encryption metadata from the #EXT-X-KEY tag. If no key is present, both uri and iv are null
  • URL resolution: All URIs are converted to absolute URLs using url-toolkit’s buildAbsoluteURL function

Example

import { M3u8Parser } from "./m3u8-parser";

const mediaPlaylist = `#EXTM3U
#EXT-X-KEY:METHOD=AES-128,URI="key.bin",IV=0x12345678901234567890123456789012
#EXTINF:10.0,
segment0.ts
#EXTINF:10.0,
segment1.ts`;

const fragments = M3u8Parser.parseLevelPlaylist(
  mediaPlaylist,
  "https://example.com/stream.m3u8"
);

console.log(fragments);
// [
//   {
//     index: 0,
//     uri: "https://example.com/segment0.ts",
//     key: {
//       uri: "https://example.com/key.bin",
//       iv: "0x12345678901234567890123456789012"
//     }
//   },
//   ...
// ]

inspectLevelEncryption

Extracts encryption metadata from a media playlist without parsing individual segments.
inspectLevelEncryption(string: string, baseurl: string): ParsedEncryption

Parameters

string
string
required
Raw M3U8 media playlist content
baseurl
string
required
Base URL for resolving relative key URIs

Returns

ParsedEncryption
Object containing encryption methods, key URIs, and initialization vector

ParsedEncryption structure

methods
string[]
Array of encryption methods used (e.g., ["AES-128"]). Excludes "NONE"
keyUris
string[]
Array of absolute URLs to encryption keys
iv
string | null
Initialization vector as a hex string (e.g., "0x123..."), or null if not found

Behavior

  • Inspects both segment keys and session keys (if present)
  • Normalizes all encryption methods to uppercase
  • Converts initialization vectors from Uint8Array or Uint32Array to hex strings
  • Returns the first IV found in the playlist

Example

import { M3u8Parser } from "./m3u8-parser";

const encryption = M3u8Parser.inspectLevelEncryption(
  mediaPlaylist,
  "https://example.com/stream.m3u8"
);

console.log(encryption);
// {
//   methods: ["AES-128"],
//   keyUris: ["https://example.com/key.bin"],
//   iv: "0x12345678901234567890123456789012"
// }
The parser uses m3u8-parser under the hood, which handles various HLS specification edge cases and vendor-specific extensions.
Relative URLs in playlists are resolved using url-toolkit. Ensure the baseurl parameter is the full URL of the playlist file, not just the domain.

TypeScript definitions

The parser includes type definitions for the underlying m3u8-parser library:
declare module "m3u8-parser" {
  var Parser: M3U8Parser;
  interface M3U8Parser {
    new (): M3U8Parser;
    manifest: Manifest;
    push(chunk: string): void;
  }
  
  type M3U8Segment = {
    uri: string;
    duration: number;
    key: {
      method: string;
      uri: string;
      iv: Uint8Array;
    };
    map: {
      uri: string;
      byterange: { length: number; offset: number };
    };
  };
  
  type M3U8Playlist = {
    uri: string;
    attributes: {
      BANDWIDTH?: number;
      RESOLUTION?: { width: number; height: number };
      "FRAME-RATE"?: number;
      AUDIO?: string;
    };
  };
  
  interface Manifest {
    playlists?: M3U8Playlist[];
    segments: M3U8Segment[];
    mediaGroups: { AUDIO: {}; SUBTITLES: {}; "CLOSED-CAPTIONS": {} };
  }
}

Source location

  • Implementation: ~/workspace/source/src/background/src/services/m3u8-parser.ts:9
  • Type definitions: ~/workspace/source/src/background/src/services/m3u8-parser.d.ts:1

Build docs developers (and LLMs) love