How Country, Language, and Category Generators Work in IPTV-ORG
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/master/scripts/generators/generator.ts):
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/master/scripts/commands/playlist/generate.ts), which executes a five-step workflow:
- Load raw data –
loadData()pulls the full list of streams, countries, languages, and categories from the@iptv-org/sdkrepository. - Parse M3U files – The
PlaylistParserprocesses all.m3ufiles in thestreams/directory into a collection ofStreammodel objects. - Deduplicate and sort the stream collection to ensure data integrity.
- Instantiate generators for countries, languages, and categories, invoking each
generate()method sequentially. - Write outputs to the
public/directory and append audit entries togenerators.log.
How the Country Generator Works
The CountriesGenerator ([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():
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
truefromisInternational()) are routed tocountries/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/master/scripts/generators/languagesGenerator.ts)) first compiles a unique set of languages from the filtered SFW streams:
streams.forEach(stream =>
stream.getLanguages().forEach(language => languages.add(language))
)
For each detected language, it filters the stream collection and persists a dedicated playlist:
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/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:
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:
{
"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:
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:
// 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.tsdefines a singlegenerate()method that all playlist builders implement. - CountriesGenerator uses
stream.getBroadcastCountries()to create geographic playlists likecountries/us.m3u, with special handling for international and undefined streams. - LanguagesGenerator filters streams using
stream.hasLanguage()to produce language-specific files such aslanguages/eng.m3u. - CategoriesGenerator constructs group titles by joining category names with semicolons, aiding player-side organization.
- All generators write to
public/and log activity togenerators.logfor 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →