thumbnail.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import { join } from 'path'
  2. import {
  3. AfterDestroy,
  4. AllowNull,
  5. BelongsTo,
  6. Column,
  7. CreatedAt,
  8. DataType,
  9. Default,
  10. ForeignKey,
  11. Model,
  12. Table,
  13. UpdatedAt
  14. } from 'sequelize-typescript'
  15. import { CONSTRAINTS_FIELDS, LAZY_STATIC_PATHS, STATIC_PATHS, WEBSERVER } from '../../initializers/constants'
  16. import { logger } from '../../helpers/logger'
  17. import { remove } from 'fs-extra'
  18. import { CONFIG } from '../../initializers/config'
  19. import { VideoModel } from './video'
  20. import { VideoPlaylistModel } from './video-playlist'
  21. import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type'
  22. import { MVideoAccountLight } from '@server/types/models'
  23. import { buildRemoteVideoBaseUrl } from '@server/helpers/activitypub'
  24. @Table({
  25. tableName: 'thumbnail',
  26. indexes: [
  27. {
  28. fields: [ 'videoId' ]
  29. },
  30. {
  31. fields: [ 'videoPlaylistId' ],
  32. unique: true
  33. }
  34. ]
  35. })
  36. export class ThumbnailModel extends Model {
  37. @AllowNull(false)
  38. @Column
  39. filename: string
  40. @AllowNull(true)
  41. @Default(null)
  42. @Column
  43. height: number
  44. @AllowNull(true)
  45. @Default(null)
  46. @Column
  47. width: number
  48. @AllowNull(false)
  49. @Column
  50. type: ThumbnailType
  51. @AllowNull(true)
  52. @Column(DataType.STRING(CONSTRAINTS_FIELDS.COMMONS.URL.max))
  53. fileUrl: string
  54. @AllowNull(true)
  55. @Column
  56. automaticallyGenerated: boolean
  57. @ForeignKey(() => VideoModel)
  58. @Column
  59. videoId: number
  60. @BelongsTo(() => VideoModel, {
  61. foreignKey: {
  62. allowNull: true
  63. },
  64. onDelete: 'CASCADE'
  65. })
  66. Video: VideoModel
  67. @ForeignKey(() => VideoPlaylistModel)
  68. @Column
  69. videoPlaylistId: number
  70. @BelongsTo(() => VideoPlaylistModel, {
  71. foreignKey: {
  72. allowNull: true
  73. },
  74. onDelete: 'CASCADE'
  75. })
  76. VideoPlaylist: VideoPlaylistModel
  77. @CreatedAt
  78. createdAt: Date
  79. @UpdatedAt
  80. updatedAt: Date
  81. private static readonly types: { [ id in ThumbnailType ]: { label: string, directory: string, staticPath: string } } = {
  82. [ThumbnailType.MINIATURE]: {
  83. label: 'miniature',
  84. directory: CONFIG.STORAGE.THUMBNAILS_DIR,
  85. staticPath: STATIC_PATHS.THUMBNAILS
  86. },
  87. [ThumbnailType.PREVIEW]: {
  88. label: 'preview',
  89. directory: CONFIG.STORAGE.PREVIEWS_DIR,
  90. staticPath: LAZY_STATIC_PATHS.PREVIEWS
  91. }
  92. }
  93. @AfterDestroy
  94. static removeFiles (instance: ThumbnailModel) {
  95. logger.info('Removing %s file %s.', ThumbnailModel.types[instance.type].label, instance.filename)
  96. // Don't block the transaction
  97. instance.removeThumbnail()
  98. .catch(err => logger.error('Cannot remove thumbnail file %s.', instance.filename, err))
  99. }
  100. static loadByName (filename: string) {
  101. const query = {
  102. where: {
  103. filename
  104. }
  105. }
  106. return ThumbnailModel.findOne(query)
  107. }
  108. static generateDefaultPreviewName (videoUUID: string) {
  109. return videoUUID + '.jpg'
  110. }
  111. getFileUrl (video: MVideoAccountLight) {
  112. const staticPath = ThumbnailModel.types[this.type].staticPath + this.filename
  113. if (video.isOwned()) return WEBSERVER.URL + staticPath
  114. if (this.fileUrl) return this.fileUrl
  115. // Fallback if we don't have a file URL
  116. return buildRemoteVideoBaseUrl(video, staticPath)
  117. }
  118. getPath () {
  119. const directory = ThumbnailModel.types[this.type].directory
  120. return join(directory, this.filename)
  121. }
  122. removeThumbnail () {
  123. return remove(this.getPath())
  124. }
  125. }