diff --git a/libs/playlist/m3u/feature-player/src/lib/video-player/video-player.component.html b/libs/playlist/m3u/feature-player/src/lib/video-player/video-player.component.html index 54aeee093..1b8a9b2cc 100644 --- a/libs/playlist/m3u/feature-player/src/lib/video-player/video-player.component.html +++ b/libs/playlist/m3u/feature-player/src/lib/video-player/video-player.component.html @@ -27,6 +27,7 @@
@if (activeChannel(); as activeChannel) { + @let playbackTarget = playbackChannel(); @if (activeChannel.radio === 'true' || shouldShowInlinePlayer(activeChannel)) {
@if (activeChannel.radio === 'true') { @@ -42,8 +43,8 @@ sources: [ { src: - activeChannel.url + - activeChannel.epgParams, + playbackTarget?.url + + playbackTarget?.epgParams, type: 'application/x-mpegURL', }, ], @@ -54,14 +55,14 @@ } @if (playerSettings.player === 'html5') { } @if (playerSettings.player === 'artplayer') { @@ -73,7 +74,9 @@ @if (activeChannel.radio !== 'true') {
- +
} 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 1f76c6f2d..13d74fe37 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 @@ -10,6 +10,7 @@ import { BehaviorSubject, of } from 'rxjs'; import { ChannelActions, selectActive, + selectActivePlaybackUrl, selectChannels, selectCurrentEpgProgram, } from 'm3u-state'; @@ -34,6 +35,7 @@ describe('VideoPlayerComponent', () => { const playlistId = signal('playlist-1'); const activeChannel = signal(null); + const activePlaybackUrl = signal(null); const channels = signal([]); const currentEpgProgram = signal(null); @@ -66,6 +68,8 @@ describe('VideoPlayerComponent', () => { switch (selector) { case selectActive: return activeChannel; + case selectActivePlaybackUrl: + return activePlaybackUrl; case selectChannels: return channels; case selectCurrentEpgProgram: @@ -143,6 +147,7 @@ describe('VideoPlayerComponent', () => { localStorage.removeItem('m3u-sidebar-width'); player.set(VideoPlayer.VideoJs); showCaptions.set(false); + activePlaybackUrl.set(null); currentEpgProgram.set(null); currentEpgProgram$.next(null); overlayMock.create.mockClear(); @@ -286,6 +291,25 @@ describe('VideoPlayerComponent', () => { ).not.toBeNull(); }); + it('uses the active playback override url when archive playback is active', () => { + syncStoreState(sampleChannel); + player.set(VideoPlayer.VideoJs); + activePlaybackUrl.set( + 'http://localhost/archive.m3u8?utc=123&lutc=456' + ); + + fixture.detectChanges(); + + expect(component.playbackChannel()?.url).toBe( + 'http://localhost/archive.m3u8?utc=123&lutc=456' + ); + + activePlaybackUrl.set(null); + fixture.detectChanges(); + + expect(component.playbackChannel()?.url).toBe(sampleChannel.url); + }); + it('updates the outer sidebar width while grouped view requests a larger total width', () => { fixture.detectChanges(); 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 9bf871527..7e573627f 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 @@ -18,6 +18,7 @@ import { Store } from '@ngrx/store'; import { StorageMap } from '@ngx-pwa/local-storage'; import { TranslatePipe } from '@ngx-translate/core'; import { ResizableDirective } from 'components'; +import { isM3uCatchupPlaybackSupported } from 'm3u-utils'; import { PlaylistContextFacade } from '@iptvnator/playlist/shared/util'; import { COMPONENT_OVERLAY_REF, @@ -28,6 +29,7 @@ import { ChannelActions, PlaylistActions, selectActive, + selectActivePlaybackUrl, selectChannels, selectCurrentEpgProgram, } from 'm3u-state'; @@ -114,8 +116,31 @@ export class VideoPlayerComponent implements OnInit, OnDestroy { /** Active selected channel */ readonly activeChannel = this.store.selectSignal(selectActive); + readonly activePlaybackUrl = this.store.selectSignal( + selectActivePlaybackUrl + ); readonly activePlaylistId = this.playlistContext.resolvedPlaylistId; readonly channels = this.store.selectSignal(selectChannels); + readonly archivePlaybackAvailable = computed(() => + isM3uCatchupPlaybackSupported(this.activeChannel()) + ); + readonly playbackChannel = computed(() => { + const activeChannel = this.activeChannel(); + if (!activeChannel) { + return null; + } + + const playbackUrl = this.activePlaybackUrl(); + if (!playbackUrl) { + return activeChannel; + } + + return { + ...activeChannel, + url: playbackUrl, + epgParams: '', + } as Channel; + }); readonly sidebarStorageKey = computed(() => this.activeView() === 'groups' ? M3U_GROUPS_SIDEBAR_STORAGE_KEY diff --git a/libs/portal/shared/ui/src/lib/components/unified-collection/unified-live-tab.component.html b/libs/portal/shared/ui/src/lib/components/unified-collection/unified-live-tab.component.html index 59369bd04..84568718c 100644 --- a/libs/portal/shared/ui/src/lib/components/unified-collection/unified-live-tab.component.html +++ b/libs/portal/shared/ui/src/lib/components/unified-collection/unified-live-tab.component.html @@ -112,6 +112,9 @@ } @else { diff --git a/libs/portal/shared/ui/src/lib/components/unified-collection/unified-live-tab.component.ts b/libs/portal/shared/ui/src/lib/components/unified-collection/unified-live-tab.component.ts index 3c5214ed6..369f8cc88 100644 --- a/libs/portal/shared/ui/src/lib/components/unified-collection/unified-live-tab.component.ts +++ b/libs/portal/shared/ui/src/lib/components/unified-collection/unified-live-tab.component.ts @@ -12,6 +12,7 @@ import { import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { isM3uCatchupPlaybackSupported } from 'm3u-utils'; import { matchesOpenLiveCollectionItem, OpenLiveCollectionItemState, @@ -106,6 +107,9 @@ export class UnifiedLiveTabComponent { return detail.channel ?? null; }); + readonly currentM3uArchivePlaybackAvailable = computed(() => + isM3uCatchupPlaybackSupported(this.currentM3uChannel()) + ); readonly activeRadioChannel = computed(() => { const channel = this.currentM3uChannel(); return channel?.radio === 'true' ? channel : null; diff --git a/libs/portal/xtream/feature/src/lib/live-stream-layout/live-stream-layout.component.html b/libs/portal/xtream/feature/src/lib/live-stream-layout/live-stream-layout.component.html index 60b6106f0..e8bd8c2e9 100644 --- a/libs/portal/xtream/feature/src/lib/live-stream-layout/live-stream-layout.component.html +++ b/libs/portal/xtream/feature/src/lib/live-stream-layout/live-stream-layout.component.html @@ -107,6 +107,9 @@ } @else if (!isElectron && epgItems().length > 0) {