always same channels
Build and Push Docker Images / build-and-push (push) Successful in 22s

This commit is contained in:
Bram committed 2026-11-07 16:33:13 +01:00
1 parent d266a8258d
commit 774200fb39
4 files changed
+38 -15

No files matched your search

@@ -25,7 +25,8 @@ View BE| DAZN 03 [Standard de Liège - SK Beveren | Jupiler Pro League (nl) (202
vrijgekomen slot wordt gevuld met het oudste wachtende event (sortering op starttijd,
daarna volgorde van binnenkomst). Geen preemptie van een al toegewezen event.
- **Altijd 3 slots**: ook bij 0, 1 of 2 wedstrijden blijven `Jupiler 1` t/m `Jupiler 3`
in de playlist staan. Een leeg slot heet `Geen wedstrijd` en `/stream/<slot>` geeft 503.
in de playlist staan met volledig vaste id's, namen en `tvg-chno`. De actuele wedstrijd
staat in de EPG en `/status`, niet in de kanaalnaam. Een leeg slot geeft 503.
- **Live-bepaling**: starttijd uit de kanaalnaam + instelbare duur. Een event is eligibel
vanaf `startAt - START_GRACE_MIN` tot `startAt + EVENT_DURATION_MIN`.
- **Einde event**: op basis van de berekende eindtijd, niet op basis van het verdwijnen
@@ -159,9 +160,9 @@ blijven de overige slots leeg (naam `Geen wedstrijd`).
## Endpoints
- `GET /` - eenvoudige HTML met playlist-link en kanaalstatus.
- `GET /playlist.m3u` - altijd `MAX_CHANNELS` entries:
`#EXTINF:-1 tvg-id="jupiler-1" tvg-name="Jupiler 1",Jupiler 1 | <titel> (<start>)`
en daaronder `http://<host>/stream/1`.
- `GET /playlist.m3u` - altijd `MAX_CHANNELS` entries met vaste metadata:
`#EXTINF:-1 tvg-id="jupiler-1" tvg-name="Jupiler 1" tvg-chno="1",Jupiler 1`
en daaronder `http://<host>/stream/1`. Wedstrijdinformatie staat in de EPG.
- `GET /epg.xml` of `/xmltv.xml` - XMLTV-gids voor de vaste kanalen. De gids toont de
actuele toewijzing plus een FIFO-projectie van toekomstige wedstrijden uit de laatste
kanaalnamen-refresh.
+4 -3
View File
@@ -55,9 +55,10 @@ Voeg daarna in je IPTV-client toe:
| `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.
De playlist bevat altijd exact dezelfde drie kanalen: `Jupiler 1`, `Jupiler 2` en
`Jupiler 3`, met vaste `tvg-id`, `tvg-name` en `tvg-chno`. De kanaalnaam verandert nooit;
de actuele wedstrijd staat in de EPG en op `/status`. Is een slot leeg, dan geeft
`/stream/N` een 503 tot er een wedstrijd op het slot staat.
## Configuratie
+2 -5
View File
@@ -9,12 +9,9 @@ function buildPlaylist(req, scheduler) {
const count = scheduler.getSlotCount();
const lines = ['#EXTM3U'];
for (let i = 0; i < count; i += 1) {
const event = scheduler.getSlotEvent(i);
const label = event
? `${event.title} (${formatLocalTime(event.startAt, settings.timezone)})`
: 'Geen wedstrijd';
const name = `Jupiler ${i + 1}`;
lines.push(
`#EXTINF:-1 tvg-id="jupiler-${i + 1}" tvg-name="Jupiler ${i + 1}",Jupiler ${i + 1} | ${label}`
`#EXTINF:-1 tvg-id="jupiler-${i + 1}" tvg-name="${name}" tvg-chno="${i + 1}",${name}`
);
lines.push(`${origin}/stream/${i + 1}`);
}
@@ -26,10 +26,34 @@ test('playlist always contains three fixed channels', () => {
assert.equal(lines[0], '#EXTM3U');
assert.equal(
lines[1],
'#EXTINF:-1 tvg-id="jupiler-1" tvg-name="Jupiler 1",Jupiler 1 | Standard de Liège - SK Beveren (19:25)'
'#EXTINF:-1 tvg-id="jupiler-1" tvg-name="Jupiler 1" tvg-chno="1",Jupiler 1'
);
assert.equal(lines[2], 'http://example.test:8080/stream/1');
assert.ok(body.includes('Jupiler 2 | Geen wedstrijd'));
assert.ok(body.includes('Jupiler 3 | Geen wedstrijd'));
assert.ok(body.includes('#EXTINF:-1 tvg-id="jupiler-2" tvg-name="Jupiler 2" tvg-chno="2",Jupiler 2'));
assert.ok(body.includes('#EXTINF:-1 tvg-id="jupiler-3" tvg-name="Jupiler 3" tvg-chno="3",Jupiler 3'));
assert.ok(body.includes('http://example.test:8080/stream/3'));
});
test('channel metadata stays identical when the assigned event changes', () => {
const first = {
getSlotCount: () => 3,
getSlotEvent: (index) => (index === 0 ? event : null),
};
const second = {
getSlotCount: () => 3,
getSlotEvent: (index) =>
index === 0
? {
key: 'b',
title: 'Anderlecht - Genk',
startAt: new Date('2026-11-06T21:00:00Z'),
endAt: new Date('2026-11-06T23:30:00Z'),
}
: null,
};
const channelLines = (body) => body.split('\n').filter((line) => line.startsWith('#EXTINF'));
assert.deepEqual(
channelLines(buildPlaylist(fakeRequest(), first)),
channelLines(buildPlaylist(fakeRequest(), second))
);
});