diff --git a/.changes/workspace-startup-first-card-ipc.md b/.changes/workspace-startup-first-card-ipc.md index fc6c7e758..7df875c2c 100644 --- a/.changes/workspace-startup-first-card-ipc.md +++ b/.changes/workspace-startup-first-card-ipc.md @@ -3,4 +3,4 @@ type: perf area: workspace --- -On launch the workspace reads the source list once instead of twice before its first source card (journey J1, `renderer.ipcCallsToFirstCard`), and M3U favorites stop re-checking the finished playlist migration for every playlist. +On launch the workspace reads the source list once instead of twice before its first source card (journey J1, `renderer.ipcCallsToFirstCard`). diff --git a/libs/services/src/lib/playlists.service.inventory-read.spec.ts b/libs/services/src/lib/playlists.service.inventory-read.spec.ts index 127984a8a..800171f83 100644 --- a/libs/services/src/lib/playlists.service.inventory-read.spec.ts +++ b/libs/services/src/lib/playlists.service.inventory-read.spec.ts @@ -44,7 +44,6 @@ describe('PlaylistsService inventory reads', () => { runtime: { supportsSqlite: true }, electronMigrationPromise: null, pendingMetas: null, - migrated: false, playlistWriteQueues: new Map(), }); const settle = async (index: number, playlists: Playlist[]) => { @@ -102,50 +101,4 @@ describe('PlaylistsService inventory reads', () => { await expect(freshRead).resolves.toEqual([added]); expect(electron.dbGetAppPlaylistMetas).toHaveBeenCalledTimes(2); }); - - it('reads the SQLite migration receipt once for M3U favorites', async () => { - const { electron, service, settle } = setup(); - - const inventory = firstValueFrom(service.getAllPlaylists()); - await settle(0, []); - await inventory; - const receiptReads = electron.dbGetAppState.mock.calls.length; - await firstValueFrom(service.getM3uFavoriteChannels('one')); - await firstValueFrom(service.getM3uFavoriteChannels('two')); - - expect(electron.dbGetAppState).toHaveBeenCalledTimes(receiptReads); - expect( - electron.dbGetAppPlaylistFavoriteChannels - ).toHaveBeenCalledTimes(2); - }); - - it.each([ - ['an empty legacy store', [], { success: true, count: 0 }, true], - ['a committed migration', [source('legacy')], { success: true, count: 1 }, true], - ['an uncommitted migration', [source('legacy')], { success: false, count: 0 }, false], - ])( - 'trusts the receipt written by %s in this session', - async (_case, legacy, result, confirmed) => { - const { electron, service, settle } = setup(); - electron.dbGetAppState.mockImplementation(async (key: string) => - key === 'm3u-playlists-indexeddb-to-sqlite-v1' ? null : '1' - ); - Object.assign(electron, { - dbMigrateAppPlaylists: jest.fn(async () => result), - }); - Object.assign(service, { - dbService: { getAll: jest.fn(() => of(legacy)) }, - }); - - const inventory = firstValueFrom(service.getAllPlaylists()); - await settle(0, []); - await inventory; - const receiptReads = electron.dbGetAppState.mock.calls.length; - await firstValueFrom(service.getM3uFavoriteChannels('one')); - - expect(electron.dbGetAppState).toHaveBeenCalledTimes( - receiptReads + (confirmed ? 0 : 1) - ); - } - ); }); diff --git a/libs/services/src/lib/playlists.service.spec.ts b/libs/services/src/lib/playlists.service.spec.ts index 172e2ef87..6b5332a2a 100644 --- a/libs/services/src/lib/playlists.service.spec.ts +++ b/libs/services/src/lib/playlists.service.spec.ts @@ -61,7 +61,6 @@ describe('PlaylistsService', () => { electronMigrationPromise: null, indexedDbMigrationPromise: null, pendingMetas: null, - migrated: false, playlistWriteQueues: new Map(), playlistDeleteCleanups: [], }); diff --git a/libs/services/src/lib/playlists.service.ts b/libs/services/src/lib/playlists.service.ts index 2cc219fa3..143d7a798 100644 --- a/libs/services/src/lib/playlists.service.ts +++ b/libs/services/src/lib/playlists.service.ts @@ -78,9 +78,7 @@ type PlaylistStorageElectronApi = { playlist: Playlist, operationId?: string ) => Promise; - dbMigrateAppPlaylists: ( - playlists: Playlist[] - ) => Promise<{ success: boolean; count: number }>; + dbMigrateAppPlaylists: (playlists: Playlist[]) => Promise; dbRecoverLegacyPlaylists?: () => Promise; dbUpsertAppPlaylists: (playlists: Playlist[]) => Promise; }; @@ -122,8 +120,6 @@ export class PlaylistsService { // XMLTV source reconciliation); both share one worker round trip. Only a // pending read is shared, and every SQLite write detaches it. private pendingMetas: Promise | null = null; - // The IndexedDB → SQLite receipt is written once and never cleared. - private migrated = false; private indexedDbMigrationPromise: Promise | null = null; private readonly playlistWriteQueues = new Map>(); @@ -203,21 +199,17 @@ export class PlaylistsService { if ( (await electron.dbGetAppState(SQLITE_PLAYLIST_MIGRATION_FLAG)) === '1' - ) { - this.migrated = true; + ) return; - } const playlists = await firstValueFrom( this.dbService.getAll(DbStores.Playlists) ); if (playlists.length) { // The worker commits rows and the receipt atomically. Keep the // original IndexedDB as a recovery source, even after success. - const result = await electron.dbMigrateAppPlaylists(playlists); - this.migrated = result?.success === true; + await electron.dbMigrateAppPlaylists(playlists); } else { await electron.dbSetAppState(SQLITE_PLAYLIST_MIGRATION_FLAG, '1'); - this.migrated = true; } } @@ -1099,14 +1091,11 @@ export class PlaylistsService { return from( (async () => { - if (!this.migrated) { - const alreadyMigrated = await electron.dbGetAppState( - SQLITE_PLAYLIST_MIGRATION_FLAG - ); - if (alreadyMigrated !== '1') { - return null; - } - this.migrated = true; + const alreadyMigrated = await electron.dbGetAppState( + SQLITE_PLAYLIST_MIGRATION_FLAG + ); + if (alreadyMigrated !== '1') { + return null; } return getFavoriteChannels(playlistId);