From 9cd278256b0e9ef2f368acbcf5127c2bdcb9409c Mon Sep 17 00:00:00 2001 From: 4gray Date: Thu, 22 Jan 2026 13:32:04 +0100 Subject: [PATCH] fix: use specific listener cleanup instead of removeAllListeners Return unsubscribe function from onPlaybackPositionUpdate to ensure only the specific listener is removed on destroy, preventing issues with multiple store instances. Co-Authored-By: Claude Opus 4.5 --- .../src/app/api/main.preload.ts | 13 ++--- .../with-playback-positions.feature.ts | 52 ++++++++++--------- apps/web/src/typings.d.ts | 3 +- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/apps/electron-backend/src/app/api/main.preload.ts b/apps/electron-backend/src/app/api/main.preload.ts index 4cc3af233..bf8e461dd 100644 --- a/apps/electron-backend/src/app/api/main.preload.ts +++ b/apps/electron-backend/src/app/api/main.preload.ts @@ -28,15 +28,12 @@ contextBridge.exposeInMainWorld('electron', { ) => { ipcRenderer.on('EPG_PROGRESS_UPDATE', (_event, data) => callback(data)); }, - // Playback position update listener + // Playback position update listener - returns unsubscribe function onPlaybackPositionUpdate: (callback: (data: any) => void) => { - ipcRenderer.on('playback-position-update', (_event, data) => - callback(data) - ); - }, - // Remove playback position listener - removePlaybackPositionListener: () => { - ipcRenderer.removeAllListeners('playback-position-update'); + const handler = (_event: Electron.IpcRendererEvent, data: any) => + callback(data); + ipcRenderer.on('playback-position-update', handler); + return () => ipcRenderer.off('playback-position-update', handler); }, // DB save content progress listener onDbSaveContentProgress: (callback: (count: number) => void) => { diff --git a/apps/web/src/app/xtream-tauri/stores/features/with-playback-positions.feature.ts b/apps/web/src/app/xtream-tauri/stores/features/with-playback-positions.feature.ts index c7c87c417..8e08294f2 100644 --- a/apps/web/src/app/xtream-tauri/stores/features/with-playback-positions.feature.ts +++ b/apps/web/src/app/xtream-tauri/stores/features/with-playback-positions.feature.ts @@ -365,31 +365,35 @@ export function withPlaybackPositions() { }; }), - withHooks({ - onInit(store) { - if (window.electron?.onPlaybackPositionUpdate) { - window.electron.onPlaybackPositionUpdate((data: any) => { - console.log( - '[withPlaybackPositions] Received update:', - data + withHooks((store) => { + let unsubscribe: (() => void) | undefined; + + return { + onInit() { + if (window.electron?.onPlaybackPositionUpdate) { + unsubscribe = window.electron.onPlaybackPositionUpdate( + (data: any) => { + console.log( + '[withPlaybackPositions] Received update:', + data + ); + // Ensure playlistId is present + if (data.playlistId) { + store.savePosition(data.playlistId, data); + } else { + console.warn( + '[withPlaybackPositions] Missing playlistId in update', + data + ); + } + } ); - // Ensure playlistId is present - if (data.playlistId) { - store.savePosition(data.playlistId, data); - } else { - console.warn( - '[withPlaybackPositions] Missing playlistId in update', - data - ); - } - }); - } - }, - onDestroy(store) { - if (window.electron?.removePlaybackPositionListener) { - window.electron.removePlaybackPositionListener(); - } - }, + } + }, + onDestroy() { + unsubscribe?.(); + }, + }; }) ); } diff --git a/apps/web/src/typings.d.ts b/apps/web/src/typings.d.ts index 9cb7b3fa4..6a36da2ce 100644 --- a/apps/web/src/typings.d.ts +++ b/apps/web/src/typings.d.ts @@ -17,8 +17,7 @@ interface Window { onEpgProgress: (callback: (data: { url: string; status: 'loading' | 'complete' | 'error'; stats?: { totalChannels: number; totalPrograms: number }; error?: string }) => void) => void; onDbSaveContentProgress: (callback: (count: number) => void) => void; removeDbSaveContentProgress: () => void; - onPlaybackPositionUpdate: (callback: (data: any) => void) => void; - removePlaybackPositionListener: () => void; + onPlaybackPositionUpdate: (callback: (data: any) => void) => () => void; // Files & System saveFileDialog: (defaultPath: string, filters?: { name: string; extensions: string[] }[]) => Promise;