aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib/video-studio.ts
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2023-07-31 14:34:36 +0200
committerChocobozzz <me@florianbigard.com>2023-08-11 15:02:33 +0200
commit3a4992633ee62d5edfbb484d9c6bcb3cf158489d (patch)
treee4510b39bdac9c318fdb4b47018d08f15368b8f0 /server/lib/video-studio.ts
parent04d1da5621d25d59bd5fa1543b725c497bf5d9a8 (diff)
downloadPeerTube-3a4992633ee62d5edfbb484d9c6bcb3cf158489d.tar.gz
PeerTube-3a4992633ee62d5edfbb484d9c6bcb3cf158489d.tar.zst
PeerTube-3a4992633ee62d5edfbb484d9c6bcb3cf158489d.zip
Migrate server to ESM
Sorry for the very big commit that may lead to git log issues and merge conflicts, but it's a major step forward: * Server can be faster at startup because imports() are async and we can easily lazy import big modules * Angular doesn't seem to support ES import (with .js extension), so we had to correctly organize peertube into a monorepo: * Use yarn workspace feature * Use typescript reference projects for dependencies * Shared projects have been moved into "packages", each one is now a node module (with a dedicated package.json/tsconfig.json) * server/tools have been moved into apps/ and is now a dedicated app bundled and published on NPM so users don't have to build peertube cli tools manually * server/tests have been moved into packages/ so we don't compile them every time we want to run the server * Use isolatedModule option: * Had to move from const enum to const (https://www.typescriptlang.org/docs/handbook/enums.html#objects-vs-enums) * Had to explictely specify "type" imports when used in decorators * Prefer tsx (that uses esbuild under the hood) instead of ts-node to load typescript files (tests with mocha or scripts): * To reduce test complexity as esbuild doesn't support decorator metadata, we only test server files that do not import server models * We still build tests files into js files for a faster CI * Remove unmaintained peertube CLI import script * Removed some barrels to speed up execution (less imports)
Diffstat (limited to 'server/lib/video-studio.ts')
-rw-r--r--server/lib/video-studio.ts130
1 files changed, 0 insertions, 130 deletions
diff --git a/server/lib/video-studio.ts b/server/lib/video-studio.ts
deleted file mode 100644
index f549a7084..000000000
--- a/server/lib/video-studio.ts
+++ /dev/null
@@ -1,130 +0,0 @@
1import { move, remove } from 'fs-extra'
2import { join } from 'path'
3import { logger, loggerTagsFactory } from '@server/helpers/logger'
4import { createTorrentAndSetInfoHashFromPath } from '@server/helpers/webtorrent'
5import { CONFIG } from '@server/initializers/config'
6import { UserModel } from '@server/models/user/user'
7import { MUser, MVideo, MVideoFile, MVideoFullLight, MVideoWithAllFiles } from '@server/types/models'
8import { getVideoStreamDuration } from '@shared/ffmpeg'
9import { VideoStudioEditionPayload, VideoStudioTask, VideoStudioTaskPayload } from '@shared/models'
10import { federateVideoIfNeeded } from './activitypub/videos'
11import { JobQueue } from './job-queue'
12import { VideoStudioTranscodingJobHandler } from './runners'
13import { createOptimizeOrMergeAudioJobs } from './transcoding/create-transcoding-job'
14import { getTranscodingJobPriority } from './transcoding/transcoding-priority'
15import { buildNewFile, removeHLSPlaylist, removeWebVideoFile } from './video-file'
16import { VideoPathManager } from './video-path-manager'
17
18const lTags = loggerTagsFactory('video-studio')
19
20export function buildTaskFileFieldname (indice: number, fieldName = 'file') {
21 return `tasks[${indice}][options][${fieldName}]`
22}
23
24export function getTaskFileFromReq (files: Express.Multer.File[], indice: number, fieldName = 'file') {
25 return files.find(f => f.fieldname === buildTaskFileFieldname(indice, fieldName))
26}
27
28export function getStudioTaskFilePath (filename: string) {
29 return join(CONFIG.STORAGE.TMP_PERSISTENT_DIR, filename)
30}
31
32export async function safeCleanupStudioTMPFiles (tasks: VideoStudioTaskPayload[]) {
33 logger.info('Removing studio task files', { tasks, ...lTags() })
34
35 for (const task of tasks) {
36 try {
37 if (task.name === 'add-intro' || task.name === 'add-outro') {
38 await remove(task.options.file)
39 } else if (task.name === 'add-watermark') {
40 await remove(task.options.file)
41 }
42 } catch (err) {
43 logger.error('Cannot remove studio file', { err })
44 }
45 }
46}
47
48// ---------------------------------------------------------------------------
49
50export async function approximateIntroOutroAdditionalSize (
51 video: MVideoFullLight,
52 tasks: VideoStudioTask[],
53 fileFinder: (i: number) => string
54) {
55 let additionalDuration = 0
56
57 for (let i = 0; i < tasks.length; i++) {
58 const task = tasks[i]
59
60 if (task.name !== 'add-intro' && task.name !== 'add-outro') continue
61
62 const filePath = fileFinder(i)
63 additionalDuration += await getVideoStreamDuration(filePath)
64 }
65
66 return (video.getMaxQualityFile().size / video.duration) * additionalDuration
67}
68
69// ---------------------------------------------------------------------------
70
71export async function createVideoStudioJob (options: {
72 video: MVideo
73 user: MUser
74 payload: VideoStudioEditionPayload
75}) {
76 const { video, user, payload } = options
77
78 const priority = await getTranscodingJobPriority({ user, type: 'studio', fallback: 0 })
79
80 if (CONFIG.VIDEO_STUDIO.REMOTE_RUNNERS.ENABLED) {
81 await new VideoStudioTranscodingJobHandler().create({ video, tasks: payload.tasks, priority })
82 return
83 }
84
85 await JobQueue.Instance.createJob({ type: 'video-studio-edition', payload, priority })
86}
87
88export async function onVideoStudioEnded (options: {
89 editionResultPath: string
90 tasks: VideoStudioTaskPayload[]
91 video: MVideoFullLight
92}) {
93 const { video, tasks, editionResultPath } = options
94
95 const newFile = await buildNewFile({ path: editionResultPath, mode: 'web-video' })
96 newFile.videoId = video.id
97
98 const outputPath = VideoPathManager.Instance.getFSVideoFileOutputPath(video, newFile)
99 await move(editionResultPath, outputPath)
100
101 await safeCleanupStudioTMPFiles(tasks)
102
103 await createTorrentAndSetInfoHashFromPath(video, newFile, outputPath)
104 await removeAllFiles(video, newFile)
105
106 await newFile.save()
107
108 video.duration = await getVideoStreamDuration(outputPath)
109 await video.save()
110
111 await federateVideoIfNeeded(video, false, undefined)
112
113 const user = await UserModel.loadByVideoId(video.id)
114
115 await createOptimizeOrMergeAudioJobs({ video, videoFile: newFile, isNewVideo: false, user, videoFileAlreadyLocked: false })
116}
117
118// ---------------------------------------------------------------------------
119// Private
120// ---------------------------------------------------------------------------
121
122async function removeAllFiles (video: MVideoWithAllFiles, webVideoFileException: MVideoFile) {
123 await removeHLSPlaylist(video)
124
125 for (const file of video.VideoFiles) {
126 if (file.id === webVideoFileException.id) continue
127
128 await removeWebVideoFile(video, file.id)
129 }
130}