From 6a4905602636afd6650c9e6f4d0fcc2105d91100 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 3 May 2023 15:17:11 +0200 Subject: Add TMP persistent directory To store files that must be preserved between peertube restarts --- .../lib/job-queue/handlers/video-studio-edition.ts | 90 ++++++++++++---------- server/lib/video-studio.ts | 23 +++++- 2 files changed, 70 insertions(+), 43 deletions(-) (limited to 'server/lib') diff --git a/server/lib/job-queue/handlers/video-studio-edition.ts b/server/lib/job-queue/handlers/video-studio-edition.ts index fbb55a388..5e8dd4f51 100644 --- a/server/lib/job-queue/handlers/video-studio-edition.ts +++ b/server/lib/job-queue/handlers/video-studio-edition.ts @@ -12,7 +12,7 @@ import { VideoTranscodingProfilesManager } from '@server/lib/transcoding/default import { isAbleToUploadVideo } from '@server/lib/user' import { buildFileMetadata, removeHLSPlaylist, removeWebTorrentFile } from '@server/lib/video-file' import { VideoPathManager } from '@server/lib/video-path-manager' -import { approximateIntroOutroAdditionalSize } from '@server/lib/video-studio' +import { approximateIntroOutroAdditionalSize, safeCleanupStudioTMPFiles } from '@server/lib/video-studio' import { UserModel } from '@server/models/user/user' import { VideoModel } from '@server/models/video/video' import { VideoFileModel } from '@server/models/video/video-file' @@ -39,63 +39,73 @@ async function processVideoStudioEdition (job: Job) { logger.info('Process video studio edition of %s in job %s.', payload.videoUUID, job.id, lTags) - const video = await VideoModel.loadFull(payload.videoUUID) + try { + const video = await VideoModel.loadFull(payload.videoUUID) - // No video, maybe deleted? - if (!video) { - logger.info('Can\'t process job %d, video does not exist.', job.id, lTags) - return undefined - } + // No video, maybe deleted? + if (!video) { + logger.info('Can\'t process job %d, video does not exist.', job.id, lTags) - await checkUserQuotaOrThrow(video, payload) + await safeCleanupStudioTMPFiles(payload) + return undefined + } - const inputFile = video.getMaxQualityFile() + await checkUserQuotaOrThrow(video, payload) - const editionResultPath = await VideoPathManager.Instance.makeAvailableVideoFile(inputFile, async originalFilePath => { - let tmpInputFilePath: string - let outputPath: string + const inputFile = video.getMaxQualityFile() - for (const task of payload.tasks) { - const outputFilename = buildUUID() + inputFile.extname - outputPath = join(CONFIG.STORAGE.TMP_DIR, outputFilename) + const editionResultPath = await VideoPathManager.Instance.makeAvailableVideoFile(inputFile, async originalFilePath => { + let tmpInputFilePath: string + let outputPath: string - await processTask({ - inputPath: tmpInputFilePath ?? originalFilePath, - video, - outputPath, - task, - lTags - }) + for (const task of payload.tasks) { + const outputFilename = buildUUID() + inputFile.extname + outputPath = join(CONFIG.STORAGE.TMP_DIR, outputFilename) - if (tmpInputFilePath) await remove(tmpInputFilePath) + await processTask({ + inputPath: tmpInputFilePath ?? originalFilePath, + video, + outputPath, + task, + lTags + }) - // For the next iteration - tmpInputFilePath = outputPath - } + if (tmpInputFilePath) await remove(tmpInputFilePath) - return outputPath - }) + // For the next iteration + tmpInputFilePath = outputPath + } - logger.info('Video edition ended for video %s.', video.uuid, lTags) + return outputPath + }) - const newFile = await buildNewFile(video, editionResultPath) + logger.info('Video edition ended for video %s.', video.uuid, lTags) - const outputPath = VideoPathManager.Instance.getFSVideoFileOutputPath(video, newFile) - await move(editionResultPath, outputPath) + const newFile = await buildNewFile(video, editionResultPath) - await createTorrentAndSetInfoHashFromPath(video, newFile, outputPath) - await removeAllFiles(video, newFile) + const outputPath = VideoPathManager.Instance.getFSVideoFileOutputPath(video, newFile) + await move(editionResultPath, outputPath) - await newFile.save() + await safeCleanupStudioTMPFiles(payload) - video.duration = await getVideoStreamDuration(outputPath) - await video.save() + await createTorrentAndSetInfoHashFromPath(video, newFile, outputPath) + await removeAllFiles(video, newFile) - await federateVideoIfNeeded(video, false, undefined) + await newFile.save() - const user = await UserModel.loadByVideoId(video.id) + video.duration = await getVideoStreamDuration(outputPath) + await video.save() - await createOptimizeOrMergeAudioJobs({ video, videoFile: newFile, isNewVideo: false, user, videoFileAlreadyLocked: false }) + await federateVideoIfNeeded(video, false, undefined) + + const user = await UserModel.loadByVideoId(video.id) + + await createOptimizeOrMergeAudioJobs({ video, videoFile: newFile, isNewVideo: false, user, videoFileAlreadyLocked: false }) + } catch (err) { + await safeCleanupStudioTMPFiles(payload) + + throw err + } } // --------------------------------------------------------------------------- diff --git a/server/lib/video-studio.ts b/server/lib/video-studio.ts index b392bdb00..beda326a0 100644 --- a/server/lib/video-studio.ts +++ b/server/lib/video-studio.ts @@ -1,15 +1,31 @@ +import { logger } from '@server/helpers/logger' import { MVideoFullLight } from '@server/types/models' import { getVideoStreamDuration } from '@shared/ffmpeg' -import { VideoStudioTask } from '@shared/models' +import { VideoStudioEditionPayload, VideoStudioTask } from '@shared/models' +import { remove } from 'fs-extra' function buildTaskFileFieldname (indice: number, fieldName = 'file') { return `tasks[${indice}][options][${fieldName}]` } -function getTaskFile (files: Express.Multer.File[], indice: number, fieldName = 'file') { +function getTaskFileFromReq (files: Express.Multer.File[], indice: number, fieldName = 'file') { return files.find(f => f.fieldname === buildTaskFileFieldname(indice, fieldName)) } +async function safeCleanupStudioTMPFiles (payload: VideoStudioEditionPayload) { + for (const task of payload.tasks) { + try { + if (task.name === 'add-intro' || task.name === 'add-outro') { + await remove(task.options.file) + } else if (task.name === 'add-watermark') { + await remove(task.options.file) + } + } catch (err) { + logger.error('Cannot remove studio file', { err }) + } + } +} + async function approximateIntroOutroAdditionalSize (video: MVideoFullLight, tasks: VideoStudioTask[], fileFinder: (i: number) => string) { let additionalDuration = 0 @@ -28,5 +44,6 @@ async function approximateIntroOutroAdditionalSize (video: MVideoFullLight, task export { approximateIntroOutroAdditionalSize, buildTaskFileFieldname, - getTaskFile + getTaskFileFromReq, + safeCleanupStudioTMPFiles } -- cgit v1.2.3