How to Extract and Validate Stream URLs from Markdown Tables in IPTV Data

The make_playlist.py script in the Free-TV/IPTV repository scans markdown tables for the [>] verification marker, parses the embedded URLs and metadata using the Channel class, and outputs standardized M3U8 playlists.

The Free-TV/IPTV project maintains curated television channel data in markdown tables organized by country. The make_playlist.py script processes these files to extract and validate stream URLs, ensuring only verified links reach the final playlists.

Overview of the Playlist Generation Process

The extraction pipeline operates in five distinct phases: directory scanning, validation filtering, row parsing, M3U8 formatting, and file output. According to the source code in make_playlist.py, the script specifically targets files in the lists/ directory and processes only rows explicitly marked as verified.

Step-by-Step URL Extraction and Validation

Scanning Markdown Files in the Lists Directory

The script initiates by walking the lists/ directory (lines 38-44 of make_playlist.py), identifying all *.md files. Each file represents a country or region containing tables with channel metadata and stream URLs.

Validating Streams with the [>] Marker

Inside the file loop, the script validates each line by checking for the "[>]" marker (line 53). This marker denotes a verified stream URL. Rows containing [x] or lacking any marker are ignored entirely, ensuring only manually confirmed streams enter the playlist.

Parsing Table Rows with the Channel Class

When a line contains "[>]", the script instantiates a Channel object (line 55). The constructor processes the markdown line through several steps:

  • The line is stripped and split on the pipe character (|) (line 99)
  • The URL column (4th position) contains a markdown link like [>] (http://example.com/stream.m3u8)
  • The raw URL is extracted by locating the opening and closing parentheses (lines 102-103)
  • The logo URL is similarly parsed from the <img src="..."> tag (lines 104-105)

Generating M3U8 Entries

The Channel.to_m3u_line() method (lines 14-21) formats the extracted data into standard #EXTINF syntax. Optional fields like tvg-chno, tvg-country, and tvg-id are appended only when present in the source data.

Implementation Example

The following example demonstrates how a markdown table row transforms into a playlist entry:


# Example markdown line from lists/united_kingdom.md

line = '| 1 | BBC News | [>] (http://example.com/bbc.m3u8) | <img src="https://i.imgur.com/logo.png" /> | EPG123 |'

# Create Channel object (as implemented in make_playlist.py)

channel = Channel(group="United Kingdom", md_line=line, country_code="GB")

print(channel.url)   # → http://example.com/bbc.m3u8

print(channel.logo)  # → https://i.imgur.com/logo.png

The M3U8 generation follows this parsing:

m3u_line = channel.to_m3u_line()
print(m3u_line)

# Output:

# #EXTINF:-1 tvg-name="BBC News" tvg-logo="https://i.imgur.com/logo.png" tvg-id="EPG123" tvg-country="GB",BBC News

# http://example.com/bbc.m3u8

File Structure and Output

The script writes each validated entry to two locations: the global playlist.m3u8 file and a country-specific playlist in the playlists/ directory (lines 57-58). This dual-output approach allows users to access either the complete channel list or region-specific subsets.

Summary

  • The make_playlist.py script processes markdown tables in the lists/ directory to build IPTV playlists
  • Only rows marked with [>] are considered valid; [x] or unmarked rows are discarded
  • The Channel class parses pipe-delimited lines to extract URLs from markdown link syntax and logos from HTML img tags
  • Validated entries are formatted as #EXTINF lines and written to both global and country-specific M3U8 files

Frequently Asked Questions

What does the [>] marker mean in Free-TV/IPTV markdown tables?

The [>] marker indicates that a stream URL has been manually verified and is currently active. According to the repository's README.md, this marker distinguishes working streams from those marked with [x] (inactive/broken) or unverified entries.

How does the script handle invalid or unverified stream URLs?

The script ignores any table row that does not contain the [>] marker. During the scanning phase (line 53 of make_playlist.py), lines containing [x] or lacking markers are skipped entirely, ensuring only validated URLs reach the final M3U8 output.

Where are the generated playlists stored?

The script generates two types of output files: playlist.m3u8 in the repository root containing all channels, and individual files in the playlists/ directory named playlist_[country_code].m3u8 containing region-specific channels.

Can I extract URLs manually without running the full script?

While manual extraction is possible by parsing the markdown syntax yourself, the Channel class in make_playlist.py provides the authoritative implementation for handling edge cases like nested parentheses in URLs and HTML-encoded logo attributes. For production use, running the complete script ensures consistent formatting and validation.

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 →