diff options
author | Chocobozzz <me@florianbigard.com> | 2021-06-10 16:57:13 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2021-06-11 09:31:59 +0200 |
commit | 1d43c3a613c72d69f7360fee9e5bfe6f662d62f7 (patch) | |
tree | d4ba891ffdb1182e39620c06feff1503365d66b5 /server/models/video | |
parent | d9bf974f5df787bbeaab5b04949ca91a2b3ca2a3 (diff) | |
download | PeerTube-1d43c3a613c72d69f7360fee9e5bfe6f662d62f7.tar.gz PeerTube-1d43c3a613c72d69f7360fee9e5bfe6f662d62f7.tar.zst PeerTube-1d43c3a613c72d69f7360fee9e5bfe6f662d62f7.zip |
Use separate queries for video files
Diffstat (limited to 'server/models/video')
8 files changed, 231 insertions, 56 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 bdf926cbe..8ed207eea 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 | |||
@@ -1,19 +1,24 @@ | |||
1 | import validator from 'validator' | ||
1 | import { AbstractVideosQueryBuilder } from './abstract-videos-query-builder' | 2 | import { AbstractVideosQueryBuilder } from './abstract-videos-query-builder' |
2 | import { VideoAttributes } from './video-attributes' | 3 | import { VideoAttributes } from './video-attributes' |
3 | import { VideoModelBuilder } from './video-model-builder' | 4 | |
5 | /** | ||
6 | * | ||
7 | * Abstract builder to create SQL query and fetch video models | ||
8 | * | ||
9 | */ | ||
4 | 10 | ||
5 | export class AbstractVideosModelQueryBuilder extends AbstractVideosQueryBuilder { | 11 | export class AbstractVideosModelQueryBuilder extends AbstractVideosQueryBuilder { |
6 | protected attributes: { [key: string]: string } = {} | 12 | protected attributes: { [key: string]: string } = {} |
7 | protected joins: string[] = [] | 13 | protected joins: string[] = [] |
14 | protected where: string | ||
8 | 15 | ||
9 | protected videoAttributes: VideoAttributes | 16 | protected videoAttributes: VideoAttributes |
10 | protected videoModelBuilder: VideoModelBuilder | ||
11 | 17 | ||
12 | constructor (private readonly mode: 'list' | 'get') { | 18 | constructor (protected readonly mode: 'list' | 'get') { |
13 | super() | 19 | super() |
14 | 20 | ||
15 | this.videoAttributes = new VideoAttributes(this.mode) | 21 | this.videoAttributes = new VideoAttributes(this.mode) |
16 | this.videoModelBuilder = new VideoModelBuilder(this.mode, this.videoAttributes) | ||
17 | } | 22 | } |
18 | 23 | ||
19 | protected buildSelect () { | 24 | protected buildSelect () { |
@@ -78,21 +83,30 @@ export class AbstractVideosModelQueryBuilder extends AbstractVideosQueryBuilder | |||
78 | } | 83 | } |
79 | } | 84 | } |
80 | 85 | ||
81 | protected includeFiles () { | 86 | protected includeWebtorrentFiles (required: boolean) { |
82 | this.joins.push( | 87 | const joinType = required ? 'INNER' : 'LEFT' |
83 | 'LEFT JOIN "videoFile" AS "VideoFiles" ON "VideoFiles"."videoId" = "video"."id"', | 88 | this.joins.push(joinType + ' JOIN "videoFile" AS "VideoFiles" ON "VideoFiles"."videoId" = "video"."id"') |
89 | |||
90 | this.attributes = { | ||
91 | ...this.attributes, | ||
92 | |||
93 | ...this.buildAttributesObject('VideoFiles', this.videoAttributes.getFileAttributes()) | ||
94 | } | ||
95 | } | ||
96 | |||
97 | protected includeStreamingPlaylistFiles (required: boolean) { | ||
98 | const joinType = required ? 'INNER' : 'LEFT' | ||
84 | 99 | ||
85 | 'LEFT JOIN "videoStreamingPlaylist" AS "VideoStreamingPlaylists" ON "VideoStreamingPlaylists"."videoId" = "video"."id"', | 100 | this.joins.push( |
101 | joinType + ' JOIN "videoStreamingPlaylist" AS "VideoStreamingPlaylists" ON "VideoStreamingPlaylists"."videoId" = "video"."id"', | ||
86 | 102 | ||
87 | 'LEFT JOIN "videoFile" AS "VideoStreamingPlaylists->VideoFiles" ' + | 103 | joinType + ' JOIN "videoFile" AS "VideoStreamingPlaylists->VideoFiles" ' + |
88 | 'ON "VideoStreamingPlaylists->VideoFiles"."videoStreamingPlaylistId" = "VideoStreamingPlaylists"."id"' | 104 | 'ON "VideoStreamingPlaylists->VideoFiles"."videoStreamingPlaylistId" = "VideoStreamingPlaylists"."id"' |
89 | ) | 105 | ) |
90 | 106 | ||
91 | this.attributes = { | 107 | this.attributes = { |
92 | ...this.attributes, | 108 | ...this.attributes, |
93 | 109 | ||
94 | ...this.buildAttributesObject('VideoFiles', this.videoAttributes.getFileAttributes()), | ||
95 | |||
96 | ...this.buildAttributesObject('VideoStreamingPlaylists', this.videoAttributes.getStreamingPlaylistAttributes()), | 110 | ...this.buildAttributesObject('VideoStreamingPlaylists', this.videoAttributes.getStreamingPlaylistAttributes()), |
97 | ...this.buildAttributesObject('VideoStreamingPlaylists->VideoFiles', this.videoAttributes.getFileAttributes()) | 111 | ...this.buildAttributesObject('VideoStreamingPlaylists->VideoFiles', this.videoAttributes.getFileAttributes()) |
98 | } | 112 | } |
@@ -196,11 +210,8 @@ export class AbstractVideosModelQueryBuilder extends AbstractVideosQueryBuilder | |||
196 | } | 210 | } |
197 | } | 211 | } |
198 | 212 | ||
199 | protected includeRedundancies () { | 213 | protected includeWebTorrentRedundancies () { |
200 | this.joins.push( | 214 | this.joins.push( |
201 | 'LEFT OUTER JOIN "videoRedundancy" AS "VideoStreamingPlaylists->RedundancyVideos" ' + | ||
202 | 'ON "VideoStreamingPlaylists"."id" = "VideoStreamingPlaylists->RedundancyVideos"."videoStreamingPlaylistId"', | ||
203 | |||
204 | 'LEFT OUTER JOIN "videoRedundancy" AS "VideoFiles->RedundancyVideos" ON ' + | 215 | 'LEFT OUTER JOIN "videoRedundancy" AS "VideoFiles->RedundancyVideos" ON ' + |
205 | '"VideoFiles"."id" = "VideoFiles->RedundancyVideos"."videoFileId"' | 216 | '"VideoFiles"."id" = "VideoFiles->RedundancyVideos"."videoFileId"' |
206 | ) | 217 | ) |
@@ -208,7 +219,19 @@ export class AbstractVideosModelQueryBuilder extends AbstractVideosQueryBuilder | |||
208 | this.attributes = { | 219 | this.attributes = { |
209 | ...this.attributes, | 220 | ...this.attributes, |
210 | 221 | ||
211 | ...this.buildAttributesObject('VideoFiles->RedundancyVideos', this.videoAttributes.getRedundancyAttributes()), | 222 | ...this.buildAttributesObject('VideoFiles->RedundancyVideos', this.videoAttributes.getRedundancyAttributes()) |
223 | } | ||
224 | } | ||
225 | |||
226 | protected includeStreamingPlaylistRedundancies () { | ||
227 | this.joins.push( | ||
228 | 'LEFT OUTER JOIN "videoRedundancy" AS "VideoStreamingPlaylists->RedundancyVideos" ' + | ||
229 | 'ON "VideoStreamingPlaylists"."id" = "VideoStreamingPlaylists->RedundancyVideos"."videoStreamingPlaylistId"' | ||
230 | ) | ||
231 | |||
232 | this.attributes = { | ||
233 | ...this.attributes, | ||
234 | |||
212 | ...this.buildAttributesObject('VideoStreamingPlaylists->RedundancyVideos', this.videoAttributes.getRedundancyAttributes()) | 235 | ...this.buildAttributesObject('VideoStreamingPlaylists->RedundancyVideos', this.videoAttributes.getRedundancyAttributes()) |
213 | } | 236 | } |
214 | } | 237 | } |
@@ -236,4 +259,14 @@ export class AbstractVideosModelQueryBuilder extends AbstractVideosQueryBuilder | |||
236 | 259 | ||
237 | return result | 260 | return result |
238 | } | 261 | } |
262 | |||
263 | protected whereId (id: string | number) { | ||
264 | if (validator.isInt('' + id)) { | ||
265 | this.where = 'WHERE "video".id = :videoId' | ||
266 | } else { | ||
267 | this.where = 'WHERE uuid = :videoId' | ||
268 | } | ||
269 | |||
270 | this.replacements.videoId = id | ||
271 | } | ||
239 | } | 272 | } |
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 01694e691..c1bbeb71e 100644 --- a/server/models/video/sql/shared/abstract-videos-query-builder.ts +++ b/server/models/video/sql/shared/abstract-videos-query-builder.ts | |||
@@ -1,6 +1,12 @@ | |||
1 | import { QueryTypes, Sequelize, Transaction } from 'sequelize' | 1 | import { QueryTypes, Sequelize, Transaction } from 'sequelize' |
2 | import { logger } from '@server/helpers/logger' | 2 | import { logger } from '@server/helpers/logger' |
3 | 3 | ||
4 | /** | ||
5 | * | ||
6 | * Abstact builder to run video SQL queries | ||
7 | * | ||
8 | */ | ||
9 | |||
4 | export class AbstractVideosQueryBuilder { | 10 | export class AbstractVideosQueryBuilder { |
5 | protected sequelize: Sequelize | 11 | protected sequelize: Sequelize |
6 | 12 | ||
diff --git a/server/models/video/sql/shared/video-attributes.ts b/server/models/video/sql/shared/video-attributes.ts index 1a1650dc7..e21b33c73 100644 --- a/server/models/video/sql/shared/video-attributes.ts +++ b/server/models/video/sql/shared/video-attributes.ts | |||
@@ -1,3 +1,9 @@ | |||
1 | |||
2 | /** | ||
3 | * | ||
4 | * Class to build video attributes we want to fetch from the database | ||
5 | * | ||
6 | */ | ||
1 | export class VideoAttributes { | 7 | export class VideoAttributes { |
2 | 8 | ||
3 | constructor (readonly mode: 'get' | 'list') { | 9 | constructor (readonly mode: 'get' | 'list') { |
diff --git a/server/models/video/sql/shared/video-file-query-builder.ts b/server/models/video/sql/shared/video-file-query-builder.ts new file mode 100644 index 000000000..29b11a298 --- /dev/null +++ b/server/models/video/sql/shared/video-file-query-builder.ts | |||
@@ -0,0 +1,66 @@ | |||
1 | import { Sequelize } from 'sequelize' | ||
2 | import { BuildVideoGetQueryOptions } from '../video-model-get-query-builder' | ||
3 | import { AbstractVideosModelQueryBuilder } from './abstract-videos-model-query-builder' | ||
4 | |||
5 | /** | ||
6 | * | ||
7 | * Fetch files (webtorrent and streaming playlist) according to a video | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | export class VideoFileQueryBuilder extends AbstractVideosModelQueryBuilder { | ||
12 | protected attributes: { [key: string]: string } | ||
13 | protected joins: string[] = [] | ||
14 | |||
15 | constructor (protected readonly sequelize: Sequelize) { | ||
16 | super('get') | ||
17 | } | ||
18 | |||
19 | queryWebTorrentVideos (options: BuildVideoGetQueryOptions) { | ||
20 | this.buildWebtorrentFilesQuery(options) | ||
21 | |||
22 | return this.runQuery(options.transaction, true) | ||
23 | } | ||
24 | |||
25 | queryStreamingPlaylistVideos (options: BuildVideoGetQueryOptions) { | ||
26 | this.buildVideoStreamingPlaylistFilesQuery(options) | ||
27 | |||
28 | return this.runQuery(options.transaction, true) | ||
29 | } | ||
30 | |||
31 | private buildWebtorrentFilesQuery (options: BuildVideoGetQueryOptions) { | ||
32 | this.attributes = { | ||
33 | '"video"."id"': '' | ||
34 | } | ||
35 | |||
36 | this.includeWebtorrentFiles(true) | ||
37 | |||
38 | if (options.forGetAPI === true) { | ||
39 | this.includeWebTorrentRedundancies() | ||
40 | } | ||
41 | |||
42 | this.whereId(options.id) | ||
43 | |||
44 | this.query = this.buildQuery() | ||
45 | } | ||
46 | |||
47 | private buildVideoStreamingPlaylistFilesQuery (options: BuildVideoGetQueryOptions) { | ||
48 | this.attributes = { | ||
49 | '"video"."id"': '' | ||
50 | } | ||
51 | |||
52 | this.includeStreamingPlaylistFiles(true) | ||
53 | |||
54 | if (options.forGetAPI === true) { | ||
55 | this.includeStreamingPlaylistRedundancies() | ||
56 | } | ||
57 | |||
58 | this.whereId(options.id) | ||
59 | |||
60 | this.query = this.buildQuery() | ||
61 | } | ||
62 | |||
63 | private buildQuery () { | ||
64 | return `${this.buildSelect()} FROM "video" ${this.joins.join(' ')} ${this.where}` | ||
65 | } | ||
66 | } | ||
diff --git a/server/models/video/sql/shared/video-model-builder.ts b/server/models/video/sql/shared/video-model-builder.ts index 9719f6d2e..627ea6443 100644 --- a/server/models/video/sql/shared/video-model-builder.ts +++ b/server/models/video/sql/shared/video-model-builder.ts | |||
@@ -17,6 +17,12 @@ import { VideoLiveModel } from '../../video-live' | |||
17 | import { VideoStreamingPlaylistModel } from '../../video-streaming-playlist' | 17 | import { VideoStreamingPlaylistModel } from '../../video-streaming-playlist' |
18 | import { VideoAttributes } from './video-attributes' | 18 | import { VideoAttributes } from './video-attributes' |
19 | 19 | ||
20 | /** | ||
21 | * | ||
22 | * Build video models from SQL rows | ||
23 | * | ||
24 | */ | ||
25 | |||
20 | export class VideoModelBuilder { | 26 | export class VideoModelBuilder { |
21 | private videosMemo: { [ id: number ]: VideoModel } | 27 | private videosMemo: { [ id: number ]: VideoModel } |
22 | private videoStreamingPlaylistMemo: { [ id: number ]: VideoStreamingPlaylistModel } | 28 | private videoStreamingPlaylistMemo: { [ id: number ]: VideoStreamingPlaylistModel } |
@@ -43,7 +49,7 @@ export class VideoModelBuilder { | |||
43 | 49 | ||
44 | } | 50 | } |
45 | 51 | ||
46 | buildVideosFromRows (rows: any[]) { | 52 | buildVideosFromRows (rows: any[], rowsWebtorrentFiles?: any[], rowsStreamingPlaylist?: any[]) { |
47 | this.reinit() | 53 | this.reinit() |
48 | 54 | ||
49 | for (const row of rows) { | 55 | for (const row of rows) { |
@@ -53,10 +59,15 @@ export class VideoModelBuilder { | |||
53 | 59 | ||
54 | this.setUserHistory(row, videoModel) | 60 | this.setUserHistory(row, videoModel) |
55 | this.addThumbnail(row, videoModel) | 61 | this.addThumbnail(row, videoModel) |
56 | this.addWebTorrentFile(row, videoModel) | ||
57 | 62 | ||
58 | this.addStreamingPlaylist(row, videoModel) | 63 | if (!rowsWebtorrentFiles) { |
59 | this.addStreamingPlaylistFile(row) | 64 | this.addWebTorrentFile(row, videoModel) |
65 | } | ||
66 | |||
67 | if (!rowsStreamingPlaylist) { | ||
68 | this.addStreamingPlaylist(row, videoModel) | ||
69 | this.addStreamingPlaylistFile(row) | ||
70 | } | ||
60 | 71 | ||
61 | if (this.mode === 'get') { | 72 | if (this.mode === 'get') { |
62 | this.addTag(row, videoModel) | 73 | this.addTag(row, videoModel) |
@@ -65,16 +76,30 @@ export class VideoModelBuilder { | |||
65 | this.setScheduleVideoUpdate(row, videoModel) | 76 | this.setScheduleVideoUpdate(row, videoModel) |
66 | this.setLive(row, videoModel) | 77 | this.setLive(row, videoModel) |
67 | 78 | ||
68 | if (row.VideoFiles.id) { | 79 | if (!rowsWebtorrentFiles && row.VideoFiles.id) { |
69 | this.addRedundancy(row.VideoFiles.RedundancyVideos, this.videoFileMemo[row.VideoFiles.id]) | 80 | this.addRedundancy(row.VideoFiles.RedundancyVideos, this.videoFileMemo[row.VideoFiles.id]) |
70 | } | 81 | } |
71 | 82 | ||
72 | if (row.VideoStreamingPlaylists.id) { | 83 | if (!rowsStreamingPlaylist && row.VideoStreamingPlaylists.id) { |
73 | this.addRedundancy(row.VideoStreamingPlaylists.RedundancyVideos, this.videoStreamingPlaylistMemo[row.VideoStreamingPlaylists.id]) | 84 | this.addRedundancy(row.VideoStreamingPlaylists.RedundancyVideos, this.videoStreamingPlaylistMemo[row.VideoStreamingPlaylists.id]) |
74 | } | 85 | } |
75 | } | 86 | } |
76 | } | 87 | } |
77 | 88 | ||
89 | for (const row of rowsWebtorrentFiles || []) { | ||
90 | const videoModel = this.videosMemo[row.id] | ||
91 | this.addWebTorrentFile(row, videoModel) | ||
92 | this.addRedundancy(row.VideoFiles.RedundancyVideos, this.videoFileMemo[row.VideoFiles.id]) | ||
93 | } | ||
94 | |||
95 | for (const row of rowsStreamingPlaylist || []) { | ||
96 | const videoModel = this.videosMemo[row.id] | ||
97 | |||
98 | this.addStreamingPlaylist(row, videoModel) | ||
99 | this.addStreamingPlaylistFile(row) | ||
100 | this.addRedundancy(row.VideoStreamingPlaylists.RedundancyVideos, this.videoStreamingPlaylistMemo[row.VideoStreamingPlaylists.id]) | ||
101 | } | ||
102 | |||
78 | return this.videos | 103 | return this.videos |
79 | } | 104 | } |
80 | 105 | ||
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 0a3723e63..1a921d802 100644 --- a/server/models/video/sql/video-model-get-query-builder.ts +++ b/server/models/video/sql/video-model-get-query-builder.ts | |||
@@ -1,6 +1,14 @@ | |||
1 | import { Sequelize, Transaction } from 'sequelize' | 1 | import { Sequelize, Transaction } from 'sequelize' |
2 | import validator from 'validator' | ||
3 | import { AbstractVideosModelQueryBuilder } from './shared/abstract-videos-model-query-builder' | 2 | import { AbstractVideosModelQueryBuilder } from './shared/abstract-videos-model-query-builder' |
3 | import { VideoAttributes } from './shared/video-attributes' | ||
4 | import { VideoFileQueryBuilder } from './shared/video-file-query-builder' | ||
5 | import { VideoModelBuilder } from './shared/video-model-builder' | ||
6 | |||
7 | /** | ||
8 | * | ||
9 | * Build a GET SQL query, fetch rows and create the video model | ||
10 | * | ||
11 | */ | ||
4 | 12 | ||
5 | export type BuildVideoGetQueryOptions = { | 13 | export type BuildVideoGetQueryOptions = { |
6 | id: number | string | 14 | id: number | string |
@@ -9,31 +17,57 @@ export type BuildVideoGetQueryOptions = { | |||
9 | forGetAPI?: boolean | 17 | forGetAPI?: boolean |
10 | } | 18 | } |
11 | 19 | ||
12 | export class VideosModelGetQueryBuilder extends AbstractVideosModelQueryBuilder { | 20 | export class VideosModelGetQueryBuilder { |
21 | videoQueryBuilder: VideosModelGetQuerySubBuilder | ||
22 | webtorrentFilesQueryBuilder: VideoFileQueryBuilder | ||
23 | streamingPlaylistFilesQueryBuilder: VideoFileQueryBuilder | ||
24 | |||
25 | private readonly videoModelBuilder: VideoModelBuilder | ||
26 | |||
27 | constructor (protected readonly sequelize: Sequelize) { | ||
28 | this.videoQueryBuilder = new VideosModelGetQuerySubBuilder(sequelize) | ||
29 | this.webtorrentFilesQueryBuilder = new VideoFileQueryBuilder(sequelize) | ||
30 | this.streamingPlaylistFilesQueryBuilder = new VideoFileQueryBuilder(sequelize) | ||
31 | |||
32 | this.videoModelBuilder = new VideoModelBuilder('get', new VideoAttributes('get')) | ||
33 | } | ||
34 | |||
35 | async queryVideos (options: BuildVideoGetQueryOptions) { | ||
36 | const [ videoRows, webtorrentFilesRows, streamingPlaylistFilesRows ] = await Promise.all([ | ||
37 | this.videoQueryBuilder.queryVideos(options), | ||
38 | this.webtorrentFilesQueryBuilder.queryWebTorrentVideos(options), | ||
39 | this.streamingPlaylistFilesQueryBuilder.queryStreamingPlaylistVideos(options) | ||
40 | ]) | ||
41 | |||
42 | const videos = this.videoModelBuilder.buildVideosFromRows(videoRows, webtorrentFilesRows, streamingPlaylistFilesRows) | ||
43 | |||
44 | if (videos.length > 1) { | ||
45 | throw new Error('Video results is more than ') | ||
46 | } | ||
47 | |||
48 | if (videos.length === 0) return null | ||
49 | return videos[0] | ||
50 | } | ||
51 | } | ||
52 | |||
53 | export class VideosModelGetQuerySubBuilder extends AbstractVideosModelQueryBuilder { | ||
13 | protected attributes: { [key: string]: string } | 54 | protected attributes: { [key: string]: string } |
14 | protected joins: string[] = [] | 55 | protected joins: string[] = [] |
15 | protected where: string | 56 | |
57 | protected webtorrentFilesQuery: string | ||
58 | protected streamingPlaylistFilesQuery: string | ||
16 | 59 | ||
17 | constructor (protected readonly sequelize: Sequelize) { | 60 | constructor (protected readonly sequelize: Sequelize) { |
18 | super('get') | 61 | super('get') |
19 | } | 62 | } |
20 | 63 | ||
21 | queryVideos (options: BuildVideoGetQueryOptions) { | 64 | queryVideos (options: BuildVideoGetQueryOptions) { |
22 | this.buildGetQuery(options) | 65 | this.buildMainGetQuery(options) |
23 | |||
24 | return this.runQuery(options.transaction, true).then(rows => { | ||
25 | const videos = this.videoModelBuilder.buildVideosFromRows(rows) | ||
26 | |||
27 | if (videos.length > 1) { | ||
28 | throw new Error('Video results is more than ') | ||
29 | } | ||
30 | 66 | ||
31 | if (videos.length === 0) return null | 67 | return this.runQuery(options.transaction, true) |
32 | return videos[0] | ||
33 | }) | ||
34 | } | 68 | } |
35 | 69 | ||
36 | private buildGetQuery (options: BuildVideoGetQueryOptions) { | 70 | private buildMainGetQuery (options: BuildVideoGetQueryOptions) { |
37 | this.attributes = { | 71 | this.attributes = { |
38 | '"video".*': '' | 72 | '"video".*': '' |
39 | } | 73 | } |
@@ -45,8 +79,6 @@ export class VideosModelGetQueryBuilder extends AbstractVideosModelQueryBuilder | |||
45 | 79 | ||
46 | this.includeThumbnails() | 80 | this.includeThumbnails() |
47 | 81 | ||
48 | this.includeFiles() | ||
49 | |||
50 | this.includeBlacklisted() | 82 | this.includeBlacklisted() |
51 | 83 | ||
52 | this.includeScheduleUpdate() | 84 | this.includeScheduleUpdate() |
@@ -59,28 +91,17 @@ export class VideosModelGetQueryBuilder extends AbstractVideosModelQueryBuilder | |||
59 | 91 | ||
60 | if (options.forGetAPI === true) { | 92 | if (options.forGetAPI === true) { |
61 | this.includeTrackers() | 93 | this.includeTrackers() |
62 | this.includeRedundancies() | ||
63 | } | 94 | } |
64 | 95 | ||
65 | this.whereId(options.id) | 96 | this.whereId(options.id) |
66 | 97 | ||
67 | const select = this.buildSelect() | 98 | this.query = this.buildQuery() |
68 | const order = this.buildOrder() | ||
69 | |||
70 | this.query = `${select} FROM "video" ${this.joins.join(' ')} ${this.where} ${order}` | ||
71 | } | 99 | } |
72 | 100 | ||
73 | private whereId (id: string | number) { | 101 | private buildQuery () { |
74 | if (validator.isInt('' + id)) { | 102 | const order = 'ORDER BY "Tags"."name" ASC' |
75 | this.where = 'WHERE "video".id = :videoId' | 103 | const from = `SELECT * FROM "video" ${this.where} LIMIT 1` |
76 | } else { | ||
77 | this.where = 'WHERE uuid = :videoId' | ||
78 | } | ||
79 | |||
80 | this.replacements.videoId = id | ||
81 | } | ||
82 | 104 | ||
83 | private buildOrder () { | 105 | return `${this.buildSelect()} FROM (${from}) AS "video" ${this.joins.join(' ')} ${this.where} ${order}` |
84 | return 'ORDER BY "Tags"."name" ASC' | ||
85 | } | 106 | } |
86 | } | 107 | } |
diff --git a/server/models/video/sql/videos-id-list-query-builder.ts b/server/models/video/sql/videos-id-list-query-builder.ts index 6e0d97d9e..30b251f0f 100644 --- a/server/models/video/sql/videos-id-list-query-builder.ts +++ b/server/models/video/sql/videos-id-list-query-builder.ts | |||
@@ -6,6 +6,12 @@ import { MUserAccountId, MUserId } from '@server/types/models' | |||
6 | import { VideoFilter, VideoPrivacy, VideoState } from '@shared/models' | 6 | import { VideoFilter, VideoPrivacy, VideoState } from '@shared/models' |
7 | import { AbstractVideosQueryBuilder } from './shared/abstract-videos-query-builder' | 7 | import { AbstractVideosQueryBuilder } from './shared/abstract-videos-query-builder' |
8 | 8 | ||
9 | /** | ||
10 | * | ||
11 | * Build videos list SQL query to fetch rows | ||
12 | * | ||
13 | */ | ||
14 | |||
9 | export type BuildVideosListQueryOptions = { | 15 | export type BuildVideosListQueryOptions = { |
10 | attributes?: string[] | 16 | attributes?: string[] |
11 | 17 | ||
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 38b9c91d0..acb76d80a 100644 --- a/server/models/video/sql/videos-model-list-query-builder.ts +++ b/server/models/video/sql/videos-model-list-query-builder.ts | |||
@@ -1,7 +1,14 @@ | |||
1 | import { Sequelize } from 'sequelize' | 1 | import { Sequelize } from 'sequelize' |
2 | import { AbstractVideosModelQueryBuilder } from './shared/abstract-videos-model-query-builder' | 2 | import { AbstractVideosModelQueryBuilder } from './shared/abstract-videos-model-query-builder' |
3 | import { VideoModelBuilder } from './shared/video-model-builder' | ||
3 | import { BuildVideosListQueryOptions, VideosIdListQueryBuilder } from './videos-id-list-query-builder' | 4 | import { BuildVideosListQueryOptions, VideosIdListQueryBuilder } from './videos-id-list-query-builder' |
4 | 5 | ||
6 | /** | ||
7 | * | ||
8 | * Build videos list SQL query and create video models | ||
9 | * | ||
10 | */ | ||
11 | |||
5 | export class VideosModelListQueryBuilder extends AbstractVideosModelQueryBuilder { | 12 | export class VideosModelListQueryBuilder extends AbstractVideosModelQueryBuilder { |
6 | protected attributes: { [key: string]: string } | 13 | protected attributes: { [key: string]: string } |
7 | protected joins: string[] = [] | 14 | protected joins: string[] = [] |
@@ -9,8 +16,12 @@ export class VideosModelListQueryBuilder extends AbstractVideosModelQueryBuilder | |||
9 | private innerQuery: string | 16 | private innerQuery: string |
10 | private innerSort: string | 17 | private innerSort: string |
11 | 18 | ||
19 | private readonly videoModelBuilder: VideoModelBuilder | ||
20 | |||
12 | constructor (protected readonly sequelize: Sequelize) { | 21 | constructor (protected readonly sequelize: Sequelize) { |
13 | super('list') | 22 | super('list') |
23 | |||
24 | this.videoModelBuilder = new VideoModelBuilder(this.mode, this.videoAttributes) | ||
14 | } | 25 | } |
15 | 26 | ||
16 | queryVideos (options: BuildVideosListQueryOptions) { | 27 | queryVideos (options: BuildVideosListQueryOptions) { |
@@ -41,7 +52,8 @@ export class VideosModelListQueryBuilder extends AbstractVideosModelQueryBuilder | |||
41 | this.includeThumbnails() | 52 | this.includeThumbnails() |
42 | 53 | ||
43 | if (options.withFiles) { | 54 | if (options.withFiles) { |
44 | this.includeFiles() | 55 | this.includeWebtorrentFiles(false) |
56 | this.includeStreamingPlaylistFiles(false) | ||
45 | } | 57 | } |
46 | 58 | ||
47 | if (options.user) { | 59 | if (options.user) { |