diff --git a/src/main/index.ts b/src/main/index.ts index aba8894..143c6e1 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -260,6 +260,15 @@ if (isPrimaryInstance) { // link it carried and hand it to the window we already have. app.on('second-instance', (_e, argv) => { if (!mainWindow) return + // A scheduled `--sync` relaunch (Task Scheduler) hit the already-running instance: + // run the watched-source sync in this window instead of no-opping. Without this the + // daily auto-download never fires while AeroFetch is open — e.g. minimize-to-tray + // users. Deliberately does NOT focus the window, so the daily sync stays unobtrusive + // (mirrors the fresh-launch `--sync` showInactive path in createWindow). + if (isSyncLaunch(argv)) { + mainWindow.webContents.send(IpcChannels.runWatchedSync) + return + } focusWindow(mainWindow) const incomingUrl = extractIncomingUrl(argv) if (incomingUrl) mainWindow.webContents.send(IpcChannels.externalUrl, incomingUrl) diff --git a/src/preload/index.ts b/src/preload/index.ts index 51b978e..216ef99 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -279,6 +279,14 @@ const api = { return () => ipcRenderer.removeListener(IpcChannels.indexProgress, listener) }, + /** Subscribe to the "run watched-source sync now" nudge a scheduled `--sync` relaunch + * sends when it hits the already-running instance. Returns an unsubscribe function. */ + onRunWatchedSync: (cb: () => void): (() => void) => { + const listener = (): void => cb() + ipcRenderer.on(IpcChannels.runWatchedSync, listener) + return () => ipcRenderer.removeListener(IpcChannels.runWatchedSync, listener) + }, + // --- Built-in yt-dlp terminal (Phase N) --- /** Run the bundled yt-dlp with raw args; output streams via onTerminalOutput. */ diff --git a/src/renderer/src/mockApi.ts b/src/renderer/src/mockApi.ts index 7a4407f..8d5ae21 100644 --- a/src/renderer/src/mockApi.ts +++ b/src/renderer/src/mockApi.ts @@ -271,6 +271,7 @@ export const mockApi: Api = { onSystemThemeUpdate: () => () => {}, openHighContrastSettings: async () => {}, onExternalUrl: () => () => {}, + onRunWatchedSync: () => () => {}, // Media-manager sources — a seeded channel so the (Phase H) Library view has // demo data in this browser-only preview. listSources: async () => [ diff --git a/src/renderer/src/store/sources.ts b/src/renderer/src/store/sources.ts index cd7d16c..6096825 100644 --- a/src/renderer/src/store/sources.ts +++ b/src/renderer/src/store/sources.ts @@ -485,13 +485,16 @@ if (!PREVIEW) { .listSources() .then((sources) => { useSources.setState({ sources }) - // If any source is watched, kick off a sync shortly after launch (covers the - // scheduled `--sync` launch and a normal launch alike). + // If any source is watched, kick off a sync shortly after launch (covers a fresh + // `--sync` launch and a normal launch alike). if (sources.some((s) => s.watched)) { setTimeout(() => useSources.getState().syncWatched(), 1500) } }) .catch(logError('startup listSources')) + // A scheduled `--sync` relaunch that hit the already-running instance nudges us here, + // so the daily sync fires even when AeroFetch was already open (e.g. tray mode). + window.api.onRunWatchedSync?.(() => useSources.getState().syncWatched()) window.api.onIndexProgress((p: IndexProgress) => { useSources.setState({ indexing: { diff --git a/src/shared/ipc.ts b/src/shared/ipc.ts index 39f7a0c..24870e8 100644 --- a/src/shared/ipc.ts +++ b/src/shared/ipc.ts @@ -105,6 +105,9 @@ export const IpcChannels = { scheduledSyncSet: 'sources:scheduled-sync-set', /** main → renderer push channel for live indexing progress */ indexProgress: 'sources:index-progress', + /** main → renderer: a scheduled `--sync` relaunch hit the running instance — run the + * watched-source sync here instead of no-opping (Phase J) */ + runWatchedSync: 'sources:run-sync', // --- Built-in yt-dlp terminal (Phase N) --- terminalRun: 'terminal:run', terminalCancel: 'terminal:cancel',