Skip to content

Commit cfebfcd

Browse files
committed
Merge branch 'release/v8.1.x' into develop
2 parents 1f127d9 + 806485b commit cfebfcd

8 files changed

Lines changed: 55 additions & 34 deletions

File tree

packages/tests/src/api/check-params/video-studio.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,14 +249,18 @@ describe('Test video studio API validator', function () {
249249
await cut(2, 2)
250250
})
251251

252-
it('Should fail with inconsistents start/end', async function () {
252+
it('Should fail with inconsistent start/end', async function () {
253253
await cut(2, 1)
254254
})
255255

256256
it('Should fail without start and end', async function () {
257257
await cut(undefined, undefined)
258258
})
259259

260+
it('Should fail with a bad end', async function () {
261+
await cut(undefined, 0)
262+
})
263+
260264
it('Should succeed with the correct params', async function () {
261265
this.timeout(360000)
262266

server/core/helpers/custom-validators/video-studio.ts

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,48 +6,54 @@ import { isArray } from './misc.js'
66
import { isVideoFileMimeTypeValid, isVideoImageValid } from './videos.js'
77
import { forceNumber } from '@peertube/peertube-core-utils'
88

9-
function isValidStudioTasksArray (tasks: any) {
9+
export function isValidStudioTasksArray (tasks: any) {
1010
if (!isArray(tasks)) return false
1111

1212
return tasks.length >= CONSTRAINTS_FIELDS.VIDEO_STUDIO.TASKS.min &&
1313
tasks.length <= CONSTRAINTS_FIELDS.VIDEO_STUDIO.TASKS.max
1414
}
1515

16-
function isStudioCutTaskValid (task: VideoStudioTask) {
16+
export function isStudioCutTaskValid (options: {
17+
task: VideoStudioTask
18+
}) {
19+
const { task } = options
20+
1721
if (task.name !== 'cut') return false
1822
if (!task.options) return false
1923

2024
const { start, end } = task.options
2125
if (!start && !end) return false
2226

23-
if (start && !validator.default.isInt(start + '', CONSTRAINTS_FIELDS.VIDEO_STUDIO.CUT_TIME)) return false
24-
if (end && !validator.default.isInt(end + '', CONSTRAINTS_FIELDS.VIDEO_STUDIO.CUT_TIME)) return false
27+
if (start && !validator.default.isInt(start + '', CONSTRAINTS_FIELDS.VIDEO_STUDIO.CUT_TIME_START)) return false
28+
if (end && !validator.default.isInt(end + '', CONSTRAINTS_FIELDS.VIDEO_STUDIO.CUT_TIME_END)) return false
2529

2630
if (!start || !end) return true
2731

2832
return forceNumber(start) < forceNumber(end)
2933
}
3034

31-
function isStudioTaskAddIntroOutroValid (task: VideoStudioTask, indice: number, files: Express.Multer.File[]) {
35+
export function isStudioTaskAddIntroOutroValid (options: {
36+
task: VideoStudioTask
37+
indice: number
38+
files: Express.Multer.File[]
39+
}) {
40+
const { task, indice, files } = options
41+
3242
const file = files.find(f => f.fieldname === buildTaskFileFieldname(indice, 'file'))
3343

3444
return (task.name === 'add-intro' || task.name === 'add-outro') &&
3545
file && isVideoFileMimeTypeValid([ file ], null)
3646
}
3747

38-
function isStudioTaskAddWatermarkValid (task: VideoStudioTask, indice: number, files: Express.Multer.File[]) {
48+
export function isStudioTaskAddWatermarkValid (options: {
49+
task: VideoStudioTask
50+
indice: number
51+
files: Express.Multer.File[]
52+
}) {
53+
const { task, indice, files } = options
54+
3955
const file = files.find(f => f.fieldname === buildTaskFileFieldname(indice, 'file'))
4056

4157
return task.name === 'add-watermark' &&
4258
file && isVideoImageValid([ file ], null, true)
4359
}
44-
45-
// ---------------------------------------------------------------------------
46-
47-
export {
48-
isValidStudioTasksArray,
49-
50-
isStudioCutTaskValid,
51-
isStudioTaskAddIntroOutroValid,
52-
isStudioTaskAddWatermarkValid
53-
}

server/core/initializers/constants.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,8 @@ export const CONSTRAINTS_FIELDS = {
516516
},
517517
VIDEO_STUDIO: {
518518
TASKS: { min: 1, max: 10 }, // Number of tasks
519-
CUT_TIME: { min: 0 } // Value
519+
CUT_TIME_START: { min: 0 }, // Value
520+
CUT_TIME_END: { min: 1 } // Value
520521
},
521522
LOGS: {
522523
CLIENT_MESSAGE: { min: 1, max: 1000 }, // Length

server/core/lib/job-queue/handlers/video-studio-edition.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
import { buildUUID } from '@peertube/peertube-node-utils'
1414
import { getFFmpegCommandWrapperOptions } from '@server/helpers/ffmpeg/index.js'
1515
import { CONFIG } from '@server/initializers/config.js'
16+
import { sequelizeTypescript } from '@server/initializers/database.js'
1617
import { VideoTranscodingProfilesManager } from '@server/lib/transcoding/default-transcoding-profiles.js'
1718
import { isUserQuotaValid } from '@server/lib/user.js'
1819
import { VideoPathManager } from '@server/lib/video-path-manager.js'
@@ -94,8 +95,12 @@ async function processVideoStudioEdition (job: Job) {
9495
await safeCleanupStudioTMPFiles(payload.tasks)
9596

9697
try {
97-
const video = await VideoModel.loadFull(payload.videoUUID)
98-
await video.setNewState(VideoState.PUBLISHED, false, undefined)
98+
await sequelizeTypescript.transaction(async transaction => {
99+
const video = await VideoModel.load(payload.videoUUID, transaction)
100+
if (!video || video.state === VideoState.PUBLISHED) return
101+
102+
await video.setNewState(VideoState.PUBLISHED, false, transaction)
103+
})
99104
} catch (err) {
100105
logger.error('Cannot reset video state after studio error', { err, ...lTags })
101106
}

server/core/lib/move-storage/move-to-object-storage.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export async function moveVideoToObjectStorage (options: {
5555
await moveToNextState({ video: { uuid: videoUUID }, ...moveVideoState })
5656
} else {
5757
const videoFull = await VideoModel.loadFull(videoUUID)
58-
await federateVideoIfNeeded(videoFull, false, undefined)
58+
if (videoFull) await federateVideoIfNeeded(videoFull, false, undefined)
5959
}
6060
}
6161

server/core/lib/runners/job-handlers/shared/utils.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { onWebVideoFileTranscoding } from '@server/lib/transcoding/web-transcodi
99
import { VideoModel } from '@server/models/video/video.js'
1010
import { MVideoFull } from '@server/types/models/index.js'
1111
import { MRunnerJob } from '@server/types/models/runners/index.js'
12+
import { Transaction } from 'sequelize'
1213

1314
export async function onVODWebVideoOrAudioMergeTranscodingJob (options: {
1415
video: MVideoFull
@@ -27,10 +28,10 @@ export async function onVODWebVideoOrAudioMergeTranscodingJob (options: {
2728
await onTranscodingEnded({ isNewVideo: privatePayload.isNewVideo, moveVideoToNextState: privatePayload.canMoveVideoState, video })
2829
}
2930

30-
export async function loadRunnerVideo (runnerJob: MRunnerJob, lTags: LoggerTagsFn) {
31+
export async function loadRunnerVideo (runnerJob: MRunnerJob, lTags: LoggerTagsFn, transaction?: Transaction) {
3132
const videoUUID = runnerJob.privatePayload.videoUUID
3233

33-
const video = await VideoModel.loadFull(videoUUID)
34+
const video = await VideoModel.loadFull(videoUUID, transaction)
3435
if (!video) {
3536
logger.info('Video %s does not exist anymore after runner job.', videoUUID, lTags(videoUUID))
3637
return undefined

server/core/lib/runners/job-handlers/video-studio-transcoding-job-handler.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,18 @@ import {
2424
} from '../runner-urls.js'
2525
import { AbstractJobHandler } from './abstract-job-handler.js'
2626
import { loadRunnerVideo } from './shared/utils.js'
27+
import { sequelizeTypescript } from '@server/initializers/database.js'
2728

2829
type CreateOptions = {
2930
video: MVideoWithFile
3031
tasks: VideoStudioTaskPayload[]
3132
priority: number
3233
}
3334

34-
// dprint-ignore
3535
// eslint-disable-next-line max-len
36-
export class VideoStudioTranscodingJobHandler extends AbstractJobHandler<CreateOptions, RunnerJobUpdatePayload, VideoStudioTranscodingSuccess> {
36+
export class VideoStudioTranscodingJobHandler
37+
extends AbstractJobHandler<CreateOptions, RunnerJobUpdatePayload, VideoStudioTranscodingSuccess>
38+
{
3739
async create (options: CreateOptions) {
3840
const { video, priority, tasks } = options
3941

@@ -161,9 +163,11 @@ export class VideoStudioTranscodingJobHandler extends AbstractJobHandler<CreateO
161163
const payload = runnerJob.privatePayload as RunnerJobVideoStudioTranscodingPrivatePayload
162164
await safeCleanupStudioTMPFiles(payload.originalTasks)
163165

164-
const video = await loadRunnerVideo(options.runnerJob, this.lTags)
165-
if (!video) return
166+
await sequelizeTypescript.transaction(async transaction => {
167+
const video = await loadRunnerVideo(options.runnerJob, this.lTags, transaction)
168+
if (!video || video.state === VideoState.PUBLISHED) return
166169

167-
return video.setNewState(VideoState.PUBLISHED, false, undefined)
170+
await video.setNewState(VideoState.PUBLISHED, false, transaction)
171+
})
168172
}
169173
}

server/core/middlewares/validators/videos/video-studio.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const videoStudioAddEditionValidator = [
2626
if (CONFIG.VIDEO_STUDIO.ENABLED !== true) {
2727
res.fail({
2828
status: HttpStatusCode.BAD_REQUEST_400,
29-
message: 'Video studio is disabled on this instance'
29+
message: req.t('Video studio is disabled on this instance')
3030
})
3131

3232
return cleanUpReqFiles(req)
@@ -47,7 +47,7 @@ const videoStudioAddEditionValidator = [
4747
if (!checkTask(req, task, i)) {
4848
res.fail({
4949
status: HttpStatusCode.BAD_REQUEST_400,
50-
message: `Task ${task.name} is invalid`
50+
message: req.t('Task {taskName} is invalid', { taskName: task.name })
5151
})
5252

5353
return cleanUpReqFiles(req)
@@ -57,7 +57,7 @@ const videoStudioAddEditionValidator = [
5757
if (task.name === 'add-intro' || task.name === 'add-outro' || task.name === 'add-watermark') {
5858
res.fail({
5959
status: HttpStatusCode.BAD_REQUEST_400,
60-
message: `Task ${task.name} is invalid: video does not contain a video stream`
60+
message: req.t('Task {taskName} is invalid: video does not contain a video stream', { taskName: task.name })
6161
})
6262

6363
return cleanUpReqFiles(req)
@@ -71,7 +71,7 @@ const videoStudioAddEditionValidator = [
7171
if (await isAudioFile(filePath)) {
7272
res.fail({
7373
status: HttpStatusCode.BAD_REQUEST_400,
74-
message: `Task ${task.name} is invalid: input file does not contain a video stream`
74+
message: req.t('Task {taskName} is invalid: input file does not contain a video stream', { taskName: task.name })
7575
})
7676

7777
return cleanUpReqFiles(req)
@@ -104,7 +104,7 @@ export {
104104
// ---------------------------------------------------------------------------
105105

106106
const taskCheckers: {
107-
[id in VideoStudioTask['name']]: (task: VideoStudioTask, indice?: number, files?: Express.Multer.File[]) => boolean
107+
[id in VideoStudioTask['name']]: (options: { task: VideoStudioTask, indice?: number, files?: Express.Multer.File[] }) => boolean
108108
} = {
109109
'cut': isStudioCutTaskValid,
110110
'add-intro': isStudioTaskAddIntroOutroValid,
@@ -116,5 +116,5 @@ function checkTask (req: express.Request, task: VideoStudioTask, indice?: number
116116
const checker = taskCheckers[task.name]
117117
if (!checker) return false
118118

119-
return checker(task, indice, req.files as Express.Multer.File[])
119+
return checker({ task, indice, files: req.files as Express.Multer.File[] })
120120
}

0 commit comments

Comments
 (0)