mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
Merge pull request #966 from 4gray/agent/playlist-delete-lifecycle
refactor(playlists): centralize delete lifecycle
This commit is contained in:
8 files changed
+209
-143
No files matched your search
+11
-31
@@ -11,7 +11,6 @@ import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { of } from 'rxjs';
|
||||
import { PlaylistActions } from '@iptvnator/m3u-state';
|
||||
import {
|
||||
PlaylistContextFacade,
|
||||
@@ -19,8 +18,7 @@ import {
|
||||
} from '@iptvnator/playlist/shared/util';
|
||||
import { DialogService } from '@iptvnator/ui/components';
|
||||
import {
|
||||
DatabaseService,
|
||||
PlaylistsService,
|
||||
PlaylistDeleteActionService,
|
||||
PortalStatusService,
|
||||
} from '@iptvnator/services';
|
||||
import { PlaylistMeta } from '@iptvnator/shared/interfaces';
|
||||
@@ -75,11 +73,7 @@ describe('PlaylistSwitcherComponent', () => {
|
||||
let dialogService: {
|
||||
openConfirmDialog: jest.Mock;
|
||||
};
|
||||
let databaseService: {
|
||||
createOperationId: jest.Mock;
|
||||
deletePlaylist: jest.Mock;
|
||||
};
|
||||
let playlistsService: {
|
||||
let playlistDeleteAction: {
|
||||
deletePlaylist: jest.Mock;
|
||||
};
|
||||
let snackBar: {
|
||||
@@ -133,6 +127,10 @@ describe('PlaylistSwitcherComponent', () => {
|
||||
provide: PlaylistRefreshActionService,
|
||||
useValue: refreshActionService,
|
||||
},
|
||||
{
|
||||
provide: PlaylistDeleteActionService,
|
||||
useValue: playlistDeleteAction,
|
||||
},
|
||||
{
|
||||
provide: MatDialog,
|
||||
useValue: dialog,
|
||||
@@ -141,14 +139,6 @@ describe('PlaylistSwitcherComponent', () => {
|
||||
provide: DialogService,
|
||||
useValue: dialogService,
|
||||
},
|
||||
{
|
||||
provide: DatabaseService,
|
||||
useValue: databaseService,
|
||||
},
|
||||
{
|
||||
provide: PlaylistsService,
|
||||
useValue: playlistsService,
|
||||
},
|
||||
{
|
||||
provide: MatSnackBar,
|
||||
useValue: snackBar,
|
||||
@@ -208,12 +198,8 @@ describe('PlaylistSwitcherComponent', () => {
|
||||
dialogService = {
|
||||
openConfirmDialog: jest.fn(),
|
||||
};
|
||||
databaseService = {
|
||||
createOperationId: jest.fn(),
|
||||
deletePlaylist: jest.fn(),
|
||||
};
|
||||
playlistsService = {
|
||||
deletePlaylist: jest.fn(() => of({ success: true })),
|
||||
playlistDeleteAction = {
|
||||
deletePlaylist: jest.fn().mockResolvedValue(true),
|
||||
};
|
||||
snackBar = {
|
||||
open: jest.fn(),
|
||||
@@ -371,12 +357,7 @@ describe('PlaylistSwitcherComponent', () => {
|
||||
expect(component.displayTitle()).toBe('Select playlist');
|
||||
});
|
||||
|
||||
it('deletes browser/PWA playlists through PlaylistsService instead of the Electron database service', async () => {
|
||||
Object.defineProperty(window, 'electron', {
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: undefined,
|
||||
});
|
||||
it('delegates playlist deletion and removes the source after confirmation', async () => {
|
||||
await createComponent();
|
||||
|
||||
component.removePlaylistFor(xtreamPlaylist);
|
||||
@@ -384,10 +365,9 @@ describe('PlaylistSwitcherComponent', () => {
|
||||
.onConfirm as () => Promise<void>;
|
||||
await confirm();
|
||||
|
||||
expect(playlistsService.deletePlaylist).toHaveBeenCalledWith(
|
||||
xtreamPlaylist._id
|
||||
expect(playlistDeleteAction.deletePlaylist).toHaveBeenCalledWith(
|
||||
xtreamPlaylist
|
||||
);
|
||||
expect(databaseService.deletePlaylist).not.toHaveBeenCalled();
|
||||
expect(store.dispatch).toHaveBeenCalledWith(
|
||||
PlaylistActions.removePlaylist({
|
||||
playlistId: xtreamPlaylist._id,
|
||||
|
||||
@@ -32,14 +32,12 @@ import {
|
||||
PlaylistRefreshActionService,
|
||||
} from '@iptvnator/playlist/shared/util';
|
||||
import {
|
||||
DatabaseService,
|
||||
PlaylistsService,
|
||||
PlaylistDeleteActionService,
|
||||
PortalStatus,
|
||||
PortalStatusService,
|
||||
RuntimeCapabilitiesService,
|
||||
} from '@iptvnator/services';
|
||||
import { PlaylistMeta } from '@iptvnator/shared/interfaces';
|
||||
import { firstValueFrom, startWith } from 'rxjs';
|
||||
import { startWith } from 'rxjs';
|
||||
import { PlaylistInfoComponent } from '../recent-playlists/playlist-info/playlist-info.component';
|
||||
|
||||
type PlaylistFilterType = 'm3u' | 'stalker' | 'xtream';
|
||||
@@ -79,9 +77,7 @@ export class PlaylistSwitcherComponent {
|
||||
private readonly refreshAction = inject(PlaylistRefreshActionService);
|
||||
private readonly dialog = inject(MatDialog);
|
||||
private readonly dialogService = inject(DialogService);
|
||||
private readonly databaseService = inject(DatabaseService);
|
||||
private readonly playlistsService = inject(PlaylistsService);
|
||||
private readonly runtime = inject(RuntimeCapabilitiesService);
|
||||
private readonly playlistDeleteAction = inject(PlaylistDeleteActionService);
|
||||
private readonly snackBar = inject(MatSnackBar);
|
||||
private readonly store = inject(Store);
|
||||
private focusSearchTimeoutId: ReturnType<typeof setTimeout> | null = null;
|
||||
@@ -315,9 +311,8 @@ export class PlaylistSwitcherComponent {
|
||||
private async removePlaylistConfirmed(
|
||||
playlist: PlaylistMeta
|
||||
): Promise<void> {
|
||||
const deleted = this.runtime.isElectron
|
||||
? await this.deletePlaylistInElectron(playlist)
|
||||
: await this.deletePlaylistInBrowser(playlist);
|
||||
const deleted =
|
||||
await this.playlistDeleteAction.deletePlaylist(playlist);
|
||||
|
||||
if (!deleted) {
|
||||
return;
|
||||
@@ -333,28 +328,6 @@ export class PlaylistSwitcherComponent {
|
||||
);
|
||||
}
|
||||
|
||||
private async deletePlaylistInElectron(
|
||||
playlist: PlaylistMeta
|
||||
): Promise<boolean> {
|
||||
const operationId = playlist.serverUrl
|
||||
? this.databaseService.createOperationId('playlist-delete')
|
||||
: undefined;
|
||||
|
||||
return this.databaseService.deletePlaylist(
|
||||
playlist._id,
|
||||
operationId ? { operationId } : undefined
|
||||
);
|
||||
}
|
||||
|
||||
private async deletePlaylistInBrowser(
|
||||
playlist: PlaylistMeta
|
||||
): Promise<boolean> {
|
||||
const result = await firstValueFrom(
|
||||
this.playlistsService.deletePlaylist(playlist._id)
|
||||
);
|
||||
return result.success;
|
||||
}
|
||||
|
||||
getPlaylistIcon(playlist: PlaylistMeta): string {
|
||||
if (playlist.macAddress) {
|
||||
return 'dashboard';
|
||||
|
||||
+19
-20
@@ -17,8 +17,9 @@ import { DialogService } from '@iptvnator/ui/components';
|
||||
import {
|
||||
DatabaseService,
|
||||
DataService,
|
||||
DbOperationEvent,
|
||||
PlaybackPositionService,
|
||||
PlaylistsService,
|
||||
PlaylistDeleteActionService,
|
||||
SortBy,
|
||||
SortOrder,
|
||||
SortService,
|
||||
@@ -77,7 +78,7 @@ describe('RecentPlaylistsComponent busy state', () => {
|
||||
let playbackPositionService: {
|
||||
getAllPlaybackPositions: jest.Mock;
|
||||
};
|
||||
let playlistsService: {
|
||||
let playlistDeleteAction: {
|
||||
deletePlaylist: jest.Mock;
|
||||
};
|
||||
let router: {
|
||||
@@ -110,8 +111,8 @@ describe('RecentPlaylistsComponent busy state', () => {
|
||||
playbackPositionService = {
|
||||
getAllPlaybackPositions: jest.fn().mockResolvedValue([]),
|
||||
};
|
||||
playlistsService = {
|
||||
deletePlaylist: jest.fn(),
|
||||
playlistDeleteAction = {
|
||||
deletePlaylist: jest.fn().mockResolvedValue(true),
|
||||
};
|
||||
router = {
|
||||
navigate: jest.fn(),
|
||||
@@ -152,8 +153,8 @@ describe('RecentPlaylistsComponent busy state', () => {
|
||||
useValue: playbackPositionService,
|
||||
},
|
||||
{
|
||||
provide: PlaylistsService,
|
||||
useValue: playlistsService,
|
||||
provide: PlaylistDeleteActionService,
|
||||
useValue: playlistDeleteAction,
|
||||
},
|
||||
{
|
||||
provide: PlaylistContextFacade,
|
||||
@@ -215,12 +216,11 @@ describe('RecentPlaylistsComponent busy state', () => {
|
||||
const item = createPlaylistMeta({ _id: 'playlist-delete-1' });
|
||||
const deletion = createDeferred<boolean>();
|
||||
|
||||
databaseService.deletePlaylist.mockImplementation(
|
||||
playlistDeleteAction.deletePlaylist.mockImplementation(
|
||||
(
|
||||
_playlistId: string,
|
||||
_playlist: PlaylistMeta,
|
||||
options?: {
|
||||
onEvent?: (event: any) => void;
|
||||
operationId?: string;
|
||||
onEvent?: (event: DbOperationEvent) => void;
|
||||
}
|
||||
) => {
|
||||
options?.onEvent?.({
|
||||
@@ -243,6 +243,9 @@ describe('RecentPlaylistsComponent busy state', () => {
|
||||
);
|
||||
expect(component.getBusyProgress(item._id)).toBe(25);
|
||||
expect(component.canCancelBusyOperation(item)).toBe(true);
|
||||
expect(playlistDeleteAction.deletePlaylist).toHaveBeenCalledWith(item, {
|
||||
onEvent: expect.any(Function),
|
||||
});
|
||||
|
||||
await component.cancelBusyOperation(item);
|
||||
expect(databaseService.cancelOperation).toHaveBeenCalledWith(
|
||||
@@ -264,7 +267,7 @@ describe('RecentPlaylistsComponent busy state', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('deletes browser/PWA playlists through PlaylistsService instead of the Electron database service', async () => {
|
||||
it('delegates playlist deletion and updates local UI state after success', async () => {
|
||||
const item = createPlaylistMeta({
|
||||
_id: 'pwa-playlist-1',
|
||||
serverUrl: undefined,
|
||||
@@ -272,17 +275,13 @@ describe('RecentPlaylistsComponent busy state', () => {
|
||||
password: undefined,
|
||||
url: 'https://example.com/playlist.m3u',
|
||||
});
|
||||
window.electron = undefined as unknown as typeof window.electron;
|
||||
(
|
||||
component as unknown as {
|
||||
isElectron: boolean;
|
||||
}
|
||||
).isElectron = false;
|
||||
playlistsService.deletePlaylist.mockReturnValue(of({ success: true }));
|
||||
playlistDeleteAction.deletePlaylist.mockResolvedValue(true);
|
||||
|
||||
await component.removePlaylist(item);
|
||||
|
||||
expect(playlistsService.deletePlaylist).toHaveBeenCalledWith(item._id);
|
||||
expect(playlistDeleteAction.deletePlaylist).toHaveBeenCalledWith(item, {
|
||||
onEvent: expect.any(Function),
|
||||
});
|
||||
expect(databaseService.deletePlaylist).not.toHaveBeenCalled();
|
||||
expect(store.dispatch).toHaveBeenCalledWith(
|
||||
PlaylistActions.removePlaylist({ playlistId: item._id })
|
||||
@@ -321,7 +320,7 @@ describe('RecentPlaylistsComponent busy state', () => {
|
||||
(
|
||||
_playlistId: string,
|
||||
options?: {
|
||||
onEvent?: (event: any) => void;
|
||||
onEvent?: (event: DbOperationEvent) => void;
|
||||
operationId?: string;
|
||||
}
|
||||
) => {
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
selectAllPlaylistsMeta,
|
||||
selectPlaylistsLoadingFlag,
|
||||
} from '@iptvnator/m3u-state';
|
||||
import { BehaviorSubject, combineLatest, firstValueFrom, map } from 'rxjs';
|
||||
import { BehaviorSubject, combineLatest, map } from 'rxjs';
|
||||
import { DialogService } from '@iptvnator/ui/components';
|
||||
import {
|
||||
DatabaseService,
|
||||
@@ -34,8 +34,8 @@ import {
|
||||
DbOperationEvent,
|
||||
isDbAbortError,
|
||||
PlaybackPositionService,
|
||||
PlaylistDeleteActionService,
|
||||
PlaylistRefreshService,
|
||||
PlaylistsService,
|
||||
RuntimeCapabilitiesService,
|
||||
SortBy,
|
||||
SortService,
|
||||
@@ -87,7 +87,7 @@ export class RecentPlaylistsComponent {
|
||||
private readonly runtime = inject(RuntimeCapabilitiesService);
|
||||
private readonly translate = inject(TranslateService);
|
||||
private readonly playlistContext = inject(PlaylistContextFacade);
|
||||
private readonly playlistsService = inject(PlaylistsService);
|
||||
private readonly playlistDeleteAction = inject(PlaylistDeleteActionService);
|
||||
private readonly pendingRestoreService = inject(
|
||||
XtreamPendingRestoreService
|
||||
);
|
||||
@@ -253,9 +253,13 @@ export class RecentPlaylistsComponent {
|
||||
|
||||
this.setPendingDeletion(item._id, true);
|
||||
try {
|
||||
const deleted = this.isElectron
|
||||
? await this.deletePlaylistInElectron(item)
|
||||
: await this.deletePlaylistInBrowser(item);
|
||||
const deleted = await this.playlistDeleteAction.deletePlaylist(
|
||||
item,
|
||||
{
|
||||
onEvent: (event) =>
|
||||
this.updateBusyOperation(item._id, event),
|
||||
}
|
||||
);
|
||||
if (deleted) {
|
||||
this.store.dispatch(
|
||||
PlaylistActions.removePlaylist({ playlistId: item._id })
|
||||
@@ -276,30 +280,6 @@ export class RecentPlaylistsComponent {
|
||||
}
|
||||
}
|
||||
|
||||
private async deletePlaylistInElectron(item: PlaylistMeta) {
|
||||
const operationId = item.serverUrl
|
||||
? this.databaseService.createOperationId('playlist-delete')
|
||||
: undefined;
|
||||
|
||||
return this.databaseService.deletePlaylist(
|
||||
item._id,
|
||||
operationId
|
||||
? {
|
||||
operationId,
|
||||
onEvent: (event) =>
|
||||
this.updateBusyOperation(item._id, event),
|
||||
}
|
||||
: undefined
|
||||
);
|
||||
}
|
||||
|
||||
private async deletePlaylistInBrowser(item: PlaylistMeta) {
|
||||
const result = await firstValueFrom(
|
||||
this.playlistsService.deletePlaylist(item._id)
|
||||
);
|
||||
return result.success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an IPC event with the playlist details to the main process to trigger the refresh operation
|
||||
* @param item playlist to update
|
||||
|
||||
@@ -3,6 +3,7 @@ export * from './lib/database-electron.service';
|
||||
export * from './lib/downloads.service';
|
||||
export * from './lib/playback-position.service';
|
||||
export * from './lib/playlist-delete-cleanup.token';
|
||||
export * from './lib/playlist-delete-action.service';
|
||||
export * from './lib/playlist-backup.service';
|
||||
export * from './lib/playlist-refresh.service';
|
||||
export * from './lib/playlists.service';
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { of } from 'rxjs';
|
||||
import { PlaylistMeta } from '@iptvnator/shared/interfaces';
|
||||
import { DatabaseService } from './database-electron.service';
|
||||
import { PlaylistDeleteActionService } from './playlist-delete-action.service';
|
||||
import { PlaylistsService } from './playlists.service';
|
||||
import { RuntimeCapabilitiesService } from './runtime-capabilities.service';
|
||||
|
||||
describe('PlaylistDeleteActionService', () => {
|
||||
const playlist = {
|
||||
_id: 'playlist-1',
|
||||
title: 'Demo Playlist',
|
||||
serverUrl: 'http://demo.example',
|
||||
} as PlaylistMeta;
|
||||
|
||||
let databaseService: {
|
||||
createOperationId: jest.Mock<string, [string]>;
|
||||
deletePlaylist: jest.Mock<Promise<boolean>, unknown[]>;
|
||||
};
|
||||
let playlistsService: {
|
||||
deletePlaylist: jest.Mock;
|
||||
};
|
||||
let runtime: {
|
||||
isElectron: boolean;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
databaseService = {
|
||||
createOperationId: jest
|
||||
.fn<string, [string]>()
|
||||
.mockReturnValue('playlist-delete-1'),
|
||||
deletePlaylist: jest.fn(async () => true),
|
||||
};
|
||||
playlistsService = {
|
||||
deletePlaylist: jest.fn(() => of({ success: true })),
|
||||
};
|
||||
runtime = {
|
||||
isElectron: false,
|
||||
};
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
PlaylistDeleteActionService,
|
||||
{ provide: DatabaseService, useValue: databaseService },
|
||||
{ provide: PlaylistsService, useValue: playlistsService },
|
||||
{ provide: RuntimeCapabilitiesService, useValue: runtime },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('deletes browser playlists through PlaylistsService', async () => {
|
||||
const service = TestBed.inject(PlaylistDeleteActionService);
|
||||
|
||||
await expect(service.deletePlaylist(playlist)).resolves.toBe(true);
|
||||
|
||||
expect(playlistsService.deletePlaylist).toHaveBeenCalledWith(
|
||||
'playlist-1'
|
||||
);
|
||||
expect(databaseService.deletePlaylist).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('deletes Electron Xtream playlists through DatabaseService with progress options', async () => {
|
||||
runtime.isElectron = true;
|
||||
const onEvent = jest.fn();
|
||||
const service = TestBed.inject(PlaylistDeleteActionService);
|
||||
|
||||
await expect(
|
||||
service.deletePlaylist(playlist, { onEvent })
|
||||
).resolves.toBe(true);
|
||||
|
||||
expect(databaseService.createOperationId).toHaveBeenCalledWith(
|
||||
'playlist-delete'
|
||||
);
|
||||
expect(databaseService.deletePlaylist).toHaveBeenCalledWith(
|
||||
'playlist-1',
|
||||
{
|
||||
operationId: 'playlist-delete-1',
|
||||
onEvent,
|
||||
}
|
||||
);
|
||||
expect(playlistsService.deletePlaylist).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('deletes Electron non-Xtream playlists without progress options', async () => {
|
||||
runtime.isElectron = true;
|
||||
const service = TestBed.inject(PlaylistDeleteActionService);
|
||||
|
||||
await expect(
|
||||
service.deletePlaylist({
|
||||
...playlist,
|
||||
serverUrl: undefined,
|
||||
} as PlaylistMeta)
|
||||
).resolves.toBe(true);
|
||||
|
||||
expect(databaseService.createOperationId).not.toHaveBeenCalled();
|
||||
expect(databaseService.deletePlaylist).toHaveBeenCalledWith(
|
||||
'playlist-1',
|
||||
undefined
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,58 @@
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { PlaylistMeta } from '@iptvnator/shared/interfaces';
|
||||
import {
|
||||
DatabaseService,
|
||||
type DbOperationEvent,
|
||||
} from './database-electron.service';
|
||||
import { PlaylistsService } from './playlists.service';
|
||||
import { RuntimeCapabilitiesService } from './runtime-capabilities.service';
|
||||
|
||||
export interface PlaylistDeleteActionOptions {
|
||||
/**
|
||||
* Receives Electron DB progress events only for Xtream-style playlists that
|
||||
* have a server URL. PWA deletes and non-Xtream Electron deletes do not emit
|
||||
* playlist delete progress events.
|
||||
*/
|
||||
readonly onEvent?: (event: DbOperationEvent) => void;
|
||||
}
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class PlaylistDeleteActionService {
|
||||
private readonly databaseService = inject(DatabaseService);
|
||||
private readonly playlistsService = inject(PlaylistsService);
|
||||
private readonly runtime = inject(RuntimeCapabilitiesService);
|
||||
|
||||
async deletePlaylist(
|
||||
playlist: PlaylistMeta,
|
||||
options: PlaylistDeleteActionOptions = {}
|
||||
): Promise<boolean> {
|
||||
if (this.runtime.isElectron) {
|
||||
return this.deletePlaylistInElectron(playlist, options);
|
||||
}
|
||||
|
||||
const result = await firstValueFrom(
|
||||
this.playlistsService.deletePlaylist(playlist._id)
|
||||
);
|
||||
return result.success;
|
||||
}
|
||||
|
||||
private deletePlaylistInElectron(
|
||||
playlist: PlaylistMeta,
|
||||
options: PlaylistDeleteActionOptions
|
||||
): Promise<boolean> {
|
||||
const operationId = playlist.serverUrl
|
||||
? this.databaseService.createOperationId('playlist-delete')
|
||||
: undefined;
|
||||
|
||||
return this.databaseService.deletePlaylist(
|
||||
playlist._id,
|
||||
operationId
|
||||
? {
|
||||
operationId,
|
||||
onEvent: options.onEvent,
|
||||
}
|
||||
: undefined
|
||||
);
|
||||
}
|
||||
}
|
||||
+4
-30
@@ -18,7 +18,6 @@ import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import {
|
||||
EmptyStateComponent,
|
||||
PlaylistInfoComponent,
|
||||
@@ -31,8 +30,7 @@ import {
|
||||
import { DialogService } from '@iptvnator/ui/components';
|
||||
import { PlaylistActions } from '@iptvnator/m3u-state';
|
||||
import {
|
||||
DatabaseService,
|
||||
PlaylistsService,
|
||||
PlaylistDeleteActionService,
|
||||
RuntimeCapabilitiesService,
|
||||
} from '@iptvnator/services';
|
||||
import {
|
||||
@@ -416,9 +414,9 @@ function isXtreamAccountPlaylist(
|
||||
})
|
||||
export class WorkspaceDashboardRailsComponent {
|
||||
readonly data = inject(DashboardDataService);
|
||||
private readonly databaseService = inject(DatabaseService);
|
||||
private readonly dialog = inject(MatDialog);
|
||||
private readonly dialogService = inject(DialogService);
|
||||
private readonly playlistDeleteAction = inject(PlaylistDeleteActionService);
|
||||
private readonly playlistRefreshAction = inject(
|
||||
PlaylistRefreshActionService
|
||||
);
|
||||
@@ -431,7 +429,6 @@ export class WorkspaceDashboardRailsComponent {
|
||||
);
|
||||
private readonly shellActions = inject(WORKSPACE_SHELL_ACTIONS);
|
||||
private readonly epgService = inject(EpgService);
|
||||
private readonly playlistsService = inject(PlaylistsService);
|
||||
private readonly runtime = inject(RuntimeCapabilitiesService);
|
||||
|
||||
readonly hasPlaylists = computed(() => this.data.playlists().length > 0);
|
||||
@@ -781,9 +778,8 @@ export class WorkspaceDashboardRailsComponent {
|
||||
}
|
||||
|
||||
private async removePlaylist(playlist: PlaylistMeta): Promise<void> {
|
||||
const deleted = this.runtime.isElectron
|
||||
? await this.deletePlaylistInElectron(playlist)
|
||||
: await this.deletePlaylistInBrowser(playlist);
|
||||
const deleted =
|
||||
await this.playlistDeleteAction.deletePlaylist(playlist);
|
||||
|
||||
if (!deleted) {
|
||||
return;
|
||||
@@ -799,28 +795,6 @@ export class WorkspaceDashboardRailsComponent {
|
||||
);
|
||||
}
|
||||
|
||||
private async deletePlaylistInElectron(
|
||||
playlist: PlaylistMeta
|
||||
): Promise<boolean> {
|
||||
const operationId = playlist.serverUrl
|
||||
? this.databaseService.createOperationId('playlist-delete')
|
||||
: undefined;
|
||||
|
||||
return this.databaseService.deletePlaylist(
|
||||
playlist._id,
|
||||
operationId ? { operationId } : undefined
|
||||
);
|
||||
}
|
||||
|
||||
private async deletePlaylistInBrowser(
|
||||
playlist: PlaylistMeta
|
||||
): Promise<boolean> {
|
||||
const result = await firstValueFrom(
|
||||
this.playlistsService.deletePlaylist(playlist._id)
|
||||
);
|
||||
return result.success;
|
||||
}
|
||||
|
||||
private t(key: string): string {
|
||||
return this.translate.instant(key);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user