How Channel Numbers (tvg-chno) Are Assigned During Playlist Generation in Free-TV/IPTV

In the Free-TV/IPTV repository, the tvg-chno attribute is extracted from the second column of pipe-delimited markdown lines and emitted in the M3U playlist only when the value is non-empty and not "0".

The Free-TV/IPTV project generates M3U playlists from markdown source files stored in the lists/ directory. Understanding how the tvg-chno attribute is populated requires examining the parsing logic in the playlist generation script, specifically how the Channel class processes raw markdown data.

Parsing Channel Numbers from Markdown Source

Identifying Channel Entries with [>] Markers

The playlist generator scans each markdown file (*.md) for lines containing the [>] marker, which indicates a channel definition. These lines use pipe-separated columns (|) to separate metadata fields.

According to the source code in make_playlist.py (lines 94–101), the parser splits each line and extracts the channel number from the second column:

parts = md_line.split("|")
self.number = parts[1].strip()          # ← second column → channel number

The self.number field captures the raw string value from the markdown source, which later becomes the basis for the tvg-chno attribute.

Validating and Storing the Channel Number

The Validation Logic in the Channel Class

Before generating the M3U output, the Channel class constructor applies validation logic to determine whether a numeric identifier should be assigned. As implemented in make_playlist.py (lines 107–108), the script stores the value in self.chno only if it is non-empty and not equal to "0":

self.chno = self.number if self.number and self.number != "0" else None

This conditional assignment ensures that:

  • Empty channel number columns result in None (no attribute emitted)
  • Explicit "0" values are treated as unset (no attribute emitted)
  • Valid numeric strings are preserved for M3U generation

Generating the M3U Output

Conditional Attribute Emission

When building the final M3U playlist line, the formatter checks for the presence of self.chno before including the tvg-chno attribute. The source code at make_playlist.py (lines 15–17) uses a conditional f-string:

chno = f' tvg-chno="{self.chno}"' if self.chno else ""

This approach means the tvg-chno tag appears only when a valid channel number exists, keeping the output clean and avoiding empty attributes.

Practical Example

Consider a channel defined in lists/usa.md:

[>] | 101 | NBC | http://example.com/nbc.m3u8 | <img src="http://example.com/nbc.png" />

This generates the following M3U entry:


#EXTINF:-1 tvg-name="NBC" tvg-logo="http://example.com/nbc.png" tvg-chno="101" group-title="Usa",NBC
http://example.com/nbc.m3u8

If the second column were empty or set to 0, the output would omit the attribute entirely:


#EXTINF:-1 tvg-name="NBC" tvg-logo="http://example.com/nbc.png" group-title="Usa",NBC
http://example.com/nbc.m3u8

Summary

  • Source location: Channel numbers are defined in the second column of pipe-delimited markdown lines marked with [>] in lists/*.md files.
  • Validation: The Channel class accepts only non-empty values that are not "0", storing them in self.chno.
  • Output: The tvg-chno attribute appears in the generated M3U only when self.chno is set, using the formatting logic in make_playlist.py.
  • Key file: make_playlist.py handles parsing (lines 94–101), validation (lines 107–108), and M3U generation (lines 15–17).

Frequently Asked Questions

What happens if the channel number is set to 0?

The value "0" is treated as a sentinel indicating "no channel number." According to the validation logic in make_playlist.py, when the second column contains 0, self.chno is set to None and the tvg-chno attribute is omitted from the final M3U output.

Can I leave the channel number column empty?

Yes. If the second column between the pipes is empty or contains only whitespace, parts[1].strip() returns an empty string. The validation check if self.number fails, resulting in self.chno = None, and the generated playlist line will not include the tvg-chno attribute.

Which file controls the tvg-chno assignment logic?

The make_playlist.py script in the repository root controls the entire assignment flow. It parses the markdown source (lines 94–101), validates the numeric value (lines 107–108), and conditionally formats the tvg-chno attribute in the M3U output (lines 15–17).

How is the channel number positioned in the markdown syntax?

The channel number must occupy the second column in the pipe-delimited format. The parser expects the structure: [>] | number | name | url | logo, where the value between the first and second pipe characters becomes the tvg-chno value in the generated playlist.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →