diff --git a/apps/electron-backend/src/app/api/main.preload.ts b/apps/electron-backend/src/app/api/main.preload.ts index b91fafabb..777495ce6 100644 --- a/apps/electron-backend/src/app/api/main.preload.ts +++ b/apps/electron-backend/src/app/api/main.preload.ts @@ -136,4 +136,5 @@ contextBridge.exposeInMainWorld('electron', { ipcRenderer.invoke('DB_REMOVE_RECENT_ITEM', contentId, playlistId), dbGetContentByXtreamId: (xtreamId: number, playlistId: string) => ipcRenderer.invoke('DB_GET_CONTENT_BY_XTREAM_ID', xtreamId, playlistId), + dbDeleteAllPlaylists: () => ipcRenderer.invoke('DB_DELETE_ALL_PLAYLISTS'), }); diff --git a/apps/electron-backend/src/app/events/database.events.ts b/apps/electron-backend/src/app/events/database.events.ts index 0e19f1548..82fad2b88 100644 --- a/apps/electron-backend/src/app/events/database.events.ts +++ b/apps/electron-backend/src/app/events/database.events.ts @@ -985,3 +985,31 @@ ipcMain.handle( } } ); + +/** + * Delete all playlists and related data from SQLite + */ +ipcMain.handle('DB_DELETE_ALL_PLAYLISTS', async () => { + try { + const db = await getDatabase(); + + // Delete in order respecting foreign key constraints + // First delete favorites and recently_viewed (they reference content) + await db.delete(schema.favorites); + await db.delete(schema.recentlyViewed); + + // Then delete content (references categories) + await db.delete(schema.content); + + // Then delete categories (references playlists) + await db.delete(schema.categories); + + // Finally delete playlists + await db.delete(schema.playlists); + + return { success: true }; + } catch (error) { + console.error('Error deleting all playlists:', error); + throw error; + } +}); diff --git a/libs/m3u-state/src/lib/effects.ts b/libs/m3u-state/src/lib/effects.ts index bc8d44346..749d91b05 100644 --- a/libs/m3u-state/src/lib/effects.ts +++ b/libs/m3u-state/src/lib/effects.ts @@ -17,6 +17,7 @@ import { } from 'rxjs'; import { DataService, EpgService, PlaylistsService } from 'services'; import { + GLOBAL_FAVORITES_PLAYLIST_ID, OPEN_MPV_PLAYER, OPEN_VLC_PLAYER, Playlist, @@ -71,6 +72,10 @@ export class PlaylistEffects { return this.actions$.pipe( ofType(PlaylistActions.setFavorites), combineLatestWith(this.store.select(selectActivePlaylistId)), + filter( + ([, playlistId]) => + playlistId !== GLOBAL_FAVORITES_PLAYLIST_ID + ), switchMap(([action, playlistId]) => this.playlistsService.setFavorites( playlistId, @@ -207,9 +212,25 @@ export class PlaylistEffects { () => { return this.actions$.pipe( ofType(PlaylistActions.removePlaylist), - switchMap((action) => - this.playlistsService.deletePlaylist(action.playlistId) - ) + switchMap(async (action) => { + // Delete from IndexedDB + await firstValueFrom( + this.playlistsService.deletePlaylist(action.playlistId) + ); + // Also delete from SQLite if running in Electron + if ((window as any).electron?.dbDeletePlaylist) { + try { + await (window as any).electron.dbDeletePlaylist( + action.playlistId + ); + } catch (error) { + console.error( + 'Error deleting playlist from SQLite:', + error + ); + } + } + }) ); }, { dispatch: false } @@ -350,8 +371,20 @@ export class PlaylistEffects { () => { return this.actions$.pipe( ofType(PlaylistActions.removeAllPlaylists), - switchMap(() => this.playlistsService.removeAll()), - tap(() => { + switchMap(async () => { + // Delete from IndexedDB + await firstValueFrom(this.playlistsService.removeAll()); + // Also delete from SQLite if running in Electron + if ((window as any).electron?.dbDeleteAllPlaylists) { + try { + await (window as any).electron.dbDeleteAllPlaylists(); + } catch (error) { + console.error( + 'Error deleting playlists from SQLite:', + error + ); + } + } this.snackBar.open( this.translate.instant('SETTINGS.PLAYLISTS_REMOVED'), undefined,