import { Sequelize, Transaction } from 'sequelize' import { AbstractVideoQueryBuilder } from './shared/abstract-video-query-builder' import { VideoFileQueryBuilder } from './shared/video-file-query-builder' import { VideoModelBuilder } from './shared/video-model-builder' import { VideoTableAttributes } from './shared/video-table-attributes' /** * * Build a GET SQL query, fetch rows and create the video model * */ export type GetType = 'api' | 'full-light' | 'account-blacklist-files' | 'all-files' | 'thumbnails' | 'thumbnails-blacklist' | 'id' | 'blacklist-rights' export type BuildVideoGetQueryOptions = { id?: number | string url?: string type: GetType userId?: number transaction?: Transaction logging?: boolean } export class VideoModelGetQueryBuilder { videoQueryBuilder: VideosModelGetQuerySubBuilder webtorrentFilesQueryBuilder: VideoFileQueryBuilder streamingPlaylistFilesQueryBuilder: VideoFileQueryBuilder private readonly videoModelBuilder: VideoModelBuilder private static readonly videoFilesInclude = new Set([ 'api', 'full-light', 'account-blacklist-files', 'all-files' ]) constructor (protected readonly sequelize: Sequelize) { this.videoQueryBuilder = new VideosModelGetQuerySubBuilder(sequelize) this.webtorrentFilesQueryBuilder = new VideoFileQueryBuilder(sequelize) this.streamingPlaylistFilesQueryBuilder = new VideoFileQueryBuilder(sequelize) this.videoModelBuilder = new VideoModelBuilder('get', new VideoTableAttributes('get')) } async queryVideo (options: BuildVideoGetQueryOptions) { const [ videoRows, webtorrentFilesRows, streamingPlaylistFilesRows ] = await Promise.all([ this.videoQueryBuilder.queryVideos(options), VideoModelGetQueryBuilder.videoFilesInclude.has(options.type) ? this.webtorrentFilesQueryBuilder.queryWebTorrentVideos(options) : Promise.resolve(undefined), VideoModelGetQueryBuilder.videoFilesInclude.has(options.type) ? this.streamingPlaylistFilesQueryBuilder.queryStreamingPlaylistVideos(options) : Promise.resolve(undefined) ]) const videos = this.videoModelBuilder.buildVideosFromRows({ rows: videoRows, rowsWebTorrentFiles: webtorrentFilesRows, rowsStreamingPlaylist: streamingPlaylistFilesRows }) if (videos.length > 1) { throw new Error('Video results is more than 1') } if (videos.length === 0) return null return videos[0] } } export class VideosModelGetQuerySubBuilder extends AbstractVideoQueryBuilder { protected attributes: { [key: string]: string } protected webtorrentFilesQuery: string protected streamingPlaylistFilesQuery: string private static readonly trackersInclude = new Set([ 'api' ]) private static readonly liveInclude = new Set([ 'api', 'full-light' ]) private static readonly scheduleUpdateInclude = new Set([ 'api', 'full-light' ]) private static readonly tagsInclude = new Set([ 'api', 'full-light' ]) private static readonly userHistoryInclude = new Set([ 'api', 'full-light' ]) private static readonly accountInclude = new Set([ 'api', 'full-light', 'account-blacklist-files' ]) private static readonly ownerUserInclude = new Set([ 'blacklist-rights' ]) private static readonly blacklistedInclude = new Set([ 'api', 'full-light', 'account-blacklist-files', 'thumbnails-blacklist', 'blacklist-rights' ]) private static readonly thumbnailsInclude = new Set([ 'api', 'full-light', 'account-blacklist-files', 'all-files', 'thumbnails', 'thumbnails-blacklist' ]) constructor (protected readonly sequelize: Sequelize) { super('get') } queryVideos (options: BuildVideoGetQueryOptions) { this.buildMainGetQuery(options) return this.runQuery(options) } private buildMainGetQuery (options: BuildVideoGetQueryOptions) { this.attributes = { '"video".*': '' } if (VideosModelGetQuerySubBuilder.thumbnailsInclude.has(options.type)) { this.includeThumbnails() } if (VideosModelGetQuerySubBuilder.blacklistedInclude.has(options.type)) { this.includeBlacklisted() } if (VideosModelGetQuerySubBuilder.accountInclude.has(options.type)) { this.includeChannels() this.includeAccounts() } if (VideosModelGetQuerySubBuilder.tagsInclude.has(options.type)) { this.includeTags() } if (VideosModelGetQuerySubBuilder.scheduleUpdateInclude.has(options.type)) { this.includeScheduleUpdate() } if (VideosModelGetQuerySubBuilder.liveInclude.has(options.type)) { this.includeLive() } if (options.userId && VideosModelGetQuerySubBuilder.userHistoryInclude.has(options.type)) { this.includeUserHistory(options.userId) } if (VideosModelGetQuerySubBuilder.ownerUserInclude.has(options.type)) { this.includeOwnerUser() } if (VideosModelGetQuerySubBuilder.trackersInclude.has(options.type)) { this.includeTrackers() } this.whereId(options) this.query = this.buildQuery(options) } private buildQuery (options: BuildVideoGetQueryOptions) { const order = VideosModelGetQuerySubBuilder.tagsInclude.has(options.type) ? 'ORDER BY "Tags"."name" ASC' : '' const from = `SELECT * FROM "video" ${this.where} LIMIT 1` return `${this.buildSelect()} FROM (${from}) AS "video" ${this.joins} ${order}` } }