aboutsummaryrefslogtreecommitdiffhomepage
path: root/packages/peertube-runner/server/process/shared/process-studio.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/peertube-runner/server/process/shared/process-studio.ts')
-rw-r--r--packages/peertube-runner/server/process/shared/process-studio.ts138
1 files changed, 138 insertions, 0 deletions
diff --git a/packages/peertube-runner/server/process/shared/process-studio.ts b/packages/peertube-runner/server/process/shared/process-studio.ts
new file mode 100644
index 000000000..f8262096e
--- /dev/null
+++ b/packages/peertube-runner/server/process/shared/process-studio.ts
@@ -0,0 +1,138 @@
1import { remove } from 'fs-extra'
2import { pick } from 'lodash'
3import { logger } from 'packages/peertube-runner/shared'
4import { extname, join } from 'path'
5import { buildUUID } from '@shared/extra-utils'
6import {
7 RunnerJobVideoEditionTranscodingPayload,
8 VideoEditionTranscodingSuccess,
9 VideoStudioTask,
10 VideoStudioTaskCutPayload,
11 VideoStudioTaskIntroPayload,
12 VideoStudioTaskOutroPayload,
13 VideoStudioTaskPayload,
14 VideoStudioTaskWatermarkPayload
15} from '@shared/models'
16import { ConfigManager } from '../../../shared/config-manager'
17import { buildFFmpegEdition, downloadInputFile, JobWithToken, ProcessOptions } from './common'
18
19export async function processStudioTranscoding (options: ProcessOptions<RunnerJobVideoEditionTranscodingPayload>) {
20 const { server, job, runnerToken } = options
21 const payload = job.payload
22
23 let outputPath: string
24 const inputPath = await downloadInputFile({ url: payload.input.videoFileUrl, runnerToken, job })
25 let tmpInputFilePath = inputPath
26
27 try {
28 for (const task of payload.tasks) {
29 const outputFilename = 'output-edition-' + buildUUID() + '.mp4'
30 outputPath = join(ConfigManager.Instance.getTranscodingDirectory(), outputFilename)
31
32 await processTask({
33 inputPath: tmpInputFilePath,
34 outputPath,
35 task,
36 job,
37 runnerToken
38 })
39
40 if (tmpInputFilePath) await remove(tmpInputFilePath)
41
42 // For the next iteration
43 tmpInputFilePath = outputPath
44 }
45
46 const successBody: VideoEditionTranscodingSuccess = {
47 videoFile: outputPath
48 }
49
50 await server.runnerJobs.success({
51 jobToken: job.jobToken,
52 jobUUID: job.uuid,
53 runnerToken,
54 payload: successBody
55 })
56 } finally {
57 await remove(tmpInputFilePath)
58 await remove(outputPath)
59 }
60}
61
62// ---------------------------------------------------------------------------
63// Private
64// ---------------------------------------------------------------------------
65
66type TaskProcessorOptions <T extends VideoStudioTaskPayload = VideoStudioTaskPayload> = {
67 inputPath: string
68 outputPath: string
69 task: T
70 runnerToken: string
71 job: JobWithToken
72}
73
74const taskProcessors: { [id in VideoStudioTask['name']]: (options: TaskProcessorOptions) => Promise<any> } = {
75 'add-intro': processAddIntroOutro,
76 'add-outro': processAddIntroOutro,
77 'cut': processCut,
78 'add-watermark': processAddWatermark
79}
80
81async function processTask (options: TaskProcessorOptions) {
82 const { task } = options
83
84 const processor = taskProcessors[options.task.name]
85 if (!process) throw new Error('Unknown task ' + task.name)
86
87 return processor(options)
88}
89
90async function processAddIntroOutro (options: TaskProcessorOptions<VideoStudioTaskIntroPayload | VideoStudioTaskOutroPayload>) {
91 const { inputPath, task, runnerToken, job } = options
92
93 logger.debug('Adding intro/outro to ' + inputPath)
94
95 const introOutroPath = await downloadInputFile({ url: task.options.file, runnerToken, job })
96
97 return buildFFmpegEdition().addIntroOutro({
98 ...pick(options, [ 'inputPath', 'outputPath' ]),
99
100 introOutroPath,
101 type: task.name === 'add-intro'
102 ? 'intro'
103 : 'outro'
104 })
105}
106
107function processCut (options: TaskProcessorOptions<VideoStudioTaskCutPayload>) {
108 const { inputPath, task } = options
109
110 logger.debug(`Cutting ${inputPath}`)
111
112 return buildFFmpegEdition().cutVideo({
113 ...pick(options, [ 'inputPath', 'outputPath' ]),
114
115 start: task.options.start,
116 end: task.options.end
117 })
118}
119
120async function processAddWatermark (options: TaskProcessorOptions<VideoStudioTaskWatermarkPayload>) {
121 const { inputPath, task, runnerToken, job } = options
122
123 logger.debug('Adding watermark to ' + inputPath)
124
125 const watermarkPath = await downloadInputFile({ url: task.options.file, runnerToken, job })
126
127 return buildFFmpegEdition().addWatermark({
128 ...pick(options, [ 'inputPath', 'outputPath' ]),
129
130 watermarkPath,
131
132 videoFilters: {
133 watermarkSizeRatio: task.options.watermarkSizeRatio,
134 horitonzalMarginRatio: task.options.horitonzalMarginRatio,
135 verticalMarginRatio: task.options.verticalMarginRatio
136 }
137 })
138}