]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/models/video/thumbnail.ts
Add url field in caption and use it for thumbnails
[github/Chocobozzz/PeerTube.git] / server / models / video / thumbnail.ts
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/typings/models'
23 import { buildRemoteVideoBaseUrl } from '@server/helpers/activitypub'
24
25 @Table({
26 tableName: 'thumbnail',
27 indexes: [
28 {
29 fields: [ 'videoId' ]
30 },
31 {
32 fields: [ 'videoPlaylistId' ],
33 unique: true
34 }
35 ]
36 })
37 export class ThumbnailModel extends Model<ThumbnailModel> {
38
39 @AllowNull(false)
40 @Column
41 filename: string
42
43 @AllowNull(true)
44 @Default(null)
45 @Column
46 height: number
47
48 @AllowNull(true)
49 @Default(null)
50 @Column
51 width: number
52
53 @AllowNull(false)
54 @Column
55 type: ThumbnailType
56
57 @AllowNull(true)
58 @Column(DataType.STRING(CONSTRAINTS_FIELDS.COMMONS.URL.max))
59 fileUrl: string
60
61 @AllowNull(true)
62 @Column
63 automaticallyGenerated: boolean
64
65 @ForeignKey(() => VideoModel)
66 @Column
67 videoId: number
68
69 @BelongsTo(() => VideoModel, {
70 foreignKey: {
71 allowNull: true
72 },
73 onDelete: 'CASCADE'
74 })
75 Video: VideoModel
76
77 @ForeignKey(() => VideoPlaylistModel)
78 @Column
79 videoPlaylistId: number
80
81 @BelongsTo(() => VideoPlaylistModel, {
82 foreignKey: {
83 allowNull: true
84 },
85 onDelete: 'CASCADE'
86 })
87 VideoPlaylist: VideoPlaylistModel
88
89 @CreatedAt
90 createdAt: Date
91
92 @UpdatedAt
93 updatedAt: Date
94
95 private static types: { [ id in ThumbnailType ]: { label: string, directory: string, staticPath: string } } = {
96 [ThumbnailType.MINIATURE]: {
97 label: 'miniature',
98 directory: CONFIG.STORAGE.THUMBNAILS_DIR,
99 staticPath: STATIC_PATHS.THUMBNAILS
100 },
101 [ThumbnailType.PREVIEW]: {
102 label: 'preview',
103 directory: CONFIG.STORAGE.PREVIEWS_DIR,
104 staticPath: LAZY_STATIC_PATHS.PREVIEWS
105 }
106 }
107
108 @AfterDestroy
109 static removeFiles (instance: ThumbnailModel) {
110 logger.info('Removing %s file %s.', ThumbnailModel.types[instance.type].label, instance.filename)
111
112 // Don't block the transaction
113 instance.removeThumbnail()
114 .catch(err => logger.error('Cannot remove thumbnail file %s.', instance.filename, err))
115 }
116
117 static loadByName (filename: string) {
118 const query = {
119 where: {
120 filename
121 }
122 }
123
124 return ThumbnailModel.findOne(query)
125 }
126
127 static generateDefaultPreviewName (videoUUID: string) {
128 return videoUUID + '.jpg'
129 }
130
131 getFileUrl (video: MVideoAccountLight) {
132 const staticPath = ThumbnailModel.types[this.type].staticPath + this.filename
133
134 if (video.isOwned()) return WEBSERVER.URL + staticPath
135 if (this.fileUrl) return this.fileUrl
136
137 // Fallback if we don't have a file URL
138 return buildRemoteVideoBaseUrl(video, staticPath)
139 }
140
141 getPath () {
142 const directory = ThumbnailModel.types[this.type].directory
143 return join(directory, this.filename)
144 }
145
146 removeThumbnail () {
147 return remove(this.getPath())
148 }
149 }