How Are EPG IDs (tvg-id) Assigned for Electronic Program Guide Integration in the Free-TV/IPTV Repository

In the Free-TV/IPTV repository, EPG IDs are extracted from the sixth column of pipe-separated channel tables in markdown files, then parsed by the Channel class in make_playlist.py and injected as tvg-id attributes into generated M3U playlists.

The Free-TV/IPTV repository generates standard M3U playlists from curated markdown channel lists stored in the lists/ directory. For electronic program guide (EPG) integration to function, each channel must map to a specific identifier recognized by XMLTV providers. This mapping is controlled through a deterministic parsing pipeline that converts plain-text table entries into IPTV-standard metadata attributes.

Channel Definition Format in Markdown Lists

Channel data is stored in markdown files (e.g., lists/portugal.md) using a pipe-separated table format. Each row represents a single channel and follows a strict six-column structure:

| <number> | <channel name> | <stream URL> | <logo HTML> | <EPG ID> |

The sixth column (index 5 when split) contains the optional EPG identifier. This value must correspond exactly to the channel id used by the XMLTV provider. If the column is omitted or empty, the channel will be generated without EPG linking.

Parsing EPG IDs in make_playlist.py

The Channel class defined in make_playlist.py handles the extraction logic during the playlist build process.

The Channel.init Method

As implemented in make_playlist.py (lines 94–102), the constructor splits each markdown line on the pipe character (|) and assigns the sixth element to the epg instance variable:


# make_playlist.py, lines 94-102

parts = md_line.split("|")
...
if len(parts) > 6:
    self.epg = parts[5].strip()
else:
    self.epg = None

The condition len(parts) > 6 ensures the line contains enough fields to include an EPG ID, accounting for the leading empty string and potential trailing pipe character inherent to markdown table syntax.

Generating M3U Output with tvg-id Attributes

When rendering the final playlist, the Channel.to_m3u_line method conditionally includes the tvg-id attribute only when self.epg is populated.

Conditional Attribute Injection

According to lines 118–120 in make_playlist.py, the method constructs the #EXTINF line using an f-string that omits tvg-id when the value is None:


# make_playlist.py, lines 118-120

if self.epg is None:
    return (f'#EXTINF:-1 tvg-name="{self.name}" tvg-logo="{self.logo}"{chno}{country} group-title="{self.group}",{self.name}\n{self.url}')
else:
    return (f'#EXTINF:-1 tvg-name="{self.name}" tvg-logo="{self.logo}" tvg-id="{self.epg}"{chno}{country} group-title="{self.group}",{self.name}\n{self.url}')

This ensures that only valid identifiers are exposed to IPTV clients, preventing empty attribute errors in players like VLC, Kodi, or TVHeadend.

EPG Source Configuration via epglist.txt

The repository links playlists to external guide data through the epglist.txt file. During playlist generation, make_playlist.py reads this file (lines 31–34) and injects the URLs as the x-tvg-url header:


# make_playlist.py, lines 31-34

with open(os.path.join(base_dir, "epglist.txt"), encoding='utf-8') as epg_file:
    epg_urls = [line.strip() for line in epg_file if line.strip()]
processed_epg_list = ", ".join(epg_urls)
head_playlist = f'#EXTM3U x-tvg-url="{processed_epg_list}"\n'

The tvg-id values assigned to individual channels must match the identifiers used by the XMLTV services listed in this file for schedule data to populate correctly.

Complete Workflow Example

Consider a channel defined in lists/united_kingdom.md:

| 101 | BBC News | (http://example.com/stream.m3u8) | <img src="http://example.com/logo.png"> | bbcnews

The Channel parser extracts bbcnews as self.epg. When to_m3u_line is called, it generates:

#EXTINF:-1 tvg-name="BBC News" tvg-logo="http://example.com/logo.png" tvg-id="bbcnews" group-title="United Kingdom",BBC News
http://example.com/stream.m3u8

The resulting M3U file begins with the aggregated EPG sources:

#EXTM3U x-tvg-url="http://epg.provider1.com/xmltv.xml, http://epg.provider2.com/xmltv.xml"

When a compatible player loads this playlist, it uses the tvg-id="bbcnews" value to query the specified EPG endpoints for scheduling information.

Summary

  • Source Location: EPG IDs originate from the sixth column of pipe-separated tables in markdown files within the lists/ directory.
  • Parsing Logic: The Channel.__init__ method in make_playlist.py (lines 94–102) extracts the identifier from parts[5] when the field exists.
  • M3U Generation: The Channel.to_m3u_line method (lines 118–120) injects the value as the tvg-id attribute only when present.
  • EPG Linking: The epglist.txt file defines XMLTV source URLs that make_playlist.py (lines 31–34) embeds as the x-tvg-url header in generated playlists.

Frequently Asked Questions

What happens if a channel does not have an EPG ID defined?

If the sixth column is missing or the line has fewer than seven pipe-separated elements, self.epg remains None. The to_m3u_line method consequently omits the tvg-id attribute from the #EXTINF line, and the channel will not have program guide data in IPTV clients.

How do I verify that an EPG ID matches the provider's data?

The string in the sixth column must exactly match the channel id attribute or internal identifier used by the XMLTV feeds listed in epglist.txt. Consult your EPG provider's XMLTV file to confirm the correct identifier formatting, as mismatches will result in missing guide data.

Where are the EPG source URLs configured in the repository?

The root-level file epglist.txt contains the URLs of XMLTV providers. The script reads these entries (lines 31–34 of make_playlist.py) and combines them into a comma-separated list assigned to the x-tvg-url attribute in the M3U header.

Can multiple EPG providers be used for a single playlist?

Yes. The build script aggregates all non-empty lines from epglist.txt into a single x-tvg-url value containing comma-separated URLs. IPTV clients supporting multiple EPG sources can query all listed endpoints to resolve program data for channels based on their assigned tvg-id values.

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 →