4ba521b973f5133c0a9d305838fc98d84ad29c5a
[oweals/peertube.git] / server / lib / thumbnail.ts
1 import { VideoFileModel } from '../models/video/video-file'
2 import { generateImageFromVideoFile } from '../helpers/ffmpeg-utils'
3 import { CONFIG } from '../initializers/config'
4 import { PREVIEWS_SIZE, THUMBNAILS_SIZE } from '../initializers/constants'
5 import { VideoModel } from '../models/video/video'
6 import { ThumbnailModel } from '../models/video/thumbnail'
7 import { ThumbnailType } from '../../shared/models/videos/thumbnail.type'
8 import { processImage } from '../helpers/image-utils'
9 import { join } from 'path'
10 import { downloadImage } from '../helpers/requests'
11 import { VideoPlaylistModel } from '../models/video/video-playlist'
12
13 type ImageSize = { height: number, width: number }
14
15 function createPlaylistMiniatureFromExisting (inputPath: string, playlist: VideoPlaylistModel, keepOriginal = false, size?: ImageSize) {
16   const { filename, outputPath, height, width, existingThumbnail } = buildMetadataFromPlaylist(playlist, size)
17   const type = ThumbnailType.MINIATURE
18
19   const thumbnailCreator = () => processImage(inputPath, outputPath, { width, height }, keepOriginal)
20   return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail })
21 }
22
23 function createPlaylistMiniatureFromUrl (url: string, playlist: VideoPlaylistModel, size?: ImageSize) {
24   const { filename, basePath, height, width, existingThumbnail } = buildMetadataFromPlaylist(playlist, size)
25   const type = ThumbnailType.MINIATURE
26
27   const thumbnailCreator = () => downloadImage(url, basePath, filename, { width, height })
28   return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail, url })
29 }
30
31 function createVideoMiniatureFromUrl (url: string, video: VideoModel, type: ThumbnailType, size?: ImageSize) {
32   const { filename, basePath, height, width, existingThumbnail } = buildMetadataFromVideo(video, type, size)
33   const thumbnailCreator = () => downloadImage(url, basePath, filename, { width, height })
34
35   return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail, url })
36 }
37
38 function createVideoMiniatureFromExisting (inputPath: string, video: VideoModel, type: ThumbnailType, size?: ImageSize) {
39   const { filename, outputPath, height, width, existingThumbnail } = buildMetadataFromVideo(video, type, size)
40   const thumbnailCreator = () => processImage(inputPath, outputPath, { width, height })
41
42   return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail })
43 }
44
45 function generateVideoMiniature (video: VideoModel, videoFile: VideoFileModel, type: ThumbnailType) {
46   const input = video.getVideoFilePath(videoFile)
47
48   const { filename, basePath, height, width, existingThumbnail } = buildMetadataFromVideo(video, type)
49   const thumbnailCreator = () => generateImageFromVideoFile(input, basePath, filename, { height, width })
50
51   return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail })
52 }
53
54 function createPlaceholderThumbnail (url: string, video: VideoModel, type: ThumbnailType, size: ImageSize) {
55   const { filename, height, width, existingThumbnail } = buildMetadataFromVideo(video, type, size)
56
57   const thumbnail = existingThumbnail ? existingThumbnail : new ThumbnailModel()
58
59   thumbnail.filename = filename
60   thumbnail.height = height
61   thumbnail.width = width
62   thumbnail.type = type
63   thumbnail.url = url
64
65   return thumbnail
66 }
67
68 // ---------------------------------------------------------------------------
69
70 export {
71   generateVideoMiniature,
72   createVideoMiniatureFromUrl,
73   createVideoMiniatureFromExisting,
74   createPlaceholderThumbnail,
75   createPlaylistMiniatureFromUrl,
76   createPlaylistMiniatureFromExisting
77 }
78
79 function buildMetadataFromPlaylist (playlist: VideoPlaylistModel, size: ImageSize) {
80   const filename = playlist.generateThumbnailName()
81   const basePath = CONFIG.STORAGE.THUMBNAILS_DIR
82
83   return {
84     filename,
85     basePath,
86     existingThumbnail: playlist.Thumbnail,
87     outputPath: join(basePath, filename),
88     height: size ? size.height : THUMBNAILS_SIZE.height,
89     width: size ? size.width : THUMBNAILS_SIZE.width
90   }
91 }
92
93 function buildMetadataFromVideo (video: VideoModel, type: ThumbnailType, size?: ImageSize) {
94   const existingThumbnail = Array.isArray(video.Thumbnails)
95     ? video.Thumbnails.find(t => t.type === type)
96     : undefined
97
98   if (type === ThumbnailType.MINIATURE) {
99     const filename = video.generateThumbnailName()
100     const basePath = CONFIG.STORAGE.THUMBNAILS_DIR
101
102     return {
103       filename,
104       basePath,
105       existingThumbnail,
106       outputPath: join(basePath, filename),
107       height: size ? size.height : THUMBNAILS_SIZE.height,
108       width: size ? size.width : THUMBNAILS_SIZE.width
109     }
110   }
111
112   if (type === ThumbnailType.PREVIEW) {
113     const filename = video.generatePreviewName()
114     const basePath = CONFIG.STORAGE.PREVIEWS_DIR
115
116     return {
117       filename,
118       basePath,
119       existingThumbnail,
120       outputPath: join(basePath, filename),
121       height: size ? size.height : PREVIEWS_SIZE.height,
122       width: size ? size.width : PREVIEWS_SIZE.width
123     }
124   }
125
126   return undefined
127 }
128
129 async function createThumbnailFromFunction (parameters: {
130   thumbnailCreator: () => Promise<any>,
131   filename: string,
132   height: number,
133   width: number,
134   type: ThumbnailType,
135   url?: string,
136   existingThumbnail?: ThumbnailModel
137 }) {
138   const { thumbnailCreator, filename, width, height, type, existingThumbnail, url = null } = parameters
139
140   const thumbnail = existingThumbnail ? existingThumbnail : new ThumbnailModel()
141
142   thumbnail.filename = filename
143   thumbnail.height = height
144   thumbnail.width = width
145   thumbnail.type = type
146   thumbnail.url = url
147
148   await thumbnailCreator()
149
150   return thumbnail
151 }