mirror of https://github.com/Chocobozzz/PeerTube
235 lines
11 KiB
TypeScript
235 lines
11 KiB
TypeScript
|
|
||
|
import { MUserId } from '@server/types/models'
|
||
|
import { Sequelize } from 'sequelize'
|
||
|
import { AbstractVideosQueryBuilder } from './abstract-videos-query-builder'
|
||
|
import { buildVideosFromRows } from './video-model-builder'
|
||
|
import { BuildVideosListQueryOptions, VideosIdListQueryBuilder } from './videos-id-list-query-builder'
|
||
|
|
||
|
export class VideosModelListQueryBuilder extends AbstractVideosQueryBuilder {
|
||
|
private attributes: { [key: string]: string }
|
||
|
|
||
|
private joins: string[] = []
|
||
|
|
||
|
private innerQuery: string
|
||
|
private innerSort: string
|
||
|
|
||
|
constructor (protected readonly sequelize: Sequelize) {
|
||
|
super()
|
||
|
}
|
||
|
|
||
|
queryVideos (options: BuildVideosListQueryOptions) {
|
||
|
this.buildInnerQuery(options)
|
||
|
this.buildListQueryFromIdsQuery(options)
|
||
|
|
||
|
return this.runQuery(true).then(rows => buildVideosFromRows(rows))
|
||
|
}
|
||
|
|
||
|
private buildInnerQuery (options: BuildVideosListQueryOptions) {
|
||
|
const idsQueryBuilder = new VideosIdListQueryBuilder(this.sequelize)
|
||
|
const { query, sort, replacements } = idsQueryBuilder.getIdsListQueryAndSort(options)
|
||
|
|
||
|
this.replacements = replacements
|
||
|
this.innerQuery = query
|
||
|
this.innerSort = sort
|
||
|
}
|
||
|
|
||
|
private buildListQueryFromIdsQuery (options: BuildVideosListQueryOptions) {
|
||
|
this.attributes = {
|
||
|
'"video".*': ''
|
||
|
}
|
||
|
|
||
|
this.joins = [ 'INNER JOIN "video" ON "tmp"."id" = "video"."id"' ]
|
||
|
|
||
|
this.includeChannels()
|
||
|
this.includeAccounts()
|
||
|
this.includeThumbnails()
|
||
|
|
||
|
if (options.withFiles) {
|
||
|
this.includeFiles()
|
||
|
}
|
||
|
|
||
|
if (options.user) {
|
||
|
this.includeUserHistory(options.user)
|
||
|
}
|
||
|
|
||
|
if (options.videoPlaylistId) {
|
||
|
this.includePlaylist(options.videoPlaylistId)
|
||
|
}
|
||
|
|
||
|
const select = this.buildSelect()
|
||
|
|
||
|
this.query = `${select} FROM (${this.innerQuery}) AS "tmp" ${this.joins.join(' ')} ${this.innerSort}`
|
||
|
}
|
||
|
|
||
|
private includeChannels () {
|
||
|
this.attributes = {
|
||
|
...this.attributes,
|
||
|
|
||
|
'"VideoChannel"."id"': '"VideoChannel.id"',
|
||
|
'"VideoChannel"."name"': '"VideoChannel.name"',
|
||
|
'"VideoChannel"."description"': '"VideoChannel.description"',
|
||
|
'"VideoChannel"."actorId"': '"VideoChannel.actorId"',
|
||
|
'"VideoChannel->Actor"."id"': '"VideoChannel.Actor.id"',
|
||
|
'"VideoChannel->Actor"."preferredUsername"': '"VideoChannel.Actor.preferredUsername"',
|
||
|
'"VideoChannel->Actor"."url"': '"VideoChannel.Actor.url"',
|
||
|
'"VideoChannel->Actor"."serverId"': '"VideoChannel.Actor.serverId"',
|
||
|
'"VideoChannel->Actor"."avatarId"': '"VideoChannel.Actor.avatarId"',
|
||
|
'"VideoChannel->Actor->Server"."id"': '"VideoChannel.Actor.Server.id"',
|
||
|
'"VideoChannel->Actor->Server"."host"': '"VideoChannel.Actor.Server.host"',
|
||
|
'"VideoChannel->Actor->Avatar"."id"': '"VideoChannel.Actor.Avatar.id"',
|
||
|
'"VideoChannel->Actor->Avatar"."filename"': '"VideoChannel.Actor.Avatar.filename"',
|
||
|
'"VideoChannel->Actor->Avatar"."fileUrl"': '"VideoChannel.Actor.Avatar.fileUrl"',
|
||
|
'"VideoChannel->Actor->Avatar"."onDisk"': '"VideoChannel.Actor.Avatar.onDisk"',
|
||
|
'"VideoChannel->Actor->Avatar"."createdAt"': '"VideoChannel.Actor.Avatar.createdAt"',
|
||
|
'"VideoChannel->Actor->Avatar"."updatedAt"': '"VideoChannel.Actor.Avatar.updatedAt"'
|
||
|
}
|
||
|
|
||
|
this.joins = this.joins.concat([
|
||
|
'INNER JOIN "videoChannel" AS "VideoChannel" ON "video"."channelId" = "VideoChannel"."id"',
|
||
|
'INNER JOIN "actor" AS "VideoChannel->Actor" ON "VideoChannel"."actorId" = "VideoChannel->Actor"."id"',
|
||
|
|
||
|
'LEFT OUTER JOIN "server" AS "VideoChannel->Actor->Server" ON "VideoChannel->Actor"."serverId" = "VideoChannel->Actor->Server"."id"',
|
||
|
'LEFT OUTER JOIN "actorImage" AS "VideoChannel->Actor->Avatar" ' +
|
||
|
'ON "VideoChannel->Actor"."avatarId" = "VideoChannel->Actor->Avatar"."id"'
|
||
|
])
|
||
|
}
|
||
|
|
||
|
private includeAccounts () {
|
||
|
this.attributes = {
|
||
|
...this.attributes,
|
||
|
|
||
|
'"VideoChannel->Account"."id"': '"VideoChannel.Account.id"',
|
||
|
'"VideoChannel->Account"."name"': '"VideoChannel.Account.name"',
|
||
|
'"VideoChannel->Account->Actor"."id"': '"VideoChannel.Account.Actor.id"',
|
||
|
'"VideoChannel->Account->Actor"."preferredUsername"': '"VideoChannel.Account.Actor.preferredUsername"',
|
||
|
'"VideoChannel->Account->Actor"."url"': '"VideoChannel.Account.Actor.url"',
|
||
|
'"VideoChannel->Account->Actor"."serverId"': '"VideoChannel.Account.Actor.serverId"',
|
||
|
'"VideoChannel->Account->Actor"."avatarId"': '"VideoChannel.Account.Actor.avatarId"',
|
||
|
'"VideoChannel->Account->Actor->Server"."id"': '"VideoChannel.Account.Actor.Server.id"',
|
||
|
'"VideoChannel->Account->Actor->Server"."host"': '"VideoChannel.Account.Actor.Server.host"',
|
||
|
'"VideoChannel->Account->Actor->Avatar"."id"': '"VideoChannel.Account.Actor.Avatar.id"',
|
||
|
'"VideoChannel->Account->Actor->Avatar"."filename"': '"VideoChannel.Account.Actor.Avatar.filename"',
|
||
|
'"VideoChannel->Account->Actor->Avatar"."fileUrl"': '"VideoChannel.Account.Actor.Avatar.fileUrl"',
|
||
|
'"VideoChannel->Account->Actor->Avatar"."onDisk"': '"VideoChannel.Account.Actor.Avatar.onDisk"',
|
||
|
'"VideoChannel->Account->Actor->Avatar"."createdAt"': '"VideoChannel.Account.Actor.Avatar.createdAt"',
|
||
|
'"VideoChannel->Account->Actor->Avatar"."updatedAt"': '"VideoChannel.Account.Actor.Avatar.updatedAt"'
|
||
|
}
|
||
|
|
||
|
this.joins = this.joins.concat([
|
||
|
'INNER JOIN "account" AS "VideoChannel->Account" ON "VideoChannel"."accountId" = "VideoChannel->Account"."id"',
|
||
|
'INNER JOIN "actor" AS "VideoChannel->Account->Actor" ON "VideoChannel->Account"."actorId" = "VideoChannel->Account->Actor"."id"',
|
||
|
|
||
|
'LEFT OUTER JOIN "server" AS "VideoChannel->Account->Actor->Server" ' +
|
||
|
'ON "VideoChannel->Account->Actor"."serverId" = "VideoChannel->Account->Actor->Server"."id"',
|
||
|
|
||
|
'LEFT OUTER JOIN "actorImage" AS "VideoChannel->Account->Actor->Avatar" ' +
|
||
|
'ON "VideoChannel->Account->Actor"."avatarId" = "VideoChannel->Account->Actor->Avatar"."id"'
|
||
|
])
|
||
|
}
|
||
|
|
||
|
private includeThumbnails () {
|
||
|
this.attributes = {
|
||
|
...this.attributes,
|
||
|
|
||
|
'"Thumbnails"."id"': '"Thumbnails.id"',
|
||
|
'"Thumbnails"."type"': '"Thumbnails.type"',
|
||
|
'"Thumbnails"."filename"': '"Thumbnails.filename"'
|
||
|
}
|
||
|
|
||
|
this.joins.push('LEFT OUTER JOIN "thumbnail" AS "Thumbnails" ON "video"."id" = "Thumbnails"."videoId"')
|
||
|
}
|
||
|
|
||
|
private includeFiles () {
|
||
|
this.attributes = {
|
||
|
...this.attributes,
|
||
|
|
||
|
'"VideoFiles"."id"': '"VideoFiles.id"',
|
||
|
'"VideoFiles"."createdAt"': '"VideoFiles.createdAt"',
|
||
|
'"VideoFiles"."updatedAt"': '"VideoFiles.updatedAt"',
|
||
|
'"VideoFiles"."resolution"': '"VideoFiles.resolution"',
|
||
|
'"VideoFiles"."size"': '"VideoFiles.size"',
|
||
|
'"VideoFiles"."extname"': '"VideoFiles.extname"',
|
||
|
'"VideoFiles"."filename"': '"VideoFiles.filename"',
|
||
|
'"VideoFiles"."fileUrl"': '"VideoFiles.fileUrl"',
|
||
|
'"VideoFiles"."torrentFilename"': '"VideoFiles.torrentFilename"',
|
||
|
'"VideoFiles"."torrentUrl"': '"VideoFiles.torrentUrl"',
|
||
|
'"VideoFiles"."infoHash"': '"VideoFiles.infoHash"',
|
||
|
'"VideoFiles"."fps"': '"VideoFiles.fps"',
|
||
|
'"VideoFiles"."videoId"': '"VideoFiles.videoId"',
|
||
|
|
||
|
'"VideoStreamingPlaylists"."id"': '"VideoStreamingPlaylists.id"',
|
||
|
'"VideoStreamingPlaylists"."playlistUrl"': '"VideoStreamingPlaylists.playlistUrl"',
|
||
|
'"VideoStreamingPlaylists"."type"': '"VideoStreamingPlaylists.type"',
|
||
|
'"VideoStreamingPlaylists->VideoFiles"."id"': '"VideoStreamingPlaylists.VideoFiles.id"',
|
||
|
'"VideoStreamingPlaylists->VideoFiles"."createdAt"': '"VideoStreamingPlaylists.VideoFiles.createdAt"',
|
||
|
'"VideoStreamingPlaylists->VideoFiles"."updatedAt"': '"VideoStreamingPlaylists.VideoFiles.updatedAt"',
|
||
|
'"VideoStreamingPlaylists->VideoFiles"."resolution"': '"VideoStreamingPlaylists.VideoFiles.resolution"',
|
||
|
'"VideoStreamingPlaylists->VideoFiles"."size"': '"VideoStreamingPlaylists.VideoFiles.size"',
|
||
|
'"VideoStreamingPlaylists->VideoFiles"."extname"': '"VideoStreamingPlaylists.VideoFiles.extname"',
|
||
|
'"VideoStreamingPlaylists->VideoFiles"."filename"': '"VideoStreamingPlaylists.VideoFiles.filename"',
|
||
|
'"VideoStreamingPlaylists->VideoFiles"."fileUrl"': '"VideoStreamingPlaylists.VideoFiles.fileUrl"',
|
||
|
'"VideoStreamingPlaylists->VideoFiles"."torrentFilename"': '"VideoStreamingPlaylists.VideoFiles.torrentFilename"',
|
||
|
'"VideoStreamingPlaylists->VideoFiles"."torrentUrl"': '"VideoStreamingPlaylists.VideoFiles.torrentUrl"',
|
||
|
'"VideoStreamingPlaylists->VideoFiles"."infoHash"': '"VideoStreamingPlaylists.VideoFiles.infoHash"',
|
||
|
'"VideoStreamingPlaylists->VideoFiles"."fps"': '"VideoStreamingPlaylists.VideoFiles.fps"',
|
||
|
'"VideoStreamingPlaylists->VideoFiles"."videoStreamingPlaylistId"': '"VideoStreamingPlaylists.VideoFiles.videoStreamingPlaylistId"',
|
||
|
'"VideoStreamingPlaylists->VideoFiles"."videoId"': '"VideoStreamingPlaylists.VideoFiles.videoId"'
|
||
|
}
|
||
|
|
||
|
this.joins = this.joins.concat([
|
||
|
'LEFT JOIN "videoFile" AS "VideoFiles" ON "VideoFiles"."videoId" = "video"."id"',
|
||
|
|
||
|
'LEFT JOIN "videoStreamingPlaylist" AS "VideoStreamingPlaylists" ON "VideoStreamingPlaylists"."videoId" = "video"."id"',
|
||
|
|
||
|
'LEFT JOIN "videoFile" AS "VideoStreamingPlaylists->VideoFiles" ' +
|
||
|
'ON "VideoStreamingPlaylists->VideoFiles"."videoStreamingPlaylistId" = "VideoStreamingPlaylists"."id"'
|
||
|
])
|
||
|
}
|
||
|
|
||
|
private includeUserHistory (user: MUserId) {
|
||
|
this.attributes = {
|
||
|
...this.attributes,
|
||
|
|
||
|
'"userVideoHistory"."id"': '"userVideoHistory.id"',
|
||
|
'"userVideoHistory"."currentTime"': '"userVideoHistory.currentTime"'
|
||
|
}
|
||
|
|
||
|
this.joins.push(
|
||
|
'LEFT OUTER JOIN "userVideoHistory" ' +
|
||
|
'ON "video"."id" = "userVideoHistory"."videoId" AND "userVideoHistory"."userId" = :userVideoHistoryId'
|
||
|
)
|
||
|
|
||
|
this.replacements.userVideoHistoryId = user.id
|
||
|
}
|
||
|
|
||
|
private includePlaylist (playlistId: number) {
|
||
|
this.attributes = {
|
||
|
...this.attributes,
|
||
|
|
||
|
'"VideoPlaylistElement"."createdAt"': '"VideoPlaylistElement.createdAt"',
|
||
|
'"VideoPlaylistElement"."updatedAt"': '"VideoPlaylistElement.updatedAt"',
|
||
|
'"VideoPlaylistElement"."url"': '"VideoPlaylistElement.url"',
|
||
|
'"VideoPlaylistElement"."position"': '"VideoPlaylistElement.position"',
|
||
|
'"VideoPlaylistElement"."startTimestamp"': '"VideoPlaylistElement.startTimestamp"',
|
||
|
'"VideoPlaylistElement"."stopTimestamp"': '"VideoPlaylistElement.stopTimestamp"',
|
||
|
'"VideoPlaylistElement"."videoPlaylistId"': '"VideoPlaylistElement.videoPlaylistId"'
|
||
|
}
|
||
|
|
||
|
this.joins.push(
|
||
|
'INNER JOIN "videoPlaylistElement" as "VideoPlaylistElement" ON "videoPlaylistElement"."videoId" = "video"."id" ' +
|
||
|
'AND "VideoPlaylistElement"."videoPlaylistId" = :videoPlaylistId'
|
||
|
)
|
||
|
|
||
|
this.replacements.videoPlaylistId = playlistId
|
||
|
}
|
||
|
|
||
|
private buildSelect () {
|
||
|
return 'SELECT ' + Object.keys(this.attributes).map(key => {
|
||
|
const value = this.attributes[key]
|
||
|
if (value) return `${key} AS ${value}`
|
||
|
|
||
|
return key
|
||
|
}).join(', ')
|
||
|
}
|
||
|
}
|