diff --git a/server/src/services/asset.service.spec.ts b/server/src/services/asset.service.spec.ts index 75e7fc5e87..9a9c3e0e09 100755 --- a/server/src/services/asset.service.spec.ts +++ b/server/src/services/asset.service.spec.ts @@ -543,16 +543,9 @@ describe(AssetService.name, () => { await sut.handleAssetDeletion({ id: asset.id, deleteOnDisk: true }); - expect(mocks.job.queue.mock.calls).toEqual([ - [ - { - name: JobName.FileDelete, - data: { - files: [...asset.files.map(({ path }) => path), asset.originalPath], - }, - }, - ], - ]); + expect(mocks.storage.unlink.mock.calls).toEqual( + [...asset.files.map(({ path }) => path), asset.originalPath].map((file) => [file]), + ); expect(mocks.asset.remove).toHaveBeenCalledWith(getForAssetDeletion(asset)); }); @@ -581,8 +574,8 @@ describe(AssetService.name, () => { expect(mocks.job.queue.mock.calls).toEqual([ [{ name: JobName.AssetDelete, data: { id: motionAsset.id, deleteOnDisk: true } }], - [{ name: JobName.FileDelete, data: { files: [asset.originalPath] } }], ]); + expect(mocks.storage.unlink).toHaveBeenCalledWith(asset.originalPath); }); it('should not delete a live motion part if it is being used by another asset', async () => { @@ -592,9 +585,8 @@ describe(AssetService.name, () => { await sut.handleAssetDeletion({ id: asset.id, deleteOnDisk: true }); - expect(mocks.job.queue.mock.calls).toEqual([ - [{ name: JobName.FileDelete, data: { files: [`/data/library/IMG_${asset.id}.jpg`] } }], - ]); + expect(mocks.job.queue.mock.calls).toEqual([]); + expect(mocks.storage.unlink).toHaveBeenCalledWith(`/data/library/IMG_${asset.id}.jpg`); }); it('should update usage', async () => { diff --git a/server/src/services/asset.service.ts b/server/src/services/asset.service.ts index e2d2d95f81..a63c61952c 100644 --- a/server/src/services/asset.service.ts +++ b/server/src/services/asset.service.ts @@ -314,6 +314,11 @@ export class AssetService extends BaseService { return JobStatus.Failed; } + const fileDeletionStatus = await this.deleteAssetFiles(id, this.getFilesForDeletion(asset, deleteOnDisk)); + if (fileDeletionStatus === JobStatus.Failed) { + return JobStatus.Failed; + } + // replace the parent of the stack children with a new asset if (asset.stack?.primaryAssetId === id) { // this only includes timeline visible assets and excludes the primary asset @@ -347,6 +352,13 @@ export class AssetService extends BaseService { } } + return JobStatus.Success; + } + + private getFilesForDeletion( + asset: { files: AssetFile[]; originalPath: string; isOffline: boolean }, + deleteOnDisk: boolean, + ): string[] { const assetFiles = getAssetFiles(asset.files ?? []); const files = [ assetFiles.thumbnailFile?.path, @@ -362,7 +374,18 @@ export class AssetService extends BaseService { files.push(assetFiles.sidecarFile?.path, asset.originalPath); } - await this.jobRepository.queue({ name: JobName.FileDelete, data: { files: files.filter(Boolean) } }); + return files.filter((file): file is string => file !== undefined); + } + + private async deleteAssetFiles(assetId: string, files: string[]): Promise { + for (const file of files) { + try { + await this.storageRepository.unlink(file); + } catch (error) { + this.logger.warn(`Unable to remove asset file for asset ${assetId}: ${file}`, error); + return JobStatus.Failed; + } + } return JobStatus.Success; }