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