-import { pick } from 'lodash'
+
import { AccountModel } from '@server/models/account/account'
+import { AccountBlocklistModel } from '@server/models/account/account-blocklist'
import { ActorModel } from '@server/models/actor/actor'
import { ActorImageModel } from '@server/models/actor/actor-image'
import { VideoRedundancyModel } from '@server/models/redundancy/video-redundancy'
import { ServerModel } from '@server/models/server/server'
+import { ServerBlocklistModel } from '@server/models/server/server-blocklist'
import { TrackerModel } from '@server/models/server/tracker'
import { UserVideoHistoryModel } from '@server/models/user/user-video-history'
+import { VideoInclude } from '@shared/models'
import { ScheduleVideoUpdateModel } from '../../schedule-video-update'
import { TagModel } from '../../tag'
import { ThumbnailModel } from '../../thumbnail'
import { VideoFileModel } from '../../video-file'
import { VideoLiveModel } from '../../video-live'
import { VideoStreamingPlaylistModel } from '../../video-streaming-playlist'
-import { VideoAttributes } from './video-attributes'
+import { VideoTableAttributes } from './video-table-attributes'
+
+type SQLRow = { [id: string]: string | number }
+
+/**
+ *
+ * Build video models from SQL rows
+ *
+ */
export class VideoModelBuilder {
private videosMemo: { [ id: number ]: VideoModel }
private videoStreamingPlaylistMemo: { [ id: number ]: VideoStreamingPlaylistModel }
private videoFileMemo: { [ id: number ]: VideoFileModel }
- private thumbnailsDone: Set<number>
- private historyDone: Set<number>
- private blacklistDone: Set<number>
- private liveDone: Set<number>
- private redundancyDone: Set<number>
- private scheduleVideoUpdateDone: Set<number>
+ private thumbnailsDone: Set<any>
+ private historyDone: Set<any>
+ private blacklistDone: Set<any>
+ private accountBlocklistDone: Set<any>
+ private serverBlocklistDone: Set<any>
+ private liveDone: Set<any>
+ private redundancyDone: Set<any>
+ private scheduleVideoUpdateDone: Set<any>
private trackersDone: Set<string>
private tagsDone: Set<string>
constructor (
readonly mode: 'get' | 'list',
- readonly videoAttributes: VideoAttributes
+ readonly tables: VideoTableAttributes
) {
}
- buildVideosFromRows (rows: any[]) {
+ buildVideosFromRows (options: {
+ rows: SQLRow[]
+ include?: VideoInclude
+ rowsWebTorrentFiles?: SQLRow[]
+ rowsStreamingPlaylist?: SQLRow[]
+ }) {
+ const { rows, rowsWebTorrentFiles, rowsStreamingPlaylist, include } = options
+
this.reinit()
for (const row of rows) {
- this.buildVideo(row)
+ this.buildVideoAndAccount(row)
const videoModel = this.videosMemo[row.id]
this.setUserHistory(row, videoModel)
this.addThumbnail(row, videoModel)
- this.addWebTorrentFile(row, videoModel)
- this.addStreamingPlaylist(row, videoModel)
- this.addStreamingPlaylistFile(row)
+ if (!rowsWebTorrentFiles) {
+ this.addWebTorrentFile(row, videoModel)
+ }
+
+ if (!rowsStreamingPlaylist) {
+ this.addStreamingPlaylist(row, videoModel)
+ this.addStreamingPlaylistFile(row)
+ }
if (this.mode === 'get') {
this.addTag(row, videoModel)
this.setBlacklisted(row, videoModel)
this.setScheduleVideoUpdate(row, videoModel)
this.setLive(row, videoModel)
-
- if (row.VideoFiles.id) {
- this.addRedundancy(row.VideoFiles.RedundancyVideos, this.videoFileMemo[row.VideoFiles.id])
+ } else {
+ if (include & VideoInclude.BLACKLISTED) {
+ this.setBlacklisted(row, videoModel)
}
- if (row.VideoStreamingPlaylists.id) {
- this.addRedundancy(row.VideoStreamingPlaylists.RedundancyVideos, this.videoStreamingPlaylistMemo[row.VideoStreamingPlaylists.id])
+ if (include & VideoInclude.BLOCKED_OWNER) {
+ this.setBlockedOwner(row, videoModel)
+ this.setBlockedServer(row, videoModel)
}
}
}
+ this.grabSeparateWebTorrentFiles(rowsWebTorrentFiles)
+ this.grabSeparateStreamingPlaylistFiles(rowsStreamingPlaylist)
+
return this.videos
}
this.videoStreamingPlaylistMemo = {}
this.videoFileMemo = {}
- this.thumbnailsDone = new Set<number>()
- this.historyDone = new Set<number>()
- this.blacklistDone = new Set<number>()
- this.liveDone = new Set<number>()
- this.redundancyDone = new Set<number>()
- this.scheduleVideoUpdateDone = new Set<number>()
+ this.thumbnailsDone = new Set()
+ this.historyDone = new Set()
+ this.blacklistDone = new Set()
+ this.liveDone = new Set()
+ this.redundancyDone = new Set()
+ this.scheduleVideoUpdateDone = new Set()
- this.trackersDone = new Set<string>()
- this.tagsDone = new Set<string>()
+ this.accountBlocklistDone = new Set()
+ this.serverBlocklistDone = new Set()
+
+ this.trackersDone = new Set()
+ this.tagsDone = new Set()
this.videos = []
}
- private buildVideo (row: any) {
- if (this.videosMemo[row.id]) return
+ private grabSeparateWebTorrentFiles (rowsWebTorrentFiles?: SQLRow[]) {
+ if (!rowsWebTorrentFiles) return
- // Build Channel
- const channel = row.VideoChannel
- const channelModel = new VideoChannelModel(pick(channel, this.videoAttributes.getChannelAttributes()), this.buildOpts)
- channelModel.Actor = this.buildActor(channel.Actor)
+ for (const row of rowsWebTorrentFiles) {
+ const id = row['VideoFiles.id']
+ if (!id) continue
- const account = row.VideoChannel.Account
- const accountModel = new AccountModel(pick(account, this.videoAttributes.getAccountAttributes()), this.buildOpts)
- accountModel.Actor = this.buildActor(account.Actor)
+ const videoModel = this.videosMemo[row.id]
+ this.addWebTorrentFile(row, videoModel)
+ this.addRedundancy(row, 'VideoFiles', this.videoFileMemo[id])
+ }
+ }
- channelModel.Account = accountModel
+ private grabSeparateStreamingPlaylistFiles (rowsStreamingPlaylist?: SQLRow[]) {
+ if (!rowsStreamingPlaylist) return
- const videoModel = new VideoModel(pick(row, this.videoAttributes.getVideoAttributes()), this.buildOpts)
- videoModel.VideoChannel = channelModel
+ for (const row of rowsStreamingPlaylist) {
+ const id = row['VideoStreamingPlaylists.id']
+ if (!id) continue
- this.videosMemo[row.id] = videoModel
+ const videoModel = this.videosMemo[row.id]
+
+ this.addStreamingPlaylist(row, videoModel)
+ this.addStreamingPlaylistFile(row)
+ this.addRedundancy(row, 'VideoStreamingPlaylists', this.videoStreamingPlaylistMemo[id])
+ }
+ }
+
+ private buildVideoAndAccount (row: SQLRow) {
+ if (this.videosMemo[row.id]) return
+
+ const videoModel = new VideoModel(this.grab(row, this.tables.getVideoAttributes(), ''), this.buildOpts)
videoModel.UserVideoHistories = []
videoModel.Thumbnails = []
videoModel.Tags = []
videoModel.Trackers = []
+ this.buildAccount(row, videoModel)
+
+ this.videosMemo[row.id] = videoModel
+
// Keep rows order
this.videos.push(videoModel)
}
- private buildActor (rowActor: any) {
- const avatarModel = rowActor.Avatar.id !== null
- ? new ActorImageModel(pick(rowActor.Avatar, this.videoAttributes.getAvatarAttributes()), this.buildOpts)
+ private buildAccount (row: SQLRow, videoModel: VideoModel) {
+ const id = row['VideoChannel.Account.id']
+ if (!id) return
+
+ const channelModel = new VideoChannelModel(this.grab(row, this.tables.getChannelAttributes(), 'VideoChannel'), this.buildOpts)
+ channelModel.Actor = this.buildActor(row, 'VideoChannel')
+
+ const accountModel = new AccountModel(this.grab(row, this.tables.getAccountAttributes(), 'VideoChannel.Account'), this.buildOpts)
+ accountModel.Actor = this.buildActor(row, 'VideoChannel.Account')
+
+ accountModel.BlockedBy = []
+
+ channelModel.Account = accountModel
+
+ videoModel.VideoChannel = channelModel
+ }
+
+ private buildActor (row: SQLRow, prefix: string) {
+ const actorPrefix = `${prefix}.Actor`
+ const avatarPrefix = `${actorPrefix}.Avatar`
+ const serverPrefix = `${actorPrefix}.Server`
+
+ const avatarModel = row[`${avatarPrefix}.id`] !== null
+ ? new ActorImageModel(this.grab(row, this.tables.getAvatarAttributes(), avatarPrefix), this.buildOpts)
: null
- const serverModel = rowActor.Server.id !== null
- ? new ServerModel(pick(rowActor.Server, this.videoAttributes.getServerAttributes()), this.buildOpts)
+ const serverModel = row[`${serverPrefix}.id`] !== null
+ ? new ServerModel(this.grab(row, this.tables.getServerAttributes(), serverPrefix), this.buildOpts)
: null
- const actorModel = new ActorModel(pick(rowActor, this.videoAttributes.getActorAttributes()), this.buildOpts)
+ if (serverModel) serverModel.BlockedBy = []
+
+ const actorModel = new ActorModel(this.grab(row, this.tables.getActorAttributes(), actorPrefix), this.buildOpts)
actorModel.Avatar = avatarModel
actorModel.Server = serverModel
return actorModel
}
- private setUserHistory (row: any, videoModel: VideoModel) {
- if (!row.userVideoHistory?.id || this.historyDone.has(row.userVideoHistory.id)) return
+ private setUserHistory (row: SQLRow, videoModel: VideoModel) {
+ const id = row['userVideoHistory.id']
+ if (!id || this.historyDone.has(id)) return
- const attributes = pick(row.userVideoHistory, this.videoAttributes.getUserHistoryAttributes())
+ const attributes = this.grab(row, this.tables.getUserHistoryAttributes(), 'userVideoHistory')
const historyModel = new UserVideoHistoryModel(attributes, this.buildOpts)
videoModel.UserVideoHistories.push(historyModel)
- this.historyDone.add(row.userVideoHistory.id)
+ this.historyDone.add(id)
}
- private addThumbnail (row: any, videoModel: VideoModel) {
- if (!row.Thumbnails?.id || this.thumbnailsDone.has(row.Thumbnails.id)) return
+ private addThumbnail (row: SQLRow, videoModel: VideoModel) {
+ const id = row['Thumbnails.id']
+ if (!id || this.thumbnailsDone.has(id)) return
- const attributes = pick(row.Thumbnails, this.videoAttributes.getThumbnailAttributes())
+ const attributes = this.grab(row, this.tables.getThumbnailAttributes(), 'Thumbnails')
const thumbnailModel = new ThumbnailModel(attributes, this.buildOpts)
videoModel.Thumbnails.push(thumbnailModel)
- this.thumbnailsDone.add(row.Thumbnails.id)
+ this.thumbnailsDone.add(id)
}
- private addWebTorrentFile (row: any, videoModel: VideoModel) {
- if (!row.VideoFiles?.id || this.videoFileMemo[row.VideoFiles.id]) return
+ private addWebTorrentFile (row: SQLRow, videoModel: VideoModel) {
+ const id = row['VideoFiles.id']
+ if (!id || this.videoFileMemo[id]) return
- const attributes = pick(row.VideoFiles, this.videoAttributes.getFileAttributes())
+ const attributes = this.grab(row, this.tables.getFileAttributes(), 'VideoFiles')
const videoFileModel = new VideoFileModel(attributes, this.buildOpts)
videoModel.VideoFiles.push(videoFileModel)
- this.videoFileMemo[row.VideoFiles.id] = videoFileModel
+ this.videoFileMemo[id] = videoFileModel
}
- private addStreamingPlaylist (row: any, videoModel: VideoModel) {
- if (!row.VideoStreamingPlaylists?.id || this.videoStreamingPlaylistMemo[row.VideoStreamingPlaylists.id]) return
+ private addStreamingPlaylist (row: SQLRow, videoModel: VideoModel) {
+ const id = row['VideoStreamingPlaylists.id']
+ if (!id || this.videoStreamingPlaylistMemo[id]) return
- const attributes = pick(row.VideoStreamingPlaylists, this.videoAttributes.getStreamingPlaylistAttributes())
+ const attributes = this.grab(row, this.tables.getStreamingPlaylistAttributes(), 'VideoStreamingPlaylists')
const streamingPlaylist = new VideoStreamingPlaylistModel(attributes, this.buildOpts)
streamingPlaylist.VideoFiles = []
videoModel.VideoStreamingPlaylists.push(streamingPlaylist)
- this.videoStreamingPlaylistMemo[streamingPlaylist.id] = streamingPlaylist
+ this.videoStreamingPlaylistMemo[id] = streamingPlaylist
}
- private addStreamingPlaylistFile (row: any) {
- if (!row.VideoStreamingPlaylists?.VideoFiles?.id || this.videoFileMemo[row.VideoStreamingPlaylists.VideoFiles.id]) return
+ private addStreamingPlaylistFile (row: SQLRow) {
+ const id = row['VideoStreamingPlaylists.VideoFiles.id']
+ if (!id || this.videoFileMemo[id]) return
- const streamingPlaylist = this.videoStreamingPlaylistMemo[row.VideoStreamingPlaylists.id]
+ const streamingPlaylist = this.videoStreamingPlaylistMemo[row['VideoStreamingPlaylists.id']]
- const attributes = pick(row.VideoStreamingPlaylists.VideoFiles, this.videoAttributes.getFileAttributes())
+ const attributes = this.grab(row, this.tables.getFileAttributes(), 'VideoStreamingPlaylists.VideoFiles')
const videoFileModel = new VideoFileModel(attributes, this.buildOpts)
streamingPlaylist.VideoFiles.push(videoFileModel)
- this.videoFileMemo[row.VideoStreamingPlaylists.VideoFiles.id] = videoFileModel
+ this.videoFileMemo[id] = videoFileModel
}
- private addRedundancy (redundancyRow: any, to: VideoFileModel | VideoStreamingPlaylistModel) {
+ private addRedundancy (row: SQLRow, prefix: string, to: VideoFileModel | VideoStreamingPlaylistModel) {
if (!to.RedundancyVideos) to.RedundancyVideos = []
- if (!redundancyRow?.id || this.redundancyDone.has(redundancyRow.id)) return
+ const redundancyPrefix = `${prefix}.RedundancyVideos`
+ const id = row[`${redundancyPrefix}.id`]
+
+ if (!id || this.redundancyDone.has(id)) return
- const attributes = pick(redundancyRow, this.videoAttributes.getRedundancyAttributes())
+ const attributes = this.grab(row, this.tables.getRedundancyAttributes(), redundancyPrefix)
const redundancyModel = new VideoRedundancyModel(attributes, this.buildOpts)
to.RedundancyVideos.push(redundancyModel)
- this.redundancyDone.add(redundancyRow.id)
+ this.redundancyDone.add(id)
}
- private addTag (row: any, videoModel: VideoModel) {
- if (!row.Tags?.name) return
- const association = row.Tags.VideoTagModel
+ private addTag (row: SQLRow, videoModel: VideoModel) {
+ if (!row['Tags.name']) return
- const key = `${association.videoId}-${association.tagId}`
+ const key = `${row['Tags.VideoTagModel.videoId']}-${row['Tags.VideoTagModel.tagId']}`
if (this.tagsDone.has(key)) return
- const attributes = pick(row.Tags, this.videoAttributes.getTagAttributes())
+ const attributes = this.grab(row, this.tables.getTagAttributes(), 'Tags')
const tagModel = new TagModel(attributes, this.buildOpts)
videoModel.Tags.push(tagModel)
this.tagsDone.add(key)
}
- private addTracker (row: any, videoModel: VideoModel) {
- if (!row.Trackers?.id) return
- const association = row.Trackers.VideoTrackerModel
+ private addTracker (row: SQLRow, videoModel: VideoModel) {
+ if (!row['Trackers.id']) return
- const key = `${association.videoId}-${association.trackerId}`
+ const key = `${row['Trackers.VideoTrackerModel.videoId']}-${row['Trackers.VideoTrackerModel.trackerId']}`
if (this.trackersDone.has(key)) return
- const attributes = pick(row.Trackers, this.videoAttributes.getTrackerAttributes())
+ const attributes = this.grab(row, this.tables.getTrackerAttributes(), 'Trackers')
const trackerModel = new TrackerModel(attributes, this.buildOpts)
videoModel.Trackers.push(trackerModel)
this.trackersDone.add(key)
}
- private setBlacklisted (row: any, videoModel: VideoModel) {
- if (!row.VideoBlacklist?.id) return
- if (this.blacklistDone.has(row.VideoBlacklist.id)) return
+ private setBlacklisted (row: SQLRow, videoModel: VideoModel) {
+ const id = row['VideoBlacklist.id']
+ if (!id || this.blacklistDone.has(id)) return
- const attributes = pick(row.VideoBlacklist, this.videoAttributes.getBlacklistedAttributes())
+ const attributes = this.grab(row, this.tables.getBlacklistedAttributes(), 'VideoBlacklist')
videoModel.VideoBlacklist = new VideoBlacklistModel(attributes, this.buildOpts)
- this.blacklistDone.add(row.VideoBlacklist.id)
+ this.blacklistDone.add(id)
+ }
+
+ private setBlockedOwner (row: SQLRow, videoModel: VideoModel) {
+ const id = row['VideoChannel.Account.AccountBlocklist.id']
+ if (!id) return
+
+ const key = `${videoModel.id}-${id}`
+ if (this.accountBlocklistDone.has(key)) return
+
+ const attributes = this.grab(row, this.tables.getBlocklistAttributes(), 'VideoChannel.Account.AccountBlocklist')
+ videoModel.VideoChannel.Account.BlockedBy.push(new AccountBlocklistModel(attributes, this.buildOpts))
+
+ this.accountBlocklistDone.add(key)
}
- private setScheduleVideoUpdate (row: any, videoModel: VideoModel) {
- if (!row.ScheduleVideoUpdate?.id) return
- if (this.scheduleVideoUpdateDone.has(row.ScheduleVideoUpdate.id)) return
+ private setBlockedServer (row: SQLRow, videoModel: VideoModel) {
+ const id = row['VideoChannel.Account.Actor.Server.ServerBlocklist.id']
+ if (!id || this.serverBlocklistDone.has(id)) return
+
+ const key = `${videoModel.id}-${id}`
+ if (this.serverBlocklistDone.has(key)) return
+
+ const attributes = this.grab(row, this.tables.getBlocklistAttributes(), 'VideoChannel.Account.Actor.Server.ServerBlocklist')
+ videoModel.VideoChannel.Account.Actor.Server.BlockedBy.push(new ServerBlocklistModel(attributes, this.buildOpts))
+
+ this.serverBlocklistDone.add(key)
+ }
- const attributes = pick(row.ScheduleVideoUpdate, this.videoAttributes.getScheduleUpdateAttributes())
+ private setScheduleVideoUpdate (row: SQLRow, videoModel: VideoModel) {
+ const id = row['ScheduleVideoUpdate.id']
+ if (!id || this.scheduleVideoUpdateDone.has(id)) return
+
+ const attributes = this.grab(row, this.tables.getScheduleUpdateAttributes(), 'ScheduleVideoUpdate')
videoModel.ScheduleVideoUpdate = new ScheduleVideoUpdateModel(attributes, this.buildOpts)
- this.scheduleVideoUpdateDone.add(row.ScheduleVideoUpdate.id)
+ this.scheduleVideoUpdateDone.add(id)
}
- private setLive (row: any, videoModel: VideoModel) {
- if (!row.VideoLive?.id) return
- if (this.liveDone.has(row.VideoLive.id)) return
+ private setLive (row: SQLRow, videoModel: VideoModel) {
+ const id = row['VideoLive.id']
+ if (!id || this.liveDone.has(id)) return
- const attributes = pick(row.VideoLive, this.videoAttributes.getLiveAttributes())
+ const attributes = this.grab(row, this.tables.getLiveAttributes(), 'VideoLive')
videoModel.VideoLive = new VideoLiveModel(attributes, this.buildOpts)
- this.liveDone.add(row.ScheduleVideoUpdate.id)
+ this.liveDone.add(id)
+ }
+
+ private grab (row: SQLRow, attributes: string[], prefix: string) {
+ const result: { [ id: string ]: string | number } = {}
+
+ for (const a of attributes) {
+ const key = prefix
+ ? prefix + '.' + a
+ : a
+
+ result[a] = row[key]
+ }
+
+ return result
}
}