From 7ee6e97ceb0abf1c3d0ac8212c3360f5ab3fea47 Mon Sep 17 00:00:00 2001 From: 4gray Date: Mon, 27 Jul 2026 11:04:21 +0200 Subject: [PATCH] fix(stalker): preserve VOD series season shape --- .../stalker-operation-adapter.spec.ts | 43 +++++++++++++++++++ .../stalker-operation-adapter.ts | 12 +++++- .../src/lib/stalker-request-adapter.spec.ts | 4 ++ .../src/lib/stalker-request-adapter.ts | 2 + .../stalker-session-operations.interface.ts | 3 ++ 5 files changed, 62 insertions(+), 2 deletions(-) diff --git a/apps/electron-backend/src/app/services/stalker-session/stalker-operation-adapter.spec.ts b/apps/electron-backend/src/app/services/stalker-session/stalker-operation-adapter.spec.ts index 6b316c474..666524d35 100644 --- a/apps/electron-backend/src/app/services/stalker-session/stalker-operation-adapter.spec.ts +++ b/apps/electron-backend/src/app/services/stalker-session/stalker-operation-adapter.spec.ts @@ -197,6 +197,49 @@ describe('stalker-operation-adapter', () => { }); }); + it('preserves the distinct VOD-series season request shape', () => { + const mapped = mapRemote( + STALKER_SESSION_APPLICATION_OPERATIONS.SeriesSeasons, + { + contentType: 'vod', + seriesId: '51', + } + ); + + expect(mapped.parameters).toEqual({ + action: 'get_ordered_list', + JsHttpRequest: '1-xml', + movie_id: '51', + p: 1, + type: 'vod', + }); + expect( + mapped.mapResult({ + js: { + data: [ + { + id: 'season-2', + is_season: '1', + name: 'Season 2', + season_number: '2', + video_id: '51', + }, + ], + }, + }) + ).toEqual({ + seasons: [ + { + id: 'season-2', + isSeason: true, + number: 2, + title: 'Season 2', + videoId: '51', + }, + ], + }); + }); + it('normalizes catalog pages through an allowlist and drops secret-shaped raw fields', () => { const mapped = mapRemote( STALKER_SESSION_APPLICATION_OPERATIONS.CatalogItems, diff --git a/apps/electron-backend/src/app/services/stalker-session/stalker-operation-adapter.ts b/apps/electron-backend/src/app/services/stalker-session/stalker-operation-adapter.ts index 7b7ae882e..4c4754284 100644 --- a/apps/electron-backend/src/app/services/stalker-session/stalker-operation-adapter.ts +++ b/apps/electron-backend/src/app/services/stalker-session/stalker-operation-adapter.ts @@ -163,13 +163,19 @@ function mapSearch( function mapSeasons( parameters: StalkerSessionOperationParameters ): StalkerMappedOperation { - const seriesId = readEntityId(readRecord(parameters)['seriesId']); + const record = readRecord(parameters); + const seriesId = readEntityId(record['seriesId']); + const contentType = + record['contentType'] === undefined + ? 'series' + : readContentType(record['contentType'], ['series', 'vod']); return remote( { action: 'get_ordered_list', JsHttpRequest: JS_HTTP_REQUEST, movie_id: seriesId, - type: 'series', + ...(contentType === 'vod' ? { p: 1 } : {}), + type: contentType, }, mapSeasonResult ); @@ -410,9 +416,11 @@ function mapSeasonResult(value: unknown): StalkerSessionSeasonsResult { number, command: optionalString(record['cmd']), episodeNumbers: readNumberArray(record['series']), + isSeason: optionalBoolean(record['is_season']), title: optionalString(record['name']) ?? optionalString(record['title']), + videoId: optionalEntityId(record['video_id']), }), ]; }); diff --git a/libs/portal/stalker/data-access/src/lib/stalker-request-adapter.spec.ts b/libs/portal/stalker/data-access/src/lib/stalker-request-adapter.spec.ts index d0f2fcc32..0e1eccbdc 100644 --- a/libs/portal/stalker/data-access/src/lib/stalker-request-adapter.spec.ts +++ b/libs/portal/stalker/data-access/src/lib/stalker-request-adapter.spec.ts @@ -365,8 +365,10 @@ describe('mapStalkerSessionResultToLegacyResponse', () => { command: '/series/42', episodeNumbers: [3, 4], id: '42:2', + isSeason: true, number: 2, title: 'Season 2', + videoId: '42', }, ], } @@ -376,9 +378,11 @@ describe('mapStalkerSessionResultToLegacyResponse', () => { { cmd: '/series/42', id: '42:2', + is_season: true, name: 'Season 2', season_number: 2, series: [3, 4], + video_id: '42', }, ], }); diff --git a/libs/portal/stalker/data-access/src/lib/stalker-request-adapter.ts b/libs/portal/stalker/data-access/src/lib/stalker-request-adapter.ts index dafbd6b2f..31ec8e32d 100644 --- a/libs/portal/stalker/data-access/src/lib/stalker-request-adapter.ts +++ b/libs/portal/stalker/data-access/src/lib/stalker-request-adapter.ts @@ -148,10 +148,12 @@ export function mapStalkerSessionResultToLegacyResponse< js: seasons.seasons.map((season) => compact({ id: season.id, + is_season: season.isSeason, season_number: season.number, name: season.title, cmd: season.command, series: season.episodeNumbers, + video_id: season.videoId, }) ), }; diff --git a/libs/shared/interfaces/src/lib/stalker-session-operations.interface.ts b/libs/shared/interfaces/src/lib/stalker-session-operations.interface.ts index 7c35d9260..039be77d2 100644 --- a/libs/shared/interfaces/src/lib/stalker-session-operations.interface.ts +++ b/libs/shared/interfaces/src/lib/stalker-session-operations.interface.ts @@ -58,6 +58,7 @@ export interface StalkerSessionSearchParameters { export interface StalkerSessionSeriesSeasonsParameters { seriesId: StalkerSessionEntityId; + contentType?: 'series' | 'vod'; } export interface StalkerSessionSeriesEpisodesParameters { @@ -156,6 +157,8 @@ export interface StalkerSessionCategoriesResult { export interface StalkerSessionSeason { id: StalkerSessionEntityId; number: number; + isSeason?: boolean; + videoId?: StalkerSessionEntityId; title?: string; command?: string; episodeNumbers?: readonly number[];