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