thumbnail.ts 6.3 KB

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