# How to Update Broken or Invalid Stream URLs in the Free-TV IPTV Repository

> Quickly update broken Free TV IPTV stream URLs. Learn the simple markdown editing workflow to exclude invalid channels from your playlist without touching Python scripts.

- Repository: [Free TV/IPTV](https://github.com/Free-TV/IPTV)
- Tags: how-to-guide
- Published: 2026-06-17

---

**To update broken or invalid stream URLs in the Free-TV IPTV repository, edit the country-specific markdown files in the `lists/` directory by replacing the `[>]` marker with `[x]`, which excludes the channel from the automatically generated playlist without modifying the Python build scripts.**

The Free-TV/IPTV project maintains thousands of television streams across country-specific markdown files rather than a centralized database. Understanding this workflow for updating broken or invalid stream URLs ensures contributors maintain clean git history while respecting the repository's automated generation pipeline.

## How the Playlist Generation Works

The repository uses a marker-based filtering system implemented in [`make_playlist.py`](https://github.com/Free-TV/IPTV/blob/main/make_playlist.py). During the build process, the script iterates through every markdown file in the `lists/` directory and applies a strict filter to determine playlist inclusion.

According to the source code in [`make_playlist.py`](https://github.com/Free-TV/IPTV/blob/main/make_playlist.py):

```python

# Only lines that contain the "[>]" marker are turned into playlist entries

if "[>]" not in line:
    continue
channel = Channel(group, line, country_code)

```

The `Channel` class parses each qualifying line via `Channel.__init__`, extracting the stream URL, channel name, and optional EPG data. The `to_m3u_line` method subsequently formats this data into a valid M3U8 entry. Lines lacking the `[>]` marker—specifically those marked with `[x]`—are skipped entirely, effectively filtering out dead streams from the final output.

## Step-by-Step Workflow for Updating Broken URLs

### Locate the Channel Entry

Navigate to the appropriate country file within the `lists/` directory. For example, United States channels reside in [`lists/usa.md`](https://github.com/Free-TV/IPTV/blob/main/lists/usa.md). Each channel occupies a single table row following this pipe-delimited format:

```markdown
| 1 | ABC News | [>](http://example.com/stream.m3u8) | <img src="https://i.imgur.com/abc.png" width="100"> |

```

### Mark the URL as Invalid

Replace the `[>]` marker with `[x]` to signal the stream is broken. Retain the URL inside the parentheses for future reference and potential reactivation:

```markdown
| 1 | ABC News | [x](http://example.com/broken.m3u8) | <img src="https://i.imgur.com/abc.png" width="100"> |

```

This marker change causes [`make_playlist.py`](https://github.com/Free-TV/IPTV/blob/main/make_playlist.py) to skip the entry during the next playlist generation cycle.

### Submit Your Changes

Commit only the markdown source files. Do not touch `playlist.m3u8` or any other generated artifacts—these files regenerate automatically via the repository's CI/CD pipeline when your pull request merges.

## Reactivating Fixed Streams

When a previously broken URL becomes valid again, reverse the workflow. Locate the entry in the appropriate `lists/*.md` file and restore the `[>]` marker:

```markdown
| 1 | ABC News | [>](http://example.com/working-again.m3u8) | <img src="https://i.imgur.com/abc.png" width="100"> |

```

The channel will automatically reappear in the next playlist build without requiring additional code changes.

## Adding New Channels

To contribute a new working stream, append a line to the appropriate country file using the `[>]` marker:

```markdown
| 99 | New Channel | [>](http://newstream.example.com/stream.m3u8) | <img src="https://i.imgur.com/new.png" width="100"> |

```

The script will include this entry in the generated M3U8 output as long as the `[>]` marker precedes the URL.

## Summary

- **Single source of truth**: The markdown files in `lists/` contain the definitive channel data; never edit the generated `playlist.m3u8` directly.
- **Marker system**: `[>]` indicates valid active streams; `[x]` marks broken or invalid URLs for exclusion from playlist generation.
- **Build logic**: [`make_playlist.py`](https://github.com/Free-TV/IPTV/blob/main/make_playlist.py) implements the filter via `if "[>]" not in line: continue`, processes valid entries through the `Channel` class, and produces M3U8 output via `to_m3u_line`.
- **Preservation**: Keep broken URLs in the markdown with `[x]` markers rather than deleting lines entirely, enabling easy reactivation when streams recover.

## Frequently Asked Questions

### What happens if I edit playlist.m3u8 directly?

Direct modifications to `playlist.m3u8` are overwritten by the automated CI/CD pipeline. This file is generated deterministically from the markdown sources in `lists/` every time changes merge to the default branch. Always edit the source markdown files instead.

### Can I delete broken URLs instead of marking them with [x]?

While deletion is possible, the repository convention recommends using `[x]` to preserve the URL for future reference. This practice allows contributors to test the link later or update it without reconstructing the entire table row, including the channel number and logo reference.

### How does make_playlist.py determine which channels to include?

The script applies a strict string filter in [`make_playlist.py`](https://github.com/Free-TV/IPTV/blob/main/make_playlist.py): `if "[>]" not in line: continue`. Only lines containing the `[>]` marker proceed to the `Channel` constructor and subsequent `to_m3u_line` conversion. Lines with `[x]` or no marker are ignored during M3U8 generation.

### Do I need to run make_playlist.py locally before submitting a PR?

No. The repository automation handles playlist generation server-side. Contributors only need to edit the markdown files in `lists/` and submit the pull request. The automated workflow validates changes and regenerates `playlist.m3u8` after merge.