1 import { expect } from 'chai'
2 import { expectStartWith, getAllFiles } from '@server/tests/shared'
3 import { areObjectStorageTestsDisabled } from '@shared/core-utils'
4 import { VideoEditorTask } from '@shared/models'
11 setAccessTokensToServers,
12 setDefaultVideoChannel,
15 } from '@shared/server-commands'
17 describe('Test video editor', 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: VideoEditorTask[]) {
43 await servers[0].videoEditor.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.updateExistingSubConfig({
68 describe('Cutting', function () {
70 it('Should cut the beginning of the video', async function () {
74 await waitJobs(servers)
76 const beforeTasks = new Date()
87 for (const server of servers) {
88 await checkDuration(server, 3)
90 const video = await server.videos.get({ id: videoUUID })
91 expect(new Date(video.publishedAt)).to.be.below(beforeTasks)
95 it('Should cut the end of the video', async function () {
108 for (const server of servers) {
109 await checkDuration(server, 2)
113 it('Should cut start/end of the video', async function () {
114 this.timeout(120_000)
115 await renewVideo('video_short1.webm') // 10 seconds video duration
127 for (const server of servers) {
128 await checkDuration(server, 4)
133 describe('Intro/Outro', function () {
135 it('Should add an intro', async function () {
136 this.timeout(120_000)
143 file: 'video_short.webm'
148 for (const server of servers) {
149 await checkDuration(server, 10)
153 it('Should add an outro', async function () {
154 this.timeout(120_000)
161 file: 'video_very_short_240p.mp4'
166 for (const server of servers) {
167 await checkDuration(server, 7)
171 it('Should add an intro/outro', async function () {
172 this.timeout(120_000)
179 file: 'video_very_short_240p.mp4'
185 // Different frame rate
186 file: 'video_short2.webm'
191 for (const server of servers) {
192 await checkDuration(server, 12)
196 it('Should add an intro to a video without audio', async function () {
197 this.timeout(120_000)
198 await renewVideo('video_short_no_audio.mp4')
204 file: 'video_very_short_240p.mp4'
209 for (const server of servers) {
210 await checkDuration(server, 7)
214 it('Should add an outro without audio to a video with audio', async function () {
215 this.timeout(120_000)
222 file: 'video_short_no_audio.mp4'
227 for (const server of servers) {
228 await checkDuration(server, 10)
232 it('Should add an outro without audio to a video with audio', async function () {
233 this.timeout(120_000)
234 await renewVideo('video_short_no_audio.mp4')
240 file: 'video_short_no_audio.mp4'
245 for (const server of servers) {
246 await checkDuration(server, 10)
251 describe('Watermark', function () {
253 it('Should add a watermark to the video', async function () {
254 this.timeout(120_000)
257 const video = await servers[0].videos.get({ id: videoUUID })
258 const oldFileUrls = getAllFiles(video).map(f => f.fileUrl)
262 name: 'add-watermark',
264 file: 'thumbnail.png'
269 for (const server of servers) {
270 const video = await server.videos.get({ id: videoUUID })
271 const fileUrls = getAllFiles(video).map(f => f.fileUrl)
273 for (const oldUrl of oldFileUrls) {
274 expect(fileUrls).to.not.include(oldUrl)
280 describe('Complex tasks', function () {
281 it('Should run a complex task', async function () {
282 this.timeout(240_000)
285 await createTasks(VideoEditorCommand.getComplexTask())
287 for (const server of servers) {
288 await checkDuration(server, 9)
293 describe('HLS only video edition', function () {
295 before(async function () {
296 // Disable webtorrent
297 await servers[0].config.updateExistingSubConfig({
308 it('Should run a complex task on HLS only video', async function () {
309 this.timeout(240_000)
312 await createTasks(VideoEditorCommand.getComplexTask())
314 for (const server of servers) {
315 const video = await server.videos.get({ id: videoUUID })
316 expect(video.files).to.have.lengthOf(0)
318 await checkDuration(server, 9)
323 describe('Object storage video edition', function () {
324 if (areObjectStorageTestsDisabled()) return
326 before(async function () {
327 await ObjectStorageCommand.prepareDefaultBuckets()
329 await servers[0].kill()
330 await servers[0].run(ObjectStorageCommand.getDefaultConfig())
332 await servers[0].config.enableMinimumTranscoding()
335 it('Should run a complex task on a video in object storage', async function () {
336 this.timeout(240_000)
339 const video = await servers[0].videos.get({ id: videoUUID })
340 const oldFileUrls = getAllFiles(video).map(f => f.fileUrl)
342 await createTasks(VideoEditorCommand.getComplexTask())
344 for (const server of servers) {
345 const video = await server.videos.get({ id: videoUUID })
346 const files = getAllFiles(video)
348 for (const f of files) {
349 expect(oldFileUrls).to.not.include(f.fileUrl)
352 for (const webtorrentFile of video.files) {
353 expectStartWith(webtorrentFile.fileUrl, ObjectStorageCommand.getWebTorrentBaseUrl())
356 for (const hlsFile of video.streamingPlaylists[0].files) {
357 expectStartWith(hlsFile.fileUrl, ObjectStorageCommand.getPlaylistBaseUrl())
360 await checkDuration(server, 9)
365 after(async function () {
366 await cleanupTests(servers)