]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/controllers/api/videos/studio.ts
2ccb2fb89fc548eff419e2f209c9d765f5c204a5
[github/Chocobozzz/PeerTube.git] / server / controllers / api / videos / studio.ts
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'
10 import {
11 HttpStatusCode,
12 VideoState,
13 VideoStudioCreateEdition,
14 VideoStudioTask,
15 VideoStudioTaskCut,
16 VideoStudioTaskIntro,
17 VideoStudioTaskOutro,
18 VideoStudioTaskPayload,
19 VideoStudioTaskWatermark
20 } from '@shared/models'
21 import { asyncMiddleware, authenticate, videoStudioAddEditionValidator } from '../../../middlewares'
22
23 const studioRouter = express.Router()
24
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
29
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))
33
34 const indice = parseInt(matches[1])
35 const task = body.tasks[indice]
36
37 if (!task) return cb(new Error('Cannot find array element of indice ' + indice + ' for ' + file.fieldname))
38
39 if (
40 [ 'add-intro', 'add-outro', 'add-watermark' ].includes(task.name) &&
41 file.fieldname === buildTaskFileFieldname(indice)
42 ) {
43 return cb(null, true)
44 }
45
46 return cb(null, false)
47 }
48 )
49
50 studioRouter.post('/:videoId/studio/edit',
51 authenticate,
52 tasksFiles,
53 asyncMiddleware(videoStudioAddEditionValidator),
54 asyncMiddleware(createEditionTasks)
55 )
56
57 // ---------------------------------------------------------------------------
58
59 export {
60 studioRouter
61 }
62
63 // ---------------------------------------------------------------------------
64
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
69
70 video.state = VideoState.TO_EDIT
71 await video.save()
72
73 const payload = {
74 videoUUID: video.uuid,
75 tasks: await Bluebird.mapSeries(body.tasks, (t, i) => buildTaskPayload(t, i, files))
76 }
77
78 JobQueue.Instance.createJobAsync({ type: 'video-studio-edition', payload })
79
80 return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
81 }
82
83 const taskPayloadBuilders: {
84 [id in VideoStudioTask['name']]: (
85 task: VideoStudioTask,
86 indice?: number,
87 files?: Express.Multer.File[]
88 ) => Promise<VideoStudioTaskPayload>
89 } = {
90 'add-intro': buildIntroOutroTask,
91 'add-outro': buildIntroOutroTask,
92 'cut': buildCutTask,
93 'add-watermark': buildWatermarkTask
94 }
95
96 function buildTaskPayload (task: VideoStudioTask, indice: number, files: Express.Multer.File[]): Promise<VideoStudioTaskPayload> {
97 return taskPayloadBuilders[task.name](task, indice, files)
98 }
99
100 async function buildIntroOutroTask (task: VideoStudioTaskIntro | VideoStudioTaskOutro, indice: number, files: Express.Multer.File[]) {
101 const destination = await moveStudioFileToPersistentTMP(getTaskFileFromReq(files, indice).path)
102
103 return {
104 name: task.name,
105 options: {
106 file: destination
107 }
108 }
109 }
110
111 function buildCutTask (task: VideoStudioTaskCut) {
112 return Promise.resolve({
113 name: task.name,
114 options: {
115 start: task.options.start,
116 end: task.options.end
117 }
118 })
119 }
120
121 async function buildWatermarkTask (task: VideoStudioTaskWatermark, indice: number, files: Express.Multer.File[]) {
122 const destination = await moveStudioFileToPersistentTMP(getTaskFileFromReq(files, indice).path)
123
124 return {
125 name: task.name,
126 options: {
127 file: destination
128 }
129 }
130 }
131
132 async function moveStudioFileToPersistentTMP (file: string) {
133 const destination = join(CONFIG.STORAGE.TMP_PERSISTENT_DIR, basename(file))
134
135 await move(file, destination)
136
137 return destination
138 }