diff --git a/.changes/dashboard-fresh-m3u-favorite.md b/.changes/dashboard-fresh-m3u-favorite.md new file mode 100644 index 000000000..68a104a3b --- /dev/null +++ b/.changes/dashboard-fresh-m3u-favorite.md @@ -0,0 +1,8 @@ +--- +type: fix +area: dashboard +--- + +An M3U channel added to favorites right before opening the dashboard now +appears in the favorites rail immediately, instead of only after the next +reload. diff --git a/libs/services/src/lib/playlists.service.spec.ts b/libs/services/src/lib/playlists.service.spec.ts index 71a4961f6..54d5e49b4 100644 --- a/libs/services/src/lib/playlists.service.spec.ts +++ b/libs/services/src/lib/playlists.service.spec.ts @@ -345,6 +345,49 @@ describe('PlaylistsService', () => { expect(electron.dbGetAppPlaylists).not.toHaveBeenCalled(); }); + it('reads resolved M3U favorites only after a queued favorites write lands', async () => { + let storedFavorites: string[] = []; + let releaseWrite!: () => void; + const writeGate = new Promise((resolve) => { + releaseWrite = resolve; + }); + const electron = { + dbGetAppPlaylist: jest.fn(async () => { + await writeGate; + return { _id: 'playlist-1', favorites: storedFavorites }; + }), + dbGetAppPlaylistFavoriteChannels: jest.fn(async () => + storedFavorites.map((id) => ({ id })) + ), + dbGetAppPlaylists: jest.fn(async () => []), + dbGetAppState: jest.fn(async (key: string) => + key === SQLITE_PLAYLIST_MIGRATION_FLAG || + key === STALKER_PLAYLIST_METADATA_MIGRATION_FLAG + ? '1' + : null + ), + dbSetAppState: jest.fn(), + dbUpsertAppPlaylist: jest.fn(async (playlist: Playlist) => { + storedFavorites = playlist.favorites as string[]; + }), + dbUpsertAppPlaylists: jest.fn(), + }; + testWindow.electron = electron; + + const service = createService(); + const write = firstValueFrom( + service.updateFavorites('playlist-1', ['channel-1']) + ); + const read = firstValueFrom( + service.getM3uFavoriteChannels('playlist-1') + ); + await new Promise((resolve) => setTimeout(resolve)); + releaseWrite(); + + await write; + await expect(read).resolves.toEqual([{ id: 'channel-1' }]); + }); + it('falls back from resolved M3U favorites when SQLite playlist migration is incomplete', async () => { const electron = { dbGetAppPlaylist: jest.fn(), diff --git a/libs/services/src/lib/playlists.service.ts b/libs/services/src/lib/playlists.service.ts index 9719348bf..b00cbb034 100644 --- a/libs/services/src/lib/playlists.service.ts +++ b/libs/services/src/lib/playlists.service.ts @@ -1092,6 +1092,9 @@ export class PlaylistsService { return from( (async () => { + // A favorite toggled just before this read may still be queued; + // the queue tail never rejects. + await this.playlistWriteQueues.get(playlistId); const alreadyMigrated = await electron.dbGetAppState( SQLITE_PLAYLIST_MIGRATION_FLAG );