Fix splitting audio/video of existing videos

This commit is contained in:
Chocobozzz 2024-09-25 13:49:21 +02:00
parent 7e9fba3ae5
commit 093a9bf749
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
5 changed files with 313 additions and 163 deletions

View File

@ -1,8 +1,7 @@
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import { expect } from 'chai'
import { areMockObjectStorageTestsDisabled } from '@peertube/peertube-node-utils'
import { HttpStatusCode, VideoDetails } from '@peertube/peertube-models' import { HttpStatusCode, VideoDetails } from '@peertube/peertube-models'
import { areMockObjectStorageTestsDisabled } from '@peertube/peertube-node-utils'
import { import {
cleanupTests, cleanupTests,
ConfigCommand, ConfigCommand,
@ -16,7 +15,8 @@ import {
waitJobs waitJobs
} from '@peertube/peertube-server-commands' } from '@peertube/peertube-server-commands'
import { expectStartWith } from '@tests/shared/checks.js' import { expectStartWith } from '@tests/shared/checks.js'
import { checkResolutionsInMasterPlaylist } from '@tests/shared/streaming-playlists.js' import { checkResolutionsInMasterPlaylist, completeCheckHlsPlaylist } from '@tests/shared/streaming-playlists.js'
import { expect } from 'chai'
async function checkFilesInObjectStorage (objectStorage: ObjectStorageCommand, video: VideoDetails) { async function checkFilesInObjectStorage (objectStorage: ObjectStorageCommand, video: VideoDetails) {
for (const file of video.files) { for (const file of video.files) {
@ -81,175 +81,273 @@ function runTests (options: {
await servers[0].config.setTranscodingConcurrency(concurrency) await servers[0].config.setTranscodingConcurrency(concurrency)
}) })
it('Should generate HLS', async function () { describe('Common transcoding', function () {
this.timeout(60000)
await servers[0].videos.runTranscoding({ it('Should generate HLS', async function () {
videoId: videoUUID, this.timeout(60000)
transcodingType: 'hls'
await servers[0].videos.runTranscoding({
videoId: videoUUID,
transcodingType: 'hls'
})
await waitJobs(servers)
await expectNoFailedTranscodingJob(servers[0])
for (const server of servers) {
const videoDetails = await server.videos.get({ id: videoUUID })
expect(videoDetails.files).to.have.lengthOf(1)
expect(videoDetails.streamingPlaylists).to.have.lengthOf(1)
expect(videoDetails.streamingPlaylists[0].files).to.have.lengthOf(5)
if (enableObjectStorage) await checkFilesInObjectStorage(objectStorage, videoDetails)
}
}) })
await waitJobs(servers) it('Should generate Web Video', async function () {
await expectNoFailedTranscodingJob(servers[0]) this.timeout(60000)
for (const server of servers) { await servers[0].videos.runTranscoding({
const videoDetails = await server.videos.get({ id: videoUUID }) videoId: videoUUID,
transcodingType: 'web-video'
})
expect(videoDetails.files).to.have.lengthOf(1) await waitJobs(servers)
expect(videoDetails.streamingPlaylists).to.have.lengthOf(1)
expect(videoDetails.streamingPlaylists[0].files).to.have.lengthOf(5)
if (enableObjectStorage) await checkFilesInObjectStorage(objectStorage, videoDetails) for (const server of servers) {
} const videoDetails = await server.videos.get({ id: videoUUID })
})
it('Should generate Web Video', async function () { expect(videoDetails.files).to.have.lengthOf(5)
this.timeout(60000) expect(videoDetails.streamingPlaylists).to.have.lengthOf(1)
expect(videoDetails.streamingPlaylists[0].files).to.have.lengthOf(5)
await servers[0].videos.runTranscoding({ if (enableObjectStorage) await checkFilesInObjectStorage(objectStorage, videoDetails)
videoId: videoUUID, }
transcodingType: 'web-video'
}) })
await waitJobs(servers) it('Should generate Web Video from HLS only video', async function () {
this.timeout(60000)
for (const server of servers) { await servers[0].videos.removeAllWebVideoFiles({ videoId: videoUUID })
const videoDetails = await server.videos.get({ id: videoUUID }) await waitJobs(servers)
expect(videoDetails.files).to.have.lengthOf(5) await servers[0].videos.runTranscoding({ videoId: videoUUID, transcodingType: 'web-video' })
expect(videoDetails.streamingPlaylists).to.have.lengthOf(1) await waitJobs(servers)
expect(videoDetails.streamingPlaylists[0].files).to.have.lengthOf(5)
if (enableObjectStorage) await checkFilesInObjectStorage(objectStorage, videoDetails) for (const server of servers) {
} const videoDetails = await server.videos.get({ id: videoUUID })
})
it('Should generate Web Video from HLS only video', async function () { expect(videoDetails.files).to.have.lengthOf(5)
this.timeout(60000) expect(videoDetails.streamingPlaylists).to.have.lengthOf(1)
expect(videoDetails.streamingPlaylists[0].files).to.have.lengthOf(5)
await servers[0].videos.removeAllWebVideoFiles({ videoId: videoUUID }) if (enableObjectStorage) await checkFilesInObjectStorage(objectStorage, videoDetails)
await waitJobs(servers) }
})
await servers[0].videos.runTranscoding({ videoId: videoUUID, transcodingType: 'web-video' }) it('Should only generate Web Video', async function () {
await waitJobs(servers) this.timeout(60000)
for (const server of servers) { await servers[0].videos.removeHLSPlaylist({ videoId: videoUUID })
const videoDetails = await server.videos.get({ id: videoUUID }) await waitJobs(servers)
expect(videoDetails.files).to.have.lengthOf(5) await servers[0].videos.runTranscoding({ videoId: videoUUID, transcodingType: 'web-video' })
expect(videoDetails.streamingPlaylists).to.have.lengthOf(1) await waitJobs(servers)
expect(videoDetails.streamingPlaylists[0].files).to.have.lengthOf(5)
if (enableObjectStorage) await checkFilesInObjectStorage(objectStorage, videoDetails) for (const server of servers) {
} const videoDetails = await server.videos.get({ id: videoUUID })
})
it('Should only generate Web Video', async function () { expect(videoDetails.files).to.have.lengthOf(5)
this.timeout(60000) expect(videoDetails.streamingPlaylists).to.have.lengthOf(0)
await servers[0].videos.removeHLSPlaylist({ videoId: videoUUID }) if (enableObjectStorage) await checkFilesInObjectStorage(objectStorage, videoDetails)
await waitJobs(servers) }
})
await servers[0].videos.runTranscoding({ videoId: videoUUID, transcodingType: 'web-video' }) it('Should correctly update HLS playlist on resolution change', async function () {
await waitJobs(servers) this.timeout(120000)
for (const server of servers) { await servers[0].config.updateExistingConfig({
const videoDetails = await server.videos.get({ id: videoUUID }) newConfig: {
transcoding: {
enabled: true,
resolutions: ConfigCommand.getConfigResolutions(false),
expect(videoDetails.files).to.have.lengthOf(5) webVideos: {
expect(videoDetails.streamingPlaylists).to.have.lengthOf(0) enabled: true
},
if (enableObjectStorage) await checkFilesInObjectStorage(objectStorage, videoDetails) hls: {
} enabled: true
}) }
it('Should correctly update HLS playlist on resolution change', async function () {
this.timeout(120000)
await servers[0].config.updateExistingConfig({
newConfig: {
transcoding: {
enabled: true,
resolutions: ConfigCommand.getConfigResolutions(false),
webVideos: {
enabled: true
},
hls: {
enabled: true
} }
} }
})
const { uuid } = await servers[0].videos.quickUpload({ name: 'quick' })
await waitJobs(servers)
for (const server of servers) {
const videoDetails = await server.videos.get({ id: uuid })
expect(videoDetails.files).to.have.lengthOf(1)
expect(videoDetails.streamingPlaylists).to.have.lengthOf(1)
expect(videoDetails.streamingPlaylists[0].files).to.have.lengthOf(1)
if (enableObjectStorage) await checkFilesInObjectStorage(objectStorage, videoDetails)
shouldBeDeleted = [
videoDetails.streamingPlaylists[0].files[0].fileUrl,
videoDetails.streamingPlaylists[0].playlistUrl,
videoDetails.streamingPlaylists[0].segmentsSha256Url
]
}
await servers[0].config.updateExistingConfig({
newConfig: {
transcoding: {
enabled: true,
resolutions: ConfigCommand.getConfigResolutions(true),
webVideos: {
enabled: true
},
hls: {
enabled: true
}
}
}
})
await servers[0].videos.runTranscoding({ videoId: uuid, transcodingType: 'hls' })
await waitJobs(servers)
for (const server of servers) {
const videoDetails = await server.videos.get({ id: uuid })
expect(videoDetails.streamingPlaylists).to.have.lengthOf(1)
expect(videoDetails.streamingPlaylists[0].files).to.have.lengthOf(5)
if (enableObjectStorage) {
await checkFilesInObjectStorage(objectStorage, videoDetails)
const hlsPlaylist = videoDetails.streamingPlaylists[0]
const resolutions = hlsPlaylist.files.map(f => f.resolution.id)
await checkResolutionsInMasterPlaylist({ server: servers[0], playlistUrl: hlsPlaylist.playlistUrl, resolutions })
const shaBody = await servers[0].streamingPlaylists.getSegmentSha256({ url: hlsPlaylist.segmentsSha256Url, withRetry: true })
expect(Object.keys(shaBody)).to.have.lengthOf(5)
}
} }
}) })
const { uuid } = await servers[0].videos.quickUpload({ name: 'quick' }) it('Should have correctly deleted previous files', async function () {
for (const fileUrl of shouldBeDeleted) {
await waitJobs(servers) await makeRawRequest({ url: fileUrl, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
for (const server of servers) {
const videoDetails = await server.videos.get({ id: uuid })
expect(videoDetails.files).to.have.lengthOf(1)
expect(videoDetails.streamingPlaylists).to.have.lengthOf(1)
expect(videoDetails.streamingPlaylists[0].files).to.have.lengthOf(1)
if (enableObjectStorage) await checkFilesInObjectStorage(objectStorage, videoDetails)
shouldBeDeleted = [
videoDetails.streamingPlaylists[0].files[0].fileUrl,
videoDetails.streamingPlaylists[0].playlistUrl,
videoDetails.streamingPlaylists[0].segmentsSha256Url
]
}
await servers[0].config.updateExistingConfig({
newConfig: {
transcoding: {
enabled: true,
resolutions: ConfigCommand.getConfigResolutions(true),
webVideos: {
enabled: true
},
hls: {
enabled: true
}
}
} }
}) })
await servers[0].videos.runTranscoding({ videoId: uuid, transcodingType: 'hls' }) it('Should not have updated published at attributes', async function () {
await waitJobs(servers) const video = await servers[0].videos.get({ id: videoUUID })
for (const server of servers) { expect(video.publishedAt).to.equal(publishedAt)
const videoDetails = await server.videos.get({ id: uuid }) })
})
expect(videoDetails.streamingPlaylists).to.have.lengthOf(1) describe('With split audio and video', function () {
expect(videoDetails.streamingPlaylists[0].files).to.have.lengthOf(5)
if (enableObjectStorage) { async function runTest (options: {
await checkFilesInObjectStorage(objectStorage, videoDetails) audio: boolean
hls: boolean
webVideo: boolean
afterWebVideo: boolean
resolutions?: number[]
}) {
let resolutions = options.resolutions
const hlsPlaylist = videoDetails.streamingPlaylists[0] if (!resolutions) {
const resolutions = hlsPlaylist.files.map(f => f.resolution.id) resolutions = [ 720, 240 ]
await checkResolutionsInMasterPlaylist({ server: servers[0], playlistUrl: hlsPlaylist.playlistUrl, resolutions })
const shaBody = await servers[0].streamingPlaylists.getSegmentSha256({ url: hlsPlaylist.segmentsSha256Url, withRetry: true }) if (options.audio) resolutions.push(0)
expect(Object.keys(shaBody)).to.have.lengthOf(5)
} }
const objectStorageBaseUrl = enableObjectStorage
? objectStorage?.getMockPlaylistBaseUrl()
: undefined
await servers[0].config.enableTranscoding({
resolutions,
hls: options.hls,
splitAudioAndVideo: false,
webVideo: options.webVideo
})
const { uuid: videoUUID } = await servers[0].videos.quickUpload({ name: 'hls splitted' })
await waitJobs(servers)
await completeCheckHlsPlaylist({
servers,
resolutions,
videoUUID,
hlsOnly: !options.webVideo,
splittedAudio: false,
objectStorageBaseUrl
})
await servers[0].config.enableTranscoding({
resolutions,
hls: true,
splitAudioAndVideo: true,
webVideo: options.afterWebVideo
})
await servers[0].videos.runTranscoding({ videoId: videoUUID, transcodingType: 'hls' })
await waitJobs(servers)
if (options.afterWebVideo) {
await servers[0].videos.runTranscoding({ videoId: videoUUID, transcodingType: 'web-video' })
await waitJobs(servers)
}
await completeCheckHlsPlaylist({
servers,
resolutions,
videoUUID,
hlsOnly: !options.afterWebVideo,
splittedAudio: true,
objectStorageBaseUrl
})
} }
})
it('Should have correctly deleted previous files', async function () { it('Should split audio and video from an existing Web & HLS video', async function () {
for (const fileUrl of shouldBeDeleted) { this.timeout(60000)
await makeRawRequest({ url: fileUrl, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
}
})
it('Should not have updated published at attributes', async function () { await runTest({ webVideo: true, hls: true, afterWebVideo: true, audio: false })
const video = await servers[0].videos.get({ id: videoUUID }) })
expect(video.publishedAt).to.equal(publishedAt) it('Should split audio and video from an existing HLS video without audio resolution', async function () {
this.timeout(60000)
await runTest({ webVideo: false, hls: true, afterWebVideo: true, audio: false })
})
it('Should split audio and video to a HLS only video from an existing HLS video without audio resolution', async function () {
this.timeout(60000)
await runTest({ webVideo: false, hls: true, afterWebVideo: false, audio: false })
})
it('Should split audio and video to a HLS only video from an existing HLS video with audio resolution', async function () {
this.timeout(60000)
await runTest({ webVideo: false, hls: true, afterWebVideo: false, audio: false })
})
it('Should split audio and video on HLS only video that only have 1 resolution', async function () {
this.timeout(60000)
await runTest({ webVideo: false, hls: true, afterWebVideo: false, audio: false, resolutions: [ 720 ] })
})
}) })
after(async function () { after(async function () {

View File

@ -243,6 +243,41 @@ describe('Test VOD transcoding in peertube-runner program', function () {
resolutions: [ 720, 480, 360, 240, 144, 0 ] resolutions: [ 720, 480, 360, 240, 144, 0 ]
}) })
}) })
it('Should re-transcode a non splitted audio/video HLS only video', async function () {
this.timeout(240000)
const resolutions = [ 720, 240 ]
await servers[0].config.enableTranscoding({
hls: true,
webVideo: false,
resolutions,
splitAudioAndVideo: false
})
const { uuid } = await servers[0].videos.quickUpload({ name: 'manual hls only transcoding', fixture: 'video_short.mp4' })
await waitJobs(servers, { runnerJobs: true })
await servers[0].config.enableTranscoding({
hls: hlsEnabled,
webVideo: webVideoEnabled,
resolutions,
splitAudioAndVideo: splittedAudio
})
await servers[0].videos.runTranscoding({ transcodingType: 'hls', videoId: uuid })
await waitJobs(servers, { runnerJobs: true })
await completeCheckHlsPlaylist({
hlsOnly: true,
servers: [ servers[0] ],
videoUUID: uuid,
splittedAudio,
objectStorageBaseUrl: objectStorageBaseUrlHLS,
resolutions
})
})
} }
before(async function () { before(async function () {
@ -266,10 +301,12 @@ describe('Test VOD transcoding in peertube-runner program', function () {
}) })
function runSuites (objectStorage?: ObjectStorageCommand) { function runSuites (objectStorage?: ObjectStorageCommand) {
const resolutions = 'max'
describe('Web video only enabled', function () { describe('Web video only enabled', function () {
before(async function () { before(async function () {
await servers[0].config.enableTranscoding({ resolutions: 'max', webVideo: true, hls: false, with0p: true }) await servers[0].config.enableTranscoding({ resolutions, webVideo: true, hls: false, with0p: true })
}) })
runSpecificSuite({ webVideoEnabled: true, hlsEnabled: false, objectStorage }) runSpecificSuite({ webVideoEnabled: true, hlsEnabled: false, objectStorage })
@ -278,7 +315,7 @@ describe('Test VOD transcoding in peertube-runner program', function () {
describe('HLS videos only enabled', function () { describe('HLS videos only enabled', function () {
before(async function () { before(async function () {
await servers[0].config.enableTranscoding({ webVideo: false, hls: true, with0p: true }) await servers[0].config.enableTranscoding({ resolutions, webVideo: false, hls: true, with0p: true })
}) })
runSpecificSuite({ webVideoEnabled: false, hlsEnabled: true, objectStorage }) runSpecificSuite({ webVideoEnabled: false, hlsEnabled: true, objectStorage })
@ -287,7 +324,7 @@ describe('Test VOD transcoding in peertube-runner program', function () {
describe('HLS only with separated audio only enabled', function () { describe('HLS only with separated audio only enabled', function () {
before(async function () { before(async function () {
await servers[0].config.enableTranscoding({ webVideo: false, hls: true, splitAudioAndVideo: true, with0p: true }) await servers[0].config.enableTranscoding({ resolutions, webVideo: false, hls: true, splitAudioAndVideo: true, with0p: true })
}) })
runSpecificSuite({ webVideoEnabled: false, hlsEnabled: true, splittedAudio: true, objectStorage }) runSpecificSuite({ webVideoEnabled: false, hlsEnabled: true, splittedAudio: true, objectStorage })
@ -296,7 +333,7 @@ describe('Test VOD transcoding in peertube-runner program', function () {
describe('Web video & HLS with separated audio only enabled', function () { describe('Web video & HLS with separated audio only enabled', function () {
before(async function () { before(async function () {
await servers[0].config.enableTranscoding({ hls: true, webVideo: true, splitAudioAndVideo: true, with0p: true }) await servers[0].config.enableTranscoding({ resolutions, hls: true, webVideo: true, splitAudioAndVideo: true, with0p: true })
}) })
runSpecificSuite({ webVideoEnabled: true, hlsEnabled: true, splittedAudio: true, objectStorage }) runSpecificSuite({ webVideoEnabled: true, hlsEnabled: true, splittedAudio: true, objectStorage })
@ -305,7 +342,7 @@ describe('Test VOD transcoding in peertube-runner program', function () {
describe('Web video & HLS enabled', function () { describe('Web video & HLS enabled', function () {
before(async function () { before(async function () {
await servers[0].config.enableTranscoding({ hls: true, webVideo: true, with0p: true, splitAudioAndVideo: false }) await servers[0].config.enableTranscoding({ resolutions, hls: true, webVideo: true, with0p: true, splitAudioAndVideo: false })
}) })
runSpecificSuite({ webVideoEnabled: true, hlsEnabled: true, objectStorage }) runSpecificSuite({ webVideoEnabled: true, hlsEnabled: true, objectStorage })

View File

@ -127,8 +127,7 @@ export abstract class AbstractJobBuilder <P> {
} }
await this.createJobs({ await this.createJobs({
parent: mergeOrOptimizePayload, payloads: [ [ mergeOrOptimizePayload ], ...children ],
children,
user, user,
video video
}) })
@ -151,19 +150,24 @@ export abstract class AbstractJobBuilder <P> {
const inputFPS = video.getMaxFPS() const inputFPS = video.getMaxFPS()
const children = childrenResolutions.map(resolution => { const children = childrenResolutions
const fps = computeOutputFPS({ inputFPS, resolution, isOriginResolution: maxResolution === resolution, type: 'vod' }) .map(resolution => {
const fps = computeOutputFPS({ inputFPS, resolution, isOriginResolution: maxResolution === resolution, type: 'vod' })
if (transcodingType === 'hls') { if (transcodingType === 'hls') {
return this.buildHLSJobPayload({ video, resolution, fps, isNewVideo, separatedAudio }) // We'll generate audio resolution in a parent job
} if (resolution === VideoResolution.H_NOVIDEO && separatedAudio) return undefined
if (transcodingType === 'webtorrent' || transcodingType === 'web-video') { return this.buildHLSJobPayload({ video, resolution, fps, isNewVideo, separatedAudio })
return this.buildWebVideoJobPayload({ video, resolution, fps, isNewVideo }) }
}
throw new Error('Unknown transcoding type') if (transcodingType === 'webtorrent' || transcodingType === 'web-video') {
}) return this.buildWebVideoJobPayload({ video, resolution, fps, isNewVideo })
}
throw new Error('Unknown transcoding type')
})
.filter(r => !!r)
const fps = computeOutputFPS({ inputFPS, resolution: maxResolution, isOriginResolution: true, type: 'vod' }) const fps = computeOutputFPS({ inputFPS, resolution: maxResolution, isOriginResolution: true, type: 'vod' })
@ -171,9 +175,17 @@ export abstract class AbstractJobBuilder <P> {
? this.buildHLSJobPayload({ video, resolution: maxResolution, fps, isNewVideo, separatedAudio }) ? this.buildHLSJobPayload({ video, resolution: maxResolution, fps, isNewVideo, separatedAudio })
: this.buildWebVideoJobPayload({ video, resolution: maxResolution, fps, isNewVideo }) : this.buildWebVideoJobPayload({ video, resolution: maxResolution, fps, isNewVideo })
// Process the last resolution after the other ones to prevent concurrency issue // Low resolutions use the biggest one as ffmpeg input so we need to process max resolution (with audio) independently
// Because low resolutions use the biggest one as ffmpeg input const payloads: [ [ P ], ...(P[][]) ] = [ [ parent ] ]
await this.createJobs({ video, parent, children: [ children ], user: null })
// Process audio first to not override the max resolution where the audio stream will be removed
if (transcodingType === 'hls' && separatedAudio) {
payloads.unshift([ this.buildHLSJobPayload({ video, resolution: VideoResolution.H_NOVIDEO, fps, isNewVideo, separatedAudio }) ])
}
if (children && children.length !== 0) payloads.push(children)
await this.createJobs({ video, payloads, user: null })
} }
private async buildLowerResolutionJobPayloads (options: { private async buildLowerResolutionJobPayloads (options: {
@ -247,8 +259,7 @@ export abstract class AbstractJobBuilder <P> {
protected abstract createJobs (options: { protected abstract createJobs (options: {
video: MVideoFullLight video: MVideoFullLight
parent: P payloads: [ [ P ], ...(P[][]) ] // Array of sequential jobs to create that depend on parent job
children: P[][]
user: MUserId | null user: MUserId | null
}): Promise<void> }): Promise<void>

View File

@ -22,14 +22,16 @@ export class TranscodingJobQueueBuilder extends AbstractJobBuilder <Payload> {
protected async createJobs (options: { protected async createJobs (options: {
video: MVideo video: MVideo
parent: Payload payloads: [ [ Payload ], ...(Payload[][]) ] // Array of sequential jobs to create that depend on parent job
children: Payload[][]
user: MUserId | null user: MUserId | null
}): Promise<void> { }): Promise<void> {
const { video, parent, children, user } = options const { video, payloads, user } = options
const nextTranscodingSequentialJobs = await Bluebird.mapSeries(children, payloads => { const parent = payloads[0][0]
return Bluebird.mapSeries(payloads, payload => { payloads.shift()
const nextTranscodingSequentialJobs = await Bluebird.mapSeries(payloads, p => {
return Bluebird.mapSeries(p, payload => {
return this.buildTranscodingJob({ payload, user }) return this.buildTranscodingJob({ payload, user })
}) })
}) })
@ -42,9 +44,9 @@ export class TranscodingJobQueueBuilder extends AbstractJobBuilder <Payload> {
} }
} }
const mergeOrOptimizeJob = await this.buildTranscodingJob({ payload: parent, user, hasChildren: !!children.length }) const parentJob = await this.buildTranscodingJob({ payload: parent, user, hasChildren: payloads.length !== 0 })
await JobQueue.Instance.createSequentialJobFlow(mergeOrOptimizeJob, transcodingJobBuilderJob) await JobQueue.Instance.createSequentialJobFlow(parentJob, transcodingJobBuilderJob)
// transcoding-job-builder job will increase pendingTranscode // transcoding-job-builder job will increase pendingTranscode
await VideoJobInfoModel.increaseOrCreate(video.uuid, 'pendingTranscode') await VideoJobInfoModel.increaseOrCreate(video.uuid, 'pendingTranscode')

View File

@ -31,15 +31,17 @@ export class TranscodingRunnerJobBuilder extends AbstractJobBuilder <Payload> {
protected async createJobs (options: { protected async createJobs (options: {
video: MVideo video: MVideo
parent: Payload payloads: [ [ Payload ], ...(Payload[][]) ] // Array of sequential jobs to create that depend on parent job
children: Payload[][] // Array of sequential jobs to create that depend on parent job
user: MUserId | null user: MUserId | null
}): Promise<void> { }): Promise<void> {
const { parent, children, user } = options const { payloads, user } = options
const parent = payloads[0][0]
payloads.shift()
const parentJob = await this.createJob({ payload: parent, user }) const parentJob = await this.createJob({ payload: parent, user })
for (const parallelPayloads of children) { for (const parallelPayloads of payloads) {
let lastJob = parentJob let lastJob = parentJob
for (const parallelPayload of parallelPayloads) { for (const parallelPayload of parallelPayloads) {