From f48318168b14277c2f6d3ccf8e64e65672e1f4b5 Mon Sep 17 00:00:00 2001 From: mertalev <101130780+mertalev@users.noreply.github.com> Date: Mon, 27 May 2024 18:47:36 -0400 Subject: [PATCH] add extension to tmp path --- server/src/services/media.service.spec.ts | 12 +++++------ server/src/services/media.service.ts | 25 ++++++++++++++++++----- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/server/src/services/media.service.spec.ts b/server/src/services/media.service.spec.ts index 9bbb2ab535..d9088646b4 100644 --- a/server/src/services/media.service.spec.ts +++ b/server/src/services/media.service.spec.ts @@ -293,7 +293,7 @@ describe(MediaService.name, () => { await sut.handleGeneratePreview({ id: assetStub.video.id }); expect(storageMock.mkdirSync).toHaveBeenCalledWith('upload/thumbs/user-id/as/se'); - expect(mediaMock.transcode).toHaveBeenCalledWith('/original/path.ext', expect.stringMatching(/.*\.tmp/), { + expect(mediaMock.transcode).toHaveBeenCalledWith('/original/path.ext', expect.stringMatching(/.*\.tmp\.jpeg/), { inputOptions: ['-skip_frame nokey', '-sws_flags accurate_rnd+full_chroma_int'], outputOptions: [ '-fps_mode vfr', @@ -305,7 +305,7 @@ describe(MediaService.name, () => { twoPass: false, }); expect(assetMock.update).toHaveBeenCalledWith({ id: 'asset-id', previewPath }); - expect(storageMock.rename).toHaveBeenCalledWith(expect.stringMatching(/.*\.tmp/), previewPath); + expect(storageMock.rename).toHaveBeenCalledWith(expect.stringMatching(/.*\.tmp\.jpeg/), previewPath); }); it('should tonemap thumbnail for hdr video', async () => { @@ -316,7 +316,7 @@ describe(MediaService.name, () => { await sut.handleGeneratePreview({ id: assetStub.video.id }); expect(storageMock.mkdirSync).toHaveBeenCalledWith('upload/thumbs/user-id/as/se'); - expect(mediaMock.transcode).toHaveBeenCalledWith('/original/path.ext', expect.stringMatching(/.*\.tmp/), { + expect(mediaMock.transcode).toHaveBeenCalledWith('/original/path.ext', expect.stringMatching(/.*\.tmp\.jpeg/), { inputOptions: ['-skip_frame nokey', '-sws_flags accurate_rnd+full_chroma_int'], outputOptions: [ '-fps_mode vfr', @@ -328,7 +328,7 @@ describe(MediaService.name, () => { twoPass: false, }); expect(assetMock.update).toHaveBeenCalledWith({ id: 'asset-id', previewPath }); - expect(storageMock.rename).toHaveBeenCalledWith(expect.stringMatching(/.*\.tmp/), previewPath); + expect(storageMock.rename).toHaveBeenCalledWith(expect.stringMatching(/.*\.tmp\.jpeg/), previewPath); }); it('should always generate video thumbnail in one pass', async () => { @@ -341,7 +341,7 @@ describe(MediaService.name, () => { await sut.handleGeneratePreview({ id: assetStub.video.id }); - expect(mediaMock.transcode).toHaveBeenCalledWith('/original/path.ext', expect.stringMatching(/.*\.tmp/), { + expect(mediaMock.transcode).toHaveBeenCalledWith('/original/path.ext', expect.stringMatching(/.*\.tmp\.jpeg/), { inputOptions: ['-skip_frame nokey', '-sws_flags accurate_rnd+full_chroma_int'], outputOptions: [ '-fps_mode vfr', @@ -353,7 +353,7 @@ describe(MediaService.name, () => { twoPass: false, }); expect(assetMock.update).toHaveBeenCalledWith({ id: 'asset-id', previewPath }); - expect(storageMock.rename).toHaveBeenCalledWith(expect.stringMatching(/.*\.tmp/), previewPath); + expect(storageMock.rename).toHaveBeenCalledWith(expect.stringMatching(/.*\.tmp\.jpeg/), previewPath); }); it('should run successfully', async () => { diff --git a/server/src/services/media.service.ts b/server/src/services/media.service.ts index d74972f539..974a00469b 100644 --- a/server/src/services/media.service.ts +++ b/server/src/services/media.service.ts @@ -188,7 +188,7 @@ export class MediaService { const { image, ffmpeg } = await this.configCore.getConfig(); const size = type === AssetPathType.PREVIEW ? image.previewSize : image.thumbnailSize; const path = StorageCore.getImagePath(asset, type, format); - const tmpPath = StorageCore.getTempPathInDir(dirname(path)); + const tmpPath = `${StorageCore.getTempPathInDir(dirname(path))}.${format}`; this.storageCore.ensureFolders(path); switch (asset.type) { @@ -204,6 +204,9 @@ export class MediaService { const inputPath = useExtracted ? extractedPath : asset.originalPath; await this.mediaRepository.generateThumbnail(inputPath, tmpPath, imageOptions); + } catch (error) { + await this.storageRepository.unlink(tmpPath); + throw error; } finally { if (didExtract) { await this.storageRepository.unlink(extractedPath); @@ -222,7 +225,12 @@ export class MediaService { const mainAudioStream = this.getMainStream(audioStreams); const config = ThumbnailConfig.create({ ...ffmpeg, targetResolution: size.toString() }); const options = config.getCommand(TranscodeTarget.VIDEO, mainVideoStream, mainAudioStream); - await this.mediaRepository.transcode(asset.originalPath, tmpPath, options); + try { + await this.mediaRepository.transcode(asset.originalPath, tmpPath, options); + } catch (error) { + await this.storageRepository.unlink(tmpPath); + throw error; + } break; } @@ -354,9 +362,16 @@ export class MediaService { `Error occurred during transcoding. Retrying with ${ffmpeg.accel.toUpperCase()} acceleration disabled.`, ); } - const config = BaseConfig.create({ ...ffmpeg, accel: TranscodeHWAccel.DISABLED }); - command = config.getCommand(target, mainVideoStream, mainAudioStream); - await this.mediaRepository.transcode(input, tmpPath, command); + + try { + const config = BaseConfig.create({ ...ffmpeg, accel: TranscodeHWAccel.DISABLED }); + command = config.getCommand(target, mainVideoStream, mainAudioStream); + await this.mediaRepository.transcode(input, tmpPath, command); + } catch (error) { + this.logger.error(error); + await this.storageRepository.unlink(tmpPath); + return JobStatus.FAILED; + } } await this.storageRepository.rename(tmpPath, output);