diff options
author | Chocobozzz <me@florianbigard.com> | 2021-06-11 14:09:33 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2021-06-11 14:09:52 +0200 |
commit | 71d4af1efc810f853e1a0d986bf758c201692594 (patch) | |
tree | 2066053638baefb6430772c2e0a0aa1774019a51 | |
parent | 3c79c2ce86eaf9e151ab6c2c9d1f646968a16744 (diff) | |
download | PeerTube-71d4af1efc810f853e1a0d986bf758c201692594.tar.gz PeerTube-71d4af1efc810f853e1a0d986bf758c201692594.tar.zst PeerTube-71d4af1efc810f853e1a0d986bf758c201692594.zip |
Use raw SQL for most of video queries
-rw-r--r-- | scripts/create-import-video-file-job.ts | 4 | ||||
-rwxr-xr-x | scripts/prune-storage.ts | 2 | ||||
-rw-r--r-- | server/controllers/activitypub/client.ts | 7 | ||||
-rw-r--r-- | server/helpers/video.ts | 2 | ||||
-rw-r--r-- | server/lib/model-loaders/video.ts | 13 | ||||
-rw-r--r-- | server/middlewares/validators/shared/videos.ts | 8 | ||||
-rw-r--r-- | server/middlewares/validators/videos/videos.ts | 6 | ||||
-rw-r--r-- | server/models/video/sql/shared/abstract-videos-model-query-builder.ts | 24 | ||||
-rw-r--r-- | server/models/video/sql/shared/abstract-videos-query-builder.ts | 9 | ||||
-rw-r--r-- | server/models/video/sql/shared/video-file-query-builder.ts | 16 | ||||
-rw-r--r-- | server/models/video/sql/shared/video-model-builder.ts | 36 | ||||
-rw-r--r-- | server/models/video/sql/shared/video-tables.ts | 8 | ||||
-rw-r--r-- | server/models/video/sql/video-model-get-query-builder.ts | 110 | ||||
-rw-r--r-- | server/models/video/sql/videos-model-list-query-builder.ts | 3 | ||||
-rw-r--r-- | server/models/video/video.ts | 150 | ||||
-rw-r--r-- | server/typings/express/index.d.ts | 4 |
16 files changed, 206 insertions, 196 deletions
diff --git a/scripts/create-import-video-file-job.ts b/scripts/create-import-video-file-job.ts index 5d38af066..094544e05 100644 --- a/scripts/create-import-video-file-job.ts +++ b/scripts/create-import-video-file-job.ts | |||
@@ -36,7 +36,7 @@ async function run () { | |||
36 | return | 36 | return |
37 | } | 37 | } |
38 | 38 | ||
39 | const video = await VideoModel.loadByUUID(options.video) | 39 | const video = await VideoModel.load(options.video) |
40 | if (!video) throw new Error('Video not found.') | 40 | if (!video) throw new Error('Video not found.') |
41 | if (video.isOwned() === false) throw new Error('Cannot import files of a non owned video.') | 41 | if (video.isOwned() === false) throw new Error('Cannot import files of a non owned video.') |
42 | 42 | ||
@@ -45,7 +45,7 @@ async function run () { | |||
45 | filePath: resolve(options.import) | 45 | filePath: resolve(options.import) |
46 | } | 46 | } |
47 | 47 | ||
48 | await JobQueue.Instance.init() | 48 | JobQueue.Instance.init() |
49 | await JobQueue.Instance.createJobWithPromise({ type: 'video-file-import', payload: dataInput }) | 49 | await JobQueue.Instance.createJobWithPromise({ type: 'video-file-import', payload: dataInput }) |
50 | console.log('Import job for video %s created.', video.uuid) | 50 | console.log('Import job for video %s created.', video.uuid) |
51 | } | 51 | } |
diff --git a/scripts/prune-storage.ts b/scripts/prune-storage.ts index 0f2d1320e..58d24816e 100755 --- a/scripts/prune-storage.ts +++ b/scripts/prune-storage.ts | |||
@@ -89,7 +89,7 @@ async function pruneDirectory (directory: string, existFun: ExistFun) { | |||
89 | function doesVideoExist (keepOnlyOwned: boolean) { | 89 | function doesVideoExist (keepOnlyOwned: boolean) { |
90 | return async (file: string) => { | 90 | return async (file: string) => { |
91 | const uuid = getUUIDFromFilename(file) | 91 | const uuid = getUUIDFromFilename(file) |
92 | const video = await VideoModel.loadByUUID(uuid) | 92 | const video = await VideoModel.load(uuid) |
93 | 93 | ||
94 | return video && (keepOnlyOwned === false || video.isOwned()) | 94 | return video && (keepOnlyOwned === false || video.isOwned()) |
95 | } | 95 | } |
diff --git a/server/controllers/activitypub/client.ts b/server/controllers/activitypub/client.ts index 1982e171d..444a8abaa 100644 --- a/server/controllers/activitypub/client.ts +++ b/server/controllers/activitypub/client.ts | |||
@@ -78,12 +78,12 @@ activityPubClientRouter.get('/accounts?/:name/dislikes/:videoId', | |||
78 | activityPubClientRouter.get('/videos/watch/:id', | 78 | activityPubClientRouter.get('/videos/watch/:id', |
79 | executeIfActivityPub, | 79 | executeIfActivityPub, |
80 | asyncMiddleware(cacheRoute()(ROUTE_CACHE_LIFETIME.ACTIVITY_PUB.VIDEOS)), | 80 | asyncMiddleware(cacheRoute()(ROUTE_CACHE_LIFETIME.ACTIVITY_PUB.VIDEOS)), |
81 | asyncMiddleware(videosCustomGetValidator('only-video-with-rights')), | 81 | asyncMiddleware(videosCustomGetValidator('all')), |
82 | asyncMiddleware(videoController) | 82 | asyncMiddleware(videoController) |
83 | ) | 83 | ) |
84 | activityPubClientRouter.get('/videos/watch/:id/activity', | 84 | activityPubClientRouter.get('/videos/watch/:id/activity', |
85 | executeIfActivityPub, | 85 | executeIfActivityPub, |
86 | asyncMiddleware(videosCustomGetValidator('only-video-with-rights')), | 86 | asyncMiddleware(videosCustomGetValidator('all')), |
87 | asyncMiddleware(videoController) | 87 | asyncMiddleware(videoController) |
88 | ) | 88 | ) |
89 | activityPubClientRouter.get('/videos/watch/:id/announces', | 89 | activityPubClientRouter.get('/videos/watch/:id/announces', |
@@ -222,8 +222,7 @@ function getAccountVideoRateFactory (rateType: VideoRateType) { | |||
222 | } | 222 | } |
223 | 223 | ||
224 | async function videoController (req: express.Request, res: express.Response) { | 224 | async function videoController (req: express.Request, res: express.Response) { |
225 | // We need more attributes | 225 | const video = res.locals.videoAll |
226 | const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(res.locals.onlyVideoWithRights.id) | ||
227 | 226 | ||
228 | if (redirectIfNotOwned(video.url, res)) return | 227 | if (redirectIfNotOwned(video.url, res)) return |
229 | 228 | ||
diff --git a/server/helpers/video.ts b/server/helpers/video.ts index c2e15a705..f5f645d3e 100644 --- a/server/helpers/video.ts +++ b/server/helpers/video.ts | |||
@@ -4,7 +4,7 @@ import { isStreamingPlaylist, MStreamingPlaylistVideo, MVideo } from '@server/ty | |||
4 | import { VideoPrivacy, VideoState } from '@shared/models' | 4 | import { VideoPrivacy, VideoState } from '@shared/models' |
5 | 5 | ||
6 | function getVideoWithAttributes (res: Response) { | 6 | function getVideoWithAttributes (res: Response) { |
7 | return res.locals.videoAPI || res.locals.videoAll || res.locals.onlyVideo || res.locals.onlyVideoWithRights | 7 | return res.locals.videoAPI || res.locals.videoAll || res.locals.onlyVideo |
8 | } | 8 | } |
9 | 9 | ||
10 | function extractVideo (videoOrPlaylist: MVideo | MStreamingPlaylistVideo) { | 10 | function extractVideo (videoOrPlaylist: MVideo | MStreamingPlaylistVideo) { |
diff --git a/server/lib/model-loaders/video.ts b/server/lib/model-loaders/video.ts index 07b373ed3..e2bf96f62 100644 --- a/server/lib/model-loaders/video.ts +++ b/server/lib/model-loaders/video.ts | |||
@@ -3,31 +3,30 @@ import { | |||
3 | MVideoAccountLightBlacklistAllFiles, | 3 | MVideoAccountLightBlacklistAllFiles, |
4 | MVideoFormattableDetails, | 4 | MVideoFormattableDetails, |
5 | MVideoFullLight, | 5 | MVideoFullLight, |
6 | MVideoIdThumbnail, | 6 | MVideoId, |
7 | MVideoImmutable, | 7 | MVideoImmutable, |
8 | MVideoThumbnail, | 8 | MVideoThumbnail, |
9 | MVideoWithRights | 9 | MVideoWithRights |
10 | } from '@server/types/models' | 10 | } from '@server/types/models' |
11 | import { Hooks } from '../plugins/hooks' | 11 | import { Hooks } from '../plugins/hooks' |
12 | 12 | ||
13 | type VideoLoadType = 'for-api' | 'all' | 'only-video' | 'only-video-with-rights' | 'id' | 'none' | 'only-immutable-attributes' | 13 | type VideoLoadType = 'for-api' | 'all' | 'only-video' | 'id' | 'none' | 'only-immutable-attributes' |
14 | 14 | ||
15 | function loadVideo (id: number | string, fetchType: 'for-api', userId?: number): Promise<MVideoFormattableDetails> | 15 | function loadVideo (id: number | string, fetchType: 'for-api', userId?: number): Promise<MVideoFormattableDetails> |
16 | function loadVideo (id: number | string, fetchType: 'all', userId?: number): Promise<MVideoFullLight> | 16 | function loadVideo (id: number | string, fetchType: 'all', userId?: number): Promise<MVideoFullLight> |
17 | function loadVideo (id: number | string, fetchType: 'only-immutable-attributes'): Promise<MVideoImmutable> | 17 | function loadVideo (id: number | string, fetchType: 'only-immutable-attributes'): Promise<MVideoImmutable> |
18 | function loadVideo (id: number | string, fetchType: 'only-video', userId?: number): Promise<MVideoThumbnail> | 18 | function loadVideo (id: number | string, fetchType: 'only-video', userId?: number): Promise<MVideoThumbnail> |
19 | function loadVideo (id: number | string, fetchType: 'only-video-with-rights', userId?: number): Promise<MVideoWithRights> | 19 | function loadVideo (id: number | string, fetchType: 'id' | 'none', userId?: number): Promise<MVideoId> |
20 | function loadVideo (id: number | string, fetchType: 'id' | 'none', userId?: number): Promise<MVideoIdThumbnail> | ||
21 | function loadVideo ( | 20 | function loadVideo ( |
22 | id: number | string, | 21 | id: number | string, |
23 | fetchType: VideoLoadType, | 22 | fetchType: VideoLoadType, |
24 | userId?: number | 23 | userId?: number |
25 | ): Promise<MVideoFullLight | MVideoThumbnail | MVideoWithRights | MVideoIdThumbnail | MVideoImmutable> | 24 | ): Promise<MVideoFullLight | MVideoThumbnail | MVideoId | MVideoImmutable> |
26 | function loadVideo ( | 25 | function loadVideo ( |
27 | id: number | string, | 26 | id: number | string, |
28 | fetchType: VideoLoadType, | 27 | fetchType: VideoLoadType, |
29 | userId?: number | 28 | userId?: number |
30 | ): Promise<MVideoFullLight | MVideoThumbnail | MVideoWithRights | MVideoIdThumbnail | MVideoImmutable> { | 29 | ): Promise<MVideoFullLight | MVideoThumbnail | MVideoId | MVideoImmutable> { |
31 | 30 | ||
32 | if (fetchType === 'for-api') { | 31 | if (fetchType === 'for-api') { |
33 | return Hooks.wrapPromiseFun( | 32 | return Hooks.wrapPromiseFun( |
@@ -41,8 +40,6 @@ function loadVideo ( | |||
41 | 40 | ||
42 | if (fetchType === 'only-immutable-attributes') return VideoModel.loadImmutableAttributes(id) | 41 | if (fetchType === 'only-immutable-attributes') return VideoModel.loadImmutableAttributes(id) |
43 | 42 | ||
44 | if (fetchType === 'only-video-with-rights') return VideoModel.loadWithRights(id) | ||
45 | |||
46 | if (fetchType === 'only-video') return VideoModel.load(id) | 43 | if (fetchType === 'only-video') return VideoModel.load(id) |
47 | 44 | ||
48 | if (fetchType === 'id' || fetchType === 'none') return VideoModel.loadOnlyId(id) | 45 | if (fetchType === 'id' || fetchType === 'none') return VideoModel.loadOnlyId(id) |
diff --git a/server/middlewares/validators/shared/videos.ts b/server/middlewares/validators/shared/videos.ts index 1a22d6513..6131379ce 100644 --- a/server/middlewares/validators/shared/videos.ts +++ b/server/middlewares/validators/shared/videos.ts | |||
@@ -8,7 +8,7 @@ import { | |||
8 | MVideoAccountLight, | 8 | MVideoAccountLight, |
9 | MVideoFormattableDetails, | 9 | MVideoFormattableDetails, |
10 | MVideoFullLight, | 10 | MVideoFullLight, |
11 | MVideoIdThumbnail, | 11 | MVideoId, |
12 | MVideoImmutable, | 12 | MVideoImmutable, |
13 | MVideoThumbnail, | 13 | MVideoThumbnail, |
14 | MVideoWithRights | 14 | MVideoWithRights |
@@ -43,16 +43,12 @@ async function doesVideoExist (id: number | string, res: Response, fetchType: Vi | |||
43 | break | 43 | break |
44 | 44 | ||
45 | case 'id': | 45 | case 'id': |
46 | res.locals.videoId = video as MVideoIdThumbnail | 46 | res.locals.videoId = video as MVideoId |
47 | break | 47 | break |
48 | 48 | ||
49 | case 'only-video': | 49 | case 'only-video': |
50 | res.locals.onlyVideo = video as MVideoThumbnail | 50 | res.locals.onlyVideo = video as MVideoThumbnail |
51 | break | 51 | break |
52 | |||
53 | case 'only-video-with-rights': | ||
54 | res.locals.onlyVideoWithRights = video as MVideoWithRights | ||
55 | break | ||
56 | } | 52 | } |
57 | 53 | ||
58 | return true | 54 | return true |
diff --git a/server/middlewares/validators/videos/videos.ts b/server/middlewares/validators/videos/videos.ts index a707fd086..2bed5f181 100644 --- a/server/middlewares/validators/videos/videos.ts +++ b/server/middlewares/validators/videos/videos.ts | |||
@@ -4,7 +4,7 @@ import { getResumableUploadPath } from '@server/helpers/upload' | |||
4 | import { isAbleToUploadVideo } from '@server/lib/user' | 4 | import { isAbleToUploadVideo } from '@server/lib/user' |
5 | import { getServerActor } from '@server/models/application/application' | 5 | import { getServerActor } from '@server/models/application/application' |
6 | import { ExpressPromiseHandler } from '@server/types/express' | 6 | import { ExpressPromiseHandler } from '@server/types/express' |
7 | import { MUserAccountId, MVideoWithRights } from '@server/types/models' | 7 | import { MUserAccountId, MVideoFullLight } from '@server/types/models' |
8 | import { ServerErrorCode, UserRight, VideoChangeOwnershipStatus, VideoPrivacy } from '../../../../shared' | 8 | import { ServerErrorCode, UserRight, VideoChangeOwnershipStatus, VideoPrivacy } from '../../../../shared' |
9 | import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' | 9 | import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' |
10 | import { VideoChangeOwnershipAccept } from '../../../../shared/models/videos/change-ownership/video-change-ownership-accept.model' | 10 | import { VideoChangeOwnershipAccept } from '../../../../shared/models/videos/change-ownership/video-change-ownership-accept.model' |
@@ -258,7 +258,7 @@ async function checkVideoFollowConstraints (req: express.Request, res: express.R | |||
258 | } | 258 | } |
259 | 259 | ||
260 | const videosCustomGetValidator = ( | 260 | const videosCustomGetValidator = ( |
261 | fetchType: 'for-api' | 'all' | 'only-video' | 'only-video-with-rights' | 'only-immutable-attributes', | 261 | fetchType: 'for-api' | 'all' | 'only-video' | 'only-immutable-attributes', |
262 | authenticateInQuery = false | 262 | authenticateInQuery = false |
263 | ) => { | 263 | ) => { |
264 | return [ | 264 | return [ |
@@ -273,7 +273,7 @@ const videosCustomGetValidator = ( | |||
273 | // Controllers does not need to check video rights | 273 | // Controllers does not need to check video rights |
274 | if (fetchType === 'only-immutable-attributes') return next() | 274 | if (fetchType === 'only-immutable-attributes') return next() |
275 | 275 | ||
276 | const video = getVideoWithAttributes(res) as MVideoWithRights | 276 | const video = getVideoWithAttributes(res) as MVideoFullLight |
277 | 277 | ||
278 | // Video private or blacklisted | 278 | // Video private or blacklisted |
279 | if (video.requiresAuth()) { | 279 | if (video.requiresAuth()) { |
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) { |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 00fbb18f6..2d8b7b653 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -88,13 +88,12 @@ import { | |||
88 | MVideoFormattableDetails, | 88 | MVideoFormattableDetails, |
89 | MVideoForUser, | 89 | MVideoForUser, |
90 | MVideoFullLight, | 90 | MVideoFullLight, |
91 | MVideoIdThumbnail, | 91 | MVideoId, |
92 | MVideoImmutable, | 92 | MVideoImmutable, |
93 | MVideoThumbnail, | 93 | MVideoThumbnail, |
94 | MVideoThumbnailBlacklist, | 94 | MVideoThumbnailBlacklist, |
95 | MVideoWithAllFiles, | 95 | MVideoWithAllFiles, |
96 | MVideoWithFile, | 96 | MVideoWithFile |
97 | MVideoWithRights | ||
98 | } from '../../types/models' | 97 | } from '../../types/models' |
99 | import { MThumbnail } from '../../types/models/video/thumbnail' | 98 | import { MThumbnail } from '../../types/models/video/thumbnail' |
100 | import { MVideoFile, MVideoFileStreamingPlaylistVideo } from '../../types/models/video/video-file' | 99 | import { MVideoFile, MVideoFileStreamingPlaylistVideo } from '../../types/models/video/video-file' |
@@ -1301,27 +1300,16 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1301 | return VideoModel.count(options) | 1300 | return VideoModel.count(options) |
1302 | } | 1301 | } |
1303 | 1302 | ||
1304 | static load (id: number | string, t?: Transaction): Promise<MVideoThumbnail> { | 1303 | static load (id: number | string, transaction?: Transaction): Promise<MVideoThumbnail> { |
1305 | const where = buildWhereIdOrUUID(id) | 1304 | const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize) |
1306 | const options = { | ||
1307 | where, | ||
1308 | transaction: t | ||
1309 | } | ||
1310 | 1305 | ||
1311 | return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options) | 1306 | return queryBuilder.queryVideo({ id, transaction, type: 'thumbnails' }) |
1312 | } | 1307 | } |
1313 | 1308 | ||
1314 | static loadWithBlacklist (id: number | string, t?: Transaction): Promise<MVideoThumbnailBlacklist> { | 1309 | static loadWithBlacklist (id: number | string, transaction?: Transaction): Promise<MVideoThumbnailBlacklist> { |
1315 | const where = buildWhereIdOrUUID(id) | 1310 | const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize) |
1316 | const options = { | ||
1317 | where, | ||
1318 | transaction: t | ||
1319 | } | ||
1320 | 1311 | ||
1321 | return VideoModel.scope([ | 1312 | return queryBuilder.queryVideo({ id, transaction, type: 'thumbnails-blacklist' }) |
1322 | ScopeNames.WITH_THUMBNAILS, | ||
1323 | ScopeNames.WITH_BLACKLISTED | ||
1324 | ]).findOne(options) | ||
1325 | } | 1313 | } |
1326 | 1314 | ||
1327 | static loadImmutableAttributes (id: number | string, t?: Transaction): Promise<MVideoImmutable> { | 1315 | static loadImmutableAttributes (id: number | string, t?: Transaction): Promise<MVideoImmutable> { |
@@ -1342,68 +1330,6 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1342 | }) | 1330 | }) |
1343 | } | 1331 | } |
1344 | 1332 | ||
1345 | static loadWithRights (id: number | string, t?: Transaction): Promise<MVideoWithRights> { | ||
1346 | const where = buildWhereIdOrUUID(id) | ||
1347 | const options = { | ||
1348 | where, | ||
1349 | transaction: t | ||
1350 | } | ||
1351 | |||
1352 | return VideoModel.scope([ | ||
1353 | ScopeNames.WITH_BLACKLISTED, | ||
1354 | ScopeNames.WITH_USER_ID | ||
1355 | ]).findOne(options) | ||
1356 | } | ||
1357 | |||
1358 | static loadOnlyId (id: number | string, t?: Transaction): Promise<MVideoIdThumbnail> { | ||
1359 | const where = buildWhereIdOrUUID(id) | ||
1360 | |||
1361 | const options = { | ||
1362 | attributes: [ 'id' ], | ||
1363 | where, | ||
1364 | transaction: t | ||
1365 | } | ||
1366 | |||
1367 | return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options) | ||
1368 | } | ||
1369 | |||
1370 | static loadWithFiles (id: number | string, t?: Transaction, logging?: boolean): Promise<MVideoWithAllFiles> { | ||
1371 | const where = buildWhereIdOrUUID(id) | ||
1372 | |||
1373 | const query = { | ||
1374 | where, | ||
1375 | transaction: t, | ||
1376 | logging | ||
1377 | } | ||
1378 | |||
1379 | return VideoModel.scope([ | ||
1380 | ScopeNames.WITH_WEBTORRENT_FILES, | ||
1381 | ScopeNames.WITH_STREAMING_PLAYLISTS, | ||
1382 | ScopeNames.WITH_THUMBNAILS | ||
1383 | ]).findOne(query) | ||
1384 | } | ||
1385 | |||
1386 | static loadByUUID (uuid: string): Promise<MVideoThumbnail> { | ||
1387 | const options = { | ||
1388 | where: { | ||
1389 | uuid | ||
1390 | } | ||
1391 | } | ||
1392 | |||
1393 | return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options) | ||
1394 | } | ||
1395 | |||
1396 | static loadByUrl (url: string, transaction?: Transaction): Promise<MVideoThumbnail> { | ||
1397 | const query: FindOptions = { | ||
1398 | where: { | ||
1399 | url | ||
1400 | }, | ||
1401 | transaction | ||
1402 | } | ||
1403 | |||
1404 | return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(query) | ||
1405 | } | ||
1406 | |||
1407 | static loadByUrlImmutableAttributes (url: string, transaction?: Transaction): Promise<MVideoImmutable> { | 1333 | static loadByUrlImmutableAttributes (url: string, transaction?: Transaction): Promise<MVideoImmutable> { |
1408 | const fun = () => { | 1334 | const fun = () => { |
1409 | const query: FindOptions = { | 1335 | const query: FindOptions = { |
@@ -1424,50 +1350,34 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1424 | }) | 1350 | }) |
1425 | } | 1351 | } |
1426 | 1352 | ||
1427 | static loadByUrlAndPopulateAccount (url: string, transaction?: Transaction): Promise<MVideoAccountLightBlacklistAllFiles> { | 1353 | static loadOnlyId (id: number | string, transaction?: Transaction): Promise<MVideoId> { |
1428 | const query: FindOptions = { | 1354 | const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize) |
1429 | where: { | ||
1430 | url | ||
1431 | }, | ||
1432 | transaction | ||
1433 | } | ||
1434 | 1355 | ||
1435 | return VideoModel.scope([ | 1356 | return queryBuilder.queryVideo({ id, transaction, type: 'id' }) |
1436 | ScopeNames.WITH_ACCOUNT_DETAILS, | ||
1437 | ScopeNames.WITH_WEBTORRENT_FILES, | ||
1438 | ScopeNames.WITH_STREAMING_PLAYLISTS, | ||
1439 | ScopeNames.WITH_THUMBNAILS, | ||
1440 | ScopeNames.WITH_BLACKLISTED | ||
1441 | ]).findOne(query) | ||
1442 | } | 1357 | } |
1443 | 1358 | ||
1444 | static loadAndPopulateAccountAndServerAndTags (id: number | string, t?: Transaction, userId?: number): Promise<MVideoFullLight> { | 1359 | static loadWithFiles (id: number | string, transaction?: Transaction, logging?: boolean): Promise<MVideoWithAllFiles> { |
1445 | const where = buildWhereIdOrUUID(id) | 1360 | const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize) |
1446 | 1361 | ||
1447 | const options = { | 1362 | return queryBuilder.queryVideo({ id, transaction, type: 'all-files', logging }) |
1448 | order: [ [ 'Tags', 'name', 'ASC' ] ] as any, | 1363 | } |
1449 | where, | ||
1450 | transaction: t | ||
1451 | } | ||
1452 | 1364 | ||
1453 | const scopes: (string | ScopeOptions)[] = [ | 1365 | static loadByUrl (url: string, transaction?: Transaction): Promise<MVideoThumbnail> { |
1454 | ScopeNames.WITH_TAGS, | 1366 | const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize) |
1455 | ScopeNames.WITH_BLACKLISTED, | ||
1456 | ScopeNames.WITH_ACCOUNT_DETAILS, | ||
1457 | ScopeNames.WITH_SCHEDULED_UPDATE, | ||
1458 | ScopeNames.WITH_WEBTORRENT_FILES, | ||
1459 | ScopeNames.WITH_STREAMING_PLAYLISTS, | ||
1460 | ScopeNames.WITH_THUMBNAILS, | ||
1461 | ScopeNames.WITH_LIVE | ||
1462 | ] | ||
1463 | 1367 | ||
1464 | if (userId) { | 1368 | return queryBuilder.queryVideo({ url, transaction, type: 'thumbnails' }) |
1465 | scopes.push({ method: [ ScopeNames.WITH_USER_HISTORY, userId ] }) | 1369 | } |
1466 | } | 1370 | |
1371 | static loadByUrlAndPopulateAccount (url: string, transaction?: Transaction): Promise<MVideoAccountLightBlacklistAllFiles> { | ||
1372 | const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize) | ||
1373 | |||
1374 | return queryBuilder.queryVideo({ url, transaction, type: 'account-blacklist-files' }) | ||
1375 | } | ||
1376 | |||
1377 | static loadAndPopulateAccountAndServerAndTags (id: number | string, t?: Transaction, userId?: number): Promise<MVideoFullLight> { | ||
1378 | const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize) | ||
1467 | 1379 | ||
1468 | return VideoModel | 1380 | return queryBuilder.queryVideo({ id, transaction: t, type: 'full-light', userId }) |
1469 | .scope(scopes) | ||
1470 | .findOne(options) | ||
1471 | } | 1381 | } |
1472 | 1382 | ||
1473 | static loadForGetAPI (parameters: { | 1383 | static loadForGetAPI (parameters: { |
@@ -1478,7 +1388,7 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1478 | const { id, transaction, userId } = parameters | 1388 | const { id, transaction, userId } = parameters |
1479 | const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize) | 1389 | const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize) |
1480 | 1390 | ||
1481 | return queryBuilder.queryVideos({ id, transaction, forGetAPI: true, userId }) | 1391 | return queryBuilder.queryVideo({ id, transaction, type: 'api', userId }) |
1482 | } | 1392 | } |
1483 | 1393 | ||
1484 | static async getStats () { | 1394 | static async getStats () { |
diff --git a/server/typings/express/index.d.ts b/server/typings/express/index.d.ts index 00ff68943..de673f4fc 100644 --- a/server/typings/express/index.d.ts +++ b/server/typings/express/index.d.ts | |||
@@ -11,6 +11,7 @@ import { | |||
11 | MVideoChangeOwnershipFull, | 11 | MVideoChangeOwnershipFull, |
12 | MVideoFile, | 12 | MVideoFile, |
13 | MVideoFormattableDetails, | 13 | MVideoFormattableDetails, |
14 | MVideoId, | ||
14 | MVideoImmutable, | 15 | MVideoImmutable, |
15 | MVideoLive, | 16 | MVideoLive, |
16 | MVideoPlaylistFull, | 17 | MVideoPlaylistFull, |
@@ -106,8 +107,7 @@ declare module 'express' { | |||
106 | videoAll?: MVideoFullLight | 107 | videoAll?: MVideoFullLight |
107 | onlyImmutableVideo?: MVideoImmutable | 108 | onlyImmutableVideo?: MVideoImmutable |
108 | onlyVideo?: MVideoThumbnail | 109 | onlyVideo?: MVideoThumbnail |
109 | onlyVideoWithRights?: MVideoWithRights | 110 | videoId?: MVideoId |
110 | videoId?: MVideoIdThumbnail | ||
111 | 111 | ||
112 | videoLive?: MVideoLive | 112 | videoLive?: MVideoLive |
113 | 113 | ||