diff --git a/libs/portal/xtream/feature/src/lib/vod-details/vod-details-route-playback.spec.ts b/libs/portal/xtream/feature/src/lib/vod-details/vod-details-route-playback.spec.ts
index 208938ad7..786c15957 100644
--- a/libs/portal/xtream/feature/src/lib/vod-details/vod-details-route-playback.spec.ts
+++ b/libs/portal/xtream/feature/src/lib/vod-details/vod-details-route-playback.spec.ts
@@ -143,6 +143,30 @@ describe('VodDetailsRouteComponent — playback actions', () => {
expect(playDownload).not.toHaveBeenCalled();
});
+ it('stops external playback without a usable provider item', async () => {
+ currentPlaylist.set({ id: 'playlist-1' });
+ downloadsAvailable.set(true);
+ isDownloaded.mockReturnValue(true);
+ getDownloadedFilePath.mockReturnValue('/downloads/example.mp4');
+ activeSession.set({
+ player: 'mpv',
+ status: 'playing',
+ contentInfo: {
+ playlistId: 'playlist-1',
+ contentXtreamId: 650020,
+ contentType: 'vod',
+ },
+ });
+
+ const component = fixture.componentInstance;
+ expect(component.isExternalStopAction()).toBe(true);
+
+ await component.onPrimaryAction(null);
+
+ expect(closeSession).toHaveBeenCalled();
+ expect(playDownload).not.toHaveBeenCalled();
+ });
+
it('plays a completed download before provider resume or pin resolution', async () => {
currentPlaylist.set({ id: 'playlist-1' });
downloadsAvailable.set(true);
diff --git a/libs/portal/xtream/feature/src/lib/vod-details/vod-details-route.actions.spec.ts b/libs/portal/xtream/feature/src/lib/vod-details/vod-details-route.actions.spec.ts
index ddac03d9e..14f67a120 100644
--- a/libs/portal/xtream/feature/src/lib/vod-details/vod-details-route.actions.spec.ts
+++ b/libs/portal/xtream/feature/src/lib/vod-details/vod-details-route.actions.spec.ts
@@ -107,6 +107,15 @@ describe('VodDetailsRouteComponent fallback actions', () => {
container_extension: 'mp4',
},
}) as XtreamVodDetails;
+ const unplayableRichItem = (): XtreamVodDetails =>
+ ({
+ ...richItem(),
+ movie_data: {
+ stream_id: 650020,
+ name: 'Metadata movie',
+ container_extension: '',
+ },
+ }) as XtreamVodDetails;
beforeEach(async () => {
selectedItem.set(null);
downloadsAvailable.set(false);
@@ -430,6 +439,34 @@ describe('VodDetailsRouteComponent fallback actions', () => {
).toContain('DOWNLOADS.PLAY_LOCAL');
});
+ it('plays a rich downloaded movie locally without a usable provider source', async () => {
+ selectedItem.set(unplayableRichItem());
+ downloadsAvailable.set(true);
+ isDownloaded.mockReturnValue(true);
+ getDownloadedFilePath.mockReturnValue('/downloads/metadata-movie.mp4');
+
+ fixture.detectChanges();
+
+ const host = fixture.nativeElement as HTMLElement;
+ const primary =
+ host.querySelector
+ + {{ 'PORTALS.MULTI_SOURCE.PLAYING_FROM' | translate }} + + {{ + caption.source + }} + @if (multiSource.hasAlternatives()) { + + @if (caption.alternativeCount === 1) { + {{ + 'PORTALS.MULTI_SOURCE.ALSO_FOUND_IN_ONE' + | translate + }} + } @else { + {{ + 'PORTALS.MULTI_SOURCE.ALSO_FOUND_IN_OTHER' + | translate + : { + count: caption.alternativeCount, + } + }} + } + + } +
+ } } } diff --git a/libs/portal/xtream/feature/src/lib/vod-details/vod-details-route.component.ts b/libs/portal/xtream/feature/src/lib/vod-details/vod-details-route.component.ts index c548b30df..f60417f35 100644 --- a/libs/portal/xtream/feature/src/lib/vod-details/vod-details-route.component.ts +++ b/libs/portal/xtream/feature/src/lib/vod-details/vod-details-route.component.ts @@ -503,7 +503,7 @@ export class VodDetailsRouteComponent implements OnInit, OnDestroy { // make the control do the opposite of what it says — launching a // second player while the first keeps running. if (this.playback.isExternalStopAction()) { - this.playback.onPrimaryAction(vodItem); + await this.playback.stopExternalPlayback(); return; }