1 import { expect } from 'chai'
2 import { expectStartWith, getAllFiles } from '@server/tests/shared'
3 import { areObjectStorageTestsDisabled } 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 checkDuration (server: PeerTubeServer, duration: number) {
22 const video = await server.videos.get({ id: videoUUID })
24 expect(video.duration).to.be.approximately(duration, 1)
26 for (const file of video.files) {
27 const metadata = await server.videos.getFileMetadata({ url: file.metadataUrl })
29 for (const stream of metadata.streams) {
30 expect(Math.round(stream.duration)).to.be.approximately(duration, 1)
35 async function renewVideo (fixture = 'video_short.webm') {
36 const video = await servers[0].videos.quickUpload({ name: 'video', fixture })
37 videoUUID = video.uuid
39 await waitJobs(servers)
42 async function createTasks (tasks: VideoStudioTask[]) {
43 await servers[0].videoStudio.createEditionTasks({ videoId: videoUUID, tasks })
44 await waitJobs(servers)
47 before(async function () {
50 servers = await createMultipleServers(2)
52 await setAccessTokensToServers(servers)
53 await setDefaultVideoChannel(servers)
55 await doubleFollow(servers[0], servers[1])
57 await servers[0].config.enableMinimumTranscoding()
59 await servers[0].config.enableStudio()
62 describe('Cutting', function () {
64 it('Should cut the beginning of the video', async function () {
68 await waitJobs(servers)
70 const beforeTasks = new Date()
81 for (const server of servers) {
82 await checkDuration(server, 3)
84 const video = await server.videos.get({ id: videoUUID })
85 expect(new Date(video.publishedAt)).to.be.below(beforeTasks)
89 it('Should cut the end of the video', async function () {
102 for (const server of servers) {
103 await checkDuration(server, 2)
107 it('Should cut start/end of the video', async function () {
108 this.timeout(120_000)
109 await renewVideo('video_short1.webm') // 10 seconds video duration
121 for (const server of servers) {
122 await checkDuration(server, 4)
127 describe('Intro/Outro', function () {
129 it('Should add an intro', async function () {
130 this.timeout(120_000)
137 file: 'video_short.webm'
142 for (const server of servers) {
143 await checkDuration(server, 10)
147 it('Should add an outro', async function () {
148 this.timeout(120_000)
155 file: 'video_very_short_240p.mp4'
160 for (const server of servers) {
161 await checkDuration(server, 7)
165 it('Should add an intro/outro', async function () {
166 this.timeout(120_000)
173 file: 'video_very_short_240p.mp4'
179 // Different frame rate
180 file: 'video_short2.webm'
185 for (const server of servers) {
186 await checkDuration(server, 12)
190 it('Should add an intro to a video without audio', async function () {
191 this.timeout(120_000)
192 await renewVideo('video_short_no_audio.mp4')
198 file: 'video_very_short_240p.mp4'
203 for (const server of servers) {
204 await checkDuration(server, 7)
208 it('Should add an outro without audio to a video with audio', async function () {
209 this.timeout(120_000)
216 file: 'video_short_no_audio.mp4'
221 for (const server of servers) {
222 await checkDuration(server, 10)
226 it('Should add an outro without audio to a video with audio', async function () {
227 this.timeout(120_000)
228 await renewVideo('video_short_no_audio.mp4')
234 file: 'video_short_no_audio.mp4'
239 for (const server of servers) {
240 await checkDuration(server, 10)
245 describe('Watermark', function () {
247 it('Should add a watermark to the video', async function () {
248 this.timeout(120_000)
251 const video = await servers[0].videos.get({ id: videoUUID })
252 const oldFileUrls = getAllFiles(video).map(f => f.fileUrl)
256 name: 'add-watermark',
258 file: 'thumbnail.png'
263 for (const server of servers) {
264 const video = await server.videos.get({ id: videoUUID })
265 const fileUrls = getAllFiles(video).map(f => f.fileUrl)
267 for (const oldUrl of oldFileUrls) {
268 expect(fileUrls).to.not.include(oldUrl)
274 describe('Complex tasks', function () {
275 it('Should run a complex task', async function () {
276 this.timeout(240_000)
279 await createTasks(VideoStudioCommand.getComplexTask())
281 for (const server of servers) {
282 await checkDuration(server, 9)
287 describe('HLS only video edition', function () {
289 before(async function () {
290 // Disable webtorrent
291 await servers[0].config.updateExistingSubConfig({
302 it('Should run a complex task on HLS only video', async function () {
303 this.timeout(240_000)
306 await createTasks(VideoStudioCommand.getComplexTask())
308 for (const server of servers) {
309 const video = await server.videos.get({ id: videoUUID })
310 expect(video.files).to.have.lengthOf(0)
312 await checkDuration(server, 9)
317 describe('Object storage video edition', function () {
318 if (areObjectStorageTestsDisabled()) return
320 before(async function () {
321 await ObjectStorageCommand.prepareDefaultBuckets()
323 await servers[0].kill()
324 await servers[0].run(ObjectStorageCommand.getDefaultConfig())
326 await servers[0].config.enableMinimumTranscoding()
329 it('Should run a complex task on a video in object storage', async function () {
330 this.timeout(240_000)
333 const video = await servers[0].videos.get({ id: videoUUID })
334 const oldFileUrls = getAllFiles(video).map(f => f.fileUrl)
336 await createTasks(VideoStudioCommand.getComplexTask())
338 for (const server of servers) {
339 const video = await server.videos.get({ id: videoUUID })
340 const files = getAllFiles(video)
342 for (const f of files) {
343 expect(oldFileUrls).to.not.include(f.fileUrl)
346 for (const webtorrentFile of video.files) {
347 expectStartWith(webtorrentFile.fileUrl, ObjectStorageCommand.getWebTorrentBaseUrl())
350 for (const hlsFile of video.streamingPlaylists[0].files) {
351 expectStartWith(hlsFile.fileUrl, ObjectStorageCommand.getPlaylistBaseUrl())
354 await checkDuration(server, 9)
359 after(async function () {
360 await cleanupTests(servers)