mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
refactor(runtime): require playlist storage bridge
This commit is contained in:
1 parent
4603bd83d5
commit
f626e176d2
5 files changed
+77
-23
No files matched your search
@@ -70,9 +70,11 @@ 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. `supportsDownloads` requires the complete downloads
|
||||
preload API surface used by `DownloadsService`, `supportsPlaylistRefresh`
|
||||
requires the native playlist refresh/cancel/progress bridge, and
|
||||
from one shared boundary. `supportsSqlite` requires the complete playlist
|
||||
storage preload API surface used by `PlaylistsService`, `supportsDownloads`
|
||||
requires the complete downloads preload API surface used by `DownloadsService`,
|
||||
`supportsPlaylistRefresh` requires the native playlist refresh/cancel/progress
|
||||
bridge, and
|
||||
`supportsManagedExternalPlayers` requires the MPV and VLC preload launch methods
|
||||
(`openInMpv` and `openInVlc`); a partial Electron bridge must not expose
|
||||
desktop-only actions in the PWA/shared UI.
|
||||
|
||||
@@ -26,7 +26,8 @@ describe('PlaylistDeleteActionService', () => {
|
||||
deletePlaylist: jest.Mock;
|
||||
};
|
||||
let runtime: {
|
||||
isElectron: boolean;
|
||||
supportsSqlite: boolean;
|
||||
supportsXtreamSqliteDataSource: boolean;
|
||||
};
|
||||
let injector: EnvironmentInjector;
|
||||
|
||||
@@ -41,7 +42,8 @@ describe('PlaylistDeleteActionService', () => {
|
||||
deletePlaylist: jest.fn(() => of({ success: true })),
|
||||
};
|
||||
runtime = {
|
||||
isElectron: false,
|
||||
supportsSqlite: false,
|
||||
supportsXtreamSqliteDataSource: false,
|
||||
};
|
||||
|
||||
injector = createEnvironmentInjector(
|
||||
@@ -76,8 +78,8 @@ describe('PlaylistDeleteActionService', () => {
|
||||
expect(databaseService.deletePlaylist).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('deletes Electron Xtream playlists through DatabaseService with progress options', async () => {
|
||||
runtime.isElectron = true;
|
||||
it('deletes SQLite-backed Xtream playlists through DatabaseService with progress options', async () => {
|
||||
runtime.supportsXtreamSqliteDataSource = true;
|
||||
const onEvent = jest.fn();
|
||||
const service = createService();
|
||||
|
||||
@@ -98,8 +100,8 @@ describe('PlaylistDeleteActionService', () => {
|
||||
expect(playlistsService.deletePlaylist).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('deletes Electron non-Xtream playlists without progress options', async () => {
|
||||
runtime.isElectron = true;
|
||||
it('deletes SQLite-backed non-Xtream playlists without progress options', async () => {
|
||||
runtime.supportsSqlite = true;
|
||||
const service = createService();
|
||||
|
||||
await expect(
|
||||
@@ -115,4 +117,17 @@ describe('PlaylistDeleteActionService', () => {
|
||||
undefined
|
||||
);
|
||||
});
|
||||
|
||||
it('uses browser playlist storage when an Xtream playlist lacks Xtream SQLite support', async () => {
|
||||
runtime.supportsSqlite = true;
|
||||
runtime.supportsXtreamSqliteDataSource = false;
|
||||
const service = createService();
|
||||
|
||||
await expect(service.deletePlaylist(playlist)).resolves.toBe(true);
|
||||
|
||||
expect(playlistsService.deletePlaylist).toHaveBeenCalledWith(
|
||||
'playlist-1'
|
||||
);
|
||||
expect(databaseService.deletePlaylist).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -27,7 +27,11 @@ export class PlaylistDeleteActionService {
|
||||
playlist: PlaylistMeta,
|
||||
options: PlaylistDeleteActionOptions = {}
|
||||
): Promise<boolean> {
|
||||
if (this.runtime.isElectron) {
|
||||
const supportsElectronDelete = playlist.serverUrl
|
||||
? this.runtime.supportsXtreamSqliteDataSource
|
||||
: this.runtime.supportsSqlite;
|
||||
|
||||
if (supportsElectronDelete) {
|
||||
return this.deletePlaylistInElectron(playlist, options);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,8 +36,12 @@ describe('RuntimeCapabilitiesService', () => {
|
||||
it('reports Electron capabilities from the available preload bridge methods', () => {
|
||||
testWindow.electron = {
|
||||
platform: 'darwin',
|
||||
dbDeleteAllPlaylists: jest.fn(),
|
||||
dbDeletePlaylist: jest.fn(),
|
||||
dbGetAppPlaylist: jest.fn(),
|
||||
dbGetAppPlaylists: jest.fn(),
|
||||
dbUpsertAppPlaylist: jest.fn(),
|
||||
dbUpsertAppPlaylists: jest.fn(),
|
||||
dbGetAppState: jest.fn(),
|
||||
dbSetAppState: jest.fn(),
|
||||
dbGetRecentlyViewed: jest.fn(),
|
||||
@@ -57,7 +61,6 @@ describe('RuntimeCapabilitiesService', () => {
|
||||
dbGetPlaylist: jest.fn(),
|
||||
dbCreatePlaylist: jest.fn(),
|
||||
dbUpdatePlaylist: jest.fn(),
|
||||
dbDeletePlaylist: jest.fn(),
|
||||
dbHasCategories: jest.fn(),
|
||||
dbGetCategories: jest.fn(),
|
||||
dbSaveCategories: jest.fn(),
|
||||
@@ -158,12 +161,7 @@ describe('RuntimeCapabilitiesService', () => {
|
||||
});
|
||||
|
||||
it('keeps the Xtream SQLite data source disabled when only generic SQLite methods exist', () => {
|
||||
testWindow.electron = {
|
||||
dbGetAppPlaylists: jest.fn(),
|
||||
dbUpsertAppPlaylist: jest.fn(),
|
||||
dbGetAppState: jest.fn(),
|
||||
dbSetAppState: jest.fn(),
|
||||
};
|
||||
testWindow.electron = createPlaylistStorageBridge();
|
||||
|
||||
const service = new RuntimeCapabilitiesService();
|
||||
|
||||
@@ -235,4 +233,35 @@ describe('RuntimeCapabilitiesService', () => {
|
||||
|
||||
expect(service.supportsPlaylistRefresh).toBe(true);
|
||||
});
|
||||
|
||||
it('requires the complete playlist storage SQLite preload surface', () => {
|
||||
testWindow.electron = {
|
||||
dbGetAppPlaylists: jest.fn(),
|
||||
dbUpsertAppPlaylist: jest.fn(),
|
||||
dbGetAppState: jest.fn(),
|
||||
dbSetAppState: jest.fn(),
|
||||
};
|
||||
|
||||
const service = new RuntimeCapabilitiesService();
|
||||
|
||||
expect(service.isElectron).toBe(true);
|
||||
expect(service.supportsSqlite).toBe(false);
|
||||
|
||||
testWindow.electron = createPlaylistStorageBridge();
|
||||
|
||||
expect(service.supportsSqlite).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
function createPlaylistStorageBridge(): Record<string, jest.Mock> {
|
||||
return {
|
||||
dbDeleteAllPlaylists: jest.fn(),
|
||||
dbDeletePlaylist: jest.fn(),
|
||||
dbGetAppPlaylist: jest.fn(),
|
||||
dbGetAppPlaylists: jest.fn(),
|
||||
dbGetAppState: jest.fn(),
|
||||
dbSetAppState: jest.fn(),
|
||||
dbUpsertAppPlaylist: jest.fn(),
|
||||
dbUpsertAppPlaylists: jest.fn(),
|
||||
};
|
||||
}
|
||||
@@ -36,12 +36,16 @@ export class RuntimeCapabilitiesService {
|
||||
}
|
||||
|
||||
get supportsSqlite(): boolean {
|
||||
return (
|
||||
this.hasElectronMethod('dbGetAppPlaylists') &&
|
||||
this.hasElectronMethod('dbUpsertAppPlaylist') &&
|
||||
this.hasElectronMethod('dbGetAppState') &&
|
||||
this.hasElectronMethod('dbSetAppState')
|
||||
);
|
||||
return [
|
||||
'dbDeleteAllPlaylists',
|
||||
'dbDeletePlaylist',
|
||||
'dbGetAppPlaylist',
|
||||
'dbGetAppPlaylists',
|
||||
'dbGetAppState',
|
||||
'dbSetAppState',
|
||||
'dbUpsertAppPlaylist',
|
||||
'dbUpsertAppPlaylists',
|
||||
].every((methodName) => this.hasElectronMethod(methodName));
|
||||
}
|
||||
|
||||
get supportsXtreamSqliteDataSource(): boolean {
|
||||
|
||||
Reference in new issue
Block a user