diff options
Diffstat (limited to 'server/models/video/sql')
7 files changed, 157 insertions, 49 deletions
diff --git a/server/models/video/sql/shared/abstract-videos-model-query-builder.ts b/server/models/video/sql/shared/abstract-videos-model-query-builder.ts index 65df8d914..d959cb5d0 100644 --- a/server/models/video/sql/shared/abstract-videos-model-query-builder.ts +++ b/server/models/video/sql/shared/abstract-videos-model-query-builder.ts | |||
@@ -80,6 +80,18 @@ export class AbstractVideosModelQueryBuilder extends AbstractVideosQueryBuilder | |||
80 | } | 80 | } |
81 | } | 81 | } |
82 | 82 | ||
83 | protected includeOwnerUser () { | ||
84 | this.addJoin('INNER JOIN "videoChannel" AS "VideoChannel" ON "video"."channelId" = "VideoChannel"."id"') | ||
85 | this.addJoin('INNER JOIN "account" AS "VideoChannel->Account" ON "VideoChannel"."accountId" = "VideoChannel->Account"."id"') | ||
86 | |||
87 | this.attributes = { | ||
88 | ...this.attributes, | ||
89 | |||
90 | ...this.buildAttributesObject('VideoChannel', this.tables.getChannelAttributes()), | ||
91 | ...this.buildAttributesObject('VideoChannel->Account', this.tables.getUserAccountAttributes()) | ||
92 | } | ||
93 | } | ||
94 | |||
83 | protected includeThumbnails () { | 95 | protected includeThumbnails () { |
84 | this.addJoin('LEFT OUTER JOIN "thumbnail" AS "Thumbnails" ON "video"."id" = "Thumbnails"."videoId"') | 96 | this.addJoin('LEFT OUTER JOIN "thumbnail" AS "Thumbnails" ON "video"."id" = "Thumbnails"."videoId"') |
85 | 97 | ||
@@ -269,14 +281,20 @@ export class AbstractVideosModelQueryBuilder extends AbstractVideosQueryBuilder | |||
269 | return result | 281 | return result |
270 | } | 282 | } |
271 | 283 | ||
272 | protected whereId (id: string | number) { | 284 | protected whereId (options: { id?: string | number, url?: string }) { |
273 | if (validator.isInt('' + id)) { | 285 | if (options.url) { |
286 | this.where = 'WHERE "video"."url" = :videoUrl' | ||
287 | this.replacements.videoUrl = options.url | ||
288 | return | ||
289 | } | ||
290 | |||
291 | if (validator.isInt('' + options.id)) { | ||
274 | this.where = 'WHERE "video".id = :videoId' | 292 | this.where = 'WHERE "video".id = :videoId' |
275 | } else { | 293 | } else { |
276 | this.where = 'WHERE uuid = :videoId' | 294 | this.where = 'WHERE uuid = :videoId' |
277 | } | 295 | } |
278 | 296 | ||
279 | this.replacements.videoId = id | 297 | this.replacements.videoId = options.id |
280 | } | 298 | } |
281 | 299 | ||
282 | protected addJoin (join: string) { | 300 | protected addJoin (join: string) { |
diff --git a/server/models/video/sql/shared/abstract-videos-query-builder.ts b/server/models/video/sql/shared/abstract-videos-query-builder.ts index 7e67fa34f..10699317a 100644 --- a/server/models/video/sql/shared/abstract-videos-query-builder.ts +++ b/server/models/video/sql/shared/abstract-videos-query-builder.ts | |||
@@ -13,16 +13,17 @@ export class AbstractVideosQueryBuilder { | |||
13 | protected query: string | 13 | protected query: string |
14 | protected replacements: any = {} | 14 | protected replacements: any = {} |
15 | 15 | ||
16 | protected runQuery (transaction?: Transaction) { | 16 | protected runQuery (options: { transaction?: Transaction, logging?: boolean } = {}) { |
17 | logger.debug('Running videos query.', { query: this.query, replacements: this.replacements }) | 17 | logger.debug('Running videos query.', { query: this.query, replacements: this.replacements }) |
18 | 18 | ||
19 | const options = { | 19 | const queryOptions = { |
20 | transaction, | 20 | transaction: options.transaction, |
21 | logging: options.logging, | ||
21 | replacements: this.replacements, | 22 | replacements: this.replacements, |
22 | type: QueryTypes.SELECT as QueryTypes.SELECT, | 23 | type: QueryTypes.SELECT as QueryTypes.SELECT, |
23 | next: false | 24 | next: false |
24 | } | 25 | } |
25 | 26 | ||
26 | return this.sequelize.query<any>(this.query, options) | 27 | return this.sequelize.query<any>(this.query, queryOptions) |
27 | } | 28 | } |
28 | } | 29 | } |
diff --git a/server/models/video/sql/shared/video-file-query-builder.ts b/server/models/video/sql/shared/video-file-query-builder.ts index 7d822f8fa..a62fa64f8 100644 --- a/server/models/video/sql/shared/video-file-query-builder.ts +++ b/server/models/video/sql/shared/video-file-query-builder.ts | |||
@@ -18,13 +18,13 @@ export class VideoFileQueryBuilder extends AbstractVideosModelQueryBuilder { | |||
18 | queryWebTorrentVideos (options: BuildVideoGetQueryOptions) { | 18 | queryWebTorrentVideos (options: BuildVideoGetQueryOptions) { |
19 | this.buildWebtorrentFilesQuery(options) | 19 | this.buildWebtorrentFilesQuery(options) |
20 | 20 | ||
21 | return this.runQuery(options.transaction) | 21 | return this.runQuery(options) |
22 | } | 22 | } |
23 | 23 | ||
24 | queryStreamingPlaylistVideos (options: BuildVideoGetQueryOptions) { | 24 | queryStreamingPlaylistVideos (options: BuildVideoGetQueryOptions) { |
25 | this.buildVideoStreamingPlaylistFilesQuery(options) | 25 | this.buildVideoStreamingPlaylistFilesQuery(options) |
26 | 26 | ||
27 | return this.runQuery(options.transaction) | 27 | return this.runQuery(options) |
28 | } | 28 | } |
29 | 29 | ||
30 | private buildWebtorrentFilesQuery (options: BuildVideoGetQueryOptions) { | 30 | private buildWebtorrentFilesQuery (options: BuildVideoGetQueryOptions) { |
@@ -34,11 +34,11 @@ export class VideoFileQueryBuilder extends AbstractVideosModelQueryBuilder { | |||
34 | 34 | ||
35 | this.includeWebtorrentFiles(true) | 35 | this.includeWebtorrentFiles(true) |
36 | 36 | ||
37 | if (options.forGetAPI === true) { | 37 | if (this.shouldIncludeRedundancies(options)) { |
38 | this.includeWebTorrentRedundancies() | 38 | this.includeWebTorrentRedundancies() |
39 | } | 39 | } |
40 | 40 | ||
41 | this.whereId(options.id) | 41 | this.whereId(options) |
42 | 42 | ||
43 | this.query = this.buildQuery() | 43 | this.query = this.buildQuery() |
44 | } | 44 | } |
@@ -50,11 +50,11 @@ export class VideoFileQueryBuilder extends AbstractVideosModelQueryBuilder { | |||
50 | 50 | ||
51 | this.includeStreamingPlaylistFiles(true) | 51 | this.includeStreamingPlaylistFiles(true) |
52 | 52 | ||
53 | if (options.forGetAPI === true) { | 53 | if (this.shouldIncludeRedundancies(options)) { |
54 | this.includeStreamingPlaylistRedundancies() | 54 | this.includeStreamingPlaylistRedundancies() |
55 | } | 55 | } |
56 | 56 | ||
57 | this.whereId(options.id) | 57 | this.whereId(options) |
58 | 58 | ||
59 | this.query = this.buildQuery() | 59 | this.query = this.buildQuery() |
60 | } | 60 | } |
@@ -62,4 +62,8 @@ export class VideoFileQueryBuilder extends AbstractVideosModelQueryBuilder { | |||
62 | private buildQuery () { | 62 | private buildQuery () { |
63 | return `${this.buildSelect()} FROM "video" ${this.joins} ${this.where}` | 63 | return `${this.buildSelect()} FROM "video" ${this.joins} ${this.where}` |
64 | } | 64 | } |
65 | |||
66 | private shouldIncludeRedundancies (options: BuildVideoGetQueryOptions) { | ||
67 | return options.type === 'api' | ||
68 | } | ||
65 | } | 69 | } |
diff --git a/server/models/video/sql/shared/video-model-builder.ts b/server/models/video/sql/shared/video-model-builder.ts index 2a60dab04..467a9378a 100644 --- a/server/models/video/sql/shared/video-model-builder.ts +++ b/server/models/video/sql/shared/video-model-builder.ts | |||
@@ -1,5 +1,4 @@ | |||
1 | 1 | ||
2 | import { logger } from '@server/helpers/logger' | ||
3 | import { AccountModel } from '@server/models/account/account' | 2 | import { AccountModel } from '@server/models/account/account' |
4 | import { ActorModel } from '@server/models/actor/actor' | 3 | import { ActorModel } from '@server/models/actor/actor' |
5 | import { ActorImageModel } from '@server/models/actor/actor-image' | 4 | import { ActorImageModel } from '@server/models/actor/actor-image' |
@@ -56,7 +55,7 @@ export class VideoModelBuilder { | |||
56 | this.reinit() | 55 | this.reinit() |
57 | 56 | ||
58 | for (const row of rows) { | 57 | for (const row of rows) { |
59 | this.buildVideo(row) | 58 | this.buildVideoAndAccount(row) |
60 | 59 | ||
61 | const videoModel = this.videosMemo[row.id] | 60 | const videoModel = this.videosMemo[row.id] |
62 | 61 | ||
@@ -131,22 +130,10 @@ export class VideoModelBuilder { | |||
131 | } | 130 | } |
132 | } | 131 | } |
133 | 132 | ||
134 | private buildVideo (row: SQLRow) { | 133 | private buildVideoAndAccount (row: SQLRow) { |
135 | if (this.videosMemo[row.id]) return | 134 | if (this.videosMemo[row.id]) return |
136 | 135 | ||
137 | // Build Channel | ||
138 | const channelModel = new VideoChannelModel(this.grab(row, this.tables.getChannelAttributes(), 'VideoChannel'), this.buildOpts) | ||
139 | channelModel.Actor = this.buildActor(row, 'VideoChannel') | ||
140 | |||
141 | const accountModel = new AccountModel(this.grab(row, this.tables.getAccountAttributes(), 'VideoChannel.Account'), this.buildOpts) | ||
142 | accountModel.Actor = this.buildActor(row, 'VideoChannel.Account') | ||
143 | |||
144 | channelModel.Account = accountModel | ||
145 | |||
146 | const videoModel = new VideoModel(this.grab(row, this.tables.getVideoAttributes(), ''), this.buildOpts) | 136 | const videoModel = new VideoModel(this.grab(row, this.tables.getVideoAttributes(), ''), this.buildOpts) |
147 | videoModel.VideoChannel = channelModel | ||
148 | |||
149 | this.videosMemo[row.id] = videoModel | ||
150 | 137 | ||
151 | videoModel.UserVideoHistories = [] | 138 | videoModel.UserVideoHistories = [] |
152 | videoModel.Thumbnails = [] | 139 | videoModel.Thumbnails = [] |
@@ -155,10 +142,29 @@ export class VideoModelBuilder { | |||
155 | videoModel.Tags = [] | 142 | videoModel.Tags = [] |
156 | videoModel.Trackers = [] | 143 | videoModel.Trackers = [] |
157 | 144 | ||
145 | this.buildAccount(row, videoModel) | ||
146 | |||
147 | this.videosMemo[row.id] = videoModel | ||
148 | |||
158 | // Keep rows order | 149 | // Keep rows order |
159 | this.videos.push(videoModel) | 150 | this.videos.push(videoModel) |
160 | } | 151 | } |
161 | 152 | ||
153 | private buildAccount (row: SQLRow, videoModel: VideoModel) { | ||
154 | const id = row['VideoChannel.Account.id'] | ||
155 | if (!id) return | ||
156 | |||
157 | const channelModel = new VideoChannelModel(this.grab(row, this.tables.getChannelAttributes(), 'VideoChannel'), this.buildOpts) | ||
158 | channelModel.Actor = this.buildActor(row, 'VideoChannel') | ||
159 | |||
160 | const accountModel = new AccountModel(this.grab(row, this.tables.getAccountAttributes(), 'VideoChannel.Account'), this.buildOpts) | ||
161 | accountModel.Actor = this.buildActor(row, 'VideoChannel.Account') | ||
162 | |||
163 | channelModel.Account = accountModel | ||
164 | |||
165 | videoModel.VideoChannel = channelModel | ||
166 | } | ||
167 | |||
162 | private buildActor (row: SQLRow, prefix: string) { | 168 | private buildActor (row: SQLRow, prefix: string) { |
163 | const actorPrefix = `${prefix}.Actor` | 169 | const actorPrefix = `${prefix}.Actor` |
164 | const avatarPrefix = `${actorPrefix}.Avatar` | 170 | const avatarPrefix = `${actorPrefix}.Avatar` |
diff --git a/server/models/video/sql/shared/video-tables.ts b/server/models/video/sql/shared/video-tables.ts index fddf1210c..52929fa5e 100644 --- a/server/models/video/sql/shared/video-tables.ts +++ b/server/models/video/sql/shared/video-tables.ts | |||
@@ -10,6 +10,10 @@ export class VideoTables { | |||
10 | 10 | ||
11 | } | 11 | } |
12 | 12 | ||
13 | getChannelAttributesForUser () { | ||
14 | return [ 'id', 'accountId' ] | ||
15 | } | ||
16 | |||
13 | getChannelAttributes () { | 17 | getChannelAttributes () { |
14 | let attributeKeys = [ | 18 | let attributeKeys = [ |
15 | 'id', | 19 | 'id', |
@@ -29,6 +33,10 @@ export class VideoTables { | |||
29 | return attributeKeys | 33 | return attributeKeys |
30 | } | 34 | } |
31 | 35 | ||
36 | getUserAccountAttributes () { | ||
37 | return [ 'id', 'userId' ] | ||
38 | } | ||
39 | |||
32 | getAccountAttributes () { | 40 | getAccountAttributes () { |
33 | let attributeKeys = [ 'id', 'name', 'actorId' ] | 41 | let attributeKeys = [ 'id', 'name', 'actorId' ] |
34 | 42 | ||
diff --git a/server/models/video/sql/video-model-get-query-builder.ts b/server/models/video/sql/video-model-get-query-builder.ts index 4aab9ff1d..f56fdd474 100644 --- a/server/models/video/sql/video-model-get-query-builder.ts +++ b/server/models/video/sql/video-model-get-query-builder.ts | |||
@@ -11,10 +11,15 @@ import { VideoTables } from './shared/video-tables' | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | export type BuildVideoGetQueryOptions = { | 13 | export type BuildVideoGetQueryOptions = { |
14 | id: number | string | 14 | id?: number | string |
15 | transaction?: Transaction | 15 | url?: string |
16 | |||
17 | type: 'api' | 'full-light' | 'account-blacklist-files' | 'all-files' | 'thumbnails' | 'thumbnails-blacklist' | 'id' | 'blacklist-rights' | ||
18 | |||
16 | userId?: number | 19 | userId?: number |
17 | forGetAPI?: boolean | 20 | transaction?: Transaction |
21 | |||
22 | logging?: boolean | ||
18 | } | 23 | } |
19 | 24 | ||
20 | export class VideosModelGetQueryBuilder { | 25 | export class VideosModelGetQueryBuilder { |
@@ -32,11 +37,17 @@ export class VideosModelGetQueryBuilder { | |||
32 | this.videoModelBuilder = new VideoModelBuilder('get', new VideoTables('get')) | 37 | this.videoModelBuilder = new VideoModelBuilder('get', new VideoTables('get')) |
33 | } | 38 | } |
34 | 39 | ||
35 | async queryVideos (options: BuildVideoGetQueryOptions) { | 40 | async queryVideo (options: BuildVideoGetQueryOptions) { |
36 | const [ videoRows, webtorrentFilesRows, streamingPlaylistFilesRows ] = await Promise.all([ | 41 | const [ videoRows, webtorrentFilesRows, streamingPlaylistFilesRows ] = await Promise.all([ |
37 | this.videoQueryBuilder.queryVideos(options), | 42 | this.videoQueryBuilder.queryVideos(options), |
38 | this.webtorrentFilesQueryBuilder.queryWebTorrentVideos(options), | 43 | |
39 | this.streamingPlaylistFilesQueryBuilder.queryStreamingPlaylistVideos(options) | 44 | this.shouldQueryVideoFiles(options) |
45 | ? this.webtorrentFilesQueryBuilder.queryWebTorrentVideos(options) | ||
46 | : Promise.resolve(undefined), | ||
47 | |||
48 | this.shouldQueryVideoFiles(options) | ||
49 | ? this.streamingPlaylistFilesQueryBuilder.queryStreamingPlaylistVideos(options) | ||
50 | : Promise.resolve(undefined) | ||
40 | ]) | 51 | ]) |
41 | 52 | ||
42 | const videos = this.videoModelBuilder.buildVideosFromRows(videoRows, webtorrentFilesRows, streamingPlaylistFilesRows) | 53 | const videos = this.videoModelBuilder.buildVideosFromRows(videoRows, webtorrentFilesRows, streamingPlaylistFilesRows) |
@@ -48,6 +59,10 @@ export class VideosModelGetQueryBuilder { | |||
48 | if (videos.length === 0) return null | 59 | if (videos.length === 0) return null |
49 | return videos[0] | 60 | return videos[0] |
50 | } | 61 | } |
62 | |||
63 | private shouldQueryVideoFiles (options: BuildVideoGetQueryOptions) { | ||
64 | return [ 'api', 'full-light', 'account-blacklist-files', 'all-files' ].includes(options.type) | ||
65 | } | ||
51 | } | 66 | } |
52 | 67 | ||
53 | export class VideosModelGetQuerySubBuilder extends AbstractVideosModelQueryBuilder { | 68 | export class VideosModelGetQuerySubBuilder extends AbstractVideosModelQueryBuilder { |
@@ -63,7 +78,7 @@ export class VideosModelGetQuerySubBuilder extends AbstractVideosModelQueryBuild | |||
63 | queryVideos (options: BuildVideoGetQueryOptions) { | 78 | queryVideos (options: BuildVideoGetQueryOptions) { |
64 | this.buildMainGetQuery(options) | 79 | this.buildMainGetQuery(options) |
65 | 80 | ||
66 | return this.runQuery(options.transaction) | 81 | return this.runQuery(options) |
67 | } | 82 | } |
68 | 83 | ||
69 | private buildMainGetQuery (options: BuildVideoGetQueryOptions) { | 84 | private buildMainGetQuery (options: BuildVideoGetQueryOptions) { |
@@ -71,36 +86,91 @@ export class VideosModelGetQuerySubBuilder extends AbstractVideosModelQueryBuild | |||
71 | '"video".*': '' | 86 | '"video".*': '' |
72 | } | 87 | } |
73 | 88 | ||
74 | this.includeChannels() | 89 | if (this.shouldIncludeThumbnails(options)) { |
75 | this.includeAccounts() | 90 | this.includeThumbnails() |
91 | } | ||
76 | 92 | ||
77 | this.includeTags() | 93 | if (this.shouldIncludeBlacklisted(options)) { |
94 | this.includeBlacklisted() | ||
95 | } | ||
78 | 96 | ||
79 | this.includeThumbnails() | 97 | if (this.shouldIncludeAccount(options)) { |
98 | this.includeChannels() | ||
99 | this.includeAccounts() | ||
100 | } | ||
80 | 101 | ||
81 | this.includeBlacklisted() | 102 | if (this.shouldIncludeTags(options)) { |
103 | this.includeTags() | ||
104 | } | ||
82 | 105 | ||
83 | this.includeScheduleUpdate() | 106 | if (this.shouldIncludeScheduleUpdate(options)) { |
107 | this.includeScheduleUpdate() | ||
108 | } | ||
84 | 109 | ||
85 | this.includeLive() | 110 | if (this.shouldIncludeLive(options)) { |
111 | this.includeLive() | ||
112 | } | ||
86 | 113 | ||
87 | if (options.userId) { | 114 | if (options.userId && this.shouldIncludeUserHistory(options)) { |
88 | this.includeUserHistory(options.userId) | 115 | this.includeUserHistory(options.userId) |
89 | } | 116 | } |
90 | 117 | ||
91 | if (options.forGetAPI === true) { | 118 | if (this.shouldIncludeOwnerUser(options)) { |
119 | this.includeOwnerUser() | ||
120 | } | ||
121 | |||
122 | if (this.shouldIncludeTrackers(options)) { | ||
92 | this.includeTrackers() | 123 | this.includeTrackers() |
93 | } | 124 | } |
94 | 125 | ||
95 | this.whereId(options.id) | 126 | this.whereId(options) |
96 | 127 | ||
97 | this.query = this.buildQuery() | 128 | this.query = this.buildQuery(options) |
98 | } | 129 | } |
99 | 130 | ||
100 | private buildQuery () { | 131 | private buildQuery (options: BuildVideoGetQueryOptions) { |
101 | const order = 'ORDER BY "Tags"."name" ASC' | 132 | const order = this.shouldIncludeTags(options) |
133 | ? 'ORDER BY "Tags"."name" ASC' | ||
134 | : '' | ||
135 | |||
102 | const from = `SELECT * FROM "video" ${this.where} LIMIT 1` | 136 | const from = `SELECT * FROM "video" ${this.where} LIMIT 1` |
103 | 137 | ||
104 | return `${this.buildSelect()} FROM (${from}) AS "video" ${this.joins} ${order}` | 138 | return `${this.buildSelect()} FROM (${from}) AS "video" ${this.joins} ${order}` |
105 | } | 139 | } |
140 | |||
141 | private shouldIncludeTrackers (options: BuildVideoGetQueryOptions) { | ||
142 | return options.type === 'api' | ||
143 | } | ||
144 | |||
145 | private shouldIncludeLive (options: BuildVideoGetQueryOptions) { | ||
146 | return [ 'api', 'full-light' ].includes(options.type) | ||
147 | } | ||
148 | |||
149 | private shouldIncludeScheduleUpdate (options: BuildVideoGetQueryOptions) { | ||
150 | return [ 'api', 'full-light' ].includes(options.type) | ||
151 | } | ||
152 | |||
153 | private shouldIncludeTags (options: BuildVideoGetQueryOptions) { | ||
154 | return [ 'api', 'full-light' ].includes(options.type) | ||
155 | } | ||
156 | |||
157 | private shouldIncludeUserHistory (options: BuildVideoGetQueryOptions) { | ||
158 | return [ 'api', 'full-light' ].includes(options.type) | ||
159 | } | ||
160 | |||
161 | private shouldIncludeAccount (options: BuildVideoGetQueryOptions) { | ||
162 | return [ 'api', 'full-light', 'account-blacklist-files' ].includes(options.type) | ||
163 | } | ||
164 | |||
165 | private shouldIncludeBlacklisted (options: BuildVideoGetQueryOptions) { | ||
166 | return [ 'api', 'full-light', 'account-blacklist-files', 'thumbnails-blacklist', 'blacklist-rights' ].includes(options.type) | ||
167 | } | ||
168 | |||
169 | private shouldIncludeOwnerUser (options: BuildVideoGetQueryOptions) { | ||
170 | return options.type === 'blacklist-rights' | ||
171 | } | ||
172 | |||
173 | private shouldIncludeThumbnails (options: BuildVideoGetQueryOptions) { | ||
174 | return [ 'api', 'full-light', 'account-blacklist-files', 'thumbnails', 'thumbnails-blacklist' ].includes(options.type) | ||
175 | } | ||
106 | } | 176 | } |
diff --git a/server/models/video/sql/videos-model-list-query-builder.ts b/server/models/video/sql/videos-model-list-query-builder.ts index d3a9a9466..43040fc5e 100644 --- a/server/models/video/sql/videos-model-list-query-builder.ts +++ b/server/models/video/sql/videos-model-list-query-builder.ts | |||
@@ -27,7 +27,8 @@ export class VideosModelListQueryBuilder extends AbstractVideosModelQueryBuilder | |||
27 | this.buildInnerQuery(options) | 27 | this.buildInnerQuery(options) |
28 | this.buildListQueryFromIdsQuery(options) | 28 | this.buildListQueryFromIdsQuery(options) |
29 | 29 | ||
30 | return this.runQuery(undefined).then(rows => this.videoModelBuilder.buildVideosFromRows(rows)) | 30 | return this.runQuery() |
31 | .then(rows => this.videoModelBuilder.buildVideosFromRows(rows)) | ||
31 | } | 32 | } |
32 | 33 | ||
33 | private buildInnerQuery (options: BuildVideosListQueryOptions) { | 34 | private buildInnerQuery (options: BuildVideosListQueryOptions) { |