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