How Free-TV/IPTV Parses Markdown Table Columns Separated by Pipe Characters
The make_playlist.py script strips whitespace from each table row, splits the string on the pipe character (|), and extracts specific indices to populate Channel object attributes.
The Free-TV/IPTV repository converts Markdown-based channel listings into M3U playlists using a Python script that interprets pipe-delimited tables. Understanding how this script parses markdown table columns separated by pipe characters reveals the data pipeline that transforms static documentation into streaming playlists. The parsing logic resides primarily in the Channel class constructor within make_playlist.py.
How the Pipe-Delimited Parsing Works
Stripping and Splitting Lines
The script begins by normalizing each line of input to remove extraneous whitespace. According to the source code in make_playlist.py (lines 98-103), the parser executes:
md_line = md_line.strip()
parts = md_line.split("|")
This operation creates a list where each element represents a column value. Because standard Markdown tables begin with a leading pipe character, the resulting list (parts) always contains an empty string at index 0.
Handling the Leading Empty Element
When processing a typical table row such as | 101 | BBC News | [link](http://stream.example.com) |, the split operation produces:
['', ' 101 ', ' BBC News ', ' [link](http://stream.example.com) ', '']
The script ignores the empty boundaries and accesses meaningful data starting at index 1.
Extracting Column Data from Split Arrays
The Channel constructor maps specific parts indices to semantic attributes as implemented in lines 101-106 of make_playlist.py:
- Channel number:
parts[1]→self.number = parts[1].strip() - Channel name:
parts[2]→self.name = parts[2].strip() - Stream URL:
parts[3]→ Extracted from Markdown link syntax - Logo URL:
parts[4]→ Extracted from HTMLimgtag - Optional EPG ID:
parts[5](if present) →self.epg = parts[5].strip()
Consider this example Markdown row:
| 101 | BBC News | [link](http://stream.example.com/bbc.m3u8) | <img src="http://logo.example.com/bbc.png"> |
The script processes it as follows:
md_line = "| 101 | BBC News | [link](http://stream.example.com/bbc.m3u8) | <img src=\"http://logo.example.com/bbc.png\"> |"
parts = md_line.strip().split("|")
# Result: ['', ' 101 ', ' BBC News ', ' [link](http://stream.example.com/bbc.m3u8) ', ' <img src="http://logo.example.com/bbc.png"> ', '']
number = parts[1].strip() # "101"
name = parts[2].strip() # "BBC News"
Parsing Embedded URLs and HTML
Extracting Stream URLs from Markdown Links
The URL column in the Markdown file uses standard link syntax: [text](http://example.com). The script extracts the actual URL by locating the parentheses boundaries:
self.url = parts[3].strip()
self.url = self.url[self.url.find("(")+1:self.url.rfind(")")]
This slices the string from the character after the opening ( to the character before the closing ), yielding the raw stream address.
Extracting Logo URLs from Image Tags
Similarly, the logo column contains an HTML <img> tag. The parser locates the src="..." attribute to isolate the image URL:
self.logo = parts[4].strip()
self.logo = self.logo[self.logo.find('src="')+5:self.logo.rfind('"')]
The +5 offset accounts for the length of src=" itself, positioning the slice at the start of the actual URL.
Complete Channel Construction Flow
The entire parsing sequence executes within the Channel constructor, which is invoked for every line containing the channel entry marker ("[>]") while iterating over the Markdown files in lists/*.md. The constructor signature and parsing logic ensure that raw table rows transform into structured objects with clean URLs ready for M3U playlist generation.
Summary
- The script uses
strip()andsplit("|")to tokenize pipe-separated table columns inmake_playlist.py. - The resulting list contains an empty element at index 0 due to the leading pipe, so data extraction begins at index 1.
- Channel numbers and names are extracted directly from indices 1 and 2 after stripping whitespace.
- Stream URLs require parsing Markdown link syntax by extracting text between
(and)characters. - Logo URLs require parsing HTML
imgtags by extracting thesrcattribute value between quotes. - Optional EPG IDs occupy index 5 when present in the table row.
Frequently Asked Questions
How does the script handle empty columns in the Markdown table?
The script relies on the pipe delimiter to maintain positional alignment. If a column is empty, the split operation creates an empty string at that index (e.g., ['', ' 101 ', '', ' ...']), which subsequent .strip() calls process as an empty value. The constructor assumes standard table structure, so missing data at expected indices may result in empty string assignments to the Channel attributes.
Why does the split result contain an empty string at the beginning?
Markdown table syntax begins with a leading pipe character (|) before the first cell content. When Python's split("|") encounters this leading delimiter, it creates an empty string as the first element of the resulting list. The script accounts for this by accessing data starting at index 1 rather than index 0.
Where does the parsing logic reside in the repository?
The core parsing logic is defined in make_playlist.py at lines 98-106, specifically within the Channel class constructor. This file reads the Markdown tables from lists/*.md, processes the pipe-separated columns, and generates the final M3U playlist files containing the extracted stream URLs.
How does the script differentiate between header rows and data rows?
The script identifies valid channel entries by checking for the [>] marker within the line before invoking the Channel constructor. This marker indicates a playable channel entry rather than a table header, separator, or empty row, ensuring only relevant data undergoes the pipe-splitting extraction process.
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 →