diff --git a/libs/playlist/shared/ui/src/lib/playlist-refresh-action.service.spec.ts b/libs/playlist/shared/ui/src/lib/playlist-refresh-action.service.spec.ts index b87054a3d..e5ebf5ee1 100644 --- a/libs/playlist/shared/ui/src/lib/playlist-refresh-action.service.spec.ts +++ b/libs/playlist/shared/ui/src/lib/playlist-refresh-action.service.spec.ts @@ -468,6 +468,8 @@ describe('PlaylistRefreshActionService', () => { }, ], playbackPositions: [], + // Normalized state always carries every collection, empty or not. + sourcePins: [], }); expect(store.dispatch).toHaveBeenCalledWith( PlaylistActions.updatePlaylistMeta({ diff --git a/libs/playlist/shared/ui/src/lib/recent-playlists/recent-playlists.component.spec.ts b/libs/playlist/shared/ui/src/lib/recent-playlists/recent-playlists.component.spec.ts index b9de1ca97..8c6b5e251 100644 --- a/libs/playlist/shared/ui/src/lib/recent-playlists/recent-playlists.component.spec.ts +++ b/libs/playlist/shared/ui/src/lib/recent-playlists/recent-playlists.component.spec.ts @@ -555,6 +555,8 @@ describe('RecentPlaylistsComponent busy state', () => { }, ], playbackPositions: [], + // Normalized state always carries every collection, empty or not. + sourcePins: [], }); expect(router.navigate).toHaveBeenCalledWith([ '/workspace', diff --git a/libs/shared/interfaces/src/lib/xtream-restore-state.util.spec.ts b/libs/shared/interfaces/src/lib/xtream-restore-state.util.spec.ts index 45a4226c0..6c117b995 100644 --- a/libs/shared/interfaces/src/lib/xtream-restore-state.util.spec.ts +++ b/libs/shared/interfaces/src/lib/xtream-restore-state.util.spec.ts @@ -6,6 +6,7 @@ describe('normalizeXtreamPendingRestoreState', () => { favorites: [], recentlyViewed: [], playbackPositions: [], + sourcePins: [], }; it.each([null, undefined, 'text', 42, []])( @@ -17,6 +18,48 @@ describe('normalizeXtreamPendingRestoreState', () => { } ); + describe('source pins', () => { + it('keeps usable pins and drops the rest', () => { + const state = normalizeXtreamPendingRestoreState({ + sourcePins: [ + { matchKey: 'tmdb:603', contentId: 501 }, + // Nothing addressable: writing either would occupy the + // unique key of a film it does not describe. + { matchKey: '', contentId: 7 }, + { matchKey: 'title:dune:1984' }, + { contentId: 9 }, + 'not an object', + ], + }); + + expect(state.sourcePins).toEqual([ + { matchKey: 'tmdb:603', contentId: 501 }, + ]); + }); + + it('keeps a string updatedAt and drops anything else', () => { + const state = normalizeXtreamPendingRestoreState({ + sourcePins: [ + { + matchKey: 'tmdb:603', + contentId: 501, + updatedAt: '2026-07-06T09:00:00.000Z', + }, + { matchKey: 'tmdb:604', contentId: 502, updatedAt: 17 }, + ], + }); + + expect(state.sourcePins).toEqual([ + { + matchKey: 'tmdb:603', + contentId: 501, + updatedAt: '2026-07-06T09:00:00.000Z', + }, + { matchKey: 'tmdb:604', contentId: 502 }, + ]); + }); + }); + it('falls back to empty arrays for missing or non-array fields', () => { expect( normalizeXtreamPendingRestoreState({