This commit is contained in:
1 parent
d7aea0be65
commit
91f22b54b4
30 files changed
+2475
No files matched your search
@@ -0,0 +1,123 @@
|
||||
# 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:
|
||||
|
||||
```text
|
||||
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
|
||||
|
||||
```bash
|
||||
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`:
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
1. Elke `REFRESH_INTERVAL_SEC` haalt de app `player_api.php?action=get_live_streams` op.
|
||||
2. Kanaalnamen met `SEARCH_TERM` worden geparsed naar wedstrijd, competitie, taal en
|
||||
starttijd. Streams met een expliciete andere taal dan `LANGUAGE` vallen af.
|
||||
3. Bronnen met dezelfde wedstrijd en starttijd worden één event. Meerdere DAZN-kanalen
|
||||
voor dezelfde wedstrijd zijn dus fallback-bronnen, geen extra FIFO-item.
|
||||
4. Een event is eligibel vanaf `START_GRACE_MIN` voor de start tot
|
||||
`EVENT_DURATION_MIN` na de start.
|
||||
5. Vrije slots worden gevuld op starttijd en daarna op moment van binnenkomst (FIFO).
|
||||
Een bestaande toewijzing wordt niet gepreempt.
|
||||
6. 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 `/status` onder `warnings`.
|
||||
- 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.
|
||||
Reference in new issue
Block a user