aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2021-02-16 08:50:40 +0100
committerChocobozzz <chocobozzz@cpy.re>2021-02-16 10:36:44 +0100
commita35a22797c99f17924347da9a226068c3dbe4787 (patch)
treeaffb713929145f90f6bda8828ded3ac2f4f73b19 /server/lib
parent6302d599cdf98b5a5363a2a1dcdc266447950191 (diff)
downloadPeerTube-a35a22797c99f17924347da9a226068c3dbe4787.tar.gz
PeerTube-a35a22797c99f17924347da9a226068c3dbe4787.tar.zst
PeerTube-a35a22797c99f17924347da9a226068c3dbe4787.zip
Remove previous thumbnail if needed
Diffstat (limited to 'server/lib')
-rw-r--r--server/lib/activitypub/playlist.ts2
-rw-r--r--server/lib/activitypub/videos.ts154
-rw-r--r--server/lib/files-cache/videos-preview-cache.ts2
-rw-r--r--server/lib/job-queue/handlers/video-import.ts12
-rw-r--r--server/lib/job-queue/handlers/video-live-ending.ts12
-rw-r--r--server/lib/thumbnail.ts110
6 files changed, 196 insertions, 96 deletions
diff --git a/server/lib/activitypub/playlist.ts b/server/lib/activitypub/playlist.ts
index 53298e968..d5a3ef7c8 100644
--- a/server/lib/activitypub/playlist.ts
+++ b/server/lib/activitypub/playlist.ts
@@ -103,7 +103,7 @@ async function createOrUpdateVideoPlaylist (playlistObject: PlaylistObject, byAc
103 103
104 if (playlistObject.icon) { 104 if (playlistObject.icon) {
105 try { 105 try {
106 const thumbnailModel = await createPlaylistMiniatureFromUrl(playlistObject.icon.url, refreshedPlaylist) 106 const thumbnailModel = await createPlaylistMiniatureFromUrl({ downloadUrl: playlistObject.icon.url, playlist: refreshedPlaylist })
107 await refreshedPlaylist.setAndSaveThumbnail(thumbnailModel, undefined) 107 await refreshedPlaylist.setAndSaveThumbnail(thumbnailModel, undefined)
108 } catch (err) { 108 } catch (err) {
109 logger.warn('Cannot generate thumbnail of %s.', playlistObject.id, { err }) 109 logger.warn('Cannot generate thumbnail of %s.', playlistObject.id, { err })
diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts
index 201ef0302..66981f43f 100644
--- a/server/lib/activitypub/videos.ts
+++ b/server/lib/activitypub/videos.ts
@@ -313,7 +313,11 @@ async function updateVideoFromAP (options: {
313 let thumbnailModel: MThumbnail 313 let thumbnailModel: MThumbnail
314 314
315 try { 315 try {
316 thumbnailModel = await createVideoMiniatureFromUrl(getThumbnailFromIcons(videoObject).url, video, ThumbnailType.MINIATURE) 316 thumbnailModel = await createVideoMiniatureFromUrl({
317 downloadUrl: getThumbnailFromIcons(videoObject).url,
318 video,
319 type: ThumbnailType.MINIATURE
320 })
317 } catch (err) { 321 } catch (err) {
318 logger.warn('Cannot generate thumbnail of %s.', videoObject.id, { err }) 322 logger.warn('Cannot generate thumbnail of %s.', videoObject.id, { err })
319 } 323 }
@@ -362,7 +366,12 @@ async function updateVideoFromAP (options: {
362 366
363 if (videoUpdated.getPreview()) { 367 if (videoUpdated.getPreview()) {
364 const previewUrl = getPreviewUrl(getPreviewFromIcons(videoObject), video) 368 const previewUrl = getPreviewUrl(getPreviewFromIcons(videoObject), video)
365 const previewModel = createPlaceholderThumbnail(previewUrl, video, ThumbnailType.PREVIEW, PREVIEWS_SIZE) 369 const previewModel = createPlaceholderThumbnail({
370 fileUrl: previewUrl,
371 video,
372 type: ThumbnailType.PREVIEW,
373 size: PREVIEWS_SIZE
374 })
366 await videoUpdated.addAndSaveThumbnail(previewModel, t) 375 await videoUpdated.addAndSaveThumbnail(previewModel, t)
367 } 376 }
368 377
@@ -585,11 +594,14 @@ async function createVideo (videoObject: VideoObject, channel: MChannelAccountLi
585 const videoData = await videoActivityObjectToDBAttributes(channel, videoObject, videoObject.to) 594 const videoData = await videoActivityObjectToDBAttributes(channel, videoObject, videoObject.to)
586 const video = VideoModel.build(videoData) as MVideoThumbnail 595 const video = VideoModel.build(videoData) as MVideoThumbnail
587 596
588 const promiseThumbnail = createVideoMiniatureFromUrl(getThumbnailFromIcons(videoObject).url, video, ThumbnailType.MINIATURE) 597 const promiseThumbnail = createVideoMiniatureFromUrl({
589 .catch(err => { 598 downloadUrl: getThumbnailFromIcons(videoObject).url,
590 logger.error('Cannot create miniature from url.', { err }) 599 video,
591 return undefined 600 type: ThumbnailType.MINIATURE
592 }) 601 }).catch(err => {
602 logger.error('Cannot create miniature from url.', { err })
603 return undefined
604 })
593 605
594 let thumbnailModel: MThumbnail 606 let thumbnailModel: MThumbnail
595 if (waitThumbnail === true) { 607 if (waitThumbnail === true) {
@@ -597,81 +609,93 @@ async function createVideo (videoObject: VideoObject, channel: MChannelAccountLi
597 } 609 }
598 610
599 const { autoBlacklisted, videoCreated } = await sequelizeTypescript.transaction(async t => { 611 const { autoBlacklisted, videoCreated } = await sequelizeTypescript.transaction(async t => {
600 const sequelizeOptions = { transaction: t } 612 try {
613 const sequelizeOptions = { transaction: t }
601 614
602 const videoCreated = await video.save(sequelizeOptions) as MVideoFullLight 615 const videoCreated = await video.save(sequelizeOptions) as MVideoFullLight
603 videoCreated.VideoChannel = channel 616 videoCreated.VideoChannel = channel
604 617
605 if (thumbnailModel) await videoCreated.addAndSaveThumbnail(thumbnailModel, t) 618 if (thumbnailModel) await videoCreated.addAndSaveThumbnail(thumbnailModel, t)
606 619
607 const previewIcon = getPreviewFromIcons(videoObject) 620 const previewUrl = getPreviewUrl(getPreviewFromIcons(videoObject), videoCreated)
608 const previewUrl = getPreviewUrl(previewIcon, videoCreated) 621 const previewModel = createPlaceholderThumbnail({
609 const previewModel = createPlaceholderThumbnail(previewUrl, videoCreated, ThumbnailType.PREVIEW, PREVIEWS_SIZE) 622 fileUrl: previewUrl,
623 video: videoCreated,
624 type: ThumbnailType.PREVIEW,
625 size: PREVIEWS_SIZE
626 })
610 627
611 if (thumbnailModel) await videoCreated.addAndSaveThumbnail(previewModel, t) 628 if (thumbnailModel) await videoCreated.addAndSaveThumbnail(previewModel, t)
612 629
613 // Process files 630 // Process files
614 const videoFileAttributes = videoFileActivityUrlToDBAttributes(videoCreated, videoObject.url) 631 const videoFileAttributes = videoFileActivityUrlToDBAttributes(videoCreated, videoObject.url)
615 632
616 const videoFilePromises = videoFileAttributes.map(f => VideoFileModel.create(f, { transaction: t })) 633 const videoFilePromises = videoFileAttributes.map(f => VideoFileModel.create(f, { transaction: t }))
617 const videoFiles = await Promise.all(videoFilePromises) 634 const videoFiles = await Promise.all(videoFilePromises)
618 635
619 const streamingPlaylistsAttributes = streamingPlaylistActivityUrlToDBAttributes(videoCreated, videoObject, videoFiles) 636 const streamingPlaylistsAttributes = streamingPlaylistActivityUrlToDBAttributes(videoCreated, videoObject, videoFiles)
620 videoCreated.VideoStreamingPlaylists = [] 637 videoCreated.VideoStreamingPlaylists = []
621 638
622 for (const playlistAttributes of streamingPlaylistsAttributes) { 639 for (const playlistAttributes of streamingPlaylistsAttributes) {
623 const playlistModel = await VideoStreamingPlaylistModel.create(playlistAttributes, { transaction: t }) 640 const playlistModel = await VideoStreamingPlaylistModel.create(playlistAttributes, { transaction: t })
624 641
625 const playlistFiles = videoFileActivityUrlToDBAttributes(playlistModel, playlistAttributes.tagAPObject) 642 const playlistFiles = videoFileActivityUrlToDBAttributes(playlistModel, playlistAttributes.tagAPObject)
626 const videoFilePromises = playlistFiles.map(f => VideoFileModel.create(f, { transaction: t })) 643 const videoFilePromises = playlistFiles.map(f => VideoFileModel.create(f, { transaction: t }))
627 playlistModel.VideoFiles = await Promise.all(videoFilePromises) 644 playlistModel.VideoFiles = await Promise.all(videoFilePromises)
628 645
629 videoCreated.VideoStreamingPlaylists.push(playlistModel) 646 videoCreated.VideoStreamingPlaylists.push(playlistModel)
630 } 647 }
631 648
632 // Process tags 649 // Process tags
633 const tags = videoObject.tag 650 const tags = videoObject.tag
634 .filter(isAPHashTagObject) 651 .filter(isAPHashTagObject)
635 .map(t => t.name) 652 .map(t => t.name)
636 await setVideoTags({ video: videoCreated, tags, transaction: t }) 653 await setVideoTags({ video: videoCreated, tags, transaction: t })
637 654
638 // Process captions 655 // Process captions
639 const videoCaptionsPromises = videoObject.subtitleLanguage.map(c => { 656 const videoCaptionsPromises = videoObject.subtitleLanguage.map(c => {
640 const caption = new VideoCaptionModel({ 657 const caption = new VideoCaptionModel({
641 videoId: videoCreated.id, 658 videoId: videoCreated.id,
642 filename: VideoCaptionModel.generateCaptionName(c.identifier), 659 filename: VideoCaptionModel.generateCaptionName(c.identifier),
643 language: c.identifier, 660 language: c.identifier,
644 fileUrl: c.url 661 fileUrl: c.url
645 }) as MVideoCaption 662 }) as MVideoCaption
646 663
647 return VideoCaptionModel.insertOrReplaceLanguage(caption, t) 664 return VideoCaptionModel.insertOrReplaceLanguage(caption, t)
648 }) 665 })
649 await Promise.all(videoCaptionsPromises) 666 await Promise.all(videoCaptionsPromises)
650 667
651 videoCreated.VideoFiles = videoFiles 668 videoCreated.VideoFiles = videoFiles
652 669
653 if (videoCreated.isLive) { 670 if (videoCreated.isLive) {
654 const videoLive = new VideoLiveModel({ 671 const videoLive = new VideoLiveModel({
655 streamKey: null, 672 streamKey: null,
656 saveReplay: videoObject.liveSaveReplay, 673 saveReplay: videoObject.liveSaveReplay,
657 permanentLive: videoObject.permanentLive, 674 permanentLive: videoObject.permanentLive,
658 videoId: videoCreated.id 675 videoId: videoCreated.id
659 }) 676 })
660 677
661 videoCreated.VideoLive = await videoLive.save({ transaction: t }) 678 videoCreated.VideoLive = await videoLive.save({ transaction: t })
662 } 679 }
663 680
664 const autoBlacklisted = await autoBlacklistVideoIfNeeded({ 681 const autoBlacklisted = await autoBlacklistVideoIfNeeded({
665 video: videoCreated, 682 video: videoCreated,
666 user: undefined, 683 user: undefined,
667 isRemote: true, 684 isRemote: true,
668 isNew: true, 685 isNew: true,
669 transaction: t 686 transaction: t
670 }) 687 })
671 688
672 logger.info('Remote video with uuid %s inserted.', videoObject.uuid) 689 logger.info('Remote video with uuid %s inserted.', videoObject.uuid)
673 690
674 return { autoBlacklisted, videoCreated } 691 return { autoBlacklisted, videoCreated }
692 } catch (err) {
693 // FIXME: Use rollback hook when https://github.com/sequelize/sequelize/pull/13038 is released
694 // Remove thumbnail
695 if (thumbnailModel) await thumbnailModel.removeThumbnail()
696
697 throw err
698 }
675 }) 699 })
676 700
677 if (waitThumbnail === false) { 701 if (waitThumbnail === false) {
diff --git a/server/lib/files-cache/videos-preview-cache.ts b/server/lib/files-cache/videos-preview-cache.ts
index 47488da74..ee72cd3f9 100644
--- a/server/lib/files-cache/videos-preview-cache.ts
+++ b/server/lib/files-cache/videos-preview-cache.ts
@@ -20,7 +20,7 @@ class VideosPreviewCache extends AbstractVideoStaticFileCache <string> {
20 } 20 }
21 21
22 async getFilePathImpl (filename: string) { 22 async getFilePathImpl (filename: string) {
23 const thumbnail = await ThumbnailModel.loadWithVideoByName(filename, ThumbnailType.PREVIEW) 23 const thumbnail = await ThumbnailModel.loadWithVideoByFilename(filename, ThumbnailType.PREVIEW)
24 if (!thumbnail) return undefined 24 if (!thumbnail) return undefined
25 25
26 if (thumbnail.Video.isOwned()) return { isOwned: true, path: thumbnail.getPath() } 26 if (thumbnail.Video.isOwned()) return { isOwned: true, path: thumbnail.getPath() }
diff --git a/server/lib/job-queue/handlers/video-import.ts b/server/lib/job-queue/handlers/video-import.ts
index 1e5e52b58..0d00c1b9d 100644
--- a/server/lib/job-queue/handlers/video-import.ts
+++ b/server/lib/job-queue/handlers/video-import.ts
@@ -162,7 +162,11 @@ async function processFile (downloader: () => Promise<string>, videoImport: MVid
162 let thumbnailModel: MThumbnail 162 let thumbnailModel: MThumbnail
163 let thumbnailSave: object 163 let thumbnailSave: object
164 if (!videoImportWithFiles.Video.getMiniature()) { 164 if (!videoImportWithFiles.Video.getMiniature()) {
165 thumbnailModel = await generateVideoMiniature(videoImportWithFiles.Video, videoFile, ThumbnailType.MINIATURE) 165 thumbnailModel = await generateVideoMiniature({
166 video: videoImportWithFiles.Video,
167 videoFile,
168 type: ThumbnailType.MINIATURE
169 })
166 thumbnailSave = thumbnailModel.toJSON() 170 thumbnailSave = thumbnailModel.toJSON()
167 } 171 }
168 172
@@ -170,7 +174,11 @@ async function processFile (downloader: () => Promise<string>, videoImport: MVid
170 let previewModel: MThumbnail 174 let previewModel: MThumbnail
171 let previewSave: object 175 let previewSave: object
172 if (!videoImportWithFiles.Video.getPreview()) { 176 if (!videoImportWithFiles.Video.getPreview()) {
173 previewModel = await generateVideoMiniature(videoImportWithFiles.Video, videoFile, ThumbnailType.PREVIEW) 177 previewModel = await generateVideoMiniature({
178 video: videoImportWithFiles.Video,
179 videoFile,
180 type: ThumbnailType.PREVIEW
181 })
174 previewSave = previewModel.toJSON() 182 previewSave = previewModel.toJSON()
175 } 183 }
176 184
diff --git a/server/lib/job-queue/handlers/video-live-ending.ts b/server/lib/job-queue/handlers/video-live-ending.ts
index db6cd3682..6d50635bb 100644
--- a/server/lib/job-queue/handlers/video-live-ending.ts
+++ b/server/lib/job-queue/handlers/video-live-ending.ts
@@ -122,11 +122,19 @@ async function saveLive (video: MVideo, live: MVideoLive) {
122 122
123 // Regenerate the thumbnail & preview? 123 // Regenerate the thumbnail & preview?
124 if (videoWithFiles.getMiniature().automaticallyGenerated === true) { 124 if (videoWithFiles.getMiniature().automaticallyGenerated === true) {
125 await generateVideoMiniature(videoWithFiles, videoWithFiles.getMaxQualityFile(), ThumbnailType.MINIATURE) 125 await generateVideoMiniature({
126 video: videoWithFiles,
127 videoFile: videoWithFiles.getMaxQualityFile(),
128 type: ThumbnailType.MINIATURE
129 })
126 } 130 }
127 131
128 if (videoWithFiles.getPreview().automaticallyGenerated === true) { 132 if (videoWithFiles.getPreview().automaticallyGenerated === true) {
129 await generateVideoMiniature(videoWithFiles, videoWithFiles.getMaxQualityFile(), ThumbnailType.PREVIEW) 133 await generateVideoMiniature({
134 video: videoWithFiles,
135 videoFile: videoWithFiles.getMaxQualityFile(),
136 type: ThumbnailType.PREVIEW
137 })
130 } 138 }
131 139
132 await publishAndFederateIfNeeded(videoWithFiles, true) 140 await publishAndFederateIfNeeded(videoWithFiles, true)
diff --git a/server/lib/thumbnail.ts b/server/lib/thumbnail.ts
index 33aa7159c..55478299c 100644
--- a/server/lib/thumbnail.ts
+++ b/server/lib/thumbnail.ts
@@ -1,33 +1,48 @@
1import { join } from 'path'
2
3import { ThumbnailType } from '../../shared/models/videos/thumbnail.type'
1import { generateImageFromVideoFile } from '../helpers/ffmpeg-utils' 4import { generateImageFromVideoFile } from '../helpers/ffmpeg-utils'
5import { processImage } from '../helpers/image-utils'
6import { downloadImage } from '../helpers/requests'
2import { CONFIG } from '../initializers/config' 7import { CONFIG } from '../initializers/config'
3import { ASSETS_PATH, PREVIEWS_SIZE, THUMBNAILS_SIZE } from '../initializers/constants' 8import { ASSETS_PATH, PREVIEWS_SIZE, THUMBNAILS_SIZE } from '../initializers/constants'
4import { ThumbnailModel } from '../models/video/thumbnail' 9import { ThumbnailModel } from '../models/video/thumbnail'
5import { ThumbnailType } from '../../shared/models/videos/thumbnail.type'
6import { processImage } from '../helpers/image-utils'
7import { join } from 'path'
8import { downloadImage } from '../helpers/requests'
9import { MVideoPlaylistThumbnail } from '../types/models/video/video-playlist'
10import { MVideoFile, MVideoThumbnail } from '../types/models' 10import { MVideoFile, MVideoThumbnail } from '../types/models'
11import { MThumbnail } from '../types/models/video/thumbnail' 11import { MThumbnail } from '../types/models/video/thumbnail'
12import { MVideoPlaylistThumbnail } from '../types/models/video/video-playlist'
12import { getVideoFilePath } from './video-paths' 13import { getVideoFilePath } from './video-paths'
13 14
14type ImageSize = { height: number, width: number } 15type ImageSize = { height: number, width: number }
15 16
16function createPlaylistMiniatureFromExisting ( 17function createPlaylistMiniatureFromExisting (options: {
17 inputPath: string, 18 inputPath: string
18 playlist: MVideoPlaylistThumbnail, 19 playlist: MVideoPlaylistThumbnail
19 automaticallyGenerated: boolean, 20 automaticallyGenerated: boolean
20 keepOriginal = false, 21 keepOriginal?: boolean // default to false
21 size?: ImageSize 22 size?: ImageSize
22) { 23}) {
24 const { inputPath, playlist, automaticallyGenerated, keepOriginal = false, size } = options
23 const { filename, outputPath, height, width, existingThumbnail } = buildMetadataFromPlaylist(playlist, size) 25 const { filename, outputPath, height, width, existingThumbnail } = buildMetadataFromPlaylist(playlist, size)
24 const type = ThumbnailType.MINIATURE 26 const type = ThumbnailType.MINIATURE
25 27
26 const thumbnailCreator = () => processImage(inputPath, outputPath, { width, height }, keepOriginal) 28 const thumbnailCreator = () => processImage(inputPath, outputPath, { width, height }, keepOriginal)
27 return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, automaticallyGenerated, existingThumbnail }) 29 return createThumbnailFromFunction({
30 thumbnailCreator,
31 filename,
32 height,
33 width,
34 type,
35 automaticallyGenerated,
36 existingThumbnail
37 })
28} 38}
29 39
30function createPlaylistMiniatureFromUrl (downloadUrl: string, playlist: MVideoPlaylistThumbnail, size?: ImageSize) { 40function createPlaylistMiniatureFromUrl (options: {
41 downloadUrl: string
42 playlist: MVideoPlaylistThumbnail
43 size?: ImageSize
44}) {
45 const { downloadUrl, playlist, size } = options
31 const { filename, basePath, height, width, existingThumbnail } = buildMetadataFromPlaylist(playlist, size) 46 const { filename, basePath, height, width, existingThumbnail } = buildMetadataFromPlaylist(playlist, size)
32 const type = ThumbnailType.MINIATURE 47 const type = ThumbnailType.MINIATURE
33 48
@@ -40,7 +55,13 @@ function createPlaylistMiniatureFromUrl (downloadUrl: string, playlist: MVideoPl
40 return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail, fileUrl }) 55 return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail, fileUrl })
41} 56}
42 57
43function createVideoMiniatureFromUrl (downloadUrl: string, video: MVideoThumbnail, type: ThumbnailType, size?: ImageSize) { 58function createVideoMiniatureFromUrl (options: {
59 downloadUrl: string
60 video: MVideoThumbnail
61 type: ThumbnailType
62 size?: ImageSize
63}) {
64 const { downloadUrl, video, type, size } = options
44 const { filename, basePath, height, width, existingThumbnail } = buildMetadataFromVideo(video, type, size) 65 const { filename, basePath, height, width, existingThumbnail } = buildMetadataFromVideo(video, type, size)
45 66
46 // Only save the file URL if it is a remote video 67 // Only save the file URL if it is a remote video
@@ -58,17 +79,31 @@ function createVideoMiniatureFromExisting (options: {
58 type: ThumbnailType 79 type: ThumbnailType
59 automaticallyGenerated: boolean 80 automaticallyGenerated: boolean
60 size?: ImageSize 81 size?: ImageSize
61 keepOriginal?: boolean 82 keepOriginal?: boolean // default to false
62}) { 83}) {
63 const { inputPath, video, type, automaticallyGenerated, size, keepOriginal } = options 84 const { inputPath, video, type, automaticallyGenerated, size, keepOriginal = false } = options
64 85
65 const { filename, outputPath, height, width, existingThumbnail } = buildMetadataFromVideo(video, type, size) 86 const { filename, outputPath, height, width, existingThumbnail } = buildMetadataFromVideo(video, type, size)
66 const thumbnailCreator = () => processImage(inputPath, outputPath, { width, height }, keepOriginal) 87 const thumbnailCreator = () => processImage(inputPath, outputPath, { width, height }, keepOriginal)
67 88
68 return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, automaticallyGenerated, existingThumbnail }) 89 return createThumbnailFromFunction({
90 thumbnailCreator,
91 filename,
92 height,
93 width,
94 type,
95 automaticallyGenerated,
96 existingThumbnail
97 })
69} 98}
70 99
71function generateVideoMiniature (video: MVideoThumbnail, videoFile: MVideoFile, type: ThumbnailType) { 100function generateVideoMiniature (options: {
101 video: MVideoThumbnail
102 videoFile: MVideoFile
103 type: ThumbnailType
104}) {
105 const { video, videoFile, type } = options
106
72 const input = getVideoFilePath(video, videoFile) 107 const input = getVideoFilePath(video, videoFile)
73 108
74 const { filename, basePath, height, width, existingThumbnail, outputPath } = buildMetadataFromVideo(video, type) 109 const { filename, basePath, height, width, existingThumbnail, outputPath } = buildMetadataFromVideo(video, type)
@@ -76,10 +111,24 @@ function generateVideoMiniature (video: MVideoThumbnail, videoFile: MVideoFile,
76 ? () => processImage(ASSETS_PATH.DEFAULT_AUDIO_BACKGROUND, outputPath, { width, height }, true) 111 ? () => processImage(ASSETS_PATH.DEFAULT_AUDIO_BACKGROUND, outputPath, { width, height }, true)
77 : () => generateImageFromVideoFile(input, basePath, filename, { height, width }) 112 : () => generateImageFromVideoFile(input, basePath, filename, { height, width })
78 113
79 return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, automaticallyGenerated: true, existingThumbnail }) 114 return createThumbnailFromFunction({
115 thumbnailCreator,
116 filename,
117 height,
118 width,
119 type,
120 automaticallyGenerated: true,
121 existingThumbnail
122 })
80} 123}
81 124
82function createPlaceholderThumbnail (fileUrl: string, video: MVideoThumbnail, type: ThumbnailType, size: ImageSize) { 125function createPlaceholderThumbnail (options: {
126 fileUrl: string
127 video: MVideoThumbnail
128 type: ThumbnailType
129 size: ImageSize
130}) {
131 const { fileUrl, video, type, size } = options
83 const { filename, height, width, existingThumbnail } = buildMetadataFromVideo(video, type, size) 132 const { filename, height, width, existingThumbnail } = buildMetadataFromVideo(video, type, size)
84 133
85 const thumbnail = existingThumbnail || new ThumbnailModel() 134 const thumbnail = existingThumbnail || new ThumbnailModel()
@@ -164,12 +213,22 @@ async function createThumbnailFromFunction (parameters: {
164 fileUrl?: string 213 fileUrl?: string
165 existingThumbnail?: MThumbnail 214 existingThumbnail?: MThumbnail
166}) { 215}) {
167 const { thumbnailCreator, filename, width, height, type, existingThumbnail, automaticallyGenerated = null, fileUrl = null } = parameters 216 const {
168 217 thumbnailCreator,
169 // Remove old file 218 filename,
170 if (existingThumbnail) await existingThumbnail.removeThumbnail() 219 width,
220 height,
221 type,
222 existingThumbnail,
223 automaticallyGenerated = null,
224 fileUrl = null
225 } = parameters
226
227 const oldFilename = existingThumbnail
228 ? existingThumbnail.filename
229 : undefined
171 230
172 const thumbnail = existingThumbnail || new ThumbnailModel() 231 const thumbnail: MThumbnail = existingThumbnail || new ThumbnailModel()
173 232
174 thumbnail.filename = filename 233 thumbnail.filename = filename
175 thumbnail.height = height 234 thumbnail.height = height
@@ -177,6 +236,7 @@ async function createThumbnailFromFunction (parameters: {
177 thumbnail.type = type 236 thumbnail.type = type
178 thumbnail.fileUrl = fileUrl 237 thumbnail.fileUrl = fileUrl
179 thumbnail.automaticallyGenerated = automaticallyGenerated 238 thumbnail.automaticallyGenerated = automaticallyGenerated
239 thumbnail.previousThumbnailFilename = oldFilename
180 240
181 await thumbnailCreator() 241 await thumbnailCreator()
182 242