aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/test.yml1
-rw-r--r--server/controllers/api/videos/upload.ts2
-rw-r--r--server/lib/object-storage/pre-signed-urls.ts41
-rw-r--r--server/middlewares/validators/videos/videos.ts6
-rw-r--r--server/tests/api/check-params/live.ts4
-rw-r--r--server/tests/api/check-params/runners.ts2
-rw-r--r--server/tests/api/check-params/video-imports.ts4
-rw-r--r--server/tests/api/check-params/video-playlists.ts4
-rw-r--r--server/tests/api/check-params/video-studio.ts6
-rw-r--r--server/tests/api/check-params/videos.ts8
-rw-r--r--server/tests/api/live/live.ts6
-rw-r--r--server/tests/api/runners/runner-studio-transcoding.ts2
-rw-r--r--server/tests/api/runners/runner-vod-transcoding.ts2
-rw-r--r--server/tests/api/transcoding/transcoder.ts4
-rw-r--r--server/tests/api/transcoding/video-studio.ts2
-rw-r--r--server/tests/api/videos/multiple-servers.ts25
-rw-r--r--server/tests/api/videos/single-server.ts4
-rw-r--r--server/tests/api/videos/video-imports.ts10
-rw-r--r--server/tests/api/videos/video-playlist-thumbnails.ts18
-rw-r--r--server/tests/api/videos/video-playlists.ts16
-rw-r--r--server/tests/api/videos/video-storyboard.ts6
-rw-r--r--server/tests/cli/prune-storage.ts2
-rw-r--r--server/tests/fixtures/custom-preview-big.pngbin0 -> 536513 bytes
-rw-r--r--server/tests/fixtures/custom-preview.jpgbin0 -> 14146 bytes
-rw-r--r--server/tests/fixtures/custom-thumbnail-big.jpgbin0 -> 20379 bytes
-rw-r--r--server/tests/fixtures/custom-thumbnail.jpgbin0 -> 6898 bytes
-rw-r--r--server/tests/fixtures/custom-thumbnail.pngbin0 -> 18070 bytes
-rw-r--r--server/tests/fixtures/preview-big.pngbin432157 -> 0 bytes
-rw-r--r--server/tests/fixtures/preview.jpgbin26147 -> 0 bytes
-rw-r--r--server/tests/fixtures/thumbnail-big.jpgbin16286 -> 0 bytes
-rw-r--r--server/tests/fixtures/thumbnail.jpgbin6493 -> 0 bytes
-rw-r--r--server/tests/fixtures/thumbnail.pngbin4221 -> 0 bytes
-rw-r--r--server/tests/fixtures/video_short1-preview.webm.jpgbin30788 -> 31188 bytes
-rw-r--r--server/tests/fixtures/video_short1.webm.jpgbin6254 -> 6334 bytes
-rw-r--r--server/tests/fixtures/video_short2.webm.jpgbin6493 -> 6607 bytes
-rw-r--r--server/tests/helpers/image.ts8
-rw-r--r--server/tests/shared/checks.ts11
-rw-r--r--server/tests/shared/videos.ts6
-rw-r--r--shared/server-commands/server/server.ts2
-rw-r--r--shared/server-commands/videos/video-studio-command.ts2
-rw-r--r--support/doc/development/tests.md1
41 files changed, 133 insertions, 72 deletions
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 407907e53..baddba758 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -46,6 +46,7 @@ jobs:
46 PGHOST: localhost 46 PGHOST: localhost
47 NODE_PENDING_JOB_WAIT: 250 47 NODE_PENDING_JOB_WAIT: 250
48 ENABLE_OBJECT_STORAGE_TESTS: true 48 ENABLE_OBJECT_STORAGE_TESTS: true
49 ENABLE_FFMPEG_THUMBNAIL_PIXEL_COMPARISON_TESTS: true
49 OBJECT_STORAGE_SCALEWAY_KEY_ID: ${{ secrets.OBJECT_STORAGE_SCALEWAY_KEY_ID }} 50 OBJECT_STORAGE_SCALEWAY_KEY_ID: ${{ secrets.OBJECT_STORAGE_SCALEWAY_KEY_ID }}
50 OBJECT_STORAGE_SCALEWAY_ACCESS_KEY: ${{ secrets.OBJECT_STORAGE_SCALEWAY_ACCESS_KEY }} 51 OBJECT_STORAGE_SCALEWAY_ACCESS_KEY: ${{ secrets.OBJECT_STORAGE_SCALEWAY_ACCESS_KEY }}
51 YOUTUBE_DL_DOWNLOAD_BEARER_TOKEN: ${{ secrets.GITHUB_TOKEN }} 52 YOUTUBE_DL_DOWNLOAD_BEARER_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/server/controllers/api/videos/upload.ts b/server/controllers/api/videos/upload.ts
index 86ab4591e..6c471ff90 100644
--- a/server/controllers/api/videos/upload.ts
+++ b/server/controllers/api/videos/upload.ts
@@ -111,7 +111,7 @@ async function addVideoLegacy (req: express.Request, res: express.Response) {
111async function addVideoResumable (req: express.Request, res: express.Response) { 111async function addVideoResumable (req: express.Request, res: express.Response) {
112 const videoPhysicalFile = res.locals.videoFileResumable 112 const videoPhysicalFile = res.locals.videoFileResumable
113 const videoInfo = videoPhysicalFile.metadata 113 const videoInfo = videoPhysicalFile.metadata
114 const files = { previewfile: videoInfo.previewfile } 114 const files = { previewfile: videoInfo.previewfile, thumbnailfile: videoInfo.thumbnailfile }
115 115
116 const response = await addVideo({ req, res, videoPhysicalFile, videoInfo, files }) 116 const response = await addVideo({ req, res, videoPhysicalFile, videoInfo, files })
117 await Redis.Instance.setUploadSession(req.query.upload_id, response) 117 await Redis.Instance.setUploadSession(req.query.upload_id, response)
diff --git a/server/lib/object-storage/pre-signed-urls.ts b/server/lib/object-storage/pre-signed-urls.ts
new file mode 100644
index 000000000..46a0750a1
--- /dev/null
+++ b/server/lib/object-storage/pre-signed-urls.ts
@@ -0,0 +1,41 @@
1import { GetObjectCommand } from '@aws-sdk/client-s3'
2import { getSignedUrl } from '@aws-sdk/s3-request-presigner'
3import { CONFIG } from '@server/initializers/config'
4import { MStreamingPlaylistVideo, MVideoFile } from '@server/types/models'
5import { generateHLSObjectStorageKey, generateWebTorrentObjectStorageKey } from './keys'
6import { buildKey, getClient } from './shared'
7
8export function generateWebVideoPresignedUrl (options: {
9 file: MVideoFile
10 downloadFilename: string
11}) {
12 const { file, downloadFilename } = options
13
14 const key = generateWebTorrentObjectStorageKey(file.filename)
15
16 const command = new GetObjectCommand({
17 Bucket: CONFIG.OBJECT_STORAGE.VIDEOS.BUCKET_NAME,
18 Key: buildKey(key, CONFIG.OBJECT_STORAGE.VIDEOS),
19 ResponseContentDisposition: `attachment; filename=${downloadFilename}`
20 })
21
22 return getSignedUrl(getClient(), command, { expiresIn: 3600 * 24 })
23}
24
25export function generateHLSFilePresignedUrl (options: {
26 streamingPlaylist: MStreamingPlaylistVideo
27 file: MVideoFile
28 downloadFilename: string
29}) {
30 const { streamingPlaylist, file, downloadFilename } = options
31
32 const key = generateHLSObjectStorageKey(streamingPlaylist, file.filename)
33
34 const command = new GetObjectCommand({
35 Bucket: CONFIG.OBJECT_STORAGE.STREAMING_PLAYLISTS.BUCKET_NAME,
36 Key: buildKey(key, CONFIG.OBJECT_STORAGE.STREAMING_PLAYLISTS),
37 ResponseContentDisposition: `attachment; filename=${downloadFilename}`
38 })
39
40 return getSignedUrl(getClient(), command, { expiresIn: 3600 * 24 })
41}
diff --git a/server/middlewares/validators/videos/videos.ts b/server/middlewares/validators/videos/videos.ts
index fc2f95aa5..9034772c0 100644
--- a/server/middlewares/validators/videos/videos.ts
+++ b/server/middlewares/validators/videos/videos.ts
@@ -223,10 +223,12 @@ const videosAddResumableInitValidator = getCommonVideoEditAttributes().concat([
223 223
224 if (!isValidPasswordProtectedPrivacy(req, res)) return cleanup() 224 if (!isValidPasswordProtectedPrivacy(req, res)) return cleanup()
225 225
226 // multer required unsetting the Content-Type, now we can set it for node-uploadx 226 // Multer required unsetting the Content-Type, now we can set it for node-uploadx
227 req.headers['content-type'] = 'application/json; charset=utf-8' 227 req.headers['content-type'] = 'application/json; charset=utf-8'
228 // place previewfile in metadata so that uploadx saves it in .META 228
229 // Place thumbnail/previewfile in metadata so that uploadx saves it in .META
229 if (req.files?.['previewfile']) req.body.previewfile = req.files['previewfile'] 230 if (req.files?.['previewfile']) req.body.previewfile = req.files['previewfile']
231 if (req.files?.['thumbnailfile']) req.body.thumbnailfile = req.files['thumbnailfile']
230 232
231 return next() 233 return next()
232 } 234 }
diff --git a/server/tests/api/check-params/live.ts b/server/tests/api/check-params/live.ts
index 406a96824..5021db516 100644
--- a/server/tests/api/check-params/live.ts
+++ b/server/tests/api/check-params/live.ts
@@ -194,7 +194,7 @@ describe('Test video lives API validator', function () {
194 it('Should fail with a big thumbnail file', async function () { 194 it('Should fail with a big thumbnail file', async function () {
195 const fields = baseCorrectParams 195 const fields = baseCorrectParams
196 const attaches = { 196 const attaches = {
197 thumbnailfile: buildAbsoluteFixturePath('preview-big.png') 197 thumbnailfile: buildAbsoluteFixturePath('custom-preview-big.png')
198 } 198 }
199 199
200 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) 200 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
@@ -212,7 +212,7 @@ describe('Test video lives API validator', function () {
212 it('Should fail with a big preview file', async function () { 212 it('Should fail with a big preview file', async function () {
213 const fields = baseCorrectParams 213 const fields = baseCorrectParams
214 const attaches = { 214 const attaches = {
215 previewfile: buildAbsoluteFixturePath('preview-big.png') 215 previewfile: buildAbsoluteFixturePath('custom-preview-big.png')
216 } 216 }
217 217
218 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) 218 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
diff --git a/server/tests/api/check-params/runners.ts b/server/tests/api/check-params/runners.ts
index 48821b678..4ba90802f 100644
--- a/server/tests/api/check-params/runners.ts
+++ b/server/tests/api/check-params/runners.ts
@@ -752,7 +752,7 @@ describe('Test managing runners', function () {
752 }) 752 })
753 753
754 it('Should fail with an invalid vod audio merge payload', async function () { 754 it('Should fail with an invalid vod audio merge payload', async function () {
755 const attributes = { name: 'audio_with_preview', previewfile: 'preview.jpg', fixture: 'sample.ogg' } 755 const attributes = { name: 'audio_with_preview', previewfile: 'custom-preview.jpg', fixture: 'sample.ogg' }
756 await server.videos.upload({ attributes, mode: 'legacy' }) 756 await server.videos.upload({ attributes, mode: 'legacy' })
757 757
758 await waitJobs([ server ]) 758 await waitJobs([ server ])
diff --git a/server/tests/api/check-params/video-imports.ts b/server/tests/api/check-params/video-imports.ts
index 7f19b9ee9..8c6f43c12 100644
--- a/server/tests/api/check-params/video-imports.ts
+++ b/server/tests/api/check-params/video-imports.ts
@@ -244,7 +244,7 @@ describe('Test video imports API validator', function () {
244 it('Should fail with a big thumbnail file', async function () { 244 it('Should fail with a big thumbnail file', async function () {
245 const fields = baseCorrectParams 245 const fields = baseCorrectParams
246 const attaches = { 246 const attaches = {
247 thumbnailfile: buildAbsoluteFixturePath('preview-big.png') 247 thumbnailfile: buildAbsoluteFixturePath('custom-preview-big.png')
248 } 248 }
249 249
250 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) 250 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
@@ -262,7 +262,7 @@ describe('Test video imports API validator', function () {
262 it('Should fail with a big preview file', async function () { 262 it('Should fail with a big preview file', async function () {
263 const fields = baseCorrectParams 263 const fields = baseCorrectParams
264 const attaches = { 264 const attaches = {
265 previewfile: buildAbsoluteFixturePath('preview-big.png') 265 previewfile: buildAbsoluteFixturePath('custom-preview-big.png')
266 } 266 }
267 267
268 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) 268 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
diff --git a/server/tests/api/check-params/video-playlists.ts b/server/tests/api/check-params/video-playlists.ts
index 8090897c1..8c3233e0b 100644
--- a/server/tests/api/check-params/video-playlists.ts
+++ b/server/tests/api/check-params/video-playlists.ts
@@ -196,7 +196,7 @@ describe('Test video playlists API validator', function () {
196 attributes: { 196 attributes: {
197 displayName: 'display name', 197 displayName: 'display name',
198 privacy: VideoPlaylistPrivacy.UNLISTED, 198 privacy: VideoPlaylistPrivacy.UNLISTED,
199 thumbnailfile: 'thumbnail.jpg', 199 thumbnailfile: 'custom-thumbnail.jpg',
200 videoChannelId: server.store.channel.id, 200 videoChannelId: server.store.channel.id,
201 201
202 ...attributes 202 ...attributes
@@ -260,7 +260,7 @@ describe('Test video playlists API validator', function () {
260 }) 260 })
261 261
262 it('Should fail with a thumbnail file too big', async function () { 262 it('Should fail with a thumbnail file too big', async function () {
263 const params = getBase({ thumbnailfile: 'preview-big.png' }) 263 const params = getBase({ thumbnailfile: 'custom-preview-big.png' })
264 264
265 await command.create(params) 265 await command.create(params)
266 await command.update(getUpdate(params, playlist.shortUUID)) 266 await command.update(getUpdate(params, playlist.shortUUID))
diff --git a/server/tests/api/check-params/video-studio.ts b/server/tests/api/check-params/video-studio.ts
index add8d9164..4ac0d93ed 100644
--- a/server/tests/api/check-params/video-studio.ts
+++ b/server/tests/api/check-params/video-studio.ts
@@ -293,7 +293,7 @@ describe('Test video studio API validator', function () {
293 it('Should succeed with the correct params', async function () { 293 it('Should succeed with the correct params', async function () {
294 this.timeout(120000) 294 this.timeout(120000)
295 295
296 await addWatermark('thumbnail.jpg', HttpStatusCode.NO_CONTENT_204) 296 await addWatermark('custom-thumbnail.jpg', HttpStatusCode.NO_CONTENT_204)
297 297
298 await waitJobs([ server ]) 298 await waitJobs([ server ])
299 }) 299 })
@@ -322,8 +322,8 @@ describe('Test video studio API validator', function () {
322 }) 322 })
323 323
324 it('Should fail with an invalid file', async function () { 324 it('Should fail with an invalid file', async function () {
325 await addIntroOutro('add-intro', 'thumbnail.jpg') 325 await addIntroOutro('add-intro', 'custom-thumbnail.jpg')
326 await addIntroOutro('add-outro', 'thumbnail.jpg') 326 await addIntroOutro('add-outro', 'custom-thumbnail.jpg')
327 }) 327 })
328 328
329 it('Should fail with a file that does not contain video stream', async function () { 329 it('Should fail with a file that does not contain video stream', async function () {
diff --git a/server/tests/api/check-params/videos.ts b/server/tests/api/check-params/videos.ts
index 094ab6891..6ee1955a7 100644
--- a/server/tests/api/check-params/videos.ts
+++ b/server/tests/api/check-params/videos.ts
@@ -384,7 +384,7 @@ describe('Test videos API validator', function () {
384 it('Should fail with a big thumbnail file', async function () { 384 it('Should fail with a big thumbnail file', async function () {
385 const fields = baseCorrectParams 385 const fields = baseCorrectParams
386 const attaches = { 386 const attaches = {
387 thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'preview-big.png'), 387 thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'custom-preview-big.png'),
388 fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') 388 fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
389 } 389 }
390 390
@@ -404,7 +404,7 @@ describe('Test videos API validator', function () {
404 it('Should fail with a big preview file', async function () { 404 it('Should fail with a big preview file', async function () {
405 const fields = baseCorrectParams 405 const fields = baseCorrectParams
406 const attaches = { 406 const attaches = {
407 previewfile: join(root(), 'server', 'tests', 'fixtures', 'preview-big.png'), 407 previewfile: join(root(), 'server', 'tests', 'fixtures', 'custom-preview-big.png'),
408 fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') 408 fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
409 } 409 }
410 410
@@ -615,7 +615,7 @@ describe('Test videos API validator', function () {
615 it('Should fail with a big thumbnail file', async function () { 615 it('Should fail with a big thumbnail file', async function () {
616 const fields = baseCorrectParams 616 const fields = baseCorrectParams
617 const attaches = { 617 const attaches = {
618 thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'preview-big.png') 618 thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'custom-preview-big.png')
619 } 619 }
620 620
621 await makeUploadRequest({ 621 await makeUploadRequest({
@@ -647,7 +647,7 @@ describe('Test videos API validator', function () {
647 it('Should fail with a big preview file', async function () { 647 it('Should fail with a big preview file', async function () {
648 const fields = baseCorrectParams 648 const fields = baseCorrectParams
649 const attaches = { 649 const attaches = {
650 previewfile: join(root(), 'server', 'tests', 'fixtures', 'preview-big.png') 650 previewfile: join(root(), 'server', 'tests', 'fixtures', 'custom-preview-big.png')
651 } 651 }
652 652
653 await makeUploadRequest({ 653 await makeUploadRequest({
diff --git a/server/tests/api/live/live.ts b/server/tests/api/live/live.ts
index 7ab67b126..2b302a8a2 100644
--- a/server/tests/api/live/live.ts
+++ b/server/tests/api/live/live.ts
@@ -2,7 +2,7 @@
2 2
3import { expect } from 'chai' 3import { expect } from 'chai'
4import { basename, join } from 'path' 4import { basename, join } from 'path'
5import { SQLCommand, testImage, testLiveVideoResolutions } from '@server/tests/shared' 5import { SQLCommand, testImageGeneratedByFFmpeg, testLiveVideoResolutions } from '@server/tests/shared'
6import { getAllFiles, wait } from '@shared/core-utils' 6import { getAllFiles, wait } from '@shared/core-utils'
7import { ffprobePromise, getVideoStream } from '@shared/ffmpeg' 7import { ffprobePromise, getVideoStream } from '@shared/ffmpeg'
8import { 8import {
@@ -121,8 +121,8 @@ describe('Test live', function () {
121 expect(video.downloadEnabled).to.be.false 121 expect(video.downloadEnabled).to.be.false
122 expect(video.privacy.id).to.equal(VideoPrivacy.PUBLIC) 122 expect(video.privacy.id).to.equal(VideoPrivacy.PUBLIC)
123 123
124 await testImage(server.url, 'video_short1-preview.webm', video.previewPath) 124 await testImageGeneratedByFFmpeg(server.url, 'video_short1-preview.webm', video.previewPath)
125 await testImage(server.url, 'video_short1.webm', video.thumbnailPath) 125 await testImageGeneratedByFFmpeg(server.url, 'video_short1.webm', video.thumbnailPath)
126 126
127 const live = await server.live.get({ videoId: liveVideoUUID }) 127 const live = await server.live.get({ videoId: liveVideoUUID })
128 128
diff --git a/server/tests/api/runners/runner-studio-transcoding.ts b/server/tests/api/runners/runner-studio-transcoding.ts
index 41c556775..443a9d02a 100644
--- a/server/tests/api/runners/runner-studio-transcoding.ts
+++ b/server/tests/api/runners/runner-studio-transcoding.ts
@@ -104,7 +104,7 @@ describe('Test runner video studio transcoding', function () {
104 { 104 {
105 name: 'add-watermark' as 'add-watermark', 105 name: 'add-watermark' as 'add-watermark',
106 options: { 106 options: {
107 file: 'thumbnail.png' 107 file: 'custom-thumbnail.png'
108 } 108 }
109 }, 109 },
110 { 110 {
diff --git a/server/tests/api/runners/runner-vod-transcoding.ts b/server/tests/api/runners/runner-vod-transcoding.ts
index d9da0f40d..ca16d9c10 100644
--- a/server/tests/api/runners/runner-vod-transcoding.ts
+++ b/server/tests/api/runners/runner-vod-transcoding.ts
@@ -424,7 +424,7 @@ describe('Test runner VOD transcoding', function () {
424 424
425 await servers[0].config.enableTranscoding(true, true) 425 await servers[0].config.enableTranscoding(true, true)
426 426
427 const attributes = { name: 'audio_with_preview', previewfile: 'preview.jpg', fixture: 'sample.ogg' } 427 const attributes = { name: 'audio_with_preview', previewfile: 'custom-preview.jpg', fixture: 'sample.ogg' }
428 const { uuid } = await servers[0].videos.upload({ attributes, mode: 'legacy' }) 428 const { uuid } = await servers[0].videos.upload({ attributes, mode: 'legacy' })
429 videoUUID = uuid 429 videoUUID = uuid
430 430
diff --git a/server/tests/api/transcoding/transcoder.ts b/server/tests/api/transcoding/transcoder.ts
index 8a0a7f6d2..3cd247a24 100644
--- a/server/tests/api/transcoding/transcoder.ts
+++ b/server/tests/api/transcoding/transcoder.ts
@@ -353,7 +353,7 @@ describe('Test video transcoding', function () {
353 it('Should merge an audio file with the preview file', async function () { 353 it('Should merge an audio file with the preview file', async function () {
354 this.timeout(60_000) 354 this.timeout(60_000)
355 355
356 const attributes = { name: 'audio_with_preview', previewfile: 'preview.jpg', fixture: 'sample.ogg' } 356 const attributes = { name: 'audio_with_preview', previewfile: 'custom-preview.jpg', fixture: 'sample.ogg' }
357 await servers[1].videos.upload({ attributes, mode }) 357 await servers[1].videos.upload({ attributes, mode })
358 358
359 await waitJobs(servers) 359 await waitJobs(servers)
@@ -416,7 +416,7 @@ describe('Test video transcoding', function () {
416 } 416 }
417 }) 417 })
418 418
419 const attributes = { name: 'audio_with_preview', previewfile: 'preview.jpg', fixture: 'sample.ogg' } 419 const attributes = { name: 'audio_with_preview', previewfile: 'custom-preview.jpg', fixture: 'sample.ogg' }
420 const { id } = await servers[1].videos.upload({ attributes, mode }) 420 const { id } = await servers[1].videos.upload({ attributes, mode })
421 421
422 await waitJobs(servers) 422 await waitJobs(servers)
diff --git a/server/tests/api/transcoding/video-studio.ts b/server/tests/api/transcoding/video-studio.ts
index d1298caf7..e97f2b689 100644
--- a/server/tests/api/transcoding/video-studio.ts
+++ b/server/tests/api/transcoding/video-studio.ts
@@ -241,7 +241,7 @@ describe('Test video studio', function () {
241 { 241 {
242 name: 'add-watermark', 242 name: 'add-watermark',
243 options: { 243 options: {
244 file: 'thumbnail.png' 244 file: 'custom-thumbnail.png'
245 } 245 }
246 } 246 }
247 ]) 247 ])
diff --git a/server/tests/api/videos/multiple-servers.ts b/server/tests/api/videos/multiple-servers.ts
index 27ba00d3d..e9aa0e3a1 100644
--- a/server/tests/api/videos/multiple-servers.ts
+++ b/server/tests/api/videos/multiple-servers.ts
@@ -9,7 +9,7 @@ import {
9 completeVideoCheck, 9 completeVideoCheck,
10 dateIsValid, 10 dateIsValid,
11 saveVideoInServers, 11 saveVideoInServers,
12 testImage 12 testImageGeneratedByFFmpeg
13} from '@server/tests/shared' 13} from '@server/tests/shared'
14import { buildAbsoluteFixturePath, wait } from '@shared/core-utils' 14import { buildAbsoluteFixturePath, wait } from '@shared/core-utils'
15import { HttpStatusCode, VideoCommentThreadTree, VideoPrivacy } from '@shared/models' 15import { HttpStatusCode, VideoCommentThreadTree, VideoPrivacy } from '@shared/models'
@@ -70,8 +70,9 @@ describe('Test multiple servers', function () {
70 }) 70 })
71 71
72 describe('Should upload the video and propagate on each server', function () { 72 describe('Should upload the video and propagate on each server', function () {
73
73 it('Should upload the video on server 1 and propagate on each server', async function () { 74 it('Should upload the video on server 1 and propagate on each server', async function () {
74 this.timeout(25000) 75 this.timeout(60000)
75 76
76 const attributes = { 77 const attributes = {
77 name: 'my super name for server 1', 78 name: 'my super name for server 1',
@@ -175,8 +176,8 @@ describe('Test multiple servers', function () {
175 support: 'my super support text for server 2', 176 support: 'my super support text for server 2',
176 tags: [ 'tag1p2', 'tag2p2', 'tag3p2' ], 177 tags: [ 'tag1p2', 'tag2p2', 'tag3p2' ],
177 fixture: 'video_short2.webm', 178 fixture: 'video_short2.webm',
178 thumbnailfile: 'thumbnail.jpg', 179 thumbnailfile: 'custom-thumbnail.jpg',
179 previewfile: 'preview.jpg' 180 previewfile: 'custom-preview.jpg'
180 } 181 }
181 await servers[1].videos.upload({ token: userAccessToken, attributes, mode: 'resumable' }) 182 await servers[1].videos.upload({ token: userAccessToken, attributes, mode: 'resumable' })
182 183
@@ -229,8 +230,8 @@ describe('Test multiple servers', function () {
229 size: 750000 230 size: 750000
230 } 231 }
231 ], 232 ],
232 thumbnailfile: 'thumbnail', 233 thumbnailfile: 'custom-thumbnail',
233 previewfile: 'preview' 234 previewfile: 'custom-preview'
234 } 235 }
235 236
236 const { data } = await server.videos.list() 237 const { data } = await server.videos.list()
@@ -619,9 +620,9 @@ describe('Test multiple servers', function () {
619 description: 'my super description updated', 620 description: 'my super description updated',
620 support: 'my super support text updated', 621 support: 'my super support text updated',
621 tags: [ 'tag_up_1', 'tag_up_2' ], 622 tags: [ 'tag_up_1', 'tag_up_2' ],
622 thumbnailfile: 'thumbnail.jpg', 623 thumbnailfile: 'custom-thumbnail.jpg',
623 originallyPublishedAt: '2019-02-11T13:38:14.449Z', 624 originallyPublishedAt: '2019-02-11T13:38:14.449Z',
624 previewfile: 'preview.jpg' 625 previewfile: 'custom-preview.jpg'
625 } 626 }
626 627
627 updatedAtMin = new Date() 628 updatedAtMin = new Date()
@@ -674,8 +675,8 @@ describe('Test multiple servers', function () {
674 size: 292677 675 size: 292677
675 } 676 }
676 ], 677 ],
677 thumbnailfile: 'thumbnail', 678 thumbnailfile: 'custom-thumbnail',
678 previewfile: 'preview' 679 previewfile: 'custom-preview'
679 } 680 }
680 await completeVideoCheck({ server, originServer: servers[2], videoUUID: videoUpdated.uuid, attributes: checkAttributes }) 681 await completeVideoCheck({ server, originServer: servers[2], videoUUID: videoUpdated.uuid, attributes: checkAttributes })
681 } 682 }
@@ -685,7 +686,7 @@ describe('Test multiple servers', function () {
685 this.timeout(30000) 686 this.timeout(30000)
686 687
687 const attributes = { 688 const attributes = {
688 thumbnailfile: 'thumbnail.jpg' 689 thumbnailfile: 'custom-thumbnail.jpg'
689 } 690 }
690 691
691 updatedAtMin = new Date() 692 updatedAtMin = new Date()
@@ -761,7 +762,7 @@ describe('Test multiple servers', function () {
761 for (const server of servers) { 762 for (const server of servers) {
762 const video = await server.videos.get({ id: videoUUID }) 763 const video = await server.videos.get({ id: videoUUID })
763 764
764 await testImage(server.url, 'video_short1-preview.webm', video.previewPath) 765 await testImageGeneratedByFFmpeg(server.url, 'video_short1-preview.webm', video.previewPath)
765 } 766 }
766 }) 767 })
767 }) 768 })
diff --git a/server/tests/api/videos/single-server.ts b/server/tests/api/videos/single-server.ts
index 0cb64d5a5..66414aa5b 100644
--- a/server/tests/api/videos/single-server.ts
+++ b/server/tests/api/videos/single-server.ts
@@ -1,7 +1,7 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import { expect } from 'chai' 3import { expect } from 'chai'
4import { checkVideoFilesWereRemoved, completeVideoCheck, testImage } from '@server/tests/shared' 4import { checkVideoFilesWereRemoved, completeVideoCheck, testImageGeneratedByFFmpeg } from '@server/tests/shared'
5import { wait } from '@shared/core-utils' 5import { wait } from '@shared/core-utils'
6import { Video, VideoPrivacy } from '@shared/models' 6import { Video, VideoPrivacy } from '@shared/models'
7import { 7import {
@@ -260,7 +260,7 @@ describe('Test a single server', function () {
260 260
261 for (const video of data) { 261 for (const video of data) {
262 const videoName = video.name.replace(' name', '') 262 const videoName = video.name.replace(' name', '')
263 await testImage(server.url, videoName, video.thumbnailPath) 263 await testImageGeneratedByFFmpeg(server.url, videoName, video.thumbnailPath)
264 } 264 }
265 }) 265 })
266 266
diff --git a/server/tests/api/videos/video-imports.ts b/server/tests/api/videos/video-imports.ts
index 192b2aeb9..a684a55a0 100644
--- a/server/tests/api/videos/video-imports.ts
+++ b/server/tests/api/videos/video-imports.ts
@@ -3,7 +3,7 @@
3import { expect } from 'chai' 3import { expect } from 'chai'
4import { pathExists, readdir, remove } from 'fs-extra' 4import { pathExists, readdir, remove } from 'fs-extra'
5import { join } from 'path' 5import { join } from 'path'
6import { FIXTURE_URLS, testCaptionFile, testImage } from '@server/tests/shared' 6import { FIXTURE_URLS, testCaptionFile, testImageGeneratedByFFmpeg } from '@server/tests/shared'
7import { areHttpImportTestsDisabled } from '@shared/core-utils' 7import { areHttpImportTestsDisabled } from '@shared/core-utils'
8import { CustomConfig, HttpStatusCode, Video, VideoImportState, VideoPrivacy, VideoResolution, VideoState } from '@shared/models' 8import { CustomConfig, HttpStatusCode, Video, VideoImportState, VideoPrivacy, VideoResolution, VideoState } from '@shared/models'
9import { 9import {
@@ -67,7 +67,7 @@ async function checkVideoServer2 (server: PeerTubeServer, id: number | string) {
67 expect(video.description).to.equal('my super description') 67 expect(video.description).to.equal('my super description')
68 expect(video.tags).to.deep.equal([ 'supertag1', 'supertag2' ]) 68 expect(video.tags).to.deep.equal([ 'supertag1', 'supertag2' ])
69 69
70 await testImage(server.url, 'thumbnail', video.thumbnailPath) 70 await testImageGeneratedByFFmpeg(server.url, 'custom-thumbnail', video.thumbnailPath)
71 71
72 expect(video.files).to.have.lengthOf(1) 72 expect(video.files).to.have.lengthOf(1)
73 73
@@ -126,8 +126,8 @@ describe('Test video imports', function () {
126 ? '_yt_dlp' 126 ? '_yt_dlp'
127 : '' 127 : ''
128 128
129 await testImage(servers[0].url, 'video_import_thumbnail' + suffix, video.thumbnailPath) 129 await testImageGeneratedByFFmpeg(servers[0].url, 'video_import_thumbnail' + suffix, video.thumbnailPath)
130 await testImage(servers[0].url, 'video_import_preview' + suffix, video.previewPath) 130 await testImageGeneratedByFFmpeg(servers[0].url, 'video_import_preview' + suffix, video.previewPath)
131 } 131 }
132 132
133 const bodyCaptions = await servers[0].captions.list({ videoId: video.id }) 133 const bodyCaptions = await servers[0].captions.list({ videoId: video.id })
@@ -266,7 +266,7 @@ describe('Test video imports', function () {
266 name: 'my super name', 266 name: 'my super name',
267 description: 'my super description', 267 description: 'my super description',
268 tags: [ 'supertag1', 'supertag2' ], 268 tags: [ 'supertag1', 'supertag2' ],
269 thumbnailfile: 'thumbnail.jpg' 269 thumbnailfile: 'custom-thumbnail.jpg'
270 } 270 }
271 }) 271 })
272 expect(video.name).to.equal('my super name') 272 expect(video.name).to.equal('my super name')
diff --git a/server/tests/api/videos/video-playlist-thumbnails.ts b/server/tests/api/videos/video-playlist-thumbnails.ts
index 356939b93..c274c20bf 100644
--- a/server/tests/api/videos/video-playlist-thumbnails.ts
+++ b/server/tests/api/videos/video-playlist-thumbnails.ts
@@ -1,7 +1,7 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import { expect } from 'chai' 3import { expect } from 'chai'
4import { testImage } from '@server/tests/shared' 4import { testImageGeneratedByFFmpeg } from '@server/tests/shared'
5import { VideoPlaylistPrivacy } from '@shared/models' 5import { VideoPlaylistPrivacy } from '@shared/models'
6import { 6import {
7 cleanupTests, 7 cleanupTests,
@@ -83,7 +83,7 @@ describe('Playlist thumbnail', function () {
83 83
84 for (const server of servers) { 84 for (const server of servers) {
85 const p = await getPlaylistWithoutThumbnail(server) 85 const p = await getPlaylistWithoutThumbnail(server)
86 await testImage(server.url, 'thumbnail-playlist', p.thumbnailPath) 86 await testImageGeneratedByFFmpeg(server.url, 'thumbnail-playlist', p.thumbnailPath)
87 } 87 }
88 }) 88 })
89 89
@@ -95,7 +95,7 @@ describe('Playlist thumbnail', function () {
95 displayName: 'playlist with thumbnail', 95 displayName: 'playlist with thumbnail',
96 privacy: VideoPlaylistPrivacy.PUBLIC, 96 privacy: VideoPlaylistPrivacy.PUBLIC,
97 videoChannelId: servers[1].store.channel.id, 97 videoChannelId: servers[1].store.channel.id,
98 thumbnailfile: 'thumbnail.jpg' 98 thumbnailfile: 'custom-thumbnail.jpg'
99 } 99 }
100 }) 100 })
101 playlistWithThumbnailId = created.id 101 playlistWithThumbnailId = created.id
@@ -110,7 +110,7 @@ describe('Playlist thumbnail', function () {
110 110
111 for (const server of servers) { 111 for (const server of servers) {
112 const p = await getPlaylistWithThumbnail(server) 112 const p = await getPlaylistWithThumbnail(server)
113 await testImage(server.url, 'thumbnail', p.thumbnailPath) 113 await testImageGeneratedByFFmpeg(server.url, 'custom-thumbnail', p.thumbnailPath)
114 } 114 }
115 }) 115 })
116 116
@@ -135,7 +135,7 @@ describe('Playlist thumbnail', function () {
135 135
136 for (const server of servers) { 136 for (const server of servers) {
137 const p = await getPlaylistWithoutThumbnail(server) 137 const p = await getPlaylistWithoutThumbnail(server)
138 await testImage(server.url, 'thumbnail-playlist', p.thumbnailPath) 138 await testImageGeneratedByFFmpeg(server.url, 'thumbnail-playlist', p.thumbnailPath)
139 } 139 }
140 }) 140 })
141 141
@@ -160,7 +160,7 @@ describe('Playlist thumbnail', function () {
160 160
161 for (const server of servers) { 161 for (const server of servers) {
162 const p = await getPlaylistWithThumbnail(server) 162 const p = await getPlaylistWithThumbnail(server)
163 await testImage(server.url, 'thumbnail', p.thumbnailPath) 163 await testImageGeneratedByFFmpeg(server.url, 'custom-thumbnail', p.thumbnailPath)
164 } 164 }
165 }) 165 })
166 166
@@ -176,7 +176,7 @@ describe('Playlist thumbnail', function () {
176 176
177 for (const server of servers) { 177 for (const server of servers) {
178 const p = await getPlaylistWithoutThumbnail(server) 178 const p = await getPlaylistWithoutThumbnail(server)
179 await testImage(server.url, 'thumbnail-playlist', p.thumbnailPath) 179 await testImageGeneratedByFFmpeg(server.url, 'thumbnail-playlist', p.thumbnailPath)
180 } 180 }
181 }) 181 })
182 182
@@ -192,7 +192,7 @@ describe('Playlist thumbnail', function () {
192 192
193 for (const server of servers) { 193 for (const server of servers) {
194 const p = await getPlaylistWithThumbnail(server) 194 const p = await getPlaylistWithThumbnail(server)
195 await testImage(server.url, 'thumbnail', p.thumbnailPath) 195 await testImageGeneratedByFFmpeg(server.url, 'custom-thumbnail', p.thumbnailPath)
196 } 196 }
197 }) 197 })
198 198
@@ -224,7 +224,7 @@ describe('Playlist thumbnail', function () {
224 224
225 for (const server of servers) { 225 for (const server of servers) {
226 const p = await getPlaylistWithThumbnail(server) 226 const p = await getPlaylistWithThumbnail(server)
227 await testImage(server.url, 'thumbnail', p.thumbnailPath) 227 await testImageGeneratedByFFmpeg(server.url, 'custom-thumbnail', p.thumbnailPath)
228 } 228 }
229 }) 229 })
230 230
diff --git a/server/tests/api/videos/video-playlists.ts b/server/tests/api/videos/video-playlists.ts
index 9277b49f4..3bfa874cb 100644
--- a/server/tests/api/videos/video-playlists.ts
+++ b/server/tests/api/videos/video-playlists.ts
@@ -1,7 +1,7 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import { expect } from 'chai' 3import { expect } from 'chai'
4import { checkPlaylistFilesWereRemoved, testImage } from '@server/tests/shared' 4import { checkPlaylistFilesWereRemoved, testImageGeneratedByFFmpeg } from '@server/tests/shared'
5import { wait } from '@shared/core-utils' 5import { wait } from '@shared/core-utils'
6import { uuidToShort } from '@shared/extra-utils' 6import { uuidToShort } from '@shared/extra-utils'
7import { 7import {
@@ -133,7 +133,7 @@ describe('Test video playlists', function () {
133 displayName: 'my super playlist', 133 displayName: 'my super playlist',
134 privacy: VideoPlaylistPrivacy.PUBLIC, 134 privacy: VideoPlaylistPrivacy.PUBLIC,
135 description: 'my super description', 135 description: 'my super description',
136 thumbnailfile: 'thumbnail.jpg', 136 thumbnailfile: 'custom-thumbnail.jpg',
137 videoChannelId: servers[0].store.channel.id 137 videoChannelId: servers[0].store.channel.id
138 } 138 }
139 }) 139 })
@@ -225,7 +225,7 @@ describe('Test video playlists', function () {
225 displayName: 'my super playlist', 225 displayName: 'my super playlist',
226 privacy: VideoPlaylistPrivacy.PUBLIC, 226 privacy: VideoPlaylistPrivacy.PUBLIC,
227 description: 'my super description', 227 description: 'my super description',
228 thumbnailfile: 'thumbnail.jpg', 228 thumbnailfile: 'custom-thumbnail.jpg',
229 videoChannelId: servers[0].store.channel.id 229 videoChannelId: servers[0].store.channel.id
230 } 230 }
231 }) 231 })
@@ -286,7 +286,7 @@ describe('Test video playlists', function () {
286 attributes: { 286 attributes: {
287 displayName: 'playlist 3', 287 displayName: 'playlist 3',
288 privacy: VideoPlaylistPrivacy.PUBLIC, 288 privacy: VideoPlaylistPrivacy.PUBLIC,
289 thumbnailfile: 'thumbnail.jpg', 289 thumbnailfile: 'custom-thumbnail.jpg',
290 videoChannelId: servers[1].store.channel.id 290 videoChannelId: servers[1].store.channel.id
291 } 291 }
292 }) 292 })
@@ -314,11 +314,11 @@ describe('Test video playlists', function () {
314 314
315 const playlist2 = body.data.find(p => p.displayName === 'playlist 2') 315 const playlist2 = body.data.find(p => p.displayName === 'playlist 2')
316 expect(playlist2).to.not.be.undefined 316 expect(playlist2).to.not.be.undefined
317 await testImage(server.url, 'thumbnail-playlist', playlist2.thumbnailPath) 317 await testImageGeneratedByFFmpeg(server.url, 'thumbnail-playlist', playlist2.thumbnailPath)
318 318
319 const playlist3 = body.data.find(p => p.displayName === 'playlist 3') 319 const playlist3 = body.data.find(p => p.displayName === 'playlist 3')
320 expect(playlist3).to.not.be.undefined 320 expect(playlist3).to.not.be.undefined
321 await testImage(server.url, 'thumbnail', playlist3.thumbnailPath) 321 await testImageGeneratedByFFmpeg(server.url, 'custom-thumbnail', playlist3.thumbnailPath)
322 } 322 }
323 323
324 const body = await servers[2].playlists.list({ start: 0, count: 5 }) 324 const body = await servers[2].playlists.list({ start: 0, count: 5 })
@@ -336,7 +336,7 @@ describe('Test video playlists', function () {
336 336
337 const playlist2 = body.data.find(p => p.displayName === 'playlist 2') 337 const playlist2 = body.data.find(p => p.displayName === 'playlist 2')
338 expect(playlist2).to.not.be.undefined 338 expect(playlist2).to.not.be.undefined
339 await testImage(servers[2].url, 'thumbnail-playlist', playlist2.thumbnailPath) 339 await testImageGeneratedByFFmpeg(servers[2].url, 'thumbnail-playlist', playlist2.thumbnailPath)
340 340
341 expect(body.data.find(p => p.displayName === 'playlist 3')).to.not.be.undefined 341 expect(body.data.find(p => p.displayName === 'playlist 3')).to.not.be.undefined
342 }) 342 })
@@ -502,7 +502,7 @@ describe('Test video playlists', function () {
502 displayName: 'playlist 3 updated', 502 displayName: 'playlist 3 updated',
503 description: 'description updated', 503 description: 'description updated',
504 privacy: VideoPlaylistPrivacy.UNLISTED, 504 privacy: VideoPlaylistPrivacy.UNLISTED,
505 thumbnailfile: 'thumbnail.jpg', 505 thumbnailfile: 'custom-thumbnail.jpg',
506 videoChannelId: servers[1].store.channel.id 506 videoChannelId: servers[1].store.channel.id
507 }, 507 },
508 playlistId: playlistServer2Id2 508 playlistId: playlistServer2Id2
diff --git a/server/tests/api/videos/video-storyboard.ts b/server/tests/api/videos/video-storyboard.ts
index 5fde6ce45..fc4b4450f 100644
--- a/server/tests/api/videos/video-storyboard.ts
+++ b/server/tests/api/videos/video-storyboard.ts
@@ -110,7 +110,11 @@ describe('Test video storyboard', function () {
110 await waitJobs(servers) 110 await waitJobs(servers)
111 111
112 for (const server of servers) { 112 for (const server of servers) {
113 await checkStoryboard({ server, uuid, tilesCount: 6, minSize: 250 }) 113 try {
114 await checkStoryboard({ server, uuid, tilesCount: 6, minSize: 250 })
115 } catch { // FIXME: to remove after ffmpeg CI upgrade, ffmpeg CI version (4.3) generates a 7.6s length video
116 await checkStoryboard({ server, uuid, tilesCount: 8, minSize: 250 })
117 }
114 } 118 }
115 }) 119 })
116 120
diff --git a/server/tests/cli/prune-storage.ts b/server/tests/cli/prune-storage.ts
index 8bdf2136d..dc8ecd3d3 100644
--- a/server/tests/cli/prune-storage.ts
+++ b/server/tests/cli/prune-storage.ts
@@ -85,7 +85,7 @@ describe('Test prune storage scripts', function () {
85 displayName: 'playlist', 85 displayName: 'playlist',
86 privacy: VideoPlaylistPrivacy.PUBLIC, 86 privacy: VideoPlaylistPrivacy.PUBLIC,
87 videoChannelId: server.store.channel.id, 87 videoChannelId: server.store.channel.id,
88 thumbnailfile: 'thumbnail.jpg' 88 thumbnailfile: 'custom-thumbnail.jpg'
89 } 89 }
90 }) 90 })
91 } 91 }
diff --git a/server/tests/fixtures/custom-preview-big.png b/server/tests/fixtures/custom-preview-big.png
new file mode 100644
index 000000000..03d171af3
--- /dev/null
+++ b/server/tests/fixtures/custom-preview-big.png
Binary files differ
diff --git a/server/tests/fixtures/custom-preview.jpg b/server/tests/fixtures/custom-preview.jpg
new file mode 100644
index 000000000..5a039d830
--- /dev/null
+++ b/server/tests/fixtures/custom-preview.jpg
Binary files differ
diff --git a/server/tests/fixtures/custom-thumbnail-big.jpg b/server/tests/fixtures/custom-thumbnail-big.jpg
new file mode 100644
index 000000000..08375e425
--- /dev/null
+++ b/server/tests/fixtures/custom-thumbnail-big.jpg
Binary files differ
diff --git a/server/tests/fixtures/custom-thumbnail.jpg b/server/tests/fixtures/custom-thumbnail.jpg
new file mode 100644
index 000000000..ef818442d
--- /dev/null
+++ b/server/tests/fixtures/custom-thumbnail.jpg
Binary files differ
diff --git a/server/tests/fixtures/custom-thumbnail.png b/server/tests/fixtures/custom-thumbnail.png
new file mode 100644
index 000000000..9f34daec1
--- /dev/null
+++ b/server/tests/fixtures/custom-thumbnail.png
Binary files differ
diff --git a/server/tests/fixtures/preview-big.png b/server/tests/fixtures/preview-big.png
deleted file mode 100644
index 612e297f1..000000000
--- a/server/tests/fixtures/preview-big.png
+++ /dev/null
Binary files differ
diff --git a/server/tests/fixtures/preview.jpg b/server/tests/fixtures/preview.jpg
deleted file mode 100644
index 1421da738..000000000
--- a/server/tests/fixtures/preview.jpg
+++ /dev/null
Binary files differ
diff --git a/server/tests/fixtures/thumbnail-big.jpg b/server/tests/fixtures/thumbnail-big.jpg
deleted file mode 100644
index 537720d24..000000000
--- a/server/tests/fixtures/thumbnail-big.jpg
+++ /dev/null
Binary files differ
diff --git a/server/tests/fixtures/thumbnail.jpg b/server/tests/fixtures/thumbnail.jpg
deleted file mode 100644
index 020853780..000000000
--- a/server/tests/fixtures/thumbnail.jpg
+++ /dev/null
Binary files differ
diff --git a/server/tests/fixtures/thumbnail.png b/server/tests/fixtures/thumbnail.png
deleted file mode 100644
index b331aba3b..000000000
--- a/server/tests/fixtures/thumbnail.png
+++ /dev/null
Binary files differ
diff --git a/server/tests/fixtures/video_short1-preview.webm.jpg b/server/tests/fixtures/video_short1-preview.webm.jpg
index f5659f6a8..15454942d 100644
--- a/server/tests/fixtures/video_short1-preview.webm.jpg
+++ b/server/tests/fixtures/video_short1-preview.webm.jpg
Binary files differ
diff --git a/server/tests/fixtures/video_short1.webm.jpg b/server/tests/fixtures/video_short1.webm.jpg
index 26a697daa..b2740d73d 100644
--- a/server/tests/fixtures/video_short1.webm.jpg
+++ b/server/tests/fixtures/video_short1.webm.jpg
Binary files differ
diff --git a/server/tests/fixtures/video_short2.webm.jpg b/server/tests/fixtures/video_short2.webm.jpg
index 020853780..afe476c7f 100644
--- a/server/tests/fixtures/video_short2.webm.jpg
+++ b/server/tests/fixtures/video_short2.webm.jpg
Binary files differ
diff --git a/server/tests/helpers/image.ts b/server/tests/helpers/image.ts
index 530c9bacd..6021ffc48 100644
--- a/server/tests/helpers/image.ts
+++ b/server/tests/helpers/image.ts
@@ -35,28 +35,28 @@ describe('Image helpers', function () {
35 const thumbnailSize = { width: 280, height: 157 } 35 const thumbnailSize = { width: 280, height: 157 }
36 36
37 it('Should skip processing if the source image is okay', async function () { 37 it('Should skip processing if the source image is okay', async function () {
38 const input = buildAbsoluteFixturePath('thumbnail.jpg') 38 const input = buildAbsoluteFixturePath('custom-thumbnail.jpg')
39 await processImage({ path: input, destination: imageDestJPG, newSize: thumbnailSize, keepOriginal: true }) 39 await processImage({ path: input, destination: imageDestJPG, newSize: thumbnailSize, keepOriginal: true })
40 40
41 await checkBuffers(input, imageDestJPG, true) 41 await checkBuffers(input, imageDestJPG, true)
42 }) 42 })
43 43
44 it('Should not skip processing if the source image does not have the appropriate extension', async function () { 44 it('Should not skip processing if the source image does not have the appropriate extension', async function () {
45 const input = buildAbsoluteFixturePath('thumbnail.png') 45 const input = buildAbsoluteFixturePath('custom-thumbnail.png')
46 await processImage({ path: input, destination: imageDestJPG, newSize: thumbnailSize, keepOriginal: true }) 46 await processImage({ path: input, destination: imageDestJPG, newSize: thumbnailSize, keepOriginal: true })
47 47
48 await checkBuffers(input, imageDestJPG, false) 48 await checkBuffers(input, imageDestJPG, false)
49 }) 49 })
50 50
51 it('Should not skip processing if the source image does not have the appropriate size', async function () { 51 it('Should not skip processing if the source image does not have the appropriate size', async function () {
52 const input = buildAbsoluteFixturePath('preview.jpg') 52 const input = buildAbsoluteFixturePath('custom-preview.jpg')
53 await processImage({ path: input, destination: imageDestJPG, newSize: thumbnailSize, keepOriginal: true }) 53 await processImage({ path: input, destination: imageDestJPG, newSize: thumbnailSize, keepOriginal: true })
54 54
55 await checkBuffers(input, imageDestJPG, false) 55 await checkBuffers(input, imageDestJPG, false)
56 }) 56 })
57 57
58 it('Should not skip processing if the source image does not have the appropriate size', async function () { 58 it('Should not skip processing if the source image does not have the appropriate size', async function () {
59 const input = buildAbsoluteFixturePath('thumbnail-big.jpg') 59 const input = buildAbsoluteFixturePath('custom-thumbnail-big.jpg')
60 await processImage({ path: input, destination: imageDestJPG, newSize: thumbnailSize, keepOriginal: true }) 60 await processImage({ path: input, destination: imageDestJPG, newSize: thumbnailSize, keepOriginal: true })
61 61
62 await checkBuffers(input, imageDestJPG, false) 62 await checkBuffers(input, imageDestJPG, false)
diff --git a/server/tests/shared/checks.ts b/server/tests/shared/checks.ts
index feaef37c6..90179c6ac 100644
--- a/server/tests/shared/checks.ts
+++ b/server/tests/shared/checks.ts
@@ -61,6 +61,16 @@ async function testImageSize (url: string, imageName: string, imageHTTPPath: str
61 expect(body.length).to.be.below(maxLength, 'the generated image is way larger than the recorded fixture') 61 expect(body.length).to.be.below(maxLength, 'the generated image is way larger than the recorded fixture')
62} 62}
63 63
64async function testImageGeneratedByFFmpeg (url: string, imageName: string, imageHTTPPath: string, extension = '.jpg') {
65 if (process.env.ENABLE_FFMPEG_THUMBNAIL_PIXEL_COMPARISON_TESTS !== 'true') {
66 console.log(
67 'Pixel comparison of image generated by ffmpeg is disabled. ' +
68 'You can enable it using `ENABLE_FFMPEG_THUMBNAIL_PIXEL_COMPARISON_TESTS=true env variable')
69 }
70
71 return testImage(url, imageName, imageHTTPPath, extension)
72}
73
64async function testImage (url: string, imageName: string, imageHTTPPath: string, extension = '.jpg') { 74async function testImage (url: string, imageName: string, imageHTTPPath: string, extension = '.jpg') {
65 const res = await makeGetRequest({ 75 const res = await makeGetRequest({
66 url, 76 url,
@@ -148,6 +158,7 @@ async function checkVideoDuration (server: PeerTubeServer, videoUUID: string, du
148 158
149export { 159export {
150 dateIsValid, 160 dateIsValid,
161 testImageGeneratedByFFmpeg,
151 testImageSize, 162 testImageSize,
152 testImage, 163 testImage,
153 expectLogDoesNotContain, 164 expectLogDoesNotContain,
diff --git a/server/tests/shared/videos.ts b/server/tests/shared/videos.ts
index 856fabd11..0bd161820 100644
--- a/server/tests/shared/videos.ts
+++ b/server/tests/shared/videos.ts
@@ -7,7 +7,7 @@ import { loadLanguages, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO
7import { getLowercaseExtension, pick, uuidRegex } from '@shared/core-utils' 7import { getLowercaseExtension, pick, uuidRegex } from '@shared/core-utils'
8import { HttpStatusCode, VideoCaption, VideoDetails, VideoPrivacy, VideoResolution } from '@shared/models' 8import { HttpStatusCode, VideoCaption, VideoDetails, VideoPrivacy, VideoResolution } from '@shared/models'
9import { makeRawRequest, PeerTubeServer, VideoEdit, waitJobs } from '@shared/server-commands' 9import { makeRawRequest, PeerTubeServer, VideoEdit, waitJobs } from '@shared/server-commands'
10import { dateIsValid, expectStartWith, testImage } from './checks' 10import { dateIsValid, expectStartWith, testImageGeneratedByFFmpeg } from './checks'
11import { checkWebTorrentWorks } from './webtorrent' 11import { checkWebTorrentWorks } from './webtorrent'
12 12
13loadLanguages() 13loadLanguages()
@@ -197,11 +197,11 @@ async function completeVideoCheck (options: {
197 expect(video.downloadEnabled).to.equal(attributes.downloadEnabled) 197 expect(video.downloadEnabled).to.equal(attributes.downloadEnabled)
198 198
199 expect(video.thumbnailPath).to.exist 199 expect(video.thumbnailPath).to.exist
200 await testImage(server.url, attributes.thumbnailfile || attributes.fixture, video.thumbnailPath) 200 await testImageGeneratedByFFmpeg(server.url, attributes.thumbnailfile || attributes.fixture, video.thumbnailPath)
201 201
202 if (attributes.previewfile) { 202 if (attributes.previewfile) {
203 expect(video.previewPath).to.exist 203 expect(video.previewPath).to.exist
204 await testImage(server.url, attributes.previewfile, video.previewPath) 204 await testImageGeneratedByFFmpeg(server.url, attributes.previewfile, video.previewPath)
205 } 205 }
206 206
207 await completeWebVideoFilesCheck({ server, originServer, videoUUID: video.uuid, ...pick(attributes, [ 'fixture', 'files' ]) }) 207 await completeWebVideoFilesCheck({ server, originServer, videoUUID: video.uuid, ...pick(attributes, [ 'fixture', 'files' ]) })
diff --git a/shared/server-commands/server/server.ts b/shared/server-commands/server/server.ts
index 6aa4296b0..9a07eb36f 100644
--- a/shared/server-commands/server/server.ts
+++ b/shared/server-commands/server/server.ts
@@ -237,7 +237,7 @@ export class PeerTubeServer {
237 } 237 }
238 238
239 // Share the environment 239 // Share the environment
240 const env = Object.create(process.env) 240 const env = { ...process.env }
241 env['NODE_ENV'] = 'test' 241 env['NODE_ENV'] = 'test'
242 env['NODE_APP_INSTANCE'] = this.internalServerNumber.toString() 242 env['NODE_APP_INSTANCE'] = this.internalServerNumber.toString()
243 env['NODE_CONFIG'] = JSON.stringify(configOverride) 243 env['NODE_CONFIG'] = JSON.stringify(configOverride)
diff --git a/shared/server-commands/videos/video-studio-command.ts b/shared/server-commands/videos/video-studio-command.ts
index 9fe467cc2..675cd84b7 100644
--- a/shared/server-commands/videos/video-studio-command.ts
+++ b/shared/server-commands/videos/video-studio-command.ts
@@ -25,7 +25,7 @@ export class VideoStudioCommand extends AbstractCommand {
25 { 25 {
26 name: 'add-watermark', 26 name: 'add-watermark',
27 options: { 27 options: {
28 file: 'thumbnail.png' 28 file: 'custom-thumbnail.png'
29 } 29 }
30 }, 30 },
31 31
diff --git a/support/doc/development/tests.md b/support/doc/development/tests.md
index e3a65c35f..1c2589c8a 100644
--- a/support/doc/development/tests.md
+++ b/support/doc/development/tests.md
@@ -71,6 +71,7 @@ Some env variables can be defined to disable/enable some tests:
71 * `ENABLE_OBJECT_STORAGE_TESTS=true`: enable object storage tests (needs `chocobozzz/s3-ninja` container first) 71 * `ENABLE_OBJECT_STORAGE_TESTS=true`: enable object storage tests (needs `chocobozzz/s3-ninja` container first)
72 * `AKISMET_KEY`: specify an Akismet key to test akismet external PeerTube plugin 72 * `AKISMET_KEY`: specify an Akismet key to test akismet external PeerTube plugin
73 * `OBJECT_STORAGE_SCALEWAY_KEY_ID` and `OBJECT_STORAGE_SCALEWAY_ACCESS_KEY`: specify Scaleway API keys to test object storage ACL (not supported by our `chocobozzz/s3-ninja` container) 73 * `OBJECT_STORAGE_SCALEWAY_KEY_ID` and `OBJECT_STORAGE_SCALEWAY_ACCESS_KEY`: specify Scaleway API keys to test object storage ACL (not supported by our `chocobozzz/s3-ninja` container)
74 * `ENABLE_FFMPEG_THUMBNAIL_PIXEL_COMPARISON_TESTS=true`: enable pixel comparison on images generated by ffmpeg. Disabled by default because a custom ffmpeg version may fails the tests
74 75
75 76
76### Debug server logs 77### Debug server logs