What Determines tvg-chno Channel Numbering in Free-TV/IPTV M3U8 Output

The tvg-chno attribute is extracted directly from the second pipe-delimited column of the source Markdown files and is omitted when the value is empty or "0".

The Free-TV/IPTV repository generates IPTV playlists from Markdown source files. The tvg-chno attribute that controls channel numbering in the final M3U8 output is determined by a specific parsing logic implemented in make_playlist.py.

How the Channel Number Is Parsed from Markdown

Column Structure in Source Files

Each channel entry in the repository's Markdown files (located in lists/*.md) follows a pipe-delimited format. Inside Channel.__init__ in make_playlist.py, the constructor splits each line on the pipe (|) character:

parts = md_line.split("|")

The mapping is explicit:

  • parts[1] → number (line 100)
  • parts[2] → name (line 101)
  • parts[3] → URL (lines 102-104)
  • parts[4] → logo (lines 105-106)

The Channel Constructor Logic

The constructor stores the parsed value in self.number, then applies a conditional check to determine if it should become a channel number tag:

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

If the field is empty or equal to the string "0", self.chno is set to None and no tvg-chno attribute is emitted in the final output.

How tvg-chno Is Generated in the M3U8 Output

The Conditional Output Logic

In Channel.to_m3u_line (line 16), the script checks the self.chno attribute before constructing the M3U8 line:

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

This string is then inserted into the #EXTINF line between the logo tag and the group title. The resulting attribute appears only when the source Markdown contains a valid, non-zero number in the second column.

Practical Examples

Example 1: Valid Channel Number

Source entry in lists/playlist_italy.md:

|101|Rai 1|http://example.com/rai1.m3u8|<img src="http://logo.com/rai1.png"/>

Generated M3U8 output:

#EXTINF:-1 tvg-name="Rai 1" tvg-logo="http://logo.com/rai1.png" tvg-chno="101" group-title="Italy",Rai 1
http://example.com/rai1.m3u8

Example 2: Empty Channel Number

Source entry with empty second column:

||Sky Sports|http://example.com/sky.m3u8|<img src="http://logo.com/sky.png"/>

Generated output (note the missing tvg-chno):

#EXTINF:-1 tvg-name="Sky Sports" tvg-logo="http://logo.com/sky.png" group-title="Italy",Sky Sports
http://example.com/sky.m3u8

Example 3: Zero as Channel Number

Source entry with "0" in the number column:

|0|TV5MONDE|http://example.com/tv5.m3u8|<img src="http://logo.com/tv5.png"/>

Generated output (treated as "no number"):

#EXTINF:-1 tvg-name="TV5MONDE" tvg-logo="http://logo.com/tv5.png" group-title="France",TV5MONDE
http://example.com/tv5.m3u8

Summary

  • The second pipe-delimited field in the Markdown source files drives the tvg-chno attribute.
  • Empty strings or the value "0" result in the omission of the tvg-chno tag entirely.
  • The logic resides in make_playlist.py, specifically in the Channel class constructor and to_m3u_line method.
  • Editing the channel number in lists/*.md files directly controls the numbering in the generated playlists/*.m3u8 files.

Frequently Asked Questions

What happens if the channel number column is empty?

If the second column is empty, the self.chno attribute is set to None in the Channel.__init__ method, and the tvg-chno attribute is completely omitted from the M3U8 output line.

Why is "0" treated differently from other numbers?

The string "0" is explicitly filtered out in line 107 of make_playlist.py (self.number != "0"), treating it as equivalent to an empty value. This allows maintainers to use "0" as a placeholder to intentionally suppress channel numbering for specific entries.

Which file contains the logic for generating tvg-chno?

The core logic resides in make_playlist.py in the root of the repository. The Channel class handles parsing in __init__ (lines 100-107) and M3U8 generation in to_m3u_line (line 16).

Can I manually edit channel numbers?

Yes. Since the tvg-chno value is taken directly from the second column of the Markdown files in lists/, you can modify these files to change channel numbering. The next run of the playlist generator will apply these changes to the output files.

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 →