5.4 KiB
Xtream PPV bundler
Bundelt alle live-streams van één Xtream-panel waarvan de kanaalnaam een zoekterm bevat
(bijv. Jupiler Pro League) in maximaal 3 vaste uitgangskanalen. Toewijzing gebeurt via
FIFO: zodra een wedstrijd klaar is, neemt de oudste wachtende wedstrijd het vrijgekomen
slot over.
De app leest periodiek de kanaalnamen van de upstream. Daaruit haalt hij wedstrijd, competitie, taal en starttijd, bijvoorbeeld:
View BE| DAZN 03 [Standard de Liège - SK Beveren | Jupiler Pro League (nl) (2026-11-06 19:25:00)]
Alleen streams met taalcode (nl) of zonder taalcode worden gebruikt. Een expliciete
(fr)- of andere taalcode wordt overgeslagen.
Snel starten
docker build -t xtream-ppv-bundler .
docker run -d --name xtream-ppv-bundler -p 8080:8080 \
-e XTREAM_URL="http://panel.example.com:8080" \
-e XTREAM_USERNAME="user" \
-e XTREAM_PASSWORD="pass" \
-e SEARCH_TERM="Jupiler Pro League" \
xtream-ppv-bundler
Of gebruik docker-compose.example.yml:
cp docker-compose.example.yml docker-compose.yml
# zet XTREAM_URL, XTREAM_USERNAME, XTREAM_PASSWORD en SEARCH_TERM in .env
docker compose up -d
Voeg daarna in je IPTV-client toe:
- Playlist:
http://<host>:8080/playlist.m3u - EPG (XMLTV):
http://<host>:8080/epg.xml
Endpoints
| Endpoint | Functie |
|---|---|
GET /playlist.m3u |
M3U met altijd MAX_CHANNELS vaste kanalen |
GET /stream/<slot> |
Live proxy naar de wedstrijd op dat slot |
GET /epg.xml of /xmltv.xml |
XMLTV-programmagids voor de 3 kanalen |
GET /status |
JSON met slots, FIFO-wachtrij, laatste refresh en waarschuwingen |
GET /health |
Healthcheck voor Docker |
GET / |
Eenvoudige statuspagina |
De playlist bevat altijd Jupiler 1 t/m Jupiler 3. Is een slot leeg, dan heet het
Jupiler N | Geen wedstrijd en geeft /stream/N een 503 tot er een wedstrijd op het slot
staat.
Configuratie
| Env | Default | Verplicht | Betekenis |
|---|---|---|---|
XTREAM_URL |
- | ja | Basis-URL van het Xtream-panel, mag een path-prefix hebben |
XTREAM_USERNAME |
- | ja | Upstream username |
XTREAM_PASSWORD |
- | ja | Upstream password |
SEARCH_TERM |
- | ja | Case-insensitive substring in de kanaalnaam |
MAX_CHANNELS |
3 |
nee | Aantal vaste uitgangsslots (1-10) |
LANGUAGE |
nl |
nee | Toegestane expliciete taalcode; ontbrekende code wordt toegelaten |
EVENT_DURATION_MIN |
150 |
nee | Duur waarna een event het slot verlaat |
START_GRACE_MIN |
10 |
nee | Minuten voor aanvang dat een event eligibel wordt |
REFRESH_INTERVAL_SEC |
60 |
nee | Hoe vaak kanaalnamen opnieuw worden gelezen |
TIMEZONE |
Europe/Brussels |
nee | Tijdzone van de tijdstempels in kanaalnamen |
LISTEN_PORT |
8080 |
nee | HTTP-poort |
UPSTREAM_TIMEOUT_MS |
15000 |
nee | Timeout voor upstream-verzoeken |
PROXY_INSECURE_TLS |
0 |
nee | 1 = self-signed upstream-certificaten accepteren |
HLS_SECRET |
random | nee | Secret voor ondertekende HLS-segment-URL's |
LOG_LEVEL |
info |
nee | debug, info, warn, error |
Werking
- Elke
REFRESH_INTERVAL_SEChaalt de appplayer_api.php?action=get_live_streamsop. - Kanaalnamen met
SEARCH_TERMworden geparsed naar wedstrijd, competitie, taal en starttijd. Streams met een expliciete andere taal danLANGUAGEvallen af. - Bronnen met dezelfde wedstrijd en starttijd worden één event. Meerdere DAZN-kanalen voor dezelfde wedstrijd zijn dus fallback-bronnen, geen extra FIFO-item.
- Een event is eligibel vanaf
START_GRACE_MINvoor de start totEVENT_DURATION_MINna de start. - Vrije slots worden gevuld op starttijd en daarna op moment van binnenkomst (FIFO). Een bestaande toewijzing wordt niet gepreempt.
- Een toegewezen event houdt zijn slot tot de berekende eindtijd, ook als de provider de kanaalnaam intussen naar de volgende wedstrijd zet. Nieuwe kijkers krijgen de actuele toewijzing; bestaande verbindingen lopen door tot de client disconnect.
EPG
/epg.xml genereert XMLTV voor de vaste kanalen. De gids gebruikt:
- de actuele toewijzing per slot;
- alle toekomstige wedstrijden uit de laatste succesvolle kanaal-refresh, geprojecteerd over de slots volgens dezelfde FIFO-regels.
De EPG is dus een projectie op basis van de kanaalnamen. Nieuwe of gewijzigde uitzendingen verschijnen na de volgende refresh. Bij een mislukte refresh blijft de laatst bekende gids staan.
Stream-URL's en HLS
De app bouwt stream-URL's primair als /live/<user>/<pass>/<stream_id>.ts, met
.m3u8- en padvarianten als fallback. Werkt geen enkele kandidaat, dan wordt eenmalig de
volledige get.php?type=m3u_plus-playlist opgehaald en gecacht om de exacte URL te vinden.
MPEG-TS wordt 1-op-1 geproxied. Bij HLS worden playlist-URI's herschreven naar ondertekende URLs op deze app, zodat upstream-credentials nooit naar de client lekken. Segmenten, keys en geneste playlists worden via dezelfde proxy opgehaald.
Beperkingen
- Het kanaalnaamformaat is provider-specifiek. Onparseerbare namen worden overgeslagen en
verschijnen in
/statusonderwarnings. - Zonder upstream-EPG is de eindtijd een aanname (
EVENT_DURATION_MIN). - De EPG is een projectie en kan afwijken van de werkelijke toewijzing als de provider kanaalnamen onverwacht wijzigt.
- De output heeft geen authenticatie; bedoeld voor LAN/self-host.
- Meerdere kijkers betekenen meerdere upstream-verbindingen.