1 import { pick } from 'lodash'
2 import { AccountModel } from '@server/models/account/account'
3 import { ActorModel } from '@server/models/actor/actor'
4 import { ActorImageModel } from '@server/models/actor/actor-image'
5 import { VideoRedundancyModel } from '@server/models/redundancy/video-redundancy'
6 import { ServerModel } from '@server/models/server/server'
7 import { TrackerModel } from '@server/models/server/tracker'
8 import { UserVideoHistoryModel } from '@server/models/user/user-video-history'
9 import { ScheduleVideoUpdateModel } from '../../schedule-video-update'
10 import { TagModel } from '../../tag'
11 import { ThumbnailModel } from '../../thumbnail'
12 import { VideoModel } from '../../video'
13 import { VideoBlacklistModel } from '../../video-blacklist'
14 import { VideoChannelModel } from '../../video-channel'
15 import { VideoFileModel } from '../../video-file'
16 import { VideoLiveModel } from '../../video-live'
17 import { VideoStreamingPlaylistModel } from '../../video-streaming-playlist'
18 import { VideoAttributes } from './video-attributes'
20 export class VideoModelBuilder {
21 private videosMemo: { [ id: number ]: VideoModel }
22 private videoStreamingPlaylistMemo: { [ id: number ]: VideoStreamingPlaylistModel }
23 private videoFileMemo: { [ id: number ]: VideoFileModel }
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>
32 private trackersDone: Set<string>
33 private tagsDone: Set<string>
35 private videos: VideoModel[]
37 private readonly buildOpts = { raw: true, isNewRecord: false }
40 readonly mode: 'get' | 'list',
41 readonly videoAttributes: VideoAttributes
46 buildVideosFromRows (rows: any[]) {
49 for (const row of rows) {
52 const videoModel = this.videosMemo[row.id]
54 this.setUserHistory(row, videoModel)
55 this.addThumbnail(row, videoModel)
56 this.addWebTorrentFile(row, videoModel)
58 this.addStreamingPlaylist(row, videoModel)
59 this.addStreamingPlaylistFile(row)
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)
68 if (row.VideoFiles.id) {
69 this.addRedundancy(row.VideoFiles.RedundancyVideos, this.videoFileMemo[row.VideoFiles.id])
72 if (row.VideoStreamingPlaylists.id) {
73 this.addRedundancy(row.VideoStreamingPlaylists.RedundancyVideos, this.videoStreamingPlaylistMemo[row.VideoStreamingPlaylists.id])
83 this.videoStreamingPlaylistMemo = {}
84 this.videoFileMemo = {}
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>()
93 this.trackersDone = new Set<string>()
94 this.tagsDone = new Set<string>()
99 private buildVideo (row: any) {
100 if (this.videosMemo[row.id]) return
103 const channel = row.VideoChannel
104 const channelModel = new VideoChannelModel(pick(channel, this.videoAttributes.getChannelAttributes()), this.buildOpts)
105 channelModel.Actor = this.buildActor(channel.Actor)
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)
111 channelModel.Account = accountModel
113 const videoModel = new VideoModel(pick(row, this.videoAttributes.getVideoAttributes()), this.buildOpts)
114 videoModel.VideoChannel = channelModel
116 this.videosMemo[row.id] = videoModel
118 videoModel.UserVideoHistories = []
119 videoModel.Thumbnails = []
120 videoModel.VideoFiles = []
121 videoModel.VideoStreamingPlaylists = []
123 videoModel.Trackers = []
126 this.videos.push(videoModel)
129 private buildActor (rowActor: any) {
130 const avatarModel = rowActor.Avatar.id !== null
131 ? new ActorImageModel(pick(rowActor.Avatar, this.videoAttributes.getAvatarAttributes()), this.buildOpts)
134 const serverModel = rowActor.Server.id !== null
135 ? new ServerModel(pick(rowActor.Server, this.videoAttributes.getServerAttributes()), this.buildOpts)
138 const actorModel = new ActorModel(pick(rowActor, this.videoAttributes.getActorAttributes()), this.buildOpts)
139 actorModel.Avatar = avatarModel
140 actorModel.Server = serverModel
145 private setUserHistory (row: any, videoModel: VideoModel) {
146 if (!row.userVideoHistory?.id || this.historyDone.has(row.userVideoHistory.id)) return
148 const attributes = pick(row.userVideoHistory, this.videoAttributes.getUserHistoryAttributes())
149 const historyModel = new UserVideoHistoryModel(attributes, this.buildOpts)
150 videoModel.UserVideoHistories.push(historyModel)
152 this.historyDone.add(row.userVideoHistory.id)
155 private addThumbnail (row: any, videoModel: VideoModel) {
156 if (!row.Thumbnails?.id || this.thumbnailsDone.has(row.Thumbnails.id)) return
158 const attributes = pick(row.Thumbnails, this.videoAttributes.getThumbnailAttributes())
159 const thumbnailModel = new ThumbnailModel(attributes, this.buildOpts)
160 videoModel.Thumbnails.push(thumbnailModel)
162 this.thumbnailsDone.add(row.Thumbnails.id)
165 private addWebTorrentFile (row: any, videoModel: VideoModel) {
166 if (!row.VideoFiles?.id || this.videoFileMemo[row.VideoFiles.id]) return
168 const attributes = pick(row.VideoFiles, this.videoAttributes.getFileAttributes())
169 const videoFileModel = new VideoFileModel(attributes, this.buildOpts)
170 videoModel.VideoFiles.push(videoFileModel)
172 this.videoFileMemo[row.VideoFiles.id] = videoFileModel
175 private addStreamingPlaylist (row: any, videoModel: VideoModel) {
176 if (!row.VideoStreamingPlaylists?.id || this.videoStreamingPlaylistMemo[row.VideoStreamingPlaylists.id]) return
178 const attributes = pick(row.VideoStreamingPlaylists, this.videoAttributes.getStreamingPlaylistAttributes())
179 const streamingPlaylist = new VideoStreamingPlaylistModel(attributes, this.buildOpts)
180 streamingPlaylist.VideoFiles = []
182 videoModel.VideoStreamingPlaylists.push(streamingPlaylist)
184 this.videoStreamingPlaylistMemo[streamingPlaylist.id] = streamingPlaylist
187 private addStreamingPlaylistFile (row: any) {
188 if (!row.VideoStreamingPlaylists?.VideoFiles?.id || this.videoFileMemo[row.VideoStreamingPlaylists.VideoFiles.id]) return
190 const streamingPlaylist = this.videoStreamingPlaylistMemo[row.VideoStreamingPlaylists.id]
192 const attributes = pick(row.VideoStreamingPlaylists.VideoFiles, this.videoAttributes.getFileAttributes())
193 const videoFileModel = new VideoFileModel(attributes, this.buildOpts)
194 streamingPlaylist.VideoFiles.push(videoFileModel)
196 this.videoFileMemo[row.VideoStreamingPlaylists.VideoFiles.id] = videoFileModel
199 private addRedundancy (redundancyRow: any, to: VideoFileModel | VideoStreamingPlaylistModel) {
200 if (!to.RedundancyVideos) to.RedundancyVideos = []
202 if (!redundancyRow?.id || this.redundancyDone.has(redundancyRow.id)) return
204 const attributes = pick(redundancyRow, this.videoAttributes.getRedundancyAttributes())
205 const redundancyModel = new VideoRedundancyModel(attributes, this.buildOpts)
206 to.RedundancyVideos.push(redundancyModel)
208 this.redundancyDone.add(redundancyRow.id)
211 private addTag (row: any, videoModel: VideoModel) {
212 if (!row.Tags?.name) return
213 const association = row.Tags.VideoTagModel
215 const key = `${association.videoId}-${association.tagId}`
216 if (this.tagsDone.has(key)) return
218 const attributes = pick(row.Tags, this.videoAttributes.getTagAttributes())
219 const tagModel = new TagModel(attributes, this.buildOpts)
220 videoModel.Tags.push(tagModel)
222 this.tagsDone.add(key)
225 private addTracker (row: any, videoModel: VideoModel) {
226 if (!row.Trackers?.id) return
227 const association = row.Trackers.VideoTrackerModel
229 const key = `${association.videoId}-${association.trackerId}`
230 if (this.trackersDone.has(key)) return
232 const attributes = pick(row.Trackers, this.videoAttributes.getTrackerAttributes())
233 const trackerModel = new TrackerModel(attributes, this.buildOpts)
234 videoModel.Trackers.push(trackerModel)
236 this.trackersDone.add(key)
239 private setBlacklisted (row: any, videoModel: VideoModel) {
240 if (!row.VideoBlacklist?.id) return
241 if (this.blacklistDone.has(row.VideoBlacklist.id)) return
243 const attributes = pick(row.VideoBlacklist, this.videoAttributes.getBlacklistedAttributes())
244 videoModel.VideoBlacklist = new VideoBlacklistModel(attributes, this.buildOpts)
246 this.blacklistDone.add(row.VideoBlacklist.id)
249 private setScheduleVideoUpdate (row: any, videoModel: VideoModel) {
250 if (!row.ScheduleVideoUpdate?.id) return
251 if (this.scheduleVideoUpdateDone.has(row.ScheduleVideoUpdate.id)) return
253 const attributes = pick(row.ScheduleVideoUpdate, this.videoAttributes.getScheduleUpdateAttributes())
254 videoModel.ScheduleVideoUpdate = new ScheduleVideoUpdateModel(attributes, this.buildOpts)
256 this.scheduleVideoUpdateDone.add(row.ScheduleVideoUpdate.id)
259 private setLive (row: any, videoModel: VideoModel) {
260 if (!row.VideoLive?.id) return
261 if (this.liveDone.has(row.VideoLive.id)) return
263 const attributes = pick(row.VideoLive, this.videoAttributes.getLiveAttributes())
264 videoModel.VideoLive = new VideoLiveModel(attributes, this.buildOpts)
266 this.liveDone.add(row.ScheduleVideoUpdate.id)