]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - server/models/video/sql/video-model-get-query-builder.ts
Update changelog
[github/Chocobozzz/PeerTube.git] / server / models / video / sql / video-model-get-query-builder.ts
index 0a3723e632aa4a68eb7f134803e3244634c761c3..a65c96097cae77741f21d7728f4677548eca8d41 100644 (file)
 import { Sequelize, Transaction } from 'sequelize'
-import validator from 'validator'
-import { AbstractVideosModelQueryBuilder } from './shared/abstract-videos-model-query-builder'
+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
-  transaction?: Transaction
+  id?: number | string
+  url?: string
+
+  type: GetType
+
   userId?: number
-  forGetAPI?: boolean
+  transaction?: Transaction
+
+  logging?: boolean
 }
 
-export class VideosModelGetQueryBuilder extends AbstractVideosModelQueryBuilder {
-  protected attributes: { [key: string]: string }
-  protected joins: string[] = []
-  protected where: string
+export class VideoModelGetQueryBuilder {
+  videoQueryBuilder: VideosModelGetQuerySubBuilder
+  webtorrentFilesQueryBuilder: VideoFileQueryBuilder
+  streamingPlaylistFilesQueryBuilder: VideoFileQueryBuilder
+
+  private readonly videoModelBuilder: VideoModelBuilder
+
+  private static readonly videoFilesInclude = new Set<GetType>([ 'api', 'full-light', 'account-blacklist-files', 'all-files' ])
 
   constructor (protected readonly sequelize: Sequelize) {
-    super('get')
+    this.videoQueryBuilder = new VideosModelGetQuerySubBuilder(sequelize)
+    this.webtorrentFilesQueryBuilder = new VideoFileQueryBuilder(sequelize)
+    this.streamingPlaylistFilesQueryBuilder = new VideoFileQueryBuilder(sequelize)
+
+    this.videoModelBuilder = new VideoModelBuilder('get', new VideoTableAttributes('get'))
   }
 
-  queryVideos (options: BuildVideoGetQueryOptions) {
-    this.buildGetQuery(options)
+  async queryVideo (options: BuildVideoGetQueryOptions) {
+    const [ videoRows, webtorrentFilesRows, streamingPlaylistFilesRows ] = await Promise.all([
+      this.videoQueryBuilder.queryVideos(options),
 
-    return this.runQuery(options.transaction, true).then(rows => {
-      const videos = this.videoModelBuilder.buildVideosFromRows(rows)
+      VideoModelGetQueryBuilder.videoFilesInclude.has(options.type)
+        ? this.webtorrentFilesQueryBuilder.queryWebTorrentVideos(options)
+        : Promise.resolve(undefined),
 
-      if (videos.length > 1) {
-        throw new Error('Video results is more than ')
-      }
+      VideoModelGetQueryBuilder.videoFilesInclude.has(options.type)
+        ? this.streamingPlaylistFilesQueryBuilder.queryStreamingPlaylistVideos(options)
+        : Promise.resolve(undefined)
+    ])
 
-      if (videos.length === 0) return null
-      return videos[0]
+    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 }
 
-  private buildGetQuery (options: BuildVideoGetQueryOptions) {
+  protected webtorrentFilesQuery: string
+  protected streamingPlaylistFilesQuery: string
+
+  private static readonly trackersInclude = new Set<GetType>([ 'api' ])
+  private static readonly liveInclude = new Set<GetType>([ 'api', 'full-light' ])
+  private static readonly scheduleUpdateInclude = new Set<GetType>([ 'api', 'full-light' ])
+  private static readonly tagsInclude = new Set<GetType>([ 'api', 'full-light' ])
+  private static readonly userHistoryInclude = new Set<GetType>([ 'api', 'full-light' ])
+  private static readonly accountInclude = new Set<GetType>([ 'api', 'full-light', 'account-blacklist-files' ])
+  private static readonly ownerUserInclude = new Set<GetType>([ 'blacklist-rights' ])
+
+  private static readonly blacklistedInclude = new Set<GetType>([
+    'api',
+    'full-light',
+    'account-blacklist-files',
+    'thumbnails-blacklist',
+    'blacklist-rights'
+  ])
+
+  private static readonly thumbnailsInclude = new Set<GetType>([
+    '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".*': ''
     }
 
-    this.includeChannels()
-    this.includeAccounts()
-
-    this.includeTags()
+    if (VideosModelGetQuerySubBuilder.thumbnailsInclude.has(options.type)) {
+      this.includeThumbnails()
+    }
 
-    this.includeThumbnails()
+    if (VideosModelGetQuerySubBuilder.blacklistedInclude.has(options.type)) {
+      this.includeBlacklisted()
+    }
 
-    this.includeFiles()
+    if (VideosModelGetQuerySubBuilder.accountInclude.has(options.type)) {
+      this.includeChannels()
+      this.includeAccounts()
+    }
 
-    this.includeBlacklisted()
+    if (VideosModelGetQuerySubBuilder.tagsInclude.has(options.type)) {
+      this.includeTags()
+    }
 
-    this.includeScheduleUpdate()
+    if (VideosModelGetQuerySubBuilder.scheduleUpdateInclude.has(options.type)) {
+      this.includeScheduleUpdate()
+    }
 
-    this.includeLive()
+    if (VideosModelGetQuerySubBuilder.liveInclude.has(options.type)) {
+      this.includeLive()
+    }
 
-    if (options.userId) {
+    if (options.userId && VideosModelGetQuerySubBuilder.userHistoryInclude.has(options.type)) {
       this.includeUserHistory(options.userId)
     }
 
-    if (options.forGetAPI === true) {
-      this.includeTrackers()
-      this.includeRedundancies()
+    if (VideosModelGetQuerySubBuilder.ownerUserInclude.has(options.type)) {
+      this.includeOwnerUser()
     }
 
-    this.whereId(options.id)
+    if (VideosModelGetQuerySubBuilder.trackersInclude.has(options.type)) {
+      this.includeTrackers()
+    }
 
-    const select = this.buildSelect()
-    const order = this.buildOrder()
+    this.whereId(options)
 
-    this.query = `${select} FROM "video" ${this.joins.join(' ')} ${this.where} ${order}`
+    this.query = this.buildQuery(options)
   }
 
-  private whereId (id: string | number) {
-    if (validator.isInt('' + id)) {
-      this.where = 'WHERE "video".id = :videoId'
-    } else {
-      this.where = 'WHERE uuid = :videoId'
-    }
+  private buildQuery (options: BuildVideoGetQueryOptions) {
+    const order = VideosModelGetQuerySubBuilder.tagsInclude.has(options.type)
+      ? 'ORDER BY "Tags"."name" ASC'
+      : ''
 
-    this.replacements.videoId = id
-  }
+    const from = `SELECT * FROM "video" ${this.where} LIMIT 1`
 
-  private buildOrder () {
-    return 'ORDER BY "Tags"."name" ASC'
+    return `${this.buildSelect()} FROM (${from}) AS "video" ${this.joins} ${order}`
   }
 }