1 import Bluebird from 'bluebird'
2 import express from 'express'
3 import { move } from 'fs-extra'
4 import { basename } from 'path'
5 import { createAnyReqFiles } from '@server/helpers/express-utils'
6 import { MIMETYPES, VIDEO_FILTERS } from '@server/initializers/constants'
7 import { buildTaskFileFieldname, createVideoStudioJob, getStudioTaskFilePath, getTaskFileFromReq } from '@server/lib/video-studio'
11 VideoStudioCreateEdition,
16 VideoStudioTaskPayload,
17 VideoStudioTaskWatermark
18 } from '@shared/models'
19 import { asyncMiddleware, authenticate, videoStudioAddEditionValidator } from '../../../middlewares'
21 const studioRouter = express.Router()
23 const tasksFiles = createAnyReqFiles(
24 MIMETYPES.VIDEO.MIMETYPE_EXT,
25 (req: express.Request, file: Express.Multer.File, cb: (err: Error, result?: boolean) => void) => {
26 const body = req.body as VideoStudioCreateEdition
28 // Fetch array element
29 const matches = file.fieldname.match(/tasks\[(\d+)\]/)
30 if (!matches) return cb(new Error('Cannot find array element indice for ' + file.fieldname))
32 const indice = parseInt(matches[1])
33 const task = body.tasks[indice]
35 if (!task) return cb(new Error('Cannot find array element of indice ' + indice + ' for ' + file.fieldname))
38 [ 'add-intro', 'add-outro', 'add-watermark' ].includes(task.name) &&
39 file.fieldname === buildTaskFileFieldname(indice)
44 return cb(null, false)
48 studioRouter.post('/:videoId/studio/edit',
51 asyncMiddleware(videoStudioAddEditionValidator),
52 asyncMiddleware(createEditionTasks)
55 // ---------------------------------------------------------------------------
61 // ---------------------------------------------------------------------------
63 async function createEditionTasks (req: express.Request, res: express.Response) {
64 const files = req.files as Express.Multer.File[]
65 const body = req.body as VideoStudioCreateEdition
66 const video = res.locals.videoAll
68 video.state = VideoState.TO_EDIT
72 videoUUID: video.uuid,
73 tasks: await Bluebird.mapSeries(body.tasks, (t, i) => buildTaskPayload(t, i, files))
76 await createVideoStudioJob({
77 user: res.locals.oauth.token.User,
82 return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
85 const taskPayloadBuilders: {
86 [id in VideoStudioTask['name']]: (
87 task: VideoStudioTask,
89 files?: Express.Multer.File[]
90 ) => Promise<VideoStudioTaskPayload>
92 'add-intro': buildIntroOutroTask,
93 'add-outro': buildIntroOutroTask,
95 'add-watermark': buildWatermarkTask
98 function buildTaskPayload (task: VideoStudioTask, indice: number, files: Express.Multer.File[]): Promise<VideoStudioTaskPayload> {
99 return taskPayloadBuilders[task.name](task, indice, files)
102 async function buildIntroOutroTask (task: VideoStudioTaskIntro | VideoStudioTaskOutro, indice: number, files: Express.Multer.File[]) {
103 const destination = await moveStudioFileToPersistentTMP(getTaskFileFromReq(files, indice).path)
113 function buildCutTask (task: VideoStudioTaskCut) {
114 return Promise.resolve({
117 start: task.options.start,
118 end: task.options.end
123 async function buildWatermarkTask (task: VideoStudioTaskWatermark, indice: number, files: Express.Multer.File[]) {
124 const destination = await moveStudioFileToPersistentTMP(getTaskFileFromReq(files, indice).path)
130 watermarkSizeRatio: VIDEO_FILTERS.WATERMARK.SIZE_RATIO,
131 horitonzalMarginRatio: VIDEO_FILTERS.WATERMARK.HORIZONTAL_MARGIN_RATIO,
132 verticalMarginRatio: VIDEO_FILTERS.WATERMARK.VERTICAL_MARGIN_RATIO
137 async function moveStudioFileToPersistentTMP (file: string) {
138 const destination = getStudioTaskFilePath(basename(file))
140 await move(file, destination)