14 } from 'sequelize-typescript'
16 isVideoFileExtnameValid,
17 isVideoFileInfoHashValid,
18 isVideoFileResolutionValid,
20 isVideoFPSResolutionValid
21 } from '../../helpers/custom-validators/videos'
22 import { parseAggregateResult, throwIfNotValid } from '../utils'
23 import { VideoModel } from './video'
24 import { VideoRedundancyModel } from '../redundancy/video-redundancy'
25 import { VideoStreamingPlaylistModel } from './video-streaming-playlist'
26 import { FindOptions, Op, QueryTypes, Transaction } from 'sequelize'
27 import { MIMETYPES } from '../../initializers/constants'
28 import { MVideoFile, MVideoFileStreamingPlaylistVideo, MVideoFileVideo } from '../../typings/models/video/video-file'
29 import { MStreamingPlaylist, MStreamingPlaylistVideo, MVideo } from '@server/typings/models'
32 tableName: 'videoFile',
35 fields: [ 'videoId' ],
43 fields: [ 'videoStreamingPlaylistId' ],
45 videoStreamingPlaylistId: {
52 fields: [ 'infoHash' ]
56 fields: [ 'videoId', 'resolution', 'fps' ],
65 fields: [ 'videoStreamingPlaylistId', 'resolution', 'fps' ],
68 videoStreamingPlaylistId: {
75 export class VideoFileModel extends Model<VideoFileModel> {
83 @Is('VideoFileResolution', value => throwIfNotValid(value, isVideoFileResolutionValid, 'resolution'))
88 @Is('VideoFileSize', value => throwIfNotValid(value, isVideoFileSizeValid, 'size'))
89 @Column(DataType.BIGINT)
93 @Is('VideoFileExtname', value => throwIfNotValid(value, isVideoFileExtnameValid, 'extname'))
98 @Is('VideoFileInfohash', value => throwIfNotValid(value, isVideoFileInfoHashValid, 'info hash'))
104 @Is('VideoFileFPS', value => throwIfNotValid(value, isVideoFPSResolutionValid, 'fps'))
108 @ForeignKey(() => VideoModel)
112 @BelongsTo(() => VideoModel, {
120 @ForeignKey(() => VideoStreamingPlaylistModel)
122 videoStreamingPlaylistId: number
124 @BelongsTo(() => VideoStreamingPlaylistModel, {
130 VideoStreamingPlaylist: VideoStreamingPlaylistModel
132 @HasMany(() => VideoRedundancyModel, {
139 RedundancyVideos: VideoRedundancyModel[]
141 static doesInfohashExist (infoHash: string) {
142 const query = 'SELECT 1 FROM "videoFile" WHERE "infoHash" = $infoHash LIMIT 1'
144 type: QueryTypes.SELECT as QueryTypes.SELECT,
149 return VideoModel.sequelize.query(query, options)
150 .then(results => results.length === 1)
153 static loadWithVideo (id: number) {
157 model: VideoModel.unscoped(),
163 return VideoFileModel.findByPk(id, options)
166 static listByStreamingPlaylist (streamingPlaylistId: number, transaction: Transaction) {
170 model: VideoModel.unscoped(),
174 model: VideoStreamingPlaylistModel.unscoped(),
177 id: streamingPlaylistId
186 return VideoFileModel.findAll(query)
190 const query: FindOptions = {
194 model: VideoModel.unscoped(),
202 return VideoFileModel.aggregate('size', 'SUM', query)
204 totalLocalVideoFilesSize: parseAggregateResult(result)
208 // Redefine upsert because sequelize does not use an appropriate where clause in the update query with 2 unique indexes
209 static async customUpsert (
210 videoFile: MVideoFile,
211 mode: 'streaming-playlist' | 'video',
212 transaction: Transaction
216 resolution: videoFile.resolution
219 if (mode === 'streaming-playlist') Object.assign(baseWhere, { videoStreamingPlaylistId: videoFile.videoStreamingPlaylistId })
220 else Object.assign(baseWhere, { videoId: videoFile.videoId })
222 const element = await VideoFileModel.findOne({ where: baseWhere, transaction })
223 if (!element) return videoFile.save({ transaction })
225 for (const k of Object.keys(videoFile.toJSON())) {
226 element[k] = videoFile[k]
229 return element.save({ transaction })
232 getVideoOrStreamingPlaylist (this: MVideoFileVideo | MVideoFileStreamingPlaylistVideo): MVideo | MStreamingPlaylistVideo {
233 if (this.videoId) return (this as MVideoFileVideo).Video
235 return (this as MVideoFileStreamingPlaylistVideo).VideoStreamingPlaylist
239 return !!MIMETYPES.AUDIO.EXT_MIMETYPE[this.extname]
242 hasSameUniqueKeysThan (other: MVideoFile) {
243 return this.fps === other.fps &&
244 this.resolution === other.resolution &&
246 (this.videoId !== null && this.videoId === other.videoId) ||
247 (this.videoStreamingPlaylistId !== null && this.videoStreamingPlaylistId === other.videoStreamingPlaylistId)