# How the IPTV Stream Data Model Works in iptv-org/iptv

> Explore the iptv stream data model in iptv-org/iptv. Learn how it parses HLS/M3U8 links, handles metadata and geographic data, and formats streams for M3U playlists.

- Repository: [iptv-org/iptv](https://github.com/iptv-org/iptv)
- Tags: architecture
- Published: 2026-02-25

---

**The IPTV stream data model in iptv-org/iptv wraps every HLS/M3U8 link in a TypeScript `Stream` class that parses metadata from M3U playlists, handles geographic broadcast data, and serializes back to standard M3U format.**

The `iptv-org/iptv` repository manages thousands of live TV streams using a structured **IPTV stream data model** that transforms raw M3U playlist entries into typed, queryable objects. Understanding this architecture is essential for contributors working with playlist generation, API integrations, or stream validation tools.

## Class Hierarchy and Core Architecture

### Extending the SDK Base Model

The repository's `Stream` class extends `sdk.Models.Stream` from the external `@iptv-org/sdk` package. This inheritance provides foundational fields like `channel`, `feed`, `url`, and `title`, while the local implementation adds repository-specific helpers, lazy-filled properties, and serialization logic that understands the local playlist format.

### File Location and Structure

The core implementation resides in [`scripts/models/stream.ts`](https://github.com/iptv-org/iptv/blob/main/scripts/models/stream.ts), which imports the base SDK model and the `iptv-playlist-parser` package to handle raw M3U data. This file defines the `Stream` class, its static factory methods, and instance methods for normalization and geographic lookups.

## Constructing Streams from Playlist Data

### The fromPlaylistItem Factory Method

When the `iptv-playlist-parser` processes a raw M3U file, it generates `parser.PlaylistItem` objects. The static `Stream.fromPlaylistItem` method transforms these into fully-fledged `Stream` instances by parsing the `tvg-id`, extracting quality markers from the name field, and capturing HTTP headers.

```typescript
// source: scripts/models/stream.ts – lines 34-74
static fromPlaylistItem(data: parser.PlaylistItem): Stream {
  // …parse the human‑readable name to extract title, label and quality…
  const [channelId, feedId] = data.tvg.id.split('@')
  const { title, label, quality } = parseName(data.name)

  const stream = new Stream({
    channel: channelId || null,
    feed: feedId || null,
    title,
    quality: quality || null,
    url: data.url,
    referrer: data.http.referrer || null,
    user_agent: data.http['user-agent'] || null
  })

  stream.tvgId = data.tvg.id               // keep the original tvg‑id
  stream.line = data.line                  // line number in the source file
  stream.label = label || null
  return stream
}

```

This factory method splits the `tvg-id` (formatted as `channel@feed`) into separate `channel` and `feed` identifiers, enabling precise linkage to the channel database. It also strips quality indicators like `[720p]` from the stream name while preserving them in the `quality` property.

## Core Properties and Metadata

The `Stream` class maintains a rich set of properties that bridge raw playlist data with the structured channel database:

- **`channel`** and **`feed`**: Identifiers extracted from the `tvg-id` that link to specific channel entries in the database repository.
- **`tvgId`**: The complete "channel@feed" string required by most IPTV players for electronic program guide (EPG) matching.
- **`url`**: The direct stream URL, normalized via `normalizeURL()` to handle encoding inconsistencies.
- **`title`**, **`label`**, and **`quality`**: Human-readable descriptors parsed from the `#EXTINF` name field, with quality strings like "720p" extracted into structured data.
- **`groupTitle`**: Playlist grouping category, defaulting to "Undefined" unless overridden by API configuration.
- **`referrer`** and **`user_agent`**: Optional HTTP headers captured from `#EXTVLCOPT` metadata lines, required by some geo-restricted streams.
- **`filepath`**: The target playlist file (e.g., `us.m3u`) determined lazily by `updateFilepath()` based on the channel's broadcast countries.
- **`line`**: The original line number in the source playlist, enabling precise error reporting and debugging.

## Normalization and Helper Methods

The `Stream` class provides several utility methods to ensure data consistency and enable efficient processing:

**URL Normalization**: The `normalizeURL()` method delegates to the shared utility in [`scripts/utils.ts`](https://github.com/iptv-org/iptv/blob/main/scripts/utils.ts) to resolve whitespace, percent-encoding, and protocol quirks before storage.

**Uniqueness Keys**: `getUniqKey()` generates a deterministic identifier combining `filepath`, `tvgId`, and `url` to prevent duplicate entries across playlist files.

**Resolution Extraction**: `getVerticalResolution()` parses quality strings (e.g., "720p") to extract numeric height values for filtering and sorting operations.

## Geographic and Categorical Lookups

Because each stream maintains a reference to its parent **feed**, it can traverse the broadcast hierarchy to determine geographic availability:

```typescript
// Example: get all countries a stream reaches
const countries = stream.getBroadcastCountries()
countries.forEach(c => console.log(`${c.name} (${c.code})`))

```

The `getBroadcastCountries()` method iterates over the feed's broadcast area, mapping each location type (country, subdivision, or city) back to `Country` models loaded from the database repository (`data.countriesKeyByCode`). Similar helpers exist for subdivisions (`getBroadcastSubdivisions`), cities (`getBroadcastCities`), and regions (`getBroadcastRegions`), enabling complex filtering logic for playlist generation.

## Serialization to M3U Format

The `toString()` method handles conversion back to standard M3U playlist format, supporting both internal and public output modes:

```typescript
// source: scripts/models/stream.ts – lines 91-122
toString(options: { public?: boolean } = {}) {
  const public = options.public ?? false
  let output = `#EXTINF:-1 tvg-id="${this.getTvgId()}"`

  if (public) {
    output += ` tvg-logo="${this.getTvgLogo()}"`
    if (this.referrer) output += ` http-referrer="${this.referrer}"`
    if (this.user_agent) output += ` http-user-agent="${this.user_agent}"`
    output += ` group-title="${this.groupTitle}"`
  }

  output += `,${this.getFullTitle()}`
  if (this.referrer) output += `\r\n#EXTVLCOPT:http-referrer=${this.referrer}`
  if (this.user_agent) output += `\r\n#EXTVLCOPT:http-user-agent=${this.user_agent}`
  output += `\r\n${this.url}`
  return output
}

```

In **public mode**, the method exposes additional attributes including `tvg-logo`, HTTP referrer headers, and user-agent strings required by certain players. The output always includes the canonical `tvg-id` and preserves `#EXTVLCOPT` lines for VLC-specific options before appending the final URL.

## Summary

- The **IPTV stream data model** centers on the `Stream` class in [`scripts/models/stream.ts`](https://github.com/iptv-org/iptv/blob/main/scripts/models/stream.ts), which extends the base SDK model to add repository-specific functionality.
- Streams are constructed from raw M3U data via `Stream.fromPlaylistItem()`, parsing `tvg-id` values and quality markers into structured properties.
- The model maintains rich metadata including geographic broadcast areas, HTTP headers, and normalization utilities for deduplication.
- Serialization via `toString()` generates standard M3U output compatible with VLC, Kodi, and other IPTV players, supporting both internal processing and public distribution formats.

## Frequently Asked Questions

### What is the relationship between the Stream class and the @iptv-org/sdk package?

The repository's `Stream` class extends `sdk.Models.Stream` from the external `@iptv-org/sdk` package. This inheritance provides foundational fields like `channel`, `feed`, and `url`, while the local implementation in [`scripts/models/stream.ts`](https://github.com/iptv-org/iptv/blob/main/scripts/models/stream.ts) adds playlist-specific parsing, geographic lookups, and M3U serialization logic that handles the repository's unique data format.

### How does the IPTV stream data model handle quality indicators like "720p" or "HD"?

When constructing a `Stream` instance via `fromPlaylistItem()`, the class parses the human-readable name field using a helper function called `parseName()`. This extracts quality strings (e.g., "720p", "1080p") into the `quality` property, while labels like "[HD]" or "[SD]" populate the `label` property. The cleaned title is stored separately, allowing players to display stream information without raw formatting artifacts.

### Can the Stream model determine which countries a stream is available in?

Yes, through the `getBroadcastCountries()` method. Because each stream maintains a reference to its parent feed, it can traverse the broadcast hierarchy defined in the database repository. The method maps location codes (countries, subdivisions, or cities) back to `Country` models loaded from `data.countriesKeyByCode`, returning an array of country objects that represent the geographic availability of that specific stream.

### How does the Stream class generate the final M3U playlist output?

The `toString()` method handles serialization, accepting an optional `public` flag. It constructs the standard `#EXTINF` line with the `tvg-id`, and when in public mode, appends additional attributes like `tvg-logo`, `http-referrer`, `http-user-agent`, and `group-title`. The method also inserts `#EXTVLCOPT` lines for VLC-specific HTTP headers before appending the final stream URL, producing output compatible with most IPTV players including VLC, Kodi, and Perfect Player.