timezone issues
Build and Push Docker Images / build-and-push (push) Successful in 28s

This commit is contained in:
Bram committed 2026-11-07 16:30:47 +01:00
1 parent 74df7780fd
commit d266a8258d
9 files changed
+32 -15

No files matched your search

+1
View File
@@ -20,6 +20,7 @@ ENV LISTEN_PORT=8080 \
EVENT_DURATION_MIN=150 \
START_GRACE_MIN=10 \
REFRESH_INTERVAL_SEC=60 \
SOURCE_TIMEZONE=UTC \
TIMEZONE=Europe/Brussels \
UPSTREAM_TIMEOUT_MS=15000 \
PROXY_INSECURE_TLS=0 \
+6 -1
View File
@@ -12,6 +12,10 @@ 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)]
```
De tijdstempels in de kanaalnamen worden standaard als **UTC** gelezen. De app toont ze
vervolgens in `TIMEZONE` (standaard `Europe/Brussels`), dus `19:25:00` UTC wordt in de
playlist en EPG als `20:25` getoond.
Alleen streams met taalcode `(nl)` of zonder taalcode worden gebruikt. Een expliciete
`(fr)`- of andere taalcode wordt overgeslagen.
@@ -68,7 +72,8 @@ staat.
| `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 |
| `SOURCE_TIMEZONE` | `UTC` | nee | Tijdzone van de tijdstempels in de kanaalnamen |
| `TIMEZONE` | `Europe/Brussels` | nee | Tijdzone voor weergave in playlist en EPG |
| `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 |
@@ -14,6 +14,7 @@ services:
EVENT_DURATION_MIN: "150"
START_GRACE_MIN: "10"
REFRESH_INTERVAL_SEC: "600"
SOURCE_TIMEZONE: "UTC"
TIMEZONE: "Europe/Brussels"
# PROXY_INSECURE_TLS: "1" # alleen nodig bij self-signed upstream-certificaten
# LOG_LEVEL: "debug"
+1
View File
@@ -40,6 +40,7 @@ function statusPayload() {
eventDurationMin: settings.eventDurationMin,
startGraceMin: settings.startGraceMin,
refreshIntervalSec: settings.refreshIntervalSec,
sourceTimezone: settings.sourceTimezone,
timezone: settings.timezone,
},
};
+1 -1
View File
@@ -160,7 +160,7 @@ function createScheduler() {
const { events, warnings } = buildEvents(streams, {
searchTerm: settings.searchTerm,
language: settings.language,
timezone: settings.timezone,
timezone: settings.sourceTimezone,
eventDurationMs: settings.eventDurationMs,
});
const now = Date.now();
+5 -3
View File
@@ -18,6 +18,7 @@ const settings = {
eventDurationMin: readNumber(process.env.EVENT_DURATION_MIN, 150, 1, 1440),
startGraceMin: readNumber(process.env.START_GRACE_MIN, 10, 0, 1440),
refreshIntervalSec: readNumber(process.env.REFRESH_INTERVAL_SEC, 60, 10, 3600),
sourceTimezone: (process.env.SOURCE_TIMEZONE || 'UTC').trim() || 'UTC',
timezone: (process.env.TIMEZONE || 'Europe/Brussels').trim() || 'Europe/Brussels',
listenPort: Math.round(readNumber(process.env.LISTEN_PORT, 8080, 1, 65535)),
upstreamTimeoutMs: readNumber(process.env.UPSTREAM_TIMEOUT_MS, 15000, 1000, 120000),
@@ -32,11 +33,11 @@ const settings = {
settings.eventDurationMs = settings.eventDurationMin * 60 * 1000;
settings.startGraceMs = settings.startGraceMin * 60 * 1000;
function validateTimezone(timezone) {
function validateTimezone(timezone, envName) {
try {
new Intl.DateTimeFormat('en-US', { timeZone: timezone });
} catch {
throw new Error(`Invalid TIMEZONE: ${timezone}`);
throw new Error(`Invalid ${envName}: ${timezone}`);
}
}
@@ -60,7 +61,8 @@ function validate() {
throw new Error('XTREAM_URL must use http or https');
}
validateTimezone(settings.timezone);
validateTimezone(settings.sourceTimezone, 'SOURCE_TIMEZONE');
validateTimezone(settings.timezone, 'TIMEZONE');
if (!settings.language) {
throw new Error('LANGUAGE must not be empty');
@@ -7,18 +7,23 @@ const { parseChannelName, normalizeText } = require('../src/channel-name');
const sample =
'View BE| DAZN 03 [Standard de Liège - SK Beveren | Jupiler Pro League (nl) (2026-11-06 19:25:00)]';
test('parses the DAZN sample', () => {
const parsed = parseChannelName(sample, { timezone: 'Europe/Brussels' });
test('parses the DAZN sample with UTC source timestamps', () => {
const parsed = parseChannelName(sample, { timezone: 'UTC' });
assert.equal(parsed.title, 'Standard de Liège - SK Beveren');
assert.equal(parsed.league, 'Jupiler Pro League');
assert.equal(parsed.language, 'nl');
assert.equal(parsed.startAt.toISOString(), '2026-11-06T19:25:00.000Z');
});
test('can parse the same timestamp in another source timezone', () => {
const parsed = parseChannelName(sample, { timezone: 'Europe/Brussels' });
assert.equal(parsed.startAt.toISOString(), '2026-11-06T18:25:00.000Z');
});
test('parses a French stream', () => {
const parsed = parseChannelName(
'View BE| DAZN 03 [Standard de Liège - SK Beveren | Jupiler Pro League (fr) (2026-11-06 19:25:00)]',
{ timezone: 'Europe/Brussels' }
{ timezone: 'UTC' }
);
assert.equal(parsed.language, 'fr');
});
@@ -26,14 +31,14 @@ test('parses a French stream', () => {
test('allows a missing language code', () => {
const parsed = parseChannelName(
'DAZN 03 [Standard de Liège - SK Beveren | Jupiler Pro League (2026-11-06 19:25:00)]',
{ timezone: 'Europe/Brussels' }
{ timezone: 'UTC' }
);
assert.equal(parsed.language, null);
});
test('returns null for unparseable names', () => {
assert.equal(parseChannelName('DAZN 03', { timezone: 'Europe/Brussels' }), null);
assert.equal(parseChannelName('', { timezone: 'Europe/Brussels' }), null);
assert.equal(parseChannelName('DAZN 03', { timezone: 'UTC' }), null);
assert.equal(parseChannelName('', { timezone: 'UTC' }), null);
});
test('normalizes diacritics and whitespace', () => {
@@ -4,7 +4,7 @@ const test = require('node:test');
const assert = require('node:assert/strict');
const { buildEvents, compareEvents, isEligible } = require('../src/events');
const timezone = 'Europe/Brussels';
const timezone = 'UTC';
function stream(id, name) {
return { stream_id: id, name };