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