mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-14 21:26:15 -08:00
Adds a global EPG display-time offset (Settings → EPG, whole minutes, ±720) for guides whose provider labels programme times with the wrong timezone. Display-only: parsed XMLTV values, SQLite rows, catch-up URLs and recording snapshots keep the provider's own times, so changing it needs no guide refresh. Closes the global part of #50. The contract lives in `libs/shared/interfaces/src/lib/epg-display-offset.util.ts` with two equivalent forms: `epgDisplayTimeMs` shifts a programme for display, `epgProviderClockMs` shifts "now" into the provider's clock for every "currently airing" decision — the batched `GET_CURRENT_PROGRAMS_BATCH` lookup takes an explicit `nowMs`, and the channel lists, the Xtream/Stalker previews, the M3U player's current-programme mirror, the unified collection resolver, the dashboard live cards and the recording overlap all pick the same programme the guide renders as "now". Portal short-EPG windows start at the provider's own "now", so under a non-zero offset the Xtream preview surfaces cut their window from the full guide at the provider clock, Stalker short-EPG requests are widened for negative offsets, and every per-stream memory of the previous offset is retired together when the setting changes. Co-authored-by: Mark Jardine <markjardine27@gmail.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
47 lines
1.4 KiB
TypeScript
47 lines
1.4 KiB
TypeScript
import {
|
|
areProgramsSame,
|
|
deduplicateProgramsByTimeSlot,
|
|
getProgramDateKey,
|
|
getProgramTimeMs,
|
|
} from './epg-program.utils';
|
|
|
|
const PROGRAM = {
|
|
start: '2026-06-28T23:30:00.000Z',
|
|
stop: '2026-06-29T00:30:00.000Z',
|
|
channel: 'channel',
|
|
title: 'Program',
|
|
desc: null,
|
|
category: null,
|
|
};
|
|
|
|
describe('epg-program.utils', () => {
|
|
it('preserves raw time with the default offset', () => {
|
|
expect(getProgramTimeMs(PROGRAM.start)).toBe(Date.parse(PROGRAM.start));
|
|
});
|
|
|
|
it('shifts ISO and numeric timestamps in display time', () => {
|
|
expect(getProgramTimeMs(PROGRAM.start, null, 60)).toBe(
|
|
Date.parse(PROGRAM.start) + 60 * 60_000
|
|
);
|
|
expect(getProgramTimeMs(PROGRAM.start, 1_000, -30)).toBe(
|
|
1_000_000 - 30 * 60_000
|
|
);
|
|
});
|
|
|
|
it('shifts date keys across midnight', () => {
|
|
expect(getProgramDateKey(PROGRAM.start, null, 60)).toBe('2026-06-29');
|
|
});
|
|
|
|
it('uses shifted times consistently for equality and deduplication', () => {
|
|
const equivalent = {
|
|
...PROGRAM,
|
|
start: '2026-06-29T00:30:00.000Z',
|
|
stop: '2026-06-29T01:30:00.000Z',
|
|
};
|
|
expect(areProgramsSame(PROGRAM, equivalent, 60)).toBe(false);
|
|
expect(
|
|
deduplicateProgramsByTimeSlot([PROGRAM, PROGRAM], 60)
|
|
).toHaveLength(1);
|
|
});
|
|
});
|