TVP still returns
GEOIP_FILTER_FAILED(403) from non-Polish infrastructure, so GitHub Actions and Cloudflare cannot refresh most channels on their own.The residential push path is implemented and has been tested end to end from a Polish home connection.
scripts/residential_push.pyrefreshed 9/9 channels, pushed validated and normalized HLS manifests to the Worker, and all nine stable Worker.m3u8URLs played successfully immediately after refresh.This confirms that the method works, but TVPI is not a guaranteed 24/7 service yet. A machine on a Polish residential IP must run the pusher roughly every 10 minutes, and the current maintainer cannot keep that machine online around the clock. Temporary outages and stale fallbacks are therefore expected.
A durable Polish residential runner or host is still wanted. See issue #15.
Live TVP channels as ready-to-use M3U playlists. The Worker playlist contains
stable per-channel .m3u8 endpoints; each channel resolves or serves its fresh
manifest only when the player opens it.
| Source | URL base | Refresh | Best for |
|---|---|---|---|
Cloudflare Worker playlist.m3u |
https://tvpi.travny.workers.dev |
per channel, when opened | stable saveable playlist |
GitHub Raw playlist.m3u |
https://raw.githubusercontent.com/trvny/tvpi/main/streams/ |
every 15 min via Actions | offline/no-Worker fallback |
Why two? TVP signs each HLS URL with a short (~15–30 min) token. The Worker playlist points to stable TVPI
.m3u8URLs, so opening a channel can obtain the current pushed manifest or resolve a fresh token. The raw git file is a static snapshot refreshed on a timer, so its token can expire before the next refresh.
| Logo | Channel | Worker | Raw mirror | Status |
|---|---|---|---|---|
| TVP 1 | m3u8 | m3u | ||
| TVP 2 | m3u8 | m3u | ||
| TVP Info | m3u8 | m3u | ||
| TVP Sport | m3u8 | m3u | ||
| TVP Dokument | m3u8 | m3u | ||
| TVP Nauka | m3u8 | m3u | ||
| TVP Rozrywka | m3u8 | m3u | ||
| TVP Historia | m3u8 | m3u | ||
| TVP Muzyka i Koncerty | m3u8 | m3u |
The Status badge pings the Worker endpoint live, so it reflects whether the service is currently responding for that channel.
The Worker links are .m3u8 endpoints: a 302 redirect to the freshly
tokenized HLS manifest. They are stable, saveable URLs — put them straight
into your own playlist and every play resolves a fresh token. (Plain .m3u
per-channel playlists still exist at the same paths for players that prefer
a nested playlist.)
Tip: the jsDelivr CDN mirror can be more reliable than raw.githubusercontent.com:
https://cdn.jsdelivr.net/gh/trvny/tvpi@main/streams/playlist.m3uNote jsDelivr caches aggressively, which works against short-lived tokens — prefer the raw URL or the Worker if you see stale streams.
- GitHub Actions runs
generate.pyevery 15 minutes (cron schedule). - The script calls the TVP API for fresh signed HLS token URLs.
- On any transient failure it reuses that channel's last-known-good URL rather
than overwriting it with a placeholder, then writes/commits
streams/*.m3u. - Your player fetches the raw file.
GitHub Actions (every 15 min)
│
▼
vod.tvp.pl API ──► signed HLS token URL (TTL ~15–30 min)
│
▼
streams/*.m3u committed to repo
│
▼
raw.githubusercontent.com/…/streams/playlist.m3u
│
▼
Your IPTV player 🎬
The Worker combined playlist skips token resolution. It lists stable channel
endpoints, and each endpoint serves the current pushed manifest or runs the
normal cache/live/fallback resolution only when that channel is opened.
- Fork or push this repo to your GitHub account.
- Actions run automatically — no secrets or extra config needed.
- After the first run (up to 15 min), grab a raw URL and add it to your player,
or deploy the Worker (
worker/, viawrangler deploy) and use the Worker URL.
- Logos in the table are channel-site favicons fetched at render time; the Status badges ping the Worker live via shields.io and may take a moment to refresh due to badge caching.
- TVP token TTL is ~15–30 min; the 15-min refresh keeps the raw files mostly valid, but GitHub may delay scheduled runs under load — the Worker is the only path that's fully immune to token expiry.
- If
generate.pycan't get a fresh URL and has no cached one for a channel, it writes a placeholder stub so the rest of the playlist still builds.
❝An average person normally blinks 20 times a minute, but when using a computer he/she blinks only 7 times a minute.❞
- The Debt Toll Booth: A Modular Solution to Addressing Sovereign Debt Crises
- Przedwojenny Oświęcim na archiwalnych fotografiach - gazetakrakowska.pl
- Pożar busa w Nowej Wsi - Fakty Oświęcim
- CHUDZIK KRZYSZTOF - Dziennik Polski
- Przegląd AI: 3 października 2026
- Zamknięcie dnia: Agenci wymknęli się spod kontroli - i mamy dowody