mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 18:36:15 -08:00
fix(xtream): address review feedback on XMLTV fallback PR
- pruneEphemeralMaps now uses getCached() so TTL-expired entries also drop their XMLTV preview / channel-id mapping, instead of clinging to them until the next explicit cache read. - portal-channels-list attaches a .catch() to the now-async enqueue so any future internal rejection surfaces in the console rather than bubbling silently as an unhandled promise rejection. - XtreamXmltvFallbackService binds the bridge receiver when calling the extracted function reference, in case a preload wrapper relies on `this`. Adds a regression test for the TTL-aware prune.
This commit is contained in:
4 files changed
+39
-9
No files matched your search
@@ -276,6 +276,34 @@ describe('EpgQueueService', () => {
|
||||
expect(priv().epgChannelByStreamId.has(100)).toBe(false);
|
||||
});
|
||||
|
||||
it('prunes XMLTV preview when its cache entry has expired (TTL-aware)', async () => {
|
||||
fallback.getCurrentProgramsBatch.mockResolvedValueOnce({
|
||||
'rtl.de': makeEpgItem('rtl.de', 'Tagesschau'),
|
||||
});
|
||||
xtreamApi.getShortEpg.mockResolvedValue([]);
|
||||
|
||||
// Initial enqueue: stream 100 visible, gets cached.
|
||||
await service.enqueue(
|
||||
[{ streamId: 100, epgChannelId: 'rtl.de' }],
|
||||
new Set([100]),
|
||||
credentials
|
||||
);
|
||||
expect(priv().xmltvPreviewByStreamId.has(100)).toBe(true);
|
||||
|
||||
// Stream 100 leaves the viewport but still has a (live) cache entry,
|
||||
// so prune keeps the preview alive — by design.
|
||||
await service.enqueue([], new Set([]), credentials);
|
||||
expect(priv().xmltvPreviewByStreamId.has(100)).toBe(true);
|
||||
|
||||
// Advance past the 5-minute cache TTL. Now the cache entry is stale;
|
||||
// prune must drop the preview rather than cling to an expired hit.
|
||||
jest.advanceTimersByTime(5 * 60 * 1000 + 1);
|
||||
await service.enqueue([], new Set([]), credentials);
|
||||
|
||||
expect(priv().xmltvPreviewByStreamId.has(100)).toBe(false);
|
||||
expect(priv().epgChannelByStreamId.has(100)).toBe(false);
|
||||
});
|
||||
|
||||
it('does not re-emit on empty→empty transitions', async () => {
|
||||
xtreamApi.getShortEpg.mockResolvedValue([]);
|
||||
const events: number[] = [];
|
||||
|
||||
@@ -189,8 +189,10 @@ export class EpgQueueService implements OnDestroy {
|
||||
}
|
||||
|
||||
private pruneEphemeralMaps(visibleIds: Set<number>): void {
|
||||
for (const id of this.epgChannelByStreamId.keys()) {
|
||||
if (!visibleIds.has(id) && !this.cache.has(id)) {
|
||||
for (const id of [...this.epgChannelByStreamId.keys()]) {
|
||||
// getCached() honors TTL and lazily evicts expired entries;
|
||||
// a raw cache.has() would keep stale previews alive forever.
|
||||
if (!visibleIds.has(id) && this.getCached(id) === null) {
|
||||
this.epgChannelByStreamId.delete(id);
|
||||
this.xmltvPreviewByStreamId.delete(id);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ export class XtreamXmltvFallbackService {
|
||||
if (typeof fn !== 'function') return [];
|
||||
|
||||
try {
|
||||
const programs = await fn(id);
|
||||
const programs = await fn.call(this.bridge, id);
|
||||
return (programs ?? []).map((p) => mapEpgProgramToEpgItem(p, id));
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
@@ -70,7 +70,7 @@ export class XtreamXmltvFallbackService {
|
||||
if (ids.length === 0) return {};
|
||||
|
||||
try {
|
||||
const rows = await fn(ids);
|
||||
const rows = await fn.call(this.bridge, ids);
|
||||
const out: Record<string, EpgItem> = {};
|
||||
for (const id of ids) {
|
||||
const row = rows?.[id];
|
||||
|
||||
+5
-5
@@ -226,11 +226,11 @@ export class PortalChannelsListComponent implements AfterViewInit, OnDestroy {
|
||||
}
|
||||
|
||||
if (uncachedEntries.length > 0) {
|
||||
this.epgQueueService.enqueue(
|
||||
uncachedEntries,
|
||||
visibleIds,
|
||||
credentials
|
||||
);
|
||||
this.epgQueueService
|
||||
.enqueue(uncachedEntries, visibleIds, credentials)
|
||||
.catch((error) => {
|
||||
console.warn('EPG enqueue failed', error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user