]>
Commit | Line | Data |
---|---|---|
c48e82b5 C |
1 | import { |
2 | AllowNull, | |
3 | BelongsTo, | |
4 | Column, | |
5 | CreatedAt, | |
6 | DataType, | |
7 | Default, | |
8 | ForeignKey, | |
9 | HasMany, | |
10 | Is, | |
11 | Model, | |
12 | Table, | |
13 | UpdatedAt | |
14 | } from 'sequelize-typescript' | |
3a6f351b | 15 | import { |
14e2014a | 16 | isVideoFileExtnameValid, |
3a6f351b C |
17 | isVideoFileInfoHashValid, |
18 | isVideoFileResolutionValid, | |
19 | isVideoFileSizeValid, | |
20 | isVideoFPSResolutionValid | |
21 | } from '../../helpers/custom-validators/videos' | |
3acc5084 | 22 | import { parseAggregateResult, throwIfNotValid } from '../utils' |
3fd3ab2d | 23 | import { VideoModel } from './video' |
c48e82b5 | 24 | import { VideoRedundancyModel } from '../redundancy/video-redundancy' |
ae9bbed4 | 25 | import { VideoStreamingPlaylistModel } from './video-streaming-playlist' |
d7a25329 | 26 | import { FindOptions, Op, QueryTypes, Transaction } from 'sequelize' |
536598cf | 27 | import { MIMETYPES } from '../../initializers/constants' |
d7a25329 C |
28 | import { MVideoFile, MVideoFileStreamingPlaylistVideo, MVideoFileVideo } from '../../typings/models/video/video-file' |
29 | import { MStreamingPlaylist, MStreamingPlaylistVideo, MVideo } from '@server/typings/models' | |
93e1258c | 30 | |
3fd3ab2d C |
31 | @Table({ |
32 | tableName: 'videoFile', | |
33 | indexes: [ | |
93e1258c | 34 | { |
d7a25329 C |
35 | fields: [ 'videoId' ], |
36 | where: { | |
37 | videoId: { | |
38 | [Op.ne]: null | |
39 | } | |
40 | } | |
41 | }, | |
42 | { | |
43 | fields: [ 'videoStreamingPlaylistId' ], | |
44 | where: { | |
45 | videoStreamingPlaylistId: { | |
46 | [Op.ne]: null | |
47 | } | |
48 | } | |
93e1258c | 49 | }, |
d7a25329 | 50 | |
93e1258c | 51 | { |
3fd3ab2d | 52 | fields: [ 'infoHash' ] |
8cd72bd3 | 53 | }, |
d7a25329 | 54 | |
8cd72bd3 C |
55 | { |
56 | fields: [ 'videoId', 'resolution', 'fps' ], | |
d7a25329 C |
57 | unique: true, |
58 | where: { | |
59 | videoId: { | |
60 | [Op.ne]: null | |
61 | } | |
62 | } | |
63 | }, | |
64 | { | |
65 | fields: [ 'videoStreamingPlaylistId', 'resolution', 'fps' ], | |
66 | unique: true, | |
67 | where: { | |
68 | videoStreamingPlaylistId: { | |
69 | [Op.ne]: null | |
70 | } | |
71 | } | |
93e1258c | 72 | } |
93e1258c | 73 | ] |
3fd3ab2d C |
74 | }) |
75 | export class VideoFileModel extends Model<VideoFileModel> { | |
76 | @CreatedAt | |
77 | createdAt: Date | |
78 | ||
79 | @UpdatedAt | |
80 | updatedAt: Date | |
81 | ||
82 | @AllowNull(false) | |
83 | @Is('VideoFileResolution', value => throwIfNotValid(value, isVideoFileResolutionValid, 'resolution')) | |
84 | @Column | |
85 | resolution: number | |
86 | ||
87 | @AllowNull(false) | |
88 | @Is('VideoFileSize', value => throwIfNotValid(value, isVideoFileSizeValid, 'size')) | |
89 | @Column(DataType.BIGINT) | |
90 | size: number | |
91 | ||
92 | @AllowNull(false) | |
14e2014a C |
93 | @Is('VideoFileExtname', value => throwIfNotValid(value, isVideoFileExtnameValid, 'extname')) |
94 | @Column | |
3fd3ab2d C |
95 | extname: string |
96 | ||
97 | @AllowNull(false) | |
09209296 | 98 | @Is('VideoFileInfohash', value => throwIfNotValid(value, isVideoFileInfoHashValid, 'info hash')) |
3fd3ab2d C |
99 | @Column |
100 | infoHash: string | |
101 | ||
2e7cf5ae C |
102 | @AllowNull(false) |
103 | @Default(-1) | |
3a6f351b C |
104 | @Is('VideoFileFPS', value => throwIfNotValid(value, isVideoFPSResolutionValid, 'fps')) |
105 | @Column | |
106 | fps: number | |
107 | ||
3fd3ab2d C |
108 | @ForeignKey(() => VideoModel) |
109 | @Column | |
110 | videoId: number | |
111 | ||
112 | @BelongsTo(() => VideoModel, { | |
93e1258c | 113 | foreignKey: { |
d7a25329 | 114 | allowNull: true |
93e1258c C |
115 | }, |
116 | onDelete: 'CASCADE' | |
117 | }) | |
3fd3ab2d | 118 | Video: VideoModel |
cc43831a | 119 | |
d7a25329 C |
120 | @ForeignKey(() => VideoStreamingPlaylistModel) |
121 | @Column | |
122 | videoStreamingPlaylistId: number | |
123 | ||
124 | @BelongsTo(() => VideoStreamingPlaylistModel, { | |
125 | foreignKey: { | |
126 | allowNull: true | |
127 | }, | |
128 | onDelete: 'CASCADE' | |
129 | }) | |
130 | VideoStreamingPlaylist: VideoStreamingPlaylistModel | |
131 | ||
c48e82b5 C |
132 | @HasMany(() => VideoRedundancyModel, { |
133 | foreignKey: { | |
09209296 | 134 | allowNull: true |
c48e82b5 C |
135 | }, |
136 | onDelete: 'CASCADE', | |
137 | hooks: true | |
138 | }) | |
139 | RedundancyVideos: VideoRedundancyModel[] | |
140 | ||
09209296 | 141 | static doesInfohashExist (infoHash: string) { |
cc43831a C |
142 | const query = 'SELECT 1 FROM "videoFile" WHERE "infoHash" = $infoHash LIMIT 1' |
143 | const options = { | |
d5d9b6d7 | 144 | type: QueryTypes.SELECT as QueryTypes.SELECT, |
cc43831a C |
145 | bind: { infoHash }, |
146 | raw: true | |
147 | } | |
148 | ||
149 | return VideoModel.sequelize.query(query, options) | |
3acc5084 | 150 | .then(results => results.length === 1) |
cc43831a | 151 | } |
e5565833 | 152 | |
25378bc8 C |
153 | static loadWithVideo (id: number) { |
154 | const options = { | |
155 | include: [ | |
156 | { | |
157 | model: VideoModel.unscoped(), | |
158 | required: true | |
159 | } | |
160 | ] | |
161 | } | |
162 | ||
9b39106d | 163 | return VideoFileModel.findByPk(id, options) |
25378bc8 C |
164 | } |
165 | ||
3acc5084 | 166 | static listByStreamingPlaylist (streamingPlaylistId: number, transaction: Transaction) { |
ae9bbed4 C |
167 | const query = { |
168 | include: [ | |
169 | { | |
170 | model: VideoModel.unscoped(), | |
171 | required: true, | |
172 | include: [ | |
173 | { | |
174 | model: VideoStreamingPlaylistModel.unscoped(), | |
175 | required: true, | |
176 | where: { | |
177 | id: streamingPlaylistId | |
178 | } | |
179 | } | |
180 | ] | |
181 | } | |
182 | ], | |
183 | transaction | |
184 | } | |
185 | ||
186 | return VideoFileModel.findAll(query) | |
187 | } | |
188 | ||
3acc5084 C |
189 | static getStats () { |
190 | const query: FindOptions = { | |
44b9c0ba C |
191 | include: [ |
192 | { | |
193 | attributes: [], | |
194 | model: VideoModel.unscoped(), | |
195 | where: { | |
196 | remote: false | |
197 | } | |
198 | } | |
199 | ] | |
44b9c0ba | 200 | } |
3acc5084 C |
201 | |
202 | return VideoFileModel.aggregate('size', 'SUM', query) | |
203 | .then(result => ({ | |
204 | totalLocalVideoFilesSize: parseAggregateResult(result) | |
205 | })) | |
44b9c0ba C |
206 | } |
207 | ||
d7a25329 C |
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 | |
213 | ) { | |
214 | const baseWhere = { | |
215 | fps: videoFile.fps, | |
216 | resolution: videoFile.resolution | |
217 | } | |
218 | ||
219 | if (mode === 'streaming-playlist') Object.assign(baseWhere, { videoStreamingPlaylistId: videoFile.videoStreamingPlaylistId }) | |
220 | else Object.assign(baseWhere, { videoId: videoFile.videoId }) | |
221 | ||
222 | const element = await VideoFileModel.findOne({ where: baseWhere, transaction }) | |
223 | if (!element) return videoFile.save({ transaction }) | |
224 | ||
225 | for (const k of Object.keys(videoFile.toJSON())) { | |
226 | element[k] = videoFile[k] | |
227 | } | |
228 | ||
229 | return element.save({ transaction }) | |
230 | } | |
231 | ||
232 | getVideoOrStreamingPlaylist (this: MVideoFileVideo | MVideoFileStreamingPlaylistVideo): MVideo | MStreamingPlaylistVideo { | |
233 | if (this.videoId) return (this as MVideoFileVideo).Video | |
234 | ||
235 | return (this as MVideoFileStreamingPlaylistVideo).VideoStreamingPlaylist | |
236 | } | |
237 | ||
536598cf C |
238 | isAudio () { |
239 | return !!MIMETYPES.AUDIO.EXT_MIMETYPE[this.extname] | |
240 | } | |
241 | ||
453e83ea | 242 | hasSameUniqueKeysThan (other: MVideoFile) { |
e5565833 C |
243 | return this.fps === other.fps && |
244 | this.resolution === other.resolution && | |
d7a25329 C |
245 | ( |
246 | (this.videoId !== null && this.videoId === other.videoId) || | |
247 | (this.videoStreamingPlaylistId !== null && this.videoStreamingPlaylistId === other.videoStreamingPlaylistId) | |
248 | ) | |
e5565833 | 249 | } |
93e1258c | 250 | } |