1 import Bluebird from 'bluebird'
2 import express from 'express'
3 import { move } from 'fs-extra'
4 import { basename, join } from 'path'
5 import { createAnyReqFiles } from '@server/helpers/express-utils'
6 import { CONFIG } from '@server/initializers/config'
7 import { MIMETYPES } from '@server/initializers/constants'
8 import { JobQueue } from '@server/lib/job-queue'
9 import { buildTaskFileFieldname, getTaskFileFromReq } from '@server/lib/video-studio'
13 VideoStudioCreateEdition,
18 VideoStudioTaskPayload,
19 VideoStudioTaskWatermark
20 } from '@shared/models'
21 import { asyncMiddleware, authenticate, videoStudioAddEditionValidator } from '../../../middlewares'
23 const studioRouter = express.Router()
25 const tasksFiles = createAnyReqFiles(
26 MIMETYPES.VIDEO.MIMETYPE_EXT,
27 (req: express.Request, file: Express.Multer.File, cb: (err: Error, result?: boolean) => void) => {
28 const body = req.body as VideoStudioCreateEdition
30 // Fetch array element
31 const matches = file.fieldname.match(/tasks\[(\d+)\]/)
32 if (!matches) return cb(new Error('Cannot find array element indice for ' + file.fieldname))
34 const indice = parseInt(matches[1])
35 const task = body.tasks[indice]
37 if (!task) return cb(new Error('Cannot find array element of indice ' + indice + ' for ' + file.fieldname))
40 [ 'add-intro', 'add-outro', 'add-watermark' ].includes(task.name) &&
41 file.fieldname === buildTaskFileFieldname(indice)
46 return cb(null, false)
50 studioRouter.post('/:videoId/studio/edit',
53 asyncMiddleware(videoStudioAddEditionValidator),
54 asyncMiddleware(createEditionTasks)
57 // ---------------------------------------------------------------------------
63 // ---------------------------------------------------------------------------
65 async function createEditionTasks (req: express.Request, res: express.Response) {
66 const files = req.files as Express.Multer.File[]
67 const body = req.body as VideoStudioCreateEdition
68 const video = res.locals.videoAll
70 video.state = VideoState.TO_EDIT
74 videoUUID: video.uuid,
75 tasks: await Bluebird.mapSeries(body.tasks, (t, i) => buildTaskPayload(t, i, files))
78 JobQueue.Instance.createJobAsync({ type: 'video-studio-edition', payload })
80 return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
83 const taskPayloadBuilders: {
84 [id in VideoStudioTask['name']]: (
85 task: VideoStudioTask,
87 files?: Express.Multer.File[]
88 ) => Promise<VideoStudioTaskPayload>
90 'add-intro': buildIntroOutroTask,
91 'add-outro': buildIntroOutroTask,
93 'add-watermark': buildWatermarkTask
96 function buildTaskPayload (task: VideoStudioTask, indice: number, files: Express.Multer.File[]): Promise<VideoStudioTaskPayload> {
97 return taskPayloadBuilders[task.name](task, indice, files)
100 async function buildIntroOutroTask (task: VideoStudioTaskIntro | VideoStudioTaskOutro, indice: number, files: Express.Multer.File[]) {
101 const destination = await moveStudioFileToPersistentTMP(getTaskFileFromReq(files, indice).path)
111 function buildCutTask (task: VideoStudioTaskCut) {
112 return Promise.resolve({
115 start: task.options.start,
116 end: task.options.end
121 async function buildWatermarkTask (task: VideoStudioTaskWatermark, indice: number, files: Express.Multer.File[]) {
122 const destination = await moveStudioFileToPersistentTMP(getTaskFileFromReq(files, indice).path)
132 async function moveStudioFileToPersistentTMP (file: string) {
133 const destination = join(CONFIG.STORAGE.TMP_PERSISTENT_DIR, basename(file))
135 await move(file, destination)