From 0524429fbd364b1fa35c42fdf0f4fe4623f87dc7 Mon Sep 17 00:00:00 2001 From: 4gray Date: Sat, 3 Oct 2026 13:14:07 +0200 Subject: [PATCH] fix(portals): fourteenth review round on the cinematic details - The hero keys its one-time stage/compact decision on a stable content identity (provider + id) that every host passes, so a TMDB rename plus a late backdrop no longer flips the visible hero. - An explicit Stalker movie launch joins its host's start generation: it supersedes an earlier start and is dropped once a Play, Start Over or later launch begins, on the controller, search, collection and catalog hosts. Co-Authored-By: Claude Fable 5.1 --- .../m3u-vod-detail.component.html | 1 + .../m3u-vod-detail.component.spec.ts | 1 + .../stalker-catalog-detail.component.ts | 16 ++++---- .../stalker-series-view.component.html | 18 +++++++-- .../lib/stalker-vod-detail-actions.spec.ts | 24 +++++++++++- .../src/lib/stalker-vod-detail-actions.ts | 39 ++++++++++++++++--- .../lib/stalker-vod-playback-controller.ts | 20 +++++++--- .../serial-details.component.html | 23 ++++++++--- .../vod-details-route.component.html | 26 +++++++++---- .../content-hero.component.spec.ts | 18 +++++++++ .../content-hero/content-hero.component.ts | 10 ++++- .../portal-detail-shell.component.html | 1 + .../portal-detail-shell.component.ts | 2 + .../vod-details/vod-details.component.html | 9 ++++- .../lib/vod-details/vod-details.component.ts | 4 ++ 15 files changed, 170 insertions(+), 42 deletions(-) diff --git a/libs/playlist/m3u/feature-player/src/lib/m3u-vod-detail/m3u-vod-detail.component.html b/libs/playlist/m3u/feature-player/src/lib/m3u-vod-detail/m3u-vod-detail.component.html index 8a5be583e..8a2505391 100644 --- a/libs/playlist/m3u/feature-player/src/lib/m3u-vod-detail/m3u-vod-detail.component.html +++ b/libs/playlist/m3u/feature-player/src/lib/m3u-vod-detail/m3u-vod-detail.component.html @@ -1,5 +1,6 @@ (); readonly posterUrl = input(); readonly backdropUrl = input(); + readonly contentKey = input(null); readonly progress = input(null); readonly isLoading = input(false); readonly errorMessage = input(); diff --git a/libs/portal/stalker/feature/src/lib/stalker-catalog-detail/stalker-catalog-detail.component.ts b/libs/portal/stalker/feature/src/lib/stalker-catalog-detail/stalker-catalog-detail.component.ts index 37d267c7c..a648bef89 100644 --- a/libs/portal/stalker/feature/src/lib/stalker-catalog-detail/stalker-catalog-detail.component.ts +++ b/libs/portal/stalker/feature/src/lib/stalker-catalog-detail/stalker-catalog-detail.component.ts @@ -49,7 +49,10 @@ import { StalkerSeriesViewComponent } from '../stalker-series-view/stalker-serie import { startStalkerVodDownload } from './stalker-vod-download'; import { createStalkerVodWatchedToggle } from '../stalker-vod-watched-toggle'; -import { createStalkerVodDetailActions } from '../stalker-vod-detail-actions'; +import { + createStalkerVodDetailActions, + beginTrackedExternalLaunch, +} from '../stalker-vod-detail-actions'; import { createPlaybackSessionKey } from '@iptvnator/playback/util'; @Component({ @@ -83,7 +86,7 @@ export class StalkerCatalogDetailComponent implements OnDestroy { private readonly downloadsService = inject(DownloadsService); private readonly logger = createLogger('StalkerCatalogDetail'); private readonly favoritesRefresh = createRefreshTrigger(); - private playbackRequestId = 0; + playbackRequestId = 0; private currentPlaybackOwnerKey = ''; readonly contentType = this.catalog.contentType; @@ -101,7 +104,7 @@ export class StalkerCatalogDetailComponent implements OnDestroy { ? createPlaybackSessionKey({ kind: 'vod', sourceId, contentId }) : ''; }); - private readonly playbackOwnerKey = computed(() => + readonly playbackOwnerKey = computed(() => JSON.stringify([this.playbackSessionKey(), this.contentType()]) ); private readonly selectedVodPosition = signal( @@ -116,7 +119,7 @@ export class StalkerCatalogDetailComponent implements OnDestroy { * keyed by its owner: a stale resolution for the previous movie must not * hold the next movie's toggle hostage. */ - private readonly pendingStart = createPendingPlaybackStart(); + readonly pendingStart = createPendingPlaybackStart(); readonly playbackStartPending = computed(() => this.pendingStart.isPendingFor(this.playbackOwnerKey()) ); @@ -278,10 +281,7 @@ export class StalkerCatalogDetailComponent implements OnDestroy { selectedVodPosition: this.selectedVodPosition, discardPendingPositionLoad: () => ++this.positionLoadGeneration, beforeExternalLaunch: () => this.closeInlinePlayer(), - beginPendingStart: () => { - const startId = this.pendingStart.begin(this.playbackOwnerKey()); - return () => this.pendingStart.settle(startId); - }, + beginPendingStart: () => beginTrackedExternalLaunch(this), afterProgressReset: (playlistId) => void this.catalog.refreshPositions(playlistId), download: (item) => diff --git a/libs/portal/stalker/feature/src/lib/stalker-series-view/stalker-series-view.component.html b/libs/portal/stalker/feature/src/lib/stalker-series-view/stalker-series-view.component.html index 0d7f72c7a..8c02ea4ce 100644 --- a/libs/portal/stalker/feature/src/lib/stalker-series-view/stalker-series-view.component.html +++ b/libs/portal/stalker/feature/src/lib/stalker-series-view/stalker-series-view.component.html @@ -7,6 +7,7 @@ [posterUrl]="serial.info.movie_image" [backdropUrl]="serial.info.tmdb_backdrop" [trailerBackdropUrl]="heroPresenter.trailerBackdropUrl()" + [contentKey]="'stalker-series:' + serial.id" [playbackActive]="!!inlinePlayback()" (backClicked)="goBack()" (closePlayerRequested)="closeInlinePlayer()" @@ -18,7 +19,10 @@ } @if (hero.statusLabel(); as status) { - + {{ status }} } @@ -44,7 +48,9 @@ @for (genre of hero.genreChips(); track genre.label) { @if (!$first) { - + } @if (genre.facet; as facet) {