diff --git a/docs/architecture/pwa-self-hosted.md b/docs/architecture/pwa-self-hosted.md index 3121766e1..e3ab98344 100644 --- a/docs/architecture/pwa-self-hosted.md +++ b/docs/architecture/pwa-self-hosted.md @@ -70,7 +70,9 @@ direct `window.electron` or `DataService.getAppEnvironment()` checks. Keep feature decisions expressed as capabilities such as `supportsEpg`, `supportsSqlite`, `supportsXtreamSqliteDataSource`, `supportsDownloads`, or `supportsManagedExternalPlayers` so PWA and Electron behavior stays auditable -from one shared boundary. +from one shared boundary. `supportsManagedExternalPlayers` requires the MPV and +VLC preload launch methods (`openInMpv` and `openInVlc`); a partial Electron +bridge must not expose managed external-player actions in the PWA/shared UI. ## Runtime Limitations diff --git a/libs/services/src/lib/runtime-capabilities.service.spec.ts b/libs/services/src/lib/runtime-capabilities.service.spec.ts index db2067c97..65392cc91 100644 --- a/libs/services/src/lib/runtime-capabilities.service.spec.ts +++ b/libs/services/src/lib/runtime-capabilities.service.spec.ts @@ -77,6 +77,8 @@ describe('RuntimeCapabilitiesService', () => { dbDeleteXtreamContent: jest.fn(), dbRestoreXtreamUserData: jest.fn(), downloadsGetList: jest.fn(), + openInMpv: jest.fn(), + openInVlc: jest.fn(), prepareEmbeddedMpv: jest.fn(), saveFileDialog: jest.fn(), writeFile: jest.fn(), @@ -119,6 +121,7 @@ describe('RuntimeCapabilitiesService', () => { expect(service.supportsXtreamSqliteDataSource).toBe(false); expect(service.supportsDownloads).toBe(false); expect(service.supportsPortalActivityStorage).toBe(false); + expect(service.supportsManagedExternalPlayers).toBe(false); expect(service.supportsEmbeddedMpv).toBe(false); expect(service.supportsDesktopFileSave).toBe(false); expect(service.supportsRemoteControl).toBe(false); @@ -150,4 +153,22 @@ describe('RuntimeCapabilitiesService', () => { expect(service.supportsSqlite).toBe(true); expect(service.supportsXtreamSqliteDataSource).toBe(false); }); + + it('requires both managed external player launch methods', () => { + testWindow.electron = { + openInMpv: jest.fn(), + }; + + const service = new RuntimeCapabilitiesService(); + + expect(service.isElectron).toBe(true); + expect(service.supportsManagedExternalPlayers).toBe(false); + + testWindow.electron = { + openInMpv: jest.fn(), + openInVlc: jest.fn(), + }; + + expect(service.supportsManagedExternalPlayers).toBe(true); + }); }); diff --git a/libs/services/src/lib/runtime-capabilities.service.ts b/libs/services/src/lib/runtime-capabilities.service.ts index 80d12546d..84b6bff5d 100644 --- a/libs/services/src/lib/runtime-capabilities.service.ts +++ b/libs/services/src/lib/runtime-capabilities.service.ts @@ -106,7 +106,9 @@ export class RuntimeCapabilitiesService { } get supportsManagedExternalPlayers(): boolean { - return this.isElectron; + return ['openInMpv', 'openInVlc'].every((methodName) => + this.hasElectronMethod(methodName) + ); } get supportsEmbeddedMpv(): boolean {