]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/models/video/sql/video/video-model-get-query-builder.ts
Feature/Add replay privacy (#5692)
[github/Chocobozzz/PeerTube.git] / server / models / video / sql / video / video-model-get-query-builder.ts
CommitLineData
d9bf974f 1import { Sequelize, Transaction } from 'sequelize'
2ec349aa 2import { pick } from '@shared/core-utils'
7e7d8e48 3import { AbstractVideoQueryBuilder } from './shared/abstract-video-query-builder'
1d43c3a6
C
4import { VideoFileQueryBuilder } from './shared/video-file-query-builder'
5import { VideoModelBuilder } from './shared/video-model-builder'
7e7d8e48 6import { VideoTableAttributes } from './shared/video-table-attributes'
1d43c3a6
C
7
8/**
9 *
10 * Build a GET SQL query, fetch rows and create the video model
11 *
12 */
d9bf974f 13
20a206c3
C
14export type GetType =
15 'api' |
4fae2b1f 16 'full' |
20a206c3
C
17 'account-blacklist-files' |
18 'all-files' |
19 'thumbnails' |
20 'thumbnails-blacklist' |
21 'id' |
22 'blacklist-rights'
23
d9bf974f 24export type BuildVideoGetQueryOptions = {
71d4af1e
C
25 id?: number | string
26 url?: string
27
20a206c3 28 type: GetType
71d4af1e 29
d9bf974f 30 userId?: number
71d4af1e
C
31 transaction?: Transaction
32
33 logging?: boolean
d9bf974f
C
34}
35
3c10840f 36export class VideoModelGetQueryBuilder {
1d43c3a6
C
37 videoQueryBuilder: VideosModelGetQuerySubBuilder
38 webtorrentFilesQueryBuilder: VideoFileQueryBuilder
39 streamingPlaylistFilesQueryBuilder: VideoFileQueryBuilder
40
41 private readonly videoModelBuilder: VideoModelBuilder
42
4fae2b1f 43 private static readonly videoFilesInclude = new Set<GetType>([ 'api', 'full', 'account-blacklist-files', 'all-files' ])
20a206c3 44
1d43c3a6
C
45 constructor (protected readonly sequelize: Sequelize) {
46 this.videoQueryBuilder = new VideosModelGetQuerySubBuilder(sequelize)
47 this.webtorrentFilesQueryBuilder = new VideoFileQueryBuilder(sequelize)
48 this.streamingPlaylistFilesQueryBuilder = new VideoFileQueryBuilder(sequelize)
49
7e7d8e48 50 this.videoModelBuilder = new VideoModelBuilder('get', new VideoTableAttributes('get'))
1d43c3a6
C
51 }
52
71d4af1e 53 async queryVideo (options: BuildVideoGetQueryOptions) {
7fb45bda
C
54 const fileQueryOptions = {
55 ...pick(options, [ 'id', 'url', 'transaction', 'logging' ]),
56
57 includeRedundancy: this.shouldIncludeRedundancies(options)
58 }
59
1d43c3a6
C
60 const [ videoRows, webtorrentFilesRows, streamingPlaylistFilesRows ] = await Promise.all([
61 this.videoQueryBuilder.queryVideos(options),
71d4af1e 62
3c10840f 63 VideoModelGetQueryBuilder.videoFilesInclude.has(options.type)
7fb45bda 64 ? this.webtorrentFilesQueryBuilder.queryWebTorrentVideos(fileQueryOptions)
71d4af1e
C
65 : Promise.resolve(undefined),
66
3c10840f 67 VideoModelGetQueryBuilder.videoFilesInclude.has(options.type)
7fb45bda 68 ? this.streamingPlaylistFilesQueryBuilder.queryStreamingPlaylistVideos(fileQueryOptions)
71d4af1e 69 : Promise.resolve(undefined)
1d43c3a6
C
70 ])
71
2760b454
C
72 const videos = this.videoModelBuilder.buildVideosFromRows({
73 rows: videoRows,
74 rowsWebTorrentFiles: webtorrentFilesRows,
75 rowsStreamingPlaylist: streamingPlaylistFilesRows
76 })
1d43c3a6
C
77
78 if (videos.length > 1) {
7e7d8e48 79 throw new Error('Video results is more than 1')
1d43c3a6
C
80 }
81
82 if (videos.length === 0) return null
7e7d8e48 83
1d43c3a6
C
84 return videos[0]
85 }
7fb45bda
C
86
87 private shouldIncludeRedundancies (options: BuildVideoGetQueryOptions) {
88 return options.type === 'api'
89 }
1d43c3a6
C
90}
91
7e7d8e48 92export class VideosModelGetQuerySubBuilder extends AbstractVideoQueryBuilder {
d9bf974f 93 protected attributes: { [key: string]: string }
1d43c3a6
C
94
95 protected webtorrentFilesQuery: string
96 protected streamingPlaylistFilesQuery: string
d9bf974f 97
20a206c3 98 private static readonly trackersInclude = new Set<GetType>([ 'api' ])
4fae2b1f
C
99 private static readonly liveInclude = new Set<GetType>([ 'api', 'full' ])
100 private static readonly scheduleUpdateInclude = new Set<GetType>([ 'api', 'full' ])
101 private static readonly tagsInclude = new Set<GetType>([ 'api', 'full' ])
102 private static readonly userHistoryInclude = new Set<GetType>([ 'api', 'full' ])
103 private static readonly accountInclude = new Set<GetType>([ 'api', 'full', 'account-blacklist-files' ])
20a206c3
C
104 private static readonly ownerUserInclude = new Set<GetType>([ 'blacklist-rights' ])
105
106 private static readonly blacklistedInclude = new Set<GetType>([
107 'api',
4fae2b1f 108 'full',
20a206c3
C
109 'account-blacklist-files',
110 'thumbnails-blacklist',
111 'blacklist-rights'
112 ])
113
114 private static readonly thumbnailsInclude = new Set<GetType>([
115 'api',
4fae2b1f 116 'full',
20a206c3 117 'account-blacklist-files',
adddb12b 118 'all-files',
20a206c3
C
119 'thumbnails',
120 'thumbnails-blacklist'
121 ])
122
d9bf974f 123 constructor (protected readonly sequelize: Sequelize) {
156c44c8 124 super(sequelize, 'get')
d9bf974f
C
125 }
126
127 queryVideos (options: BuildVideoGetQueryOptions) {
1d43c3a6 128 this.buildMainGetQuery(options)
d9bf974f 129
71d4af1e 130 return this.runQuery(options)
d9bf974f
C
131 }
132
1d43c3a6 133 private buildMainGetQuery (options: BuildVideoGetQueryOptions) {
d9bf974f
C
134 this.attributes = {
135 '"video".*': ''
136 }
137
20a206c3 138 if (VideosModelGetQuerySubBuilder.thumbnailsInclude.has(options.type)) {
71d4af1e
C
139 this.includeThumbnails()
140 }
d9bf974f 141
20a206c3 142 if (VideosModelGetQuerySubBuilder.blacklistedInclude.has(options.type)) {
71d4af1e
C
143 this.includeBlacklisted()
144 }
d9bf974f 145
20a206c3 146 if (VideosModelGetQuerySubBuilder.accountInclude.has(options.type)) {
71d4af1e
C
147 this.includeChannels()
148 this.includeAccounts()
149 }
d9bf974f 150
20a206c3 151 if (VideosModelGetQuerySubBuilder.tagsInclude.has(options.type)) {
71d4af1e
C
152 this.includeTags()
153 }
d9bf974f 154
20a206c3 155 if (VideosModelGetQuerySubBuilder.scheduleUpdateInclude.has(options.type)) {
71d4af1e
C
156 this.includeScheduleUpdate()
157 }
d9bf974f 158
20a206c3 159 if (VideosModelGetQuerySubBuilder.liveInclude.has(options.type)) {
71d4af1e
C
160 this.includeLive()
161 }
d9bf974f 162
20a206c3 163 if (options.userId && VideosModelGetQuerySubBuilder.userHistoryInclude.has(options.type)) {
d9bf974f
C
164 this.includeUserHistory(options.userId)
165 }
166
20a206c3 167 if (VideosModelGetQuerySubBuilder.ownerUserInclude.has(options.type)) {
71d4af1e
C
168 this.includeOwnerUser()
169 }
170
20a206c3 171 if (VideosModelGetQuerySubBuilder.trackersInclude.has(options.type)) {
d9bf974f 172 this.includeTrackers()
d9bf974f
C
173 }
174
71d4af1e 175 this.whereId(options)
d9bf974f 176
71d4af1e 177 this.query = this.buildQuery(options)
d9bf974f
C
178 }
179
71d4af1e 180 private buildQuery (options: BuildVideoGetQueryOptions) {
20a206c3 181 const order = VideosModelGetQuerySubBuilder.tagsInclude.has(options.type)
71d4af1e
C
182 ? 'ORDER BY "Tags"."name" ASC'
183 : ''
184
1d43c3a6 185 const from = `SELECT * FROM "video" ${this.where} LIMIT 1`
d9bf974f 186
3c79c2ce 187 return `${this.buildSelect()} FROM (${from}) AS "video" ${this.joins} ${order}`
d9bf974f
C
188 }
189}