From e60a65b3d0c8267a1dbadc109bc27339a96b56da Mon Sep 17 00:00:00 2001 From: 4gray Date: Sat, 3 Oct 2026 09:13:04 +0200 Subject: [PATCH] fix(electron): re-probe mpv after a late login shell PATH either way A Linux mpv probe that ran on the inherited PATH can be wrong in both directions: the login shell PATH may add mpv or drop the directory the inherited one found it in. forgetLinuxMpvExecutableProbe() now clears a found result as well as a missing one. Co-Authored-By: Claude Opus 5.5 --- .../src/app/events/embedded-mpv.events.spec.ts | 10 +++++----- .../src/app/events/embedded-mpv.events.ts | 4 ++-- .../services/embedded-mpv-native.service.spec.ts | 7 ++++--- .../src/app/services/embedded-mpv-native.service.ts | 13 ++++++------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/apps/electron-backend/src/app/events/embedded-mpv.events.spec.ts b/apps/electron-backend/src/app/events/embedded-mpv.events.spec.ts index 9c551275f..b496fc0c2 100644 --- a/apps/electron-backend/src/app/events/embedded-mpv.events.spec.ts +++ b/apps/electron-backend/src/app/events/embedded-mpv.events.spec.ts @@ -9,7 +9,7 @@ const mockEmbeddedMpvService = { prepareAddon: jest.fn(), getSupport: jest.fn(), willProbeLinuxMpvExecutable: jest.fn(() => false), - forgetMissingLinuxMpvExecutable: jest.fn(), + forgetLinuxMpvExecutableProbe: jest.fn(), setPaused: jest.fn(), }; const mockSessionOptions = { @@ -108,12 +108,12 @@ describe('EmbeddedMpvEvents IPC handlers', () => { settle(true); await expect(support).resolves.toEqual({ supported: true }); expect( - mockEmbeddedMpvService.forgetMissingLinuxMpvExecutable + mockEmbeddedMpvService.forgetLinuxMpvExecutableProbe ).not.toHaveBeenCalled(); } ); - it('re-probes a missing mpv once a lookup that ran out finally answers', async () => { + it('re-probes mpv once a lookup that ran out finally answers', async () => { mockEmbeddedMpvService.willProbeLinuxMpvExecutable.mockReturnValue( true ); @@ -126,13 +126,13 @@ describe('EmbeddedMpvEvents IPC handlers', () => { getIpcMainHandler(EMBEDDED_MPV_SUPPORT)({}) ).resolves.toEqual({ supported: false }); expect( - mockEmbeddedMpvService.forgetMissingLinuxMpvExecutable + mockEmbeddedMpvService.forgetLinuxMpvExecutableProbe ).not.toHaveBeenCalled(); settleLookup(); await new Promise((resolve) => setImmediate(resolve)); expect( - mockEmbeddedMpvService.forgetMissingLinuxMpvExecutable + mockEmbeddedMpvService.forgetLinuxMpvExecutableProbe ).toHaveBeenCalledTimes(1); }); diff --git a/apps/electron-backend/src/app/events/embedded-mpv.events.ts b/apps/electron-backend/src/app/events/embedded-mpv.events.ts index dae18f1cb..904bd9bb2 100644 --- a/apps/electron-backend/src/app/events/embedded-mpv.events.ts +++ b/apps/electron-backend/src/app/events/embedded-mpv.events.ts @@ -81,10 +81,10 @@ async function afterLoginShellPathIfProbing(check: () => T): Promise { return check(); } // The lookup ran out of budget, so this probe sees the inherited PATH. - // Once the shell does answer, a "missing" result is probed again. + // Once the shell does answer, the result is probed again. const result = check(); void whenLoginShellPathSettled().then(() => - getService().forgetMissingLinuxMpvExecutable() + getService().forgetLinuxMpvExecutableProbe() ); return result; } diff --git a/apps/electron-backend/src/app/services/embedded-mpv-native.service.spec.ts b/apps/electron-backend/src/app/services/embedded-mpv-native.service.spec.ts index 27b67ce48..728af5580 100644 --- a/apps/electron-backend/src/app/services/embedded-mpv-native.service.spec.ts +++ b/apps/electron-backend/src/app/services/embedded-mpv-native.service.spec.ts @@ -394,7 +394,7 @@ describe('EmbeddedMpvNativeService power blocker', () => { expect(service.willProbeLinuxMpvExecutable()).toBe(false); }); - it('probes a missing mpv again after it is forgotten, but keeps a found one', () => { + it('probes mpv again after a missing or a found result is forgotten', () => { Object.defineProperty(process, 'platform', { value: 'linux' }); process.env.DISPLAY = ':0'; delete process.env.WAYLAND_DISPLAY; @@ -403,14 +403,15 @@ describe('EmbeddedMpvNativeService power blocker', () => { mockRuntimeUsable(); expect(service.getSupport().supported).toBe(false); - service.forgetMissingLinuxMpvExecutable(); + service.forgetLinuxMpvExecutableProbe(); expect(service.willProbeLinuxMpvExecutable()).toBe(true); mockSpawnSync.mockReturnValue({ status: 0 }); service.getSupport(); expect(mockSpawnSync).toHaveBeenCalledTimes(2); - service.forgetMissingLinuxMpvExecutable(); expect(service.willProbeLinuxMpvExecutable()).toBe(false); + service.forgetLinuxMpvExecutableProbe(); + expect(service.willProbeLinuxMpvExecutable()).toBe(true); }); it('predicts no probe for the frame-copy engine or native Wayland', () => { diff --git a/apps/electron-backend/src/app/services/embedded-mpv-native.service.ts b/apps/electron-backend/src/app/services/embedded-mpv-native.service.ts index f5c3e7050..10f30a806 100644 --- a/apps/electron-backend/src/app/services/embedded-mpv-native.service.ts +++ b/apps/electron-backend/src/app/services/embedded-mpv-native.service.ts @@ -394,14 +394,13 @@ export class EmbeddedMpvNativeService { } /** - * Drops a cached "mpv missing" result, so the next support check probes - * again (a found mpv stays cached). For a probe that ran before the - * login shell PATH arrived. + * Drops the cached `mpv --version` result, found or missing, so the next + * support check probes again. For a probe that ran before the login + * shell PATH arrived: that PATH may add mpv or leave out the directory + * the inherited one found it in. */ - forgetMissingLinuxMpvExecutable(): void { - if (this.cachedLinuxMpvExecutableReason) { - this.cachedLinuxMpvExecutableReason = undefined; - } + forgetLinuxMpvExecutableProbe(): void { + this.cachedLinuxMpvExecutableReason = undefined; } getSupport(): EmbeddedMpvSupport {