aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/video/sql/shared
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2021-06-10 14:43:55 +0200
committerChocobozzz <me@florianbigard.com>2021-06-10 15:26:18 +0200
commitd9bf974f5df787bbeaab5b04949ca91a2b3ca2a3 (patch)
treeaa02ee0cc28c845432e91da43b1e6de2a2f04039 /server/models/video/sql/shared
parente5dbd5084e7ae91ce118c0bccd5b84c47b88c55f (diff)
downloadPeerTube-d9bf974f5df787bbeaab5b04949ca91a2b3ca2a3.tar.gz
PeerTube-d9bf974f5df787bbeaab5b04949ca91a2b3ca2a3.tar.zst
PeerTube-d9bf974f5df787bbeaab5b04949ca91a2b3ca2a3.zip
Use raw SQL for video get request
Diffstat (limited to 'server/models/video/sql/shared')
-rw-r--r--server/models/video/sql/shared/abstract-videos-model-query-builder.ts239
-rw-r--r--server/models/video/sql/shared/abstract-videos-query-builder.ts22
-rw-r--r--server/models/video/sql/shared/video-attributes.ts247
-rw-r--r--server/models/video/sql/shared/video-model-builder.ts268
4 files changed, 776 insertions, 0 deletions
diff --git a/server/models/video/sql/shared/abstract-videos-model-query-builder.ts b/server/models/video/sql/shared/abstract-videos-model-query-builder.ts
new file mode 100644
index 000000000..bdf926cbe
--- /dev/null
+++ b/server/models/video/sql/shared/abstract-videos-model-query-builder.ts
@@ -0,0 +1,239 @@
1import { AbstractVideosQueryBuilder } from './abstract-videos-query-builder'
2import { VideoAttributes } from './video-attributes'
3import { VideoModelBuilder } from './video-model-builder'
4
5export class AbstractVideosModelQueryBuilder extends AbstractVideosQueryBuilder {
6 protected attributes: { [key: string]: string } = {}
7 protected joins: string[] = []
8
9 protected videoAttributes: VideoAttributes
10 protected videoModelBuilder: VideoModelBuilder
11
12 constructor (private readonly mode: 'list' | 'get') {
13 super()
14
15 this.videoAttributes = new VideoAttributes(this.mode)
16 this.videoModelBuilder = new VideoModelBuilder(this.mode, this.videoAttributes)
17 }
18
19 protected buildSelect () {
20 return 'SELECT ' + Object.keys(this.attributes).map(key => {
21 const value = this.attributes[key]
22 if (value) return `${key} AS ${value}`
23
24 return key
25 }).join(', ')
26 }
27
28 protected includeChannels () {
29 this.joins.push(
30 'INNER JOIN "videoChannel" AS "VideoChannel" ON "video"."channelId" = "VideoChannel"."id"',
31 'INNER JOIN "actor" AS "VideoChannel->Actor" ON "VideoChannel"."actorId" = "VideoChannel->Actor"."id"',
32
33 'LEFT OUTER JOIN "server" AS "VideoChannel->Actor->Server" ON "VideoChannel->Actor"."serverId" = "VideoChannel->Actor->Server"."id"',
34
35 'LEFT OUTER JOIN "actorImage" AS "VideoChannel->Actor->Avatar" ' +
36 'ON "VideoChannel->Actor"."avatarId" = "VideoChannel->Actor->Avatar"."id"'
37 )
38
39 this.attributes = {
40 ...this.attributes,
41
42 ...this.buildAttributesObject('VideoChannel', this.videoAttributes.getChannelAttributes()),
43 ...this.buildActorInclude('VideoChannel->Actor'),
44 ...this.buildAvatarInclude('VideoChannel->Actor->Avatar'),
45 ...this.buildServerInclude('VideoChannel->Actor->Server')
46 }
47 }
48
49 protected includeAccounts () {
50 this.joins.push(
51 'INNER JOIN "account" AS "VideoChannel->Account" ON "VideoChannel"."accountId" = "VideoChannel->Account"."id"',
52 'INNER JOIN "actor" AS "VideoChannel->Account->Actor" ON "VideoChannel->Account"."actorId" = "VideoChannel->Account->Actor"."id"',
53
54 'LEFT OUTER JOIN "server" AS "VideoChannel->Account->Actor->Server" ' +
55 'ON "VideoChannel->Account->Actor"."serverId" = "VideoChannel->Account->Actor->Server"."id"',
56
57 'LEFT OUTER JOIN "actorImage" AS "VideoChannel->Account->Actor->Avatar" ' +
58 'ON "VideoChannel->Account->Actor"."avatarId" = "VideoChannel->Account->Actor->Avatar"."id"'
59 )
60
61 this.attributes = {
62 ...this.attributes,
63
64 ...this.buildAttributesObject('VideoChannel->Account', this.videoAttributes.getAccountAttributes()),
65 ...this.buildActorInclude('VideoChannel->Account->Actor'),
66 ...this.buildAvatarInclude('VideoChannel->Account->Actor->Avatar'),
67 ...this.buildServerInclude('VideoChannel->Account->Actor->Server')
68 }
69 }
70
71 protected includeThumbnails () {
72 this.joins.push('LEFT OUTER JOIN "thumbnail" AS "Thumbnails" ON "video"."id" = "Thumbnails"."videoId"')
73
74 this.attributes = {
75 ...this.attributes,
76
77 ...this.buildAttributesObject('Thumbnails', this.videoAttributes.getThumbnailAttributes())
78 }
79 }
80
81 protected includeFiles () {
82 this.joins.push(
83 'LEFT JOIN "videoFile" AS "VideoFiles" ON "VideoFiles"."videoId" = "video"."id"',
84
85 'LEFT JOIN "videoStreamingPlaylist" AS "VideoStreamingPlaylists" ON "VideoStreamingPlaylists"."videoId" = "video"."id"',
86
87 'LEFT JOIN "videoFile" AS "VideoStreamingPlaylists->VideoFiles" ' +
88 'ON "VideoStreamingPlaylists->VideoFiles"."videoStreamingPlaylistId" = "VideoStreamingPlaylists"."id"'
89 )
90
91 this.attributes = {
92 ...this.attributes,
93
94 ...this.buildAttributesObject('VideoFiles', this.videoAttributes.getFileAttributes()),
95
96 ...this.buildAttributesObject('VideoStreamingPlaylists', this.videoAttributes.getStreamingPlaylistAttributes()),
97 ...this.buildAttributesObject('VideoStreamingPlaylists->VideoFiles', this.videoAttributes.getFileAttributes())
98 }
99 }
100
101 protected includeUserHistory (userId: number) {
102 this.joins.push(
103 'LEFT OUTER JOIN "userVideoHistory" ' +
104 'ON "video"."id" = "userVideoHistory"."videoId" AND "userVideoHistory"."userId" = :userVideoHistoryId'
105 )
106
107 this.replacements.userVideoHistoryId = userId
108
109 this.attributes = {
110 ...this.attributes,
111
112 ...this.buildAttributesObject('userVideoHistory', this.videoAttributes.getUserHistoryAttributes())
113 }
114 }
115
116 protected includePlaylist (playlistId: number) {
117 this.joins.push(
118 'INNER JOIN "videoPlaylistElement" as "VideoPlaylistElement" ON "videoPlaylistElement"."videoId" = "video"."id" ' +
119 'AND "VideoPlaylistElement"."videoPlaylistId" = :videoPlaylistId'
120 )
121
122 this.replacements.videoPlaylistId = playlistId
123
124 this.attributes = {
125 ...this.attributes,
126
127 ...this.buildAttributesObject('VideoPlaylistElement', this.videoAttributes.getPlaylistAttributes())
128 }
129 }
130
131 protected includeTags () {
132 this.joins.push(
133 'LEFT OUTER JOIN (' +
134 '"videoTag" AS "Tags->VideoTagModel" INNER JOIN "tag" AS "Tags" ON "Tags"."id" = "Tags->VideoTagModel"."tagId"' +
135 ') ' +
136 'ON "video"."id" = "Tags->VideoTagModel"."videoId"'
137 )
138
139 this.attributes = {
140 ...this.attributes,
141
142 ...this.buildAttributesObject('Tags', this.videoAttributes.getTagAttributes()),
143 ...this.buildAttributesObject('Tags->VideoTagModel', this.videoAttributes.getVideoTagAttributes())
144 }
145 }
146
147 protected includeBlacklisted () {
148 this.joins.push(
149 'LEFT OUTER JOIN "videoBlacklist" AS "VideoBlacklist" ON "video"."id" = "VideoBlacklist"."videoId"'
150 )
151
152 this.attributes = {
153 ...this.attributes,
154
155 ...this.buildAttributesObject('VideoBlacklist', this.videoAttributes.getBlacklistedAttributes())
156 }
157 }
158
159 protected includeScheduleUpdate () {
160 this.joins.push(
161 'LEFT OUTER JOIN "scheduleVideoUpdate" AS "ScheduleVideoUpdate" ON "video"."id" = "ScheduleVideoUpdate"."videoId"'
162 )
163
164 this.attributes = {
165 ...this.attributes,
166
167 ...this.buildAttributesObject('ScheduleVideoUpdate', this.videoAttributes.getScheduleUpdateAttributes())
168 }
169 }
170
171 protected includeLive () {
172 this.joins.push(
173 'LEFT OUTER JOIN "videoLive" AS "VideoLive" ON "video"."id" = "VideoLive"."videoId"'
174 )
175
176 this.attributes = {
177 ...this.attributes,
178
179 ...this.buildAttributesObject('VideoLive', this.videoAttributes.getLiveAttributes())
180 }
181 }
182
183 protected includeTrackers () {
184 this.joins.push(
185 'LEFT OUTER JOIN (' +
186 '"videoTracker" AS "Trackers->VideoTrackerModel" ' +
187 'INNER JOIN "tracker" AS "Trackers" ON "Trackers"."id" = "Trackers->VideoTrackerModel"."trackerId"' +
188 ') ON "video"."id" = "Trackers->VideoTrackerModel"."videoId"'
189 )
190
191 this.attributes = {
192 ...this.attributes,
193
194 ...this.buildAttributesObject('Trackers', this.videoAttributes.getTrackerAttributes()),
195 ...this.buildAttributesObject('Trackers->VideoTrackerModel', this.videoAttributes.getVideoTrackerAttributes())
196 }
197 }
198
199 protected includeRedundancies () {
200 this.joins.push(
201 'LEFT OUTER JOIN "videoRedundancy" AS "VideoStreamingPlaylists->RedundancyVideos" ' +
202 'ON "VideoStreamingPlaylists"."id" = "VideoStreamingPlaylists->RedundancyVideos"."videoStreamingPlaylistId"',
203
204 'LEFT OUTER JOIN "videoRedundancy" AS "VideoFiles->RedundancyVideos" ON ' +
205 '"VideoFiles"."id" = "VideoFiles->RedundancyVideos"."videoFileId"'
206 )
207
208 this.attributes = {
209 ...this.attributes,
210
211 ...this.buildAttributesObject('VideoFiles->RedundancyVideos', this.videoAttributes.getRedundancyAttributes()),
212 ...this.buildAttributesObject('VideoStreamingPlaylists->RedundancyVideos', this.videoAttributes.getRedundancyAttributes())
213 }
214 }
215
216 protected buildActorInclude (prefixKey: string) {
217 return this.buildAttributesObject(prefixKey, this.videoAttributes.getActorAttributes())
218 }
219
220 protected buildAvatarInclude (prefixKey: string) {
221 return this.buildAttributesObject(prefixKey, this.videoAttributes.getAvatarAttributes())
222 }
223
224 protected buildServerInclude (prefixKey: string) {
225 return this.buildAttributesObject(prefixKey, this.videoAttributes.getServerAttributes())
226 }
227
228 protected buildAttributesObject (prefixKey: string, attributeKeys: string[]) {
229 const result: { [id: string]: string} = {}
230
231 const prefixValue = prefixKey.replace(/->/g, '.')
232
233 for (const attribute of attributeKeys) {
234 result[`"${prefixKey}"."${attribute}"`] = `"${prefixValue}.${attribute}"`
235 }
236
237 return result
238 }
239}
diff --git a/server/models/video/sql/shared/abstract-videos-query-builder.ts b/server/models/video/sql/shared/abstract-videos-query-builder.ts
new file mode 100644
index 000000000..01694e691
--- /dev/null
+++ b/server/models/video/sql/shared/abstract-videos-query-builder.ts
@@ -0,0 +1,22 @@
1import { QueryTypes, Sequelize, Transaction } from 'sequelize'
2import { logger } from '@server/helpers/logger'
3
4export class AbstractVideosQueryBuilder {
5 protected sequelize: Sequelize
6
7 protected query: string
8 protected replacements: any = {}
9
10 protected runQuery (transaction?: Transaction, nest?: boolean) {
11 logger.debug('Running videos query.', { query: this.query, replacements: this.replacements })
12
13 const options = {
14 transaction,
15 replacements: this.replacements,
16 type: QueryTypes.SELECT as QueryTypes.SELECT,
17 nest
18 }
19
20 return this.sequelize.query<any>(this.query, options)
21 }
22}
diff --git a/server/models/video/sql/shared/video-attributes.ts b/server/models/video/sql/shared/video-attributes.ts
new file mode 100644
index 000000000..1a1650dc7
--- /dev/null
+++ b/server/models/video/sql/shared/video-attributes.ts
@@ -0,0 +1,247 @@
1export class VideoAttributes {
2
3 constructor (readonly mode: 'get' | 'list') {
4
5 }
6
7 getChannelAttributes () {
8 let attributeKeys = [
9 'id',
10 'name',
11 'description',
12 'actorId'
13 ]
14
15 if (this.mode === 'get') {
16 attributeKeys = attributeKeys.concat([
17 'support',
18 'createdAt',
19 'updatedAt'
20 ])
21 }
22
23 return attributeKeys
24 }
25
26 getAccountAttributes () {
27 let attributeKeys = [ 'id', 'name', 'actorId' ]
28
29 if (this.mode === 'get') {
30 attributeKeys = attributeKeys.concat([
31 'description',
32 'createdAt',
33 'updatedAt'
34 ])
35 }
36
37 return attributeKeys
38 }
39
40 getThumbnailAttributes () {
41 let attributeKeys = [ 'id', 'type', 'filename' ]
42
43 if (this.mode === 'get') {
44 attributeKeys = attributeKeys.concat([
45 'height',
46 'width',
47 'fileUrl',
48 'automaticallyGenerated',
49 'videoId',
50 'videoPlaylistId',
51 'createdAt',
52 'updatedAt'
53 ])
54 }
55
56 return attributeKeys
57 }
58
59 getFileAttributes () {
60 return [
61 'id',
62 'createdAt',
63 'updatedAt',
64 'resolution',
65 'size',
66 'extname',
67 'filename',
68 'fileUrl',
69 'torrentFilename',
70 'torrentUrl',
71 'infoHash',
72 'fps',
73 'metadataUrl',
74 'videoStreamingPlaylistId',
75 'videoId'
76 ]
77 }
78
79 getStreamingPlaylistAttributes () {
80 let playlistKeys = [ 'id', 'playlistUrl', 'type' ]
81
82 if (this.mode === 'get') {
83 playlistKeys = playlistKeys.concat([
84 'p2pMediaLoaderInfohashes',
85 'p2pMediaLoaderPeerVersion',
86 'segmentsSha256Url',
87 'videoId',
88 'createdAt',
89 'updatedAt'
90 ])
91 }
92
93 return playlistKeys
94 }
95
96 getUserHistoryAttributes () {
97 return [ 'id', 'currentTime' ]
98 }
99
100 getPlaylistAttributes () {
101 return [
102 'createdAt',
103 'updatedAt',
104 'url',
105 'position',
106 'startTimestamp',
107 'stopTimestamp',
108 'videoPlaylistId'
109 ]
110 }
111
112 getTagAttributes () {
113 return [ 'id', 'name' ]
114 }
115
116 getVideoTagAttributes () {
117 return [ 'videoId', 'tagId', 'createdAt', 'updatedAt' ]
118 }
119
120 getBlacklistedAttributes () {
121 return [ 'id', 'reason', 'unfederated' ]
122 }
123
124 getScheduleUpdateAttributes () {
125 return [
126 'id',
127 'updateAt',
128 'privacy',
129 'videoId',
130 'createdAt',
131 'updatedAt'
132 ]
133 }
134
135 getLiveAttributes () {
136 return [
137 'id',
138 'streamKey',
139 'saveReplay',
140 'permanentLive',
141 'videoId',
142 'createdAt',
143 'updatedAt'
144 ]
145 }
146
147 getTrackerAttributes () {
148 return [ 'id', 'url' ]
149 }
150
151 getVideoTrackerAttributes () {
152 return [
153 'videoId',
154 'trackerId',
155 'createdAt',
156 'updatedAt'
157 ]
158 }
159
160 getRedundancyAttributes () {
161 return [ 'id', 'fileUrl' ]
162 }
163
164 getActorAttributes () {
165 let attributeKeys = [
166 'id',
167 'preferredUsername',
168 'url',
169 'serverId',
170 'avatarId'
171 ]
172
173 if (this.mode === 'get') {
174 attributeKeys = attributeKeys.concat([
175 'type',
176 'followersCount',
177 'followingCount',
178 'inboxUrl',
179 'outboxUrl',
180 'sharedInboxUrl',
181 'followersUrl',
182 'followingUrl',
183 'remoteCreatedAt',
184 'createdAt',
185 'updatedAt'
186 ])
187 }
188
189 return attributeKeys
190 }
191
192 getAvatarAttributes () {
193 let attributeKeys = [
194 'id',
195 'filename',
196 'fileUrl',
197 'onDisk',
198 'createdAt',
199 'updatedAt'
200 ]
201
202 if (this.mode === 'get') {
203 attributeKeys = attributeKeys.concat([
204 'height',
205 'width',
206 'type'
207 ])
208 }
209
210 return attributeKeys
211 }
212
213 getServerAttributes () {
214 return [ 'id', 'host' ]
215 }
216
217 getVideoAttributes () {
218 return [
219 'id',
220 'uuid',
221 'name',
222 'category',
223 'licence',
224 'language',
225 'privacy',
226 'nsfw',
227 'description',
228 'support',
229 'duration',
230 'views',
231 'likes',
232 'dislikes',
233 'remote',
234 'isLive',
235 'url',
236 'commentsEnabled',
237 'downloadEnabled',
238 'waitTranscoding',
239 'state',
240 'publishedAt',
241 'originallyPublishedAt',
242 'channelId',
243 'createdAt',
244 'updatedAt'
245 ]
246 }
247}
diff --git a/server/models/video/sql/shared/video-model-builder.ts b/server/models/video/sql/shared/video-model-builder.ts
new file mode 100644
index 000000000..9719f6d2e
--- /dev/null
+++ b/server/models/video/sql/shared/video-model-builder.ts
@@ -0,0 +1,268 @@
1import { pick } from 'lodash'
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'
18import { VideoAttributes } from './video-attributes'
19
20export class VideoModelBuilder {
21 private videosMemo: { [ id: number ]: VideoModel }
22 private videoStreamingPlaylistMemo: { [ id: number ]: VideoStreamingPlaylistModel }
23 private videoFileMemo: { [ id: number ]: VideoFileModel }
24
25 private thumbnailsDone: Set<number>
26 private historyDone: Set<number>
27 private blacklistDone: Set<number>
28 private liveDone: Set<number>
29 private redundancyDone: Set<number>
30 private scheduleVideoUpdateDone: Set<number>
31
32 private trackersDone: Set<string>
33 private tagsDone: Set<string>
34
35 private videos: VideoModel[]
36
37 private readonly buildOpts = { raw: true, isNewRecord: false }
38
39 constructor (
40 readonly mode: 'get' | 'list',
41 readonly videoAttributes: VideoAttributes
42 ) {
43
44 }
45
46 buildVideosFromRows (rows: any[]) {
47 this.reinit()
48
49 for (const row of rows) {
50 this.buildVideo(row)
51
52 const videoModel = this.videosMemo[row.id]
53
54 this.setUserHistory(row, videoModel)
55 this.addThumbnail(row, videoModel)
56 this.addWebTorrentFile(row, videoModel)
57
58 this.addStreamingPlaylist(row, videoModel)
59 this.addStreamingPlaylistFile(row)
60
61 if (this.mode === 'get') {
62 this.addTag(row, videoModel)
63 this.addTracker(row, videoModel)
64 this.setBlacklisted(row, videoModel)
65 this.setScheduleVideoUpdate(row, videoModel)
66 this.setLive(row, videoModel)
67
68 if (row.VideoFiles.id) {
69 this.addRedundancy(row.VideoFiles.RedundancyVideos, this.videoFileMemo[row.VideoFiles.id])
70 }
71
72 if (row.VideoStreamingPlaylists.id) {
73 this.addRedundancy(row.VideoStreamingPlaylists.RedundancyVideos, this.videoStreamingPlaylistMemo[row.VideoStreamingPlaylists.id])
74 }
75 }
76 }
77
78 return this.videos
79 }
80
81 private reinit () {
82 this.videosMemo = {}
83 this.videoStreamingPlaylistMemo = {}
84 this.videoFileMemo = {}
85
86 this.thumbnailsDone = new Set<number>()
87 this.historyDone = new Set<number>()
88 this.blacklistDone = new Set<number>()
89 this.liveDone = new Set<number>()
90 this.redundancyDone = new Set<number>()
91 this.scheduleVideoUpdateDone = new Set<number>()
92
93 this.trackersDone = new Set<string>()
94 this.tagsDone = new Set<string>()
95
96 this.videos = []
97 }
98
99 private buildVideo (row: any) {
100 if (this.videosMemo[row.id]) return
101
102 // Build Channel
103 const channel = row.VideoChannel
104 const channelModel = new VideoChannelModel(pick(channel, this.videoAttributes.getChannelAttributes()), this.buildOpts)
105 channelModel.Actor = this.buildActor(channel.Actor)
106
107 const account = row.VideoChannel.Account
108 const accountModel = new AccountModel(pick(account, this.videoAttributes.getAccountAttributes()), this.buildOpts)
109 accountModel.Actor = this.buildActor(account.Actor)
110
111 channelModel.Account = accountModel
112
113 const videoModel = new VideoModel(pick(row, this.videoAttributes.getVideoAttributes()), this.buildOpts)
114 videoModel.VideoChannel = channelModel
115
116 this.videosMemo[row.id] = videoModel
117
118 videoModel.UserVideoHistories = []
119 videoModel.Thumbnails = []
120 videoModel.VideoFiles = []
121 videoModel.VideoStreamingPlaylists = []
122 videoModel.Tags = []
123 videoModel.Trackers = []
124
125 // Keep rows order
126 this.videos.push(videoModel)
127 }
128
129 private buildActor (rowActor: any) {
130 const avatarModel = rowActor.Avatar.id !== null
131 ? new ActorImageModel(pick(rowActor.Avatar, this.videoAttributes.getAvatarAttributes()), this.buildOpts)
132 : null
133
134 const serverModel = rowActor.Server.id !== null
135 ? new ServerModel(pick(rowActor.Server, this.videoAttributes.getServerAttributes()), this.buildOpts)
136 : null
137
138 const actorModel = new ActorModel(pick(rowActor, this.videoAttributes.getActorAttributes()), this.buildOpts)
139 actorModel.Avatar = avatarModel
140 actorModel.Server = serverModel
141
142 return actorModel
143 }
144
145 private setUserHistory (row: any, videoModel: VideoModel) {
146 if (!row.userVideoHistory?.id || this.historyDone.has(row.userVideoHistory.id)) return
147
148 const attributes = pick(row.userVideoHistory, this.videoAttributes.getUserHistoryAttributes())
149 const historyModel = new UserVideoHistoryModel(attributes, this.buildOpts)
150 videoModel.UserVideoHistories.push(historyModel)
151
152 this.historyDone.add(row.userVideoHistory.id)
153 }
154
155 private addThumbnail (row: any, videoModel: VideoModel) {
156 if (!row.Thumbnails?.id || this.thumbnailsDone.has(row.Thumbnails.id)) return
157
158 const attributes = pick(row.Thumbnails, this.videoAttributes.getThumbnailAttributes())
159 const thumbnailModel = new ThumbnailModel(attributes, this.buildOpts)
160 videoModel.Thumbnails.push(thumbnailModel)
161
162 this.thumbnailsDone.add(row.Thumbnails.id)
163 }
164
165 private addWebTorrentFile (row: any, videoModel: VideoModel) {
166 if (!row.VideoFiles?.id || this.videoFileMemo[row.VideoFiles.id]) return
167
168 const attributes = pick(row.VideoFiles, this.videoAttributes.getFileAttributes())
169 const videoFileModel = new VideoFileModel(attributes, this.buildOpts)
170 videoModel.VideoFiles.push(videoFileModel)
171
172 this.videoFileMemo[row.VideoFiles.id] = videoFileModel
173 }
174
175 private addStreamingPlaylist (row: any, videoModel: VideoModel) {
176 if (!row.VideoStreamingPlaylists?.id || this.videoStreamingPlaylistMemo[row.VideoStreamingPlaylists.id]) return
177
178 const attributes = pick(row.VideoStreamingPlaylists, this.videoAttributes.getStreamingPlaylistAttributes())
179 const streamingPlaylist = new VideoStreamingPlaylistModel(attributes, this.buildOpts)
180 streamingPlaylist.VideoFiles = []
181
182 videoModel.VideoStreamingPlaylists.push(streamingPlaylist)
183
184 this.videoStreamingPlaylistMemo[streamingPlaylist.id] = streamingPlaylist
185 }
186
187 private addStreamingPlaylistFile (row: any) {
188 if (!row.VideoStreamingPlaylists?.VideoFiles?.id || this.videoFileMemo[row.VideoStreamingPlaylists.VideoFiles.id]) return
189
190 const streamingPlaylist = this.videoStreamingPlaylistMemo[row.VideoStreamingPlaylists.id]
191
192 const attributes = pick(row.VideoStreamingPlaylists.VideoFiles, this.videoAttributes.getFileAttributes())
193 const videoFileModel = new VideoFileModel(attributes, this.buildOpts)
194 streamingPlaylist.VideoFiles.push(videoFileModel)
195
196 this.videoFileMemo[row.VideoStreamingPlaylists.VideoFiles.id] = videoFileModel
197 }
198
199 private addRedundancy (redundancyRow: any, to: VideoFileModel | VideoStreamingPlaylistModel) {
200 if (!to.RedundancyVideos) to.RedundancyVideos = []
201
202 if (!redundancyRow?.id || this.redundancyDone.has(redundancyRow.id)) return
203
204 const attributes = pick(redundancyRow, this.videoAttributes.getRedundancyAttributes())
205 const redundancyModel = new VideoRedundancyModel(attributes, this.buildOpts)
206 to.RedundancyVideos.push(redundancyModel)
207
208 this.redundancyDone.add(redundancyRow.id)
209 }
210
211 private addTag (row: any, videoModel: VideoModel) {
212 if (!row.Tags?.name) return
213 const association = row.Tags.VideoTagModel
214
215 const key = `${association.videoId}-${association.tagId}`
216 if (this.tagsDone.has(key)) return
217
218 const attributes = pick(row.Tags, this.videoAttributes.getTagAttributes())
219 const tagModel = new TagModel(attributes, this.buildOpts)
220 videoModel.Tags.push(tagModel)
221
222 this.tagsDone.add(key)
223 }
224
225 private addTracker (row: any, videoModel: VideoModel) {
226 if (!row.Trackers?.id) return
227 const association = row.Trackers.VideoTrackerModel
228
229 const key = `${association.videoId}-${association.trackerId}`
230 if (this.trackersDone.has(key)) return
231
232 const attributes = pick(row.Trackers, this.videoAttributes.getTrackerAttributes())
233 const trackerModel = new TrackerModel(attributes, this.buildOpts)
234 videoModel.Trackers.push(trackerModel)
235
236 this.trackersDone.add(key)
237 }
238
239 private setBlacklisted (row: any, videoModel: VideoModel) {
240 if (!row.VideoBlacklist?.id) return
241 if (this.blacklistDone.has(row.VideoBlacklist.id)) return
242
243 const attributes = pick(row.VideoBlacklist, this.videoAttributes.getBlacklistedAttributes())
244 videoModel.VideoBlacklist = new VideoBlacklistModel(attributes, this.buildOpts)
245
246 this.blacklistDone.add(row.VideoBlacklist.id)
247 }
248
249 private setScheduleVideoUpdate (row: any, videoModel: VideoModel) {
250 if (!row.ScheduleVideoUpdate?.id) return
251 if (this.scheduleVideoUpdateDone.has(row.ScheduleVideoUpdate.id)) return
252
253 const attributes = pick(row.ScheduleVideoUpdate, this.videoAttributes.getScheduleUpdateAttributes())
254 videoModel.ScheduleVideoUpdate = new ScheduleVideoUpdateModel(attributes, this.buildOpts)
255
256 this.scheduleVideoUpdateDone.add(row.ScheduleVideoUpdate.id)
257 }
258
259 private setLive (row: any, videoModel: VideoModel) {
260 if (!row.VideoLive?.id) return
261 if (this.liveDone.has(row.VideoLive.id)) return
262
263 const attributes = pick(row.VideoLive, this.videoAttributes.getLiveAttributes())
264 videoModel.VideoLive = new VideoLiveModel(attributes, this.buildOpts)
265
266 this.liveDone.add(row.ScheduleVideoUpdate.id)
267 }
268}