aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2023-05-03 15:17:11 +0200
committerChocobozzz <chocobozzz@cpy.re>2023-05-09 08:57:34 +0200
commit6a4905602636afd6650c9e6f4d0fcc2105d91100 (patch)
tree1a6ffa4239f62bffa2e6e328ea61a52a65d58d35 /server/lib
parent3a0c2a77b1a6626699514ddaf8135f4397175443 (diff)
downloadPeerTube-6a4905602636afd6650c9e6f4d0fcc2105d91100.tar.gz
PeerTube-6a4905602636afd6650c9e6f4d0fcc2105d91100.tar.zst
PeerTube-6a4905602636afd6650c9e6f4d0fcc2105d91100.zip
Add TMP persistent directory
To store files that must be preserved between peertube restarts
Diffstat (limited to 'server/lib')
-rw-r--r--server/lib/job-queue/handlers/video-studio-edition.ts90
-rw-r--r--server/lib/video-studio.ts23
2 files changed, 70 insertions, 43 deletions
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
12import { isAbleToUploadVideo } from '@server/lib/user' 12import { isAbleToUploadVideo } from '@server/lib/user'
13import { buildFileMetadata, removeHLSPlaylist, removeWebTorrentFile } from '@server/lib/video-file' 13import { buildFileMetadata, removeHLSPlaylist, removeWebTorrentFile } from '@server/lib/video-file'
14import { VideoPathManager } from '@server/lib/video-path-manager' 14import { VideoPathManager } from '@server/lib/video-path-manager'
15import { approximateIntroOutroAdditionalSize } from '@server/lib/video-studio' 15import { approximateIntroOutroAdditionalSize, safeCleanupStudioTMPFiles } from '@server/lib/video-studio'
16import { UserModel } from '@server/models/user/user' 16import { UserModel } from '@server/models/user/user'
17import { VideoModel } from '@server/models/video/video' 17import { VideoModel } from '@server/models/video/video'
18import { VideoFileModel } from '@server/models/video/video-file' 18import { VideoFileModel } from '@server/models/video/video-file'
@@ -39,63 +39,73 @@ async function processVideoStudioEdition (job: Job) {
39 39
40 logger.info('Process video studio edition of %s in job %s.', payload.videoUUID, job.id, lTags) 40 logger.info('Process video studio edition of %s in job %s.', payload.videoUUID, job.id, lTags)
41 41
42 const video = await VideoModel.loadFull(payload.videoUUID) 42 try {
43 const video = await VideoModel.loadFull(payload.videoUUID)
43 44
44 // No video, maybe deleted? 45 // No video, maybe deleted?
45 if (!video) { 46 if (!video) {
46 logger.info('Can\'t process job %d, video does not exist.', job.id, lTags) 47 logger.info('Can\'t process job %d, video does not exist.', job.id, lTags)
47 return undefined
48 }
49 48
50 await checkUserQuotaOrThrow(video, payload) 49 await safeCleanupStudioTMPFiles(payload)
50 return undefined
51 }
51 52
52 const inputFile = video.getMaxQualityFile() 53 await checkUserQuotaOrThrow(video, payload)
53 54
54 const editionResultPath = await VideoPathManager.Instance.makeAvailableVideoFile(inputFile, async originalFilePath => { 55 const inputFile = video.getMaxQualityFile()
55 let tmpInputFilePath: string
56 let outputPath: string
57 56
58 for (const task of payload.tasks) { 57 const editionResultPath = await VideoPathManager.Instance.makeAvailableVideoFile(inputFile, async originalFilePath => {
59 const outputFilename = buildUUID() + inputFile.extname 58 let tmpInputFilePath: string
60 outputPath = join(CONFIG.STORAGE.TMP_DIR, outputFilename) 59 let outputPath: string
61 60
62 await processTask({ 61 for (const task of payload.tasks) {
63 inputPath: tmpInputFilePath ?? originalFilePath, 62 const outputFilename = buildUUID() + inputFile.extname
64 video, 63 outputPath = join(CONFIG.STORAGE.TMP_DIR, outputFilename)
65 outputPath,
66 task,
67 lTags
68 })
69 64
70 if (tmpInputFilePath) await remove(tmpInputFilePath) 65 await processTask({
66 inputPath: tmpInputFilePath ?? originalFilePath,
67 video,
68 outputPath,
69 task,
70 lTags
71 })
71 72
72 // For the next iteration 73 if (tmpInputFilePath) await remove(tmpInputFilePath)
73 tmpInputFilePath = outputPath
74 }
75 74
76 return outputPath 75 // For the next iteration
77 }) 76 tmpInputFilePath = outputPath
77 }
78 78
79 logger.info('Video edition ended for video %s.', video.uuid, lTags) 79 return outputPath
80 })
80 81
81 const newFile = await buildNewFile(video, editionResultPath) 82 logger.info('Video edition ended for video %s.', video.uuid, lTags)
82 83
83 const outputPath = VideoPathManager.Instance.getFSVideoFileOutputPath(video, newFile) 84 const newFile = await buildNewFile(video, editionResultPath)
84 await move(editionResultPath, outputPath)
85 85
86 await createTorrentAndSetInfoHashFromPath(video, newFile, outputPath) 86 const outputPath = VideoPathManager.Instance.getFSVideoFileOutputPath(video, newFile)
87 await removeAllFiles(video, newFile) 87 await move(editionResultPath, outputPath)
88 88
89 await newFile.save() 89 await safeCleanupStudioTMPFiles(payload)
90 90
91 video.duration = await getVideoStreamDuration(outputPath) 91 await createTorrentAndSetInfoHashFromPath(video, newFile, outputPath)
92 await video.save() 92 await removeAllFiles(video, newFile)
93 93
94 await federateVideoIfNeeded(video, false, undefined) 94 await newFile.save()
95 95
96 const user = await UserModel.loadByVideoId(video.id) 96 video.duration = await getVideoStreamDuration(outputPath)
97 await video.save()
97 98
98 await createOptimizeOrMergeAudioJobs({ video, videoFile: newFile, isNewVideo: false, user, videoFileAlreadyLocked: false }) 99 await federateVideoIfNeeded(video, false, undefined)
100
101 const user = await UserModel.loadByVideoId(video.id)
102
103 await createOptimizeOrMergeAudioJobs({ video, videoFile: newFile, isNewVideo: false, user, videoFileAlreadyLocked: false })
104 } catch (err) {
105 await safeCleanupStudioTMPFiles(payload)
106
107 throw err
108 }
99} 109}
100 110
101// --------------------------------------------------------------------------- 111// ---------------------------------------------------------------------------
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 @@
1import { logger } from '@server/helpers/logger'
1import { MVideoFullLight } from '@server/types/models' 2import { MVideoFullLight } from '@server/types/models'
2import { getVideoStreamDuration } from '@shared/ffmpeg' 3import { getVideoStreamDuration } from '@shared/ffmpeg'
3import { VideoStudioTask } from '@shared/models' 4import { VideoStudioEditionPayload, VideoStudioTask } from '@shared/models'
5import { remove } from 'fs-extra'
4 6
5function buildTaskFileFieldname (indice: number, fieldName = 'file') { 7function buildTaskFileFieldname (indice: number, fieldName = 'file') {
6 return `tasks[${indice}][options][${fieldName}]` 8 return `tasks[${indice}][options][${fieldName}]`
7} 9}
8 10
9function getTaskFile (files: Express.Multer.File[], indice: number, fieldName = 'file') { 11function getTaskFileFromReq (files: Express.Multer.File[], indice: number, fieldName = 'file') {
10 return files.find(f => f.fieldname === buildTaskFileFieldname(indice, fieldName)) 12 return files.find(f => f.fieldname === buildTaskFileFieldname(indice, fieldName))
11} 13}
12 14
15async function safeCleanupStudioTMPFiles (payload: VideoStudioEditionPayload) {
16 for (const task of payload.tasks) {
17 try {
18 if (task.name === 'add-intro' || task.name === 'add-outro') {
19 await remove(task.options.file)
20 } else if (task.name === 'add-watermark') {
21 await remove(task.options.file)
22 }
23 } catch (err) {
24 logger.error('Cannot remove studio file', { err })
25 }
26 }
27}
28
13async function approximateIntroOutroAdditionalSize (video: MVideoFullLight, tasks: VideoStudioTask[], fileFinder: (i: number) => string) { 29async function approximateIntroOutroAdditionalSize (video: MVideoFullLight, tasks: VideoStudioTask[], fileFinder: (i: number) => string) {
14 let additionalDuration = 0 30 let additionalDuration = 0
15 31
@@ -28,5 +44,6 @@ async function approximateIntroOutroAdditionalSize (video: MVideoFullLight, task
28export { 44export {
29 approximateIntroOutroAdditionalSize, 45 approximateIntroOutroAdditionalSize,
30 buildTaskFileFieldname, 46 buildTaskFileFieldname,
31 getTaskFile 47 getTaskFileFromReq,
48 safeCleanupStudioTMPFiles
32} 49}