diff options
Diffstat (limited to 'server/lib/runners/job-handlers/video-studio-transcoding-job-handler.ts')
-rw-r--r-- | server/lib/runners/job-handlers/video-studio-transcoding-job-handler.ts | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/server/lib/runners/job-handlers/video-studio-transcoding-job-handler.ts b/server/lib/runners/job-handlers/video-studio-transcoding-job-handler.ts new file mode 100644 index 000000000..f604382b7 --- /dev/null +++ b/server/lib/runners/job-handlers/video-studio-transcoding-job-handler.ts | |||
@@ -0,0 +1,157 @@ | |||
1 | |||
2 | import { basename } from 'path' | ||
3 | import { logger } from '@server/helpers/logger' | ||
4 | import { onVideoStudioEnded, safeCleanupStudioTMPFiles } from '@server/lib/video-studio' | ||
5 | import { MVideo } from '@server/types/models' | ||
6 | import { MRunnerJob } from '@server/types/models/runners' | ||
7 | import { buildUUID } from '@shared/extra-utils' | ||
8 | import { | ||
9 | isVideoStudioTaskIntro, | ||
10 | isVideoStudioTaskOutro, | ||
11 | isVideoStudioTaskWatermark, | ||
12 | RunnerJobState, | ||
13 | RunnerJobUpdatePayload, | ||
14 | RunnerJobStudioTranscodingPayload, | ||
15 | RunnerJobVideoStudioTranscodingPrivatePayload, | ||
16 | VideoStudioTranscodingSuccess, | ||
17 | VideoState, | ||
18 | VideoStudioTaskPayload | ||
19 | } from '@shared/models' | ||
20 | import { generateRunnerEditionTranscodingVideoInputFileUrl, generateRunnerTranscodingVideoInputFileUrl } from '../runner-urls' | ||
21 | import { AbstractJobHandler } from './abstract-job-handler' | ||
22 | import { loadTranscodingRunnerVideo } from './shared' | ||
23 | |||
24 | type CreateOptions = { | ||
25 | video: MVideo | ||
26 | tasks: VideoStudioTaskPayload[] | ||
27 | priority: number | ||
28 | } | ||
29 | |||
30 | // eslint-disable-next-line max-len | ||
31 | export class VideoStudioTranscodingJobHandler extends AbstractJobHandler<CreateOptions, RunnerJobUpdatePayload, VideoStudioTranscodingSuccess> { | ||
32 | |||
33 | async create (options: CreateOptions) { | ||
34 | const { video, priority, tasks } = options | ||
35 | |||
36 | const jobUUID = buildUUID() | ||
37 | const payload: RunnerJobStudioTranscodingPayload = { | ||
38 | input: { | ||
39 | videoFileUrl: generateRunnerTranscodingVideoInputFileUrl(jobUUID, video.uuid) | ||
40 | }, | ||
41 | tasks: tasks.map(t => { | ||
42 | if (isVideoStudioTaskIntro(t) || isVideoStudioTaskOutro(t)) { | ||
43 | return { | ||
44 | ...t, | ||
45 | |||
46 | options: { | ||
47 | ...t.options, | ||
48 | |||
49 | file: generateRunnerEditionTranscodingVideoInputFileUrl(jobUUID, video.uuid, basename(t.options.file)) | ||
50 | } | ||
51 | } | ||
52 | } | ||
53 | |||
54 | if (isVideoStudioTaskWatermark(t)) { | ||
55 | return { | ||
56 | ...t, | ||
57 | |||
58 | options: { | ||
59 | ...t.options, | ||
60 | |||
61 | file: generateRunnerEditionTranscodingVideoInputFileUrl(jobUUID, video.uuid, basename(t.options.file)) | ||
62 | } | ||
63 | } | ||
64 | } | ||
65 | |||
66 | return t | ||
67 | }) | ||
68 | } | ||
69 | |||
70 | const privatePayload: RunnerJobVideoStudioTranscodingPrivatePayload = { | ||
71 | videoUUID: video.uuid, | ||
72 | originalTasks: tasks | ||
73 | } | ||
74 | |||
75 | const job = await this.createRunnerJob({ | ||
76 | type: 'video-studio-transcoding', | ||
77 | jobUUID, | ||
78 | payload, | ||
79 | privatePayload, | ||
80 | priority | ||
81 | }) | ||
82 | |||
83 | return job | ||
84 | } | ||
85 | |||
86 | // --------------------------------------------------------------------------- | ||
87 | |||
88 | protected isAbortSupported () { | ||
89 | return true | ||
90 | } | ||
91 | |||
92 | protected specificUpdate (_options: { | ||
93 | runnerJob: MRunnerJob | ||
94 | }) { | ||
95 | // empty | ||
96 | } | ||
97 | |||
98 | protected specificAbort (_options: { | ||
99 | runnerJob: MRunnerJob | ||
100 | }) { | ||
101 | // empty | ||
102 | } | ||
103 | |||
104 | protected async specificComplete (options: { | ||
105 | runnerJob: MRunnerJob | ||
106 | resultPayload: VideoStudioTranscodingSuccess | ||
107 | }) { | ||
108 | const { runnerJob, resultPayload } = options | ||
109 | const privatePayload = runnerJob.privatePayload as RunnerJobVideoStudioTranscodingPrivatePayload | ||
110 | |||
111 | const video = await loadTranscodingRunnerVideo(runnerJob, this.lTags) | ||
112 | if (!video) { | ||
113 | await safeCleanupStudioTMPFiles(privatePayload.originalTasks) | ||
114 | |||
115 | } | ||
116 | |||
117 | const videoFilePath = resultPayload.videoFile as string | ||
118 | |||
119 | await onVideoStudioEnded({ video, editionResultPath: videoFilePath, tasks: privatePayload.originalTasks }) | ||
120 | |||
121 | logger.info( | ||
122 | 'Runner video edition transcoding job %s for %s ended.', | ||
123 | runnerJob.uuid, video.uuid, this.lTags(video.uuid, runnerJob.uuid) | ||
124 | ) | ||
125 | } | ||
126 | |||
127 | protected specificError (options: { | ||
128 | runnerJob: MRunnerJob | ||
129 | nextState: RunnerJobState | ||
130 | }) { | ||
131 | if (options.nextState === RunnerJobState.ERRORED) { | ||
132 | return this.specificErrorOrCancel(options) | ||
133 | } | ||
134 | |||
135 | return Promise.resolve() | ||
136 | } | ||
137 | |||
138 | protected specificCancel (options: { | ||
139 | runnerJob: MRunnerJob | ||
140 | }) { | ||
141 | return this.specificErrorOrCancel(options) | ||
142 | } | ||
143 | |||
144 | private async specificErrorOrCancel (options: { | ||
145 | runnerJob: MRunnerJob | ||
146 | }) { | ||
147 | const { runnerJob } = options | ||
148 | |||
149 | const payload = runnerJob.privatePayload as RunnerJobVideoStudioTranscodingPrivatePayload | ||
150 | await safeCleanupStudioTMPFiles(payload.originalTasks) | ||
151 | |||
152 | const video = await loadTranscodingRunnerVideo(options.runnerJob, this.lTags) | ||
153 | if (!video) return | ||
154 | |||
155 | return video.setNewState(VideoState.PUBLISHED, false, undefined) | ||
156 | } | ||
157 | } | ||