]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/models/video/sql/shared/video-model-builder.ts
Merge branch 'release/4.0.0' into develop
[github/Chocobozzz/PeerTube.git] / server / models / video / sql / shared / video-model-builder.ts
CommitLineData
17bb4538 1
d9bf974f 2import { AccountModel } from '@server/models/account/account'
2760b454 3import { AccountBlocklistModel } from '@server/models/account/account-blocklist'
d9bf974f
C
4import { ActorModel } from '@server/models/actor/actor'
5import { ActorImageModel } from '@server/models/actor/actor-image'
6import { VideoRedundancyModel } from '@server/models/redundancy/video-redundancy'
7import { ServerModel } from '@server/models/server/server'
2760b454 8import { ServerBlocklistModel } from '@server/models/server/server-blocklist'
d9bf974f
C
9import { TrackerModel } from '@server/models/server/tracker'
10import { UserVideoHistoryModel } from '@server/models/user/user-video-history'
2760b454 11import { VideoInclude } from '@shared/models'
d9bf974f
C
12import { ScheduleVideoUpdateModel } from '../../schedule-video-update'
13import { TagModel } from '../../tag'
14import { ThumbnailModel } from '../../thumbnail'
15import { VideoModel } from '../../video'
16import { VideoBlacklistModel } from '../../video-blacklist'
17import { VideoChannelModel } from '../../video-channel'
18import { VideoFileModel } from '../../video-file'
19import { VideoLiveModel } from '../../video-live'
20import { VideoStreamingPlaylistModel } from '../../video-streaming-playlist'
7e7d8e48 21import { VideoTableAttributes } from './video-table-attributes'
17bb4538
C
22
23type SQLRow = { [id: string]: string | number }
d9bf974f 24
1d43c3a6
C
25/**
26 *
27 * Build video models from SQL rows
28 *
29 */
30
d9bf974f
C
31export class VideoModelBuilder {
32 private videosMemo: { [ id: number ]: VideoModel }
33 private videoStreamingPlaylistMemo: { [ id: number ]: VideoStreamingPlaylistModel }
34 private videoFileMemo: { [ id: number ]: VideoFileModel }
35
17bb4538
C
36 private thumbnailsDone: Set<any>
37 private historyDone: Set<any>
38 private blacklistDone: Set<any>
2760b454
C
39 private accountBlocklistDone: Set<any>
40 private serverBlocklistDone: Set<any>
17bb4538
C
41 private liveDone: Set<any>
42 private redundancyDone: Set<any>
43 private scheduleVideoUpdateDone: Set<any>
d9bf974f
C
44
45 private trackersDone: Set<string>
46 private tagsDone: Set<string>
47
48 private videos: VideoModel[]
49
50 private readonly buildOpts = { raw: true, isNewRecord: false }
51
52 constructor (
53 readonly mode: 'get' | 'list',
7e7d8e48 54 readonly tables: VideoTableAttributes
d9bf974f
C
55 ) {
56
57 }
58
2760b454
C
59 buildVideosFromRows (options: {
60 rows: SQLRow[]
61 include?: VideoInclude
62 rowsWebTorrentFiles?: SQLRow[]
63 rowsStreamingPlaylist?: SQLRow[]
64 }) {
65 const { rows, rowsWebTorrentFiles, rowsStreamingPlaylist, include } = options
66
d9bf974f
C
67 this.reinit()
68
69 for (const row of rows) {
71d4af1e 70 this.buildVideoAndAccount(row)
d9bf974f
C
71
72 const videoModel = this.videosMemo[row.id]
73
74 this.setUserHistory(row, videoModel)
75 this.addThumbnail(row, videoModel)
d9bf974f 76
17bb4538 77 if (!rowsWebTorrentFiles) {
1d43c3a6
C
78 this.addWebTorrentFile(row, videoModel)
79 }
80
81 if (!rowsStreamingPlaylist) {
82 this.addStreamingPlaylist(row, videoModel)
83 this.addStreamingPlaylistFile(row)
84 }
d9bf974f
C
85
86 if (this.mode === 'get') {
87 this.addTag(row, videoModel)
88 this.addTracker(row, videoModel)
89 this.setBlacklisted(row, videoModel)
90 this.setScheduleVideoUpdate(row, videoModel)
91 this.setLive(row, videoModel)
2760b454
C
92 } else {
93 if (include & VideoInclude.BLACKLISTED) {
94 this.setBlacklisted(row, videoModel)
95 }
96
97 if (include & VideoInclude.BLOCKED_OWNER) {
98 this.setBlockedOwner(row, videoModel)
99 this.setBlockedServer(row, videoModel)
100 }
d9bf974f
C
101 }
102 }
103
17bb4538
C
104 this.grabSeparateWebTorrentFiles(rowsWebTorrentFiles)
105 this.grabSeparateStreamingPlaylistFiles(rowsStreamingPlaylist)
1d43c3a6 106
d9bf974f
C
107 return this.videos
108 }
109
110 private reinit () {
111 this.videosMemo = {}
112 this.videoStreamingPlaylistMemo = {}
113 this.videoFileMemo = {}
114
2760b454
C
115 this.thumbnailsDone = new Set()
116 this.historyDone = new Set()
117 this.blacklistDone = new Set()
118 this.liveDone = new Set()
119 this.redundancyDone = new Set()
120 this.scheduleVideoUpdateDone = new Set()
121
122 this.accountBlocklistDone = new Set()
123 this.serverBlocklistDone = new Set()
d9bf974f 124
2760b454
C
125 this.trackersDone = new Set()
126 this.tagsDone = new Set()
d9bf974f
C
127
128 this.videos = []
129 }
130
17bb4538
C
131 private grabSeparateWebTorrentFiles (rowsWebTorrentFiles?: SQLRow[]) {
132 if (!rowsWebTorrentFiles) return
133
134 for (const row of rowsWebTorrentFiles) {
668f864f
C
135 const id = row['VideoFiles.id']
136 if (!id) continue
137
17bb4538
C
138 const videoModel = this.videosMemo[row.id]
139 this.addWebTorrentFile(row, videoModel)
31d5d916 140 this.addRedundancy(row, 'VideoFiles', this.videoFileMemo[id])
17bb4538
C
141 }
142 }
143
144 private grabSeparateStreamingPlaylistFiles (rowsStreamingPlaylist?: SQLRow[]) {
145 if (!rowsStreamingPlaylist) return
146
1db57e6f 147 for (const row of rowsStreamingPlaylist) {
668f864f
C
148 const id = row['VideoStreamingPlaylists.id']
149 if (!id) continue
150
17bb4538
C
151 const videoModel = this.videosMemo[row.id]
152
153 this.addStreamingPlaylist(row, videoModel)
154 this.addStreamingPlaylistFile(row)
31d5d916 155 this.addRedundancy(row, 'VideoStreamingPlaylists', this.videoStreamingPlaylistMemo[id])
17bb4538
C
156 }
157 }
158
71d4af1e 159 private buildVideoAndAccount (row: SQLRow) {
d9bf974f
C
160 if (this.videosMemo[row.id]) return
161
17bb4538 162 const videoModel = new VideoModel(this.grab(row, this.tables.getVideoAttributes(), ''), this.buildOpts)
d9bf974f
C
163
164 videoModel.UserVideoHistories = []
165 videoModel.Thumbnails = []
166 videoModel.VideoFiles = []
167 videoModel.VideoStreamingPlaylists = []
168 videoModel.Tags = []
169 videoModel.Trackers = []
170
71d4af1e
C
171 this.buildAccount(row, videoModel)
172
173 this.videosMemo[row.id] = videoModel
174
d9bf974f
C
175 // Keep rows order
176 this.videos.push(videoModel)
177 }
178
71d4af1e
C
179 private buildAccount (row: SQLRow, videoModel: VideoModel) {
180 const id = row['VideoChannel.Account.id']
181 if (!id) return
182
183 const channelModel = new VideoChannelModel(this.grab(row, this.tables.getChannelAttributes(), 'VideoChannel'), this.buildOpts)
184 channelModel.Actor = this.buildActor(row, 'VideoChannel')
185
186 const accountModel = new AccountModel(this.grab(row, this.tables.getAccountAttributes(), 'VideoChannel.Account'), this.buildOpts)
187 accountModel.Actor = this.buildActor(row, 'VideoChannel.Account')
188
2760b454
C
189 accountModel.BlockedBy = []
190
71d4af1e
C
191 channelModel.Account = accountModel
192
193 videoModel.VideoChannel = channelModel
194 }
195
17bb4538
C
196 private buildActor (row: SQLRow, prefix: string) {
197 const actorPrefix = `${prefix}.Actor`
198 const avatarPrefix = `${actorPrefix}.Avatar`
199 const serverPrefix = `${actorPrefix}.Server`
200
201 const avatarModel = row[`${avatarPrefix}.id`] !== null
202 ? new ActorImageModel(this.grab(row, this.tables.getAvatarAttributes(), avatarPrefix), this.buildOpts)
d9bf974f
C
203 : null
204
17bb4538
C
205 const serverModel = row[`${serverPrefix}.id`] !== null
206 ? new ServerModel(this.grab(row, this.tables.getServerAttributes(), serverPrefix), this.buildOpts)
d9bf974f
C
207 : null
208
2760b454
C
209 if (serverModel) serverModel.BlockedBy = []
210
17bb4538 211 const actorModel = new ActorModel(this.grab(row, this.tables.getActorAttributes(), actorPrefix), this.buildOpts)
d9bf974f
C
212 actorModel.Avatar = avatarModel
213 actorModel.Server = serverModel
214
215 return actorModel
216 }
217
17bb4538
C
218 private setUserHistory (row: SQLRow, videoModel: VideoModel) {
219 const id = row['userVideoHistory.id']
220 if (!id || this.historyDone.has(id)) return
d9bf974f 221
17bb4538 222 const attributes = this.grab(row, this.tables.getUserHistoryAttributes(), 'userVideoHistory')
d9bf974f
C
223 const historyModel = new UserVideoHistoryModel(attributes, this.buildOpts)
224 videoModel.UserVideoHistories.push(historyModel)
225
17bb4538 226 this.historyDone.add(id)
d9bf974f
C
227 }
228
17bb4538
C
229 private addThumbnail (row: SQLRow, videoModel: VideoModel) {
230 const id = row['Thumbnails.id']
231 if (!id || this.thumbnailsDone.has(id)) return
d9bf974f 232
17bb4538 233 const attributes = this.grab(row, this.tables.getThumbnailAttributes(), 'Thumbnails')
d9bf974f
C
234 const thumbnailModel = new ThumbnailModel(attributes, this.buildOpts)
235 videoModel.Thumbnails.push(thumbnailModel)
236
17bb4538 237 this.thumbnailsDone.add(id)
d9bf974f
C
238 }
239
17bb4538
C
240 private addWebTorrentFile (row: SQLRow, videoModel: VideoModel) {
241 const id = row['VideoFiles.id']
242 if (!id || this.videoFileMemo[id]) return
d9bf974f 243
17bb4538 244 const attributes = this.grab(row, this.tables.getFileAttributes(), 'VideoFiles')
d9bf974f
C
245 const videoFileModel = new VideoFileModel(attributes, this.buildOpts)
246 videoModel.VideoFiles.push(videoFileModel)
247
17bb4538 248 this.videoFileMemo[id] = videoFileModel
d9bf974f
C
249 }
250
17bb4538
C
251 private addStreamingPlaylist (row: SQLRow, videoModel: VideoModel) {
252 const id = row['VideoStreamingPlaylists.id']
253 if (!id || this.videoStreamingPlaylistMemo[id]) return
d9bf974f 254
17bb4538 255 const attributes = this.grab(row, this.tables.getStreamingPlaylistAttributes(), 'VideoStreamingPlaylists')
d9bf974f
C
256 const streamingPlaylist = new VideoStreamingPlaylistModel(attributes, this.buildOpts)
257 streamingPlaylist.VideoFiles = []
258
259 videoModel.VideoStreamingPlaylists.push(streamingPlaylist)
260
17bb4538 261 this.videoStreamingPlaylistMemo[id] = streamingPlaylist
d9bf974f
C
262 }
263
17bb4538
C
264 private addStreamingPlaylistFile (row: SQLRow) {
265 const id = row['VideoStreamingPlaylists.VideoFiles.id']
266 if (!id || this.videoFileMemo[id]) return
d9bf974f 267
17bb4538 268 const streamingPlaylist = this.videoStreamingPlaylistMemo[row['VideoStreamingPlaylists.id']]
d9bf974f 269
17bb4538 270 const attributes = this.grab(row, this.tables.getFileAttributes(), 'VideoStreamingPlaylists.VideoFiles')
d9bf974f
C
271 const videoFileModel = new VideoFileModel(attributes, this.buildOpts)
272 streamingPlaylist.VideoFiles.push(videoFileModel)
273
17bb4538 274 this.videoFileMemo[id] = videoFileModel
d9bf974f
C
275 }
276
17bb4538 277 private addRedundancy (row: SQLRow, prefix: string, to: VideoFileModel | VideoStreamingPlaylistModel) {
d9bf974f
C
278 if (!to.RedundancyVideos) to.RedundancyVideos = []
279
17bb4538
C
280 const redundancyPrefix = `${prefix}.RedundancyVideos`
281 const id = row[`${redundancyPrefix}.id`]
282
283 if (!id || this.redundancyDone.has(id)) return
d9bf974f 284
17bb4538 285 const attributes = this.grab(row, this.tables.getRedundancyAttributes(), redundancyPrefix)
d9bf974f
C
286 const redundancyModel = new VideoRedundancyModel(attributes, this.buildOpts)
287 to.RedundancyVideos.push(redundancyModel)
288
17bb4538 289 this.redundancyDone.add(id)
d9bf974f
C
290 }
291
17bb4538
C
292 private addTag (row: SQLRow, videoModel: VideoModel) {
293 if (!row['Tags.name']) return
d9bf974f 294
17bb4538 295 const key = `${row['Tags.VideoTagModel.videoId']}-${row['Tags.VideoTagModel.tagId']}`
d9bf974f
C
296 if (this.tagsDone.has(key)) return
297
17bb4538 298 const attributes = this.grab(row, this.tables.getTagAttributes(), 'Tags')
d9bf974f
C
299 const tagModel = new TagModel(attributes, this.buildOpts)
300 videoModel.Tags.push(tagModel)
301
302 this.tagsDone.add(key)
303 }
304
17bb4538
C
305 private addTracker (row: SQLRow, videoModel: VideoModel) {
306 if (!row['Trackers.id']) return
d9bf974f 307
17bb4538 308 const key = `${row['Trackers.VideoTrackerModel.videoId']}-${row['Trackers.VideoTrackerModel.trackerId']}`
d9bf974f
C
309 if (this.trackersDone.has(key)) return
310
17bb4538 311 const attributes = this.grab(row, this.tables.getTrackerAttributes(), 'Trackers')
d9bf974f
C
312 const trackerModel = new TrackerModel(attributes, this.buildOpts)
313 videoModel.Trackers.push(trackerModel)
314
315 this.trackersDone.add(key)
316 }
317
17bb4538
C
318 private setBlacklisted (row: SQLRow, videoModel: VideoModel) {
319 const id = row['VideoBlacklist.id']
320 if (!id || this.blacklistDone.has(id)) return
d9bf974f 321
17bb4538 322 const attributes = this.grab(row, this.tables.getBlacklistedAttributes(), 'VideoBlacklist')
d9bf974f
C
323 videoModel.VideoBlacklist = new VideoBlacklistModel(attributes, this.buildOpts)
324
17bb4538 325 this.blacklistDone.add(id)
d9bf974f
C
326 }
327
2760b454
C
328 private setBlockedOwner (row: SQLRow, videoModel: VideoModel) {
329 const id = row['VideoChannel.Account.AccountBlocklist.id']
330 if (!id) return
331
332 const key = `${videoModel.id}-${id}`
333 if (this.accountBlocklistDone.has(key)) return
334
335 const attributes = this.grab(row, this.tables.getBlocklistAttributes(), 'VideoChannel.Account.AccountBlocklist')
336 videoModel.VideoChannel.Account.BlockedBy.push(new AccountBlocklistModel(attributes, this.buildOpts))
337
338 this.accountBlocklistDone.add(key)
339 }
340
341 private setBlockedServer (row: SQLRow, videoModel: VideoModel) {
342 const id = row['VideoChannel.Account.Actor.Server.ServerBlocklist.id']
343 if (!id || this.serverBlocklistDone.has(id)) return
344
345 const key = `${videoModel.id}-${id}`
346 if (this.serverBlocklistDone.has(key)) return
347
348 const attributes = this.grab(row, this.tables.getBlocklistAttributes(), 'VideoChannel.Account.Actor.Server.ServerBlocklist')
349 videoModel.VideoChannel.Account.Actor.Server.BlockedBy.push(new ServerBlocklistModel(attributes, this.buildOpts))
350
351 this.serverBlocklistDone.add(key)
352 }
353
17bb4538
C
354 private setScheduleVideoUpdate (row: SQLRow, videoModel: VideoModel) {
355 const id = row['ScheduleVideoUpdate.id']
356 if (!id || this.scheduleVideoUpdateDone.has(id)) return
d9bf974f 357
17bb4538 358 const attributes = this.grab(row, this.tables.getScheduleUpdateAttributes(), 'ScheduleVideoUpdate')
d9bf974f
C
359 videoModel.ScheduleVideoUpdate = new ScheduleVideoUpdateModel(attributes, this.buildOpts)
360
17bb4538 361 this.scheduleVideoUpdateDone.add(id)
d9bf974f
C
362 }
363
17bb4538
C
364 private setLive (row: SQLRow, videoModel: VideoModel) {
365 const id = row['VideoLive.id']
366 if (!id || this.liveDone.has(id)) return
d9bf974f 367
17bb4538 368 const attributes = this.grab(row, this.tables.getLiveAttributes(), 'VideoLive')
d9bf974f
C
369 videoModel.VideoLive = new VideoLiveModel(attributes, this.buildOpts)
370
17bb4538
C
371 this.liveDone.add(id)
372 }
373
374 private grab (row: SQLRow, attributes: string[], prefix: string) {
375 const result: { [ id: string ]: string | number } = {}
376
377 for (const a of attributes) {
378 const key = prefix
379 ? prefix + '.' + a
380 : a
381
382 result[a] = row[key]
383 }
384
385 return result
d9bf974f
C
386 }
387}