From 1c9dc98c273075d92161c0572fea5c4103926467 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 6 Jun 2023 11:12:50 +0200 Subject: Lock video files when generating storyboard --- .../lib/job-queue/handlers/generate-storyboard.ts | 118 +++++++++++---------- 1 file changed, 62 insertions(+), 56 deletions(-) (limited to 'server/lib') diff --git a/server/lib/job-queue/handlers/generate-storyboard.ts b/server/lib/job-queue/handlers/generate-storyboard.ts index 09b746a3e..ec07c568c 100644 --- a/server/lib/job-queue/handlers/generate-storyboard.ts +++ b/server/lib/job-queue/handlers/generate-storyboard.ts @@ -21,75 +21,81 @@ async function processGenerateStoryboard (job: Job): Promise { logger.info('Processing generate storyboard of %s in job %s.', payload.videoUUID, job.id, lTags) - const video = await VideoModel.loadFull(payload.videoUUID) - if (!video) { - logger.info('Video %s does not exist anymore, skipping storyboard generation.', payload.videoUUID, lTags) - return - } - - const inputFile = video.getMaxQualityFile() - - await VideoPathManager.Instance.makeAvailableVideoFile(inputFile, async videoPath => { - const isAudio = await isAudioFile(videoPath) + const inputFileMutexReleaser = await VideoPathManager.Instance.lockFiles(payload.videoUUID) - if (isAudio) { - logger.info('Do not generate a storyboard of %s since the video does not have a video stream', payload.videoUUID, lTags) + try { + const video = await VideoModel.loadFull(payload.videoUUID) + if (!video) { + logger.info('Video %s does not exist anymore, skipping storyboard generation.', payload.videoUUID, lTags) return } - const ffmpeg = new FFmpegImage(getFFmpegCommandWrapperOptions('thumbnail')) + const inputFile = video.getMaxQualityFile() - const filename = generateImageFilename() - const destination = join(CONFIG.STORAGE.STORYBOARDS_DIR, filename) + await VideoPathManager.Instance.makeAvailableVideoFile(inputFile, async videoPath => { + const isAudio = await isAudioFile(videoPath) - const totalSprites = buildTotalSprites(video) - if (totalSprites === 0) { - logger.info('Do not generate a storyboard of %s because the video is not long enough', payload.videoUUID, lTags) - return - } + if (isAudio) { + logger.info('Do not generate a storyboard of %s since the video does not have a video stream', payload.videoUUID, lTags) + return + } - const spriteDuration = Math.round(video.duration / totalSprites) + const ffmpeg = new FFmpegImage(getFFmpegCommandWrapperOptions('thumbnail')) - const spritesCount = findGridSize({ - toFind: totalSprites, - maxEdgeCount: STORYBOARD.SPRITES_MAX_EDGE_COUNT - }) + const filename = generateImageFilename() + const destination = join(CONFIG.STORAGE.STORYBOARDS_DIR, filename) - logger.debug( - 'Generating storyboard from video of %s to %s', video.uuid, destination, - { ...lTags, spritesCount, spriteDuration, videoDuration: video.duration } - ) - - await ffmpeg.generateStoryboardFromVideo({ - destination, - path: videoPath, - sprites: { - size: STORYBOARD.SPRITE_SIZE, - count: spritesCount, - duration: spriteDuration + const totalSprites = buildTotalSprites(video) + if (totalSprites === 0) { + logger.info('Do not generate a storyboard of %s because the video is not long enough', payload.videoUUID, lTags) + return } - }) - - const imageSize = await getImageSize(destination) - const existing = await StoryboardModel.loadByVideo(video.id) - if (existing) await existing.destroy() - - await StoryboardModel.create({ - filename, - totalHeight: imageSize.height, - totalWidth: imageSize.width, - spriteHeight: STORYBOARD.SPRITE_SIZE.height, - spriteWidth: STORYBOARD.SPRITE_SIZE.width, - spriteDuration, - videoId: video.id + const spriteDuration = Math.round(video.duration / totalSprites) + + const spritesCount = findGridSize({ + toFind: totalSprites, + maxEdgeCount: STORYBOARD.SPRITES_MAX_EDGE_COUNT + }) + + logger.debug( + 'Generating storyboard from video of %s to %s', video.uuid, destination, + { ...lTags, spritesCount, spriteDuration, videoDuration: video.duration } + ) + + await ffmpeg.generateStoryboardFromVideo({ + destination, + path: videoPath, + sprites: { + size: STORYBOARD.SPRITE_SIZE, + count: spritesCount, + duration: spriteDuration + } + }) + + const imageSize = await getImageSize(destination) + + const existing = await StoryboardModel.loadByVideo(video.id) + if (existing) await existing.destroy() + + await StoryboardModel.create({ + filename, + totalHeight: imageSize.height, + totalWidth: imageSize.width, + spriteHeight: STORYBOARD.SPRITE_SIZE.height, + spriteWidth: STORYBOARD.SPRITE_SIZE.width, + spriteDuration, + videoId: video.id + }) + + logger.info('Storyboard generation %s ended for video %s.', destination, video.uuid, lTags) }) - logger.info('Storyboard generation %s ended for video %s.', destination, video.uuid, lTags) - }) - - if (payload.federate) { - await federateVideoIfNeeded(video, false) + if (payload.federate) { + await federateVideoIfNeeded(video, false) + } + } finally { + inputFileMutexReleaser() } } -- cgit v1.2.3