1 import { expect } from 'chai'
2 import { checkPersistentTmpIsEmpty, checkVideoDuration, expectStartWith } from '@server/tests/shared'
3 import { areMockObjectStorageTestsDisabled, getAllFiles } from '@shared/core-utils'
4 import { VideoStudioTask } from '@shared/models'
11 setAccessTokensToServers,
12 setDefaultVideoChannel,
15 } from '@shared/server-commands'
17 describe('Test video studio', function () {
18 let servers: PeerTubeServer[] = []
21 async function renewVideo (fixture = 'video_short.webm') {
22 const video = await servers[0].videos.quickUpload({ name: 'video', fixture })
23 videoUUID = video.uuid
25 await waitJobs(servers)
28 async function createTasks (tasks: VideoStudioTask[]) {
29 await servers[0].videoStudio.createEditionTasks({ videoId: videoUUID, tasks })
30 await waitJobs(servers)
33 before(async function () {
36 servers = await createMultipleServers(2)
38 await setAccessTokensToServers(servers)
39 await setDefaultVideoChannel(servers)
41 await doubleFollow(servers[0], servers[1])
43 await servers[0].config.enableMinimumTranscoding()
45 await servers[0].config.enableStudio()
48 describe('Cutting', function () {
50 it('Should cut the beginning of the video', async function () {
54 await waitJobs(servers)
56 const beforeTasks = new Date()
67 for (const server of servers) {
68 await checkVideoDuration(server, videoUUID, 3)
70 const video = await server.videos.get({ id: videoUUID })
71 expect(new Date(video.publishedAt)).to.be.below(beforeTasks)
75 it('Should cut the end of the video', async function () {
88 for (const server of servers) {
89 await checkVideoDuration(server, videoUUID, 2)
93 it('Should cut start/end of the video', async function () {
95 await renewVideo('video_short1.webm') // 10 seconds video duration
107 for (const server of servers) {
108 await checkVideoDuration(server, videoUUID, 4)
113 describe('Intro/Outro', function () {
115 it('Should add an intro', async function () {
116 this.timeout(120_000)
123 file: 'video_short.webm'
128 for (const server of servers) {
129 await checkVideoDuration(server, videoUUID, 10)
133 it('Should add an outro', async function () {
134 this.timeout(120_000)
141 file: 'video_very_short_240p.mp4'
146 for (const server of servers) {
147 await checkVideoDuration(server, videoUUID, 7)
151 it('Should add an intro/outro', async function () {
152 this.timeout(120_000)
159 file: 'video_very_short_240p.mp4'
165 // Different frame rate
166 file: 'video_short2.webm'
171 for (const server of servers) {
172 await checkVideoDuration(server, videoUUID, 12)
176 it('Should add an intro to a video without audio', async function () {
177 this.timeout(120_000)
178 await renewVideo('video_short_no_audio.mp4')
184 file: 'video_very_short_240p.mp4'
189 for (const server of servers) {
190 await checkVideoDuration(server, videoUUID, 7)
194 it('Should add an outro without audio to a video with audio', async function () {
195 this.timeout(120_000)
202 file: 'video_short_no_audio.mp4'
207 for (const server of servers) {
208 await checkVideoDuration(server, videoUUID, 10)
212 it('Should add an outro without audio to a video with audio', async function () {
213 this.timeout(120_000)
214 await renewVideo('video_short_no_audio.mp4')
220 file: 'video_short_no_audio.mp4'
225 for (const server of servers) {
226 await checkVideoDuration(server, videoUUID, 10)
231 describe('Watermark', function () {
233 it('Should add a watermark to the video', async function () {
234 this.timeout(120_000)
237 const video = await servers[0].videos.get({ id: videoUUID })
238 const oldFileUrls = getAllFiles(video).map(f => f.fileUrl)
242 name: 'add-watermark',
244 file: 'thumbnail.png'
249 for (const server of servers) {
250 const video = await server.videos.get({ id: videoUUID })
251 const fileUrls = getAllFiles(video).map(f => f.fileUrl)
253 for (const oldUrl of oldFileUrls) {
254 expect(fileUrls).to.not.include(oldUrl)
260 describe('Complex tasks', function () {
261 it('Should run a complex task', async function () {
262 this.timeout(240_000)
265 await createTasks(VideoStudioCommand.getComplexTask())
267 for (const server of servers) {
268 await checkVideoDuration(server, videoUUID, 9)
273 describe('HLS only studio edition', function () {
275 before(async function () {
276 // Disable webtorrent
277 await servers[0].config.updateExistingSubConfig({
288 it('Should run a complex task on HLS only video', async function () {
289 this.timeout(240_000)
292 await createTasks(VideoStudioCommand.getComplexTask())
294 for (const server of servers) {
295 const video = await server.videos.get({ id: videoUUID })
296 expect(video.files).to.have.lengthOf(0)
298 await checkVideoDuration(server, videoUUID, 9)
303 describe('Server restart', function () {
305 it('Should still be able to run video edition after a server restart', async function () {
306 this.timeout(240_000)
309 await servers[0].videoStudio.createEditionTasks({ videoId: videoUUID, tasks: VideoStudioCommand.getComplexTask() })
311 await servers[0].kill()
312 await servers[0].run()
314 await waitJobs(servers)
316 for (const server of servers) {
317 await checkVideoDuration(server, videoUUID, 9)
321 it('Should have an empty persistent tmp directory', async function () {
322 await checkPersistentTmpIsEmpty(servers[0])
326 describe('Object storage studio edition', function () {
327 if (areMockObjectStorageTestsDisabled()) return
329 before(async function () {
330 await ObjectStorageCommand.prepareDefaultMockBuckets()
332 await servers[0].kill()
333 await servers[0].run(ObjectStorageCommand.getDefaultMockConfig())
335 await servers[0].config.enableMinimumTranscoding()
338 it('Should run a complex task on a video in object storage', async function () {
339 this.timeout(240_000)
342 const video = await servers[0].videos.get({ id: videoUUID })
343 const oldFileUrls = getAllFiles(video).map(f => f.fileUrl)
345 await createTasks(VideoStudioCommand.getComplexTask())
347 for (const server of servers) {
348 const video = await server.videos.get({ id: videoUUID })
349 const files = getAllFiles(video)
351 for (const f of files) {
352 expect(oldFileUrls).to.not.include(f.fileUrl)
355 for (const webtorrentFile of video.files) {
356 expectStartWith(webtorrentFile.fileUrl, ObjectStorageCommand.getMockWebTorrentBaseUrl())
359 for (const hlsFile of video.streamingPlaylists[0].files) {
360 expectStartWith(hlsFile.fileUrl, ObjectStorageCommand.getMockPlaylistBaseUrl())
363 await checkVideoDuration(server, videoUUID, 9)
368 after(async function () {
369 await cleanupTests(servers)