aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/video/sql
diff options
context:
space:
mode:
Diffstat (limited to 'server/models/video/sql')
-rw-r--r--server/models/video/sql/shared/abstract-videos-model-query-builder.ts24
-rw-r--r--server/models/video/sql/shared/abstract-videos-query-builder.ts9
-rw-r--r--server/models/video/sql/shared/video-file-query-builder.ts16
-rw-r--r--server/models/video/sql/shared/video-model-builder.ts36
-rw-r--r--server/models/video/sql/shared/video-tables.ts8
-rw-r--r--server/models/video/sql/video-model-get-query-builder.ts110
-rw-r--r--server/models/video/sql/videos-model-list-query-builder.ts3
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
2import { logger } from '@server/helpers/logger'
3import { AccountModel } from '@server/models/account/account' 2import { AccountModel } from '@server/models/account/account'
4import { ActorModel } from '@server/models/actor/actor' 3import { ActorModel } from '@server/models/actor/actor'
5import { ActorImageModel } from '@server/models/actor/actor-image' 4import { 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
13export type BuildVideoGetQueryOptions = { 13export 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
20export class VideosModelGetQueryBuilder { 25export 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
53export class VideosModelGetQuerySubBuilder extends AbstractVideosModelQueryBuilder { 68export 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) {