# How Country, Language, and Category Generators Work in IPTV-ORG

> Discover how IPTV-ORG uses TypeScript generators to organize streaming data by country, language, and category, creating efficient M3U playlists for your viewing.

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

---

**The IPTV-ORG repository uses dedicated TypeScript generator classes that implement a simple `Generator` interface to group streaming data by country, language, and category, outputting organized M3U playlists to the `public/` directory.**

The `iptv-org/iptv` repository maintains thousands of publicly available streaming channels, organized into consumable playlists. Understanding how these **country language category generators** function requires examining the TypeScript automation scripts that transform raw stream data into structured M3U files.

## The Generator Interface and Core Workflow

Every generator in the pipeline adheres to a minimal contract defined in [[`scripts/generators/generator.ts`](https://github.com/iptv-org/iptv/blob/main/scripts/generators/generator.ts)](https://github.com/iptv-org/iptv/blob/master/scripts/generators/generator.ts):

```typescript
export interface Generator {
  generate(): Promise<void>
}

```

### Data Loading and Preparation

The orchestration begins in [[`scripts/commands/playlist/generate.ts`](https://github.com/iptv-org/iptv/blob/main/scripts/commands/playlist/generate.ts)](https://github.com/iptv-org/iptv/blob/master/scripts/commands/playlist/generate.ts), which executes a five-step workflow:

1. **Load raw data** – `loadData()` pulls the full list of streams, countries, languages, and categories from the `@iptv-org/sdk` repository.
2. **Parse M3U files** – The `PlaylistParser` processes all `.m3u` files in the `streams/` directory into a collection of `Stream` model objects.
3. **Deduplicate and sort** the stream collection to ensure data integrity.
4. **Instantiate generators** for countries, languages, and categories, invoking each `generate()` method sequentially.
5. **Write outputs** to the `public/` directory and append audit entries to `generators.log`.

## How the Country Generator Works

The **CountriesGenerator** ([[`scripts/generators/countriesGenerator.ts`](https://github.com/iptv-org/iptv/blob/main/scripts/generators/countriesGenerator.ts)](https://github.com/iptv-org/iptv/blob/master/scripts/generators/countriesGenerator.ts)) groups streams by broadcast country codes retrieved via `stream.getBroadcastCountries()`:

```typescript
for (const countryCode in streamsGroupedByCountryCode) {
  const playlist = new Playlist(countryStreams, { public: true })
  const filepath = `countries/${countryCode.toLowerCase()}.m3u`
  await this.storage.save(filepath, playlist.toString())
  this.logFile.append(JSON.stringify({ type: 'country', filepath, count: playlist.streams.count() }) + EOL)
}

```

- **International streams** (those returning `true` from `isInternational()`) are routed to `countries/int.m3u`.
- Streams lacking country metadata are collected into `countries/undefined.m3u`.

## How the Language Generator Works

The **LanguagesGenerator** ([[`scripts/generators/languagesGenerator.ts`](https://github.com/iptv-org/iptv/blob/main/scripts/generators/languagesGenerator.ts)](https://github.com/iptv-org/iptv/blob/master/scripts/generators/languagesGenerator.ts)) first compiles a unique set of languages from the filtered SFW streams:

```typescript
streams.forEach(stream =>
  stream.getLanguages().forEach(language => languages.add(language))
)

```

For each detected language, it filters the stream collection and persists a dedicated playlist:

```typescript
const languageStreams = streams.filter(stream => stream.hasLanguage(language))
const playlist = new Playlist(languageStreams, { public: true })
const filepath = `languages/${language.code}.m3u`
await this.storage.save(filepath, playlist.toString())

```

Streams without language metadata are aggregated into `languages/undefined.m3u`.

## How the Category Generator Works

The **CategoriesGenerator** ([[`scripts/generators/categoriesGenerator.ts`](https://github.com/iptv-org/iptv/blob/main/scripts/generators/categoriesGenerator.ts)](https://github.com/iptv-org/iptv/blob/master/scripts/generators/categoriesGenerator.ts)) enhances playlists with **group titles** that concatenate all categories assigned to a stream. This metadata helps IPTV players visually organize channels:

```typescript
const groupTitle = stream
  .getCategories()
  .map(cat => cat.name)
  .sort()
  .join(';')
if (groupTitle) stream.groupTitle = groupTitle

```

Each category receives its own `categories/<id>.m3u` file, with uncategorized streams defaulting to `categories/undefined.m3u`.

## Logging and Audit Trail

Every generator appends structured JSON lines to `generators.log`, creating an auditable record of the build process. The command persists this file via `logStorage.saveFile(logFile)` after all generators complete. Each log entry follows this schema:

```json
{
  "type": "country",
  "filepath": "countries/us.m3u",
  "count": 342
}

```

## Practical Implementation Examples

### Running a Single Generator Manually

You can instantiate and run individual generators outside the main pipeline:

```typescript
import { Storage, File } from '@freearhey/storage-js'
import { Collection } from '@freearhey/core'
import { Stream } from './models'
import { CountriesGenerator } from './generators/countriesGenerator'

const logFile = new File('generators.log')
const generator = new CountriesGenerator({
  streams: allStreams,
  countries: allCountries,
  logFile,
})

await generator.generate()

```

### Chaining Generators in the Build Pipeline

The main command executes generators sequentially to build the complete playlist hierarchy:

```typescript
// Inside scripts/commands/playlist/generate.ts
await new CategoriesGenerator({ categories, streams, logFile }).generate()
await new LanguagesGenerator({ streams, logFile }).generate()
await new CountriesGenerator({ countries, streams, logFile }).generate()

```

## Summary

- The **Generator interface** in [`scripts/generators/generator.ts`](https://github.com/iptv-org/iptv/blob/main/scripts/generators/generator.ts) defines a single `generate()` method that all playlist builders implement.
- **CountriesGenerator** uses `stream.getBroadcastCountries()` to create geographic playlists like `countries/us.m3u`, with special handling for international and undefined streams.
- **LanguagesGenerator** filters streams using `stream.hasLanguage()` to produce language-specific files such as `languages/eng.m3u`.
- **CategoriesGenerator** constructs group titles by joining category names with semicolons, aiding player-side organization.
- All generators write to `public/` and log activity to `generators.log` for transparency and debugging.

## Frequently Asked Questions

### What file format do the generators output?

The generators produce **M3U playlist files**, a standard format supported by virtually all IPTV players and media applications. Each file contains a curated list of stream URLs along with metadata like group titles and channel names.

### How are international streams handled by the country generator?

Streams flagged as international via `stream.isInternational()` are aggregated into a special file named `countries/int.m3u` rather than being assigned to specific country codes. This ensures borderless channels remain accessible without geographic restriction.

### What happens to streams missing metadata?

Streams lacking country, language, or category information are never discarded. Instead, each generator routes these entries to dedicated fallback files: `countries/undefined.m3u`, `languages/undefined.m3u`, or `categories/undefined.m3u`, ensuring complete data coverage.

### Where can I find the generated playlist files?

After running the generation command, all playlist files reside in the `public/` directory, organized into subdirectories by type (`countries/`, `languages/`, `categories/`). These files are typically committed to the repository and served via CDN or GitHub Pages for public consumption.