]>
Commit | Line | Data |
---|---|---|
17bb4538 | 1 | |
d9bf974f | 2 | import { AccountModel } from '@server/models/account/account' |
2760b454 | 3 | import { AccountBlocklistModel } from '@server/models/account/account-blocklist' |
d9bf974f C |
4 | import { ActorModel } from '@server/models/actor/actor' |
5 | import { ActorImageModel } from '@server/models/actor/actor-image' | |
6 | import { VideoRedundancyModel } from '@server/models/redundancy/video-redundancy' | |
7 | import { ServerModel } from '@server/models/server/server' | |
2760b454 | 8 | import { ServerBlocklistModel } from '@server/models/server/server-blocklist' |
d9bf974f C |
9 | import { TrackerModel } from '@server/models/server/tracker' |
10 | import { UserVideoHistoryModel } from '@server/models/user/user-video-history' | |
2760b454 | 11 | import { VideoInclude } from '@shared/models' |
d0800f76 | 12 | import { ScheduleVideoUpdateModel } from '../../../schedule-video-update' |
13 | import { TagModel } from '../../../tag' | |
14 | import { ThumbnailModel } from '../../../thumbnail' | |
15 | import { VideoModel } from '../../../video' | |
16 | import { VideoBlacklistModel } from '../../../video-blacklist' | |
17 | import { VideoChannelModel } from '../../../video-channel' | |
18 | import { VideoFileModel } from '../../../video-file' | |
19 | import { VideoLiveModel } from '../../../video-live' | |
20 | import { VideoStreamingPlaylistModel } from '../../../video-streaming-playlist' | |
7e7d8e48 | 21 | import { VideoTableAttributes } from './video-table-attributes' |
17bb4538 C |
22 | |
23 | type SQLRow = { [id: string]: string | number } | |
d9bf974f | 24 | |
1d43c3a6 C |
25 | /** |
26 | * | |
27 | * Build video models from SQL rows | |
28 | * | |
29 | */ | |
30 | ||
d9bf974f C |
31 | export 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 | } |