diff --git a/libs/services/src/lib/downloads-metadata-update.ts b/libs/services/src/lib/downloads-metadata-update.ts new file mode 100644 index 000000000..bf911ed08 --- /dev/null +++ b/libs/services/src/lib/downloads-metadata-update.ts @@ -0,0 +1,29 @@ +import type { DownloadMetadataSnapshot } from '@iptvnator/shared/interfaces'; + +interface DownloadMetadataHost { + isAvailable(): boolean; + loadDownloads(): Promise; +} + +export async function updateDownloadMetadata( + host: DownloadMetadataHost, + downloadId: number, + metadataSnapshot: DownloadMetadataSnapshot +): Promise<{ success: boolean; error?: string }> { + if (!host.isAvailable()) return { success: false }; + + try { + const result = await window.electron.downloadsUpdateMetadata( + downloadId, + metadataSnapshot + ); + if (result.success) await host.loadDownloads(); + return result; + } catch (error) { + console.error('[DownloadsService] Metadata update error:', error); + return { + success: false, + error: error instanceof Error ? error.message : String(error), + }; + } +} diff --git a/libs/services/src/lib/downloads.service.spec.ts b/libs/services/src/lib/downloads.service.spec.ts index fe3d7e754..8a77a54c9 100644 --- a/libs/services/src/lib/downloads.service.spec.ts +++ b/libs/services/src/lib/downloads.service.spec.ts @@ -413,6 +413,33 @@ describe('DownloadsService', () => { ); }); + it('stringifies a non-Error metadata update failure', async () => { + const error = { message: 404 }; + jest.spyOn(console, 'error').mockImplementation(() => undefined); + const electron = { + downloadsGetList: jest.fn(async () => []), + downloadsUpdateMetadata: jest + .fn< + Promise<{ success: boolean; error?: string }>, + [number, DownloadMetadataSnapshot] + >() + .mockRejectedValue(error), + }; + testWindow.electron = electron; + const service = createService(); + + await expect( + service.updateMetadata(42, metadataSnapshot) + ).resolves.toEqual({ + error: '[object Object]', + success: false, + }); + expect(console.error).toHaveBeenCalledWith( + '[DownloadsService] Metadata update error:', + error + ); + }); + it('returns a safe failure when the metadata reload throws', async () => { const error = new Error('metadata reload failed'); jest.spyOn(console, 'error').mockImplementation(() => undefined); diff --git a/libs/services/src/lib/downloads.service.ts b/libs/services/src/lib/downloads.service.ts index 6e7acdd9e..e2c702c7a 100644 --- a/libs/services/src/lib/downloads.service.ts +++ b/libs/services/src/lib/downloads.service.ts @@ -1,5 +1,6 @@ import { computed, inject, Injectable, OnDestroy, signal } from '@angular/core'; import type { DownloadMetadataSnapshot } from '@iptvnator/shared/interfaces'; +import { updateDownloadMetadata } from './downloads-metadata-update'; import type { DownloadItem, DownloadStartInput } from './downloads.models'; import { formatDownloadBytes } from './downloads.utils'; import { RuntimeCapabilitiesService } from './runtime-capabilities.service'; @@ -132,7 +133,9 @@ export class DownloadsService implements OnDestroy { /** * Start a new download */ - async startDownload(data: DownloadStartInput) { + async startDownload( + data: DownloadStartInput + ): Promise<{ success: boolean; id?: number; error?: string }> { if (!this.isAvailable()) { return { success: false, error: 'Downloads not available' }; } @@ -143,15 +146,17 @@ export class DownloadsService implements OnDestroy { } try { - return await window.electron.downloadsStart({ + const result = await window.electron.downloadsStart({ ...data, downloadFolder: folder, }); + return result; } catch (error) { console.error('[DownloadsService] Error starting download:', error); - const message = - error instanceof Error ? error.message : String(error); - return { success: false, error: message }; + return { + success: false, + error: error instanceof Error ? error.message : String(error), + }; } } @@ -298,19 +303,11 @@ export class DownloadsService implements OnDestroy { } /** Update the offline metadata snapshot for a managed download. */ - async updateMetadata(id: number, snapshot: DownloadMetadataSnapshot) { - if (!this.isAvailable()) return { success: false }; - - try { - const bridge = window.electron; - const result = await bridge.downloadsUpdateMetadata(id, snapshot); - if (result.success) await this.loadDownloads(); - return result; - } catch (error) { - console.error('[DownloadsService] Metadata update error:', error); - const message = (error as Error)?.message ?? String(error); - return { success: false, error: message }; - } + async updateMetadata( + id: number, + snapshot: DownloadMetadataSnapshot + ): Promise<{ success: boolean; error?: string }> { + return updateDownloadMetadata(this, id, snapshot); } /**