diff --git a/libs/playlist/m3u/feature-player/src/lib/video-player/video-player.component.spec.ts b/libs/playlist/m3u/feature-player/src/lib/video-player/video-player.component.spec.ts index 9cf3bf8c7..bca91c1f5 100644 --- a/libs/playlist/m3u/feature-player/src/lib/video-player/video-player.component.spec.ts +++ b/libs/playlist/m3u/feature-player/src/lib/video-player/video-player.component.spec.ts @@ -929,6 +929,38 @@ describe('VideoPlayerComponent', () => { }) ); }); + + it('does not reset active timeshift on the now-tick during an EPG gap', () => { + // In catch-up (activePlaybackUrl set) with programmes that don't cover + // "now", the 30s tick must NOT dispatch resetActiveEpgProgram — that + // reducer nulls activePlaybackUrl and would silently drop the user back + // to the live stream every 30 seconds. + syncStoreState(sampleChannel); + activePlaybackUrl.set('http://localhost/catchup.m3u8'); + fixture.detectChanges(); + storeMock.dispatch.mockClear(); + + epgPrograms$.next([buildProgram('Earlier')]); // no programme airing now + fixture.detectChanges(); + + expect(storeMock.dispatch).not.toHaveBeenCalledWith( + EpgActions.resetActiveEpgProgram() + ); + }); + + it('still clears stale EPG state on the now-tick when playing live', () => { + syncStoreState(sampleChannel); + activePlaybackUrl.set(null); // live, not timeshift + fixture.detectChanges(); + storeMock.dispatch.mockClear(); + + epgPrograms$.next([buildProgram('Earlier')]); + fixture.detectChanges(); + + expect(storeMock.dispatch).toHaveBeenCalledWith( + EpgActions.resetActiveEpgProgram() + ); + }); }); function buildProgram(title: string): EpgProgram { diff --git a/libs/playlist/m3u/feature-player/src/lib/video-player/video-player.component.ts b/libs/playlist/m3u/feature-player/src/lib/video-player/video-player.component.ts index be43235a5..edda8c7f4 100644 --- a/libs/playlist/m3u/feature-player/src/lib/video-player/video-player.component.ts +++ b/libs/playlist/m3u/feature-player/src/lib/video-player/video-player.component.ts @@ -389,7 +389,12 @@ export class VideoPlayerComponent implements OnInit, OnDestroy { this.store.dispatch( EpgActions.setCurrentEpgProgram({ program: currentProgram }) ); - } else { + } else if (!this.activePlaybackUrl()) { + // No live programme right now. Only clear stale EPG state when + // NOT in catch-up/timeshift: resetActiveEpgProgram also nulls + // activePlaybackUrl, so firing it on every 30s tick would knock + // the user out of an in-progress archive playback whenever the + // channel has an EPG gap at the current clock time. this.store.dispatch(EpgActions.resetActiveEpgProgram()); } });