fix(portals): a failed episode launch is reported to its own visit only

The menu compares the playback service's series+visit page token, so a
launch started on an earlier visit of the same series does not surface
its failure after the viewer came back.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
4grayandClaude Fable 5.1 committed 2026-10-03 15:08:12 +02:00
1 parent 426de69efb
commit 023c3444af
3 files changed
+9 -9

No files matched your search

@@ -40,6 +40,8 @@ interface SerialDetailsMenuBindings {
/** A forced launch has not published its session yet: bulk watched actions would include it. */
readonly startPending: Signal<boolean>;
readonly resetProgress: () => Promise<void>;
/** Series and visit on screen; a launch's failure is reported to that page only. */
readonly pageToken: () => string;
/** The regular episode start forced to MPV/VLC, so history and the launch position are recorded. */
readonly openEpisodeExternally: (
episode: XtreamSerieEpisode,
@@ -242,8 +244,7 @@ export class SerialDetailsMenuService {
if (!bindings || !episode) {
return;
}
const seriesId = this.seriesId();
const playlistId = this.xtreamStore.currentPlaylist()?.id;
const token = bindings.pageToken();
try {
await bindings.openEpisodeExternally(
episode,
@@ -251,12 +252,10 @@ export class SerialDetailsMenuService {
);
} catch (error) {
this.logger.warn('External episode launch failed', error);
// The page is reused across series: a failure that lands after
// the viewer moved on is not the new title's problem.
if (
this.seriesId() === seriesId &&
this.xtreamStore.currentPlaylist()?.id === playlistId
) {
// The page is reused across series and visits: a failure that
// lands after the viewer moved on (or came back) is not the
// current visit's problem.
if (bindings.pageToken() === token) {
this.notify('PORTALS.PLAYBACK_ERROR');
}
}
@@ -413,7 +413,7 @@ export class SerialDetailsPlaybackService {
* only while the page still shows what it showed when the launch
* started, not after leaving and coming back.
*/
private pageToken(): string {
pageToken(): string {
return `${this.launchOwner()}#${this.pageGeneration}`;
}
@@ -229,6 +229,7 @@ export class SerialDetailsComponent implements OnDestroy {
this.playback.activeEpisodeId() !== null
),
startPending: this.playback.forcedLaunchPending,
pageToken: () => this.playback.pageToken(),
resetProgress: () => this.resetProgress(),
openEpisodeExternally: (episode, player) =>
this.playback.playEpisode(episode, player),