From: Chocobozzz Date: Fri, 11 Jun 2021 12:09:33 +0000 (+0200) Subject: Use raw SQL for most of video queries X-Git-Tag: v3.3.0-rc.1~99 X-Git-Url: https://git.immae.eu/?a=commitdiff_plain;h=71d4af1efc810f853e1a0d986bf758c201692594;hp=3c79c2ce86eaf9e151ab6c2c9d1f646968a16744;p=github%2FChocobozzz%2FPeerTube.git Use raw SQL for most of video queries --- 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 () { return } - const video = await VideoModel.loadByUUID(options.video) + const video = await VideoModel.load(options.video) if (!video) throw new Error('Video not found.') if (video.isOwned() === false) throw new Error('Cannot import files of a non owned video.') @@ -45,7 +45,7 @@ async function run () { filePath: resolve(options.import) } - await JobQueue.Instance.init() + JobQueue.Instance.init() await JobQueue.Instance.createJobWithPromise({ type: 'video-file-import', payload: dataInput }) console.log('Import job for video %s created.', video.uuid) } 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) { function doesVideoExist (keepOnlyOwned: boolean) { return async (file: string) => { const uuid = getUUIDFromFilename(file) - const video = await VideoModel.loadByUUID(uuid) + const video = await VideoModel.load(uuid) return video && (keepOnlyOwned === false || video.isOwned()) } 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', activityPubClientRouter.get('/videos/watch/:id', executeIfActivityPub, asyncMiddleware(cacheRoute()(ROUTE_CACHE_LIFETIME.ACTIVITY_PUB.VIDEOS)), - asyncMiddleware(videosCustomGetValidator('only-video-with-rights')), + asyncMiddleware(videosCustomGetValidator('all')), asyncMiddleware(videoController) ) activityPubClientRouter.get('/videos/watch/:id/activity', executeIfActivityPub, - asyncMiddleware(videosCustomGetValidator('only-video-with-rights')), + asyncMiddleware(videosCustomGetValidator('all')), asyncMiddleware(videoController) ) activityPubClientRouter.get('/videos/watch/:id/announces', @@ -222,8 +222,7 @@ function getAccountVideoRateFactory (rateType: VideoRateType) { } async function videoController (req: express.Request, res: express.Response) { - // We need more attributes - const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(res.locals.onlyVideoWithRights.id) + const video = res.locals.videoAll if (redirectIfNotOwned(video.url, res)) return 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 import { VideoPrivacy, VideoState } from '@shared/models' function getVideoWithAttributes (res: Response) { - return res.locals.videoAPI || res.locals.videoAll || res.locals.onlyVideo || res.locals.onlyVideoWithRights + return res.locals.videoAPI || res.locals.videoAll || res.locals.onlyVideo } 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 { MVideoAccountLightBlacklistAllFiles, MVideoFormattableDetails, MVideoFullLight, - MVideoIdThumbnail, + MVideoId, MVideoImmutable, MVideoThumbnail, MVideoWithRights } from '@server/types/models' import { Hooks } from '../plugins/hooks' -type VideoLoadType = 'for-api' | 'all' | 'only-video' | 'only-video-with-rights' | 'id' | 'none' | 'only-immutable-attributes' +type VideoLoadType = 'for-api' | 'all' | 'only-video' | 'id' | 'none' | 'only-immutable-attributes' function loadVideo (id: number | string, fetchType: 'for-api', userId?: number): Promise function loadVideo (id: number | string, fetchType: 'all', userId?: number): Promise function loadVideo (id: number | string, fetchType: 'only-immutable-attributes'): Promise function loadVideo (id: number | string, fetchType: 'only-video', userId?: number): Promise -function loadVideo (id: number | string, fetchType: 'only-video-with-rights', userId?: number): Promise -function loadVideo (id: number | string, fetchType: 'id' | 'none', userId?: number): Promise +function loadVideo (id: number | string, fetchType: 'id' | 'none', userId?: number): Promise function loadVideo ( id: number | string, fetchType: VideoLoadType, userId?: number -): Promise +): Promise function loadVideo ( id: number | string, fetchType: VideoLoadType, userId?: number -): Promise { +): Promise { if (fetchType === 'for-api') { return Hooks.wrapPromiseFun( @@ -41,8 +40,6 @@ function loadVideo ( if (fetchType === 'only-immutable-attributes') return VideoModel.loadImmutableAttributes(id) - if (fetchType === 'only-video-with-rights') return VideoModel.loadWithRights(id) - if (fetchType === 'only-video') return VideoModel.load(id) 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 { MVideoAccountLight, MVideoFormattableDetails, MVideoFullLight, - MVideoIdThumbnail, + MVideoId, MVideoImmutable, MVideoThumbnail, MVideoWithRights @@ -43,16 +43,12 @@ async function doesVideoExist (id: number | string, res: Response, fetchType: Vi break case 'id': - res.locals.videoId = video as MVideoIdThumbnail + res.locals.videoId = video as MVideoId break case 'only-video': res.locals.onlyVideo = video as MVideoThumbnail break - - case 'only-video-with-rights': - res.locals.onlyVideoWithRights = video as MVideoWithRights - break } 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' import { isAbleToUploadVideo } from '@server/lib/user' import { getServerActor } from '@server/models/application/application' import { ExpressPromiseHandler } from '@server/types/express' -import { MUserAccountId, MVideoWithRights } from '@server/types/models' +import { MUserAccountId, MVideoFullLight } from '@server/types/models' import { ServerErrorCode, UserRight, VideoChangeOwnershipStatus, VideoPrivacy } from '../../../../shared' import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' 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 } const videosCustomGetValidator = ( - fetchType: 'for-api' | 'all' | 'only-video' | 'only-video-with-rights' | 'only-immutable-attributes', + fetchType: 'for-api' | 'all' | 'only-video' | 'only-immutable-attributes', authenticateInQuery = false ) => { return [ @@ -273,7 +273,7 @@ const videosCustomGetValidator = ( // Controllers does not need to check video rights if (fetchType === 'only-immutable-attributes') return next() - const video = getVideoWithAttributes(res) as MVideoWithRights + const video = getVideoWithAttributes(res) as MVideoFullLight // Video private or blacklisted 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 } } + protected includeOwnerUser () { + this.addJoin('INNER JOIN "videoChannel" AS "VideoChannel" ON "video"."channelId" = "VideoChannel"."id"') + this.addJoin('INNER JOIN "account" AS "VideoChannel->Account" ON "VideoChannel"."accountId" = "VideoChannel->Account"."id"') + + this.attributes = { + ...this.attributes, + + ...this.buildAttributesObject('VideoChannel', this.tables.getChannelAttributes()), + ...this.buildAttributesObject('VideoChannel->Account', this.tables.getUserAccountAttributes()) + } + } + protected includeThumbnails () { this.addJoin('LEFT OUTER JOIN "thumbnail" AS "Thumbnails" ON "video"."id" = "Thumbnails"."videoId"') @@ -269,14 +281,20 @@ export class AbstractVideosModelQueryBuilder extends AbstractVideosQueryBuilder return result } - protected whereId (id: string | number) { - if (validator.isInt('' + id)) { + protected whereId (options: { id?: string | number, url?: string }) { + if (options.url) { + this.where = 'WHERE "video"."url" = :videoUrl' + this.replacements.videoUrl = options.url + return + } + + if (validator.isInt('' + options.id)) { this.where = 'WHERE "video".id = :videoId' } else { this.where = 'WHERE uuid = :videoId' } - this.replacements.videoId = id + this.replacements.videoId = options.id } 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 { protected query: string protected replacements: any = {} - protected runQuery (transaction?: Transaction) { + protected runQuery (options: { transaction?: Transaction, logging?: boolean } = {}) { logger.debug('Running videos query.', { query: this.query, replacements: this.replacements }) - const options = { - transaction, + const queryOptions = { + transaction: options.transaction, + logging: options.logging, replacements: this.replacements, type: QueryTypes.SELECT as QueryTypes.SELECT, next: false } - return this.sequelize.query(this.query, options) + return this.sequelize.query(this.query, queryOptions) } } 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 { queryWebTorrentVideos (options: BuildVideoGetQueryOptions) { this.buildWebtorrentFilesQuery(options) - return this.runQuery(options.transaction) + return this.runQuery(options) } queryStreamingPlaylistVideos (options: BuildVideoGetQueryOptions) { this.buildVideoStreamingPlaylistFilesQuery(options) - return this.runQuery(options.transaction) + return this.runQuery(options) } private buildWebtorrentFilesQuery (options: BuildVideoGetQueryOptions) { @@ -34,11 +34,11 @@ export class VideoFileQueryBuilder extends AbstractVideosModelQueryBuilder { this.includeWebtorrentFiles(true) - if (options.forGetAPI === true) { + if (this.shouldIncludeRedundancies(options)) { this.includeWebTorrentRedundancies() } - this.whereId(options.id) + this.whereId(options) this.query = this.buildQuery() } @@ -50,11 +50,11 @@ export class VideoFileQueryBuilder extends AbstractVideosModelQueryBuilder { this.includeStreamingPlaylistFiles(true) - if (options.forGetAPI === true) { + if (this.shouldIncludeRedundancies(options)) { this.includeStreamingPlaylistRedundancies() } - this.whereId(options.id) + this.whereId(options) this.query = this.buildQuery() } @@ -62,4 +62,8 @@ export class VideoFileQueryBuilder extends AbstractVideosModelQueryBuilder { private buildQuery () { return `${this.buildSelect()} FROM "video" ${this.joins} ${this.where}` } + + private shouldIncludeRedundancies (options: BuildVideoGetQueryOptions) { + return options.type === 'api' + } } 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 @@ -import { logger } from '@server/helpers/logger' import { AccountModel } from '@server/models/account/account' import { ActorModel } from '@server/models/actor/actor' import { ActorImageModel } from '@server/models/actor/actor-image' @@ -56,7 +55,7 @@ export class VideoModelBuilder { this.reinit() for (const row of rows) { - this.buildVideo(row) + this.buildVideoAndAccount(row) const videoModel = this.videosMemo[row.id] @@ -131,22 +130,10 @@ export class VideoModelBuilder { } } - private buildVideo (row: SQLRow) { + private buildVideoAndAccount (row: SQLRow) { if (this.videosMemo[row.id]) return - // Build Channel - const channelModel = new VideoChannelModel(this.grab(row, this.tables.getChannelAttributes(), 'VideoChannel'), this.buildOpts) - channelModel.Actor = this.buildActor(row, 'VideoChannel') - - const accountModel = new AccountModel(this.grab(row, this.tables.getAccountAttributes(), 'VideoChannel.Account'), this.buildOpts) - accountModel.Actor = this.buildActor(row, 'VideoChannel.Account') - - channelModel.Account = accountModel - const videoModel = new VideoModel(this.grab(row, this.tables.getVideoAttributes(), ''), this.buildOpts) - videoModel.VideoChannel = channelModel - - this.videosMemo[row.id] = videoModel videoModel.UserVideoHistories = [] videoModel.Thumbnails = [] @@ -155,10 +142,29 @@ export class VideoModelBuilder { videoModel.Tags = [] videoModel.Trackers = [] + this.buildAccount(row, videoModel) + + this.videosMemo[row.id] = videoModel + // Keep rows order this.videos.push(videoModel) } + private buildAccount (row: SQLRow, videoModel: VideoModel) { + const id = row['VideoChannel.Account.id'] + if (!id) return + + const channelModel = new VideoChannelModel(this.grab(row, this.tables.getChannelAttributes(), 'VideoChannel'), this.buildOpts) + channelModel.Actor = this.buildActor(row, 'VideoChannel') + + const accountModel = new AccountModel(this.grab(row, this.tables.getAccountAttributes(), 'VideoChannel.Account'), this.buildOpts) + accountModel.Actor = this.buildActor(row, 'VideoChannel.Account') + + channelModel.Account = accountModel + + videoModel.VideoChannel = channelModel + } + private buildActor (row: SQLRow, prefix: string) { const actorPrefix = `${prefix}.Actor` 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 { } + getChannelAttributesForUser () { + return [ 'id', 'accountId' ] + } + getChannelAttributes () { let attributeKeys = [ 'id', @@ -29,6 +33,10 @@ export class VideoTables { return attributeKeys } + getUserAccountAttributes () { + return [ 'id', 'userId' ] + } + getAccountAttributes () { let attributeKeys = [ 'id', 'name', 'actorId' ] 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' */ export type BuildVideoGetQueryOptions = { - id: number | string - transaction?: Transaction + id?: number | string + url?: string + + type: 'api' | 'full-light' | 'account-blacklist-files' | 'all-files' | 'thumbnails' | 'thumbnails-blacklist' | 'id' | 'blacklist-rights' + userId?: number - forGetAPI?: boolean + transaction?: Transaction + + logging?: boolean } export class VideosModelGetQueryBuilder { @@ -32,11 +37,17 @@ export class VideosModelGetQueryBuilder { this.videoModelBuilder = new VideoModelBuilder('get', new VideoTables('get')) } - async queryVideos (options: BuildVideoGetQueryOptions) { + async queryVideo (options: BuildVideoGetQueryOptions) { const [ videoRows, webtorrentFilesRows, streamingPlaylistFilesRows ] = await Promise.all([ this.videoQueryBuilder.queryVideos(options), - this.webtorrentFilesQueryBuilder.queryWebTorrentVideos(options), - this.streamingPlaylistFilesQueryBuilder.queryStreamingPlaylistVideos(options) + + this.shouldQueryVideoFiles(options) + ? this.webtorrentFilesQueryBuilder.queryWebTorrentVideos(options) + : Promise.resolve(undefined), + + this.shouldQueryVideoFiles(options) + ? this.streamingPlaylistFilesQueryBuilder.queryStreamingPlaylistVideos(options) + : Promise.resolve(undefined) ]) const videos = this.videoModelBuilder.buildVideosFromRows(videoRows, webtorrentFilesRows, streamingPlaylistFilesRows) @@ -48,6 +59,10 @@ export class VideosModelGetQueryBuilder { if (videos.length === 0) return null return videos[0] } + + private shouldQueryVideoFiles (options: BuildVideoGetQueryOptions) { + return [ 'api', 'full-light', 'account-blacklist-files', 'all-files' ].includes(options.type) + } } export class VideosModelGetQuerySubBuilder extends AbstractVideosModelQueryBuilder { @@ -63,7 +78,7 @@ export class VideosModelGetQuerySubBuilder extends AbstractVideosModelQueryBuild queryVideos (options: BuildVideoGetQueryOptions) { this.buildMainGetQuery(options) - return this.runQuery(options.transaction) + return this.runQuery(options) } private buildMainGetQuery (options: BuildVideoGetQueryOptions) { @@ -71,36 +86,91 @@ export class VideosModelGetQuerySubBuilder extends AbstractVideosModelQueryBuild '"video".*': '' } - this.includeChannels() - this.includeAccounts() + if (this.shouldIncludeThumbnails(options)) { + this.includeThumbnails() + } - this.includeTags() + if (this.shouldIncludeBlacklisted(options)) { + this.includeBlacklisted() + } - this.includeThumbnails() + if (this.shouldIncludeAccount(options)) { + this.includeChannels() + this.includeAccounts() + } - this.includeBlacklisted() + if (this.shouldIncludeTags(options)) { + this.includeTags() + } - this.includeScheduleUpdate() + if (this.shouldIncludeScheduleUpdate(options)) { + this.includeScheduleUpdate() + } - this.includeLive() + if (this.shouldIncludeLive(options)) { + this.includeLive() + } - if (options.userId) { + if (options.userId && this.shouldIncludeUserHistory(options)) { this.includeUserHistory(options.userId) } - if (options.forGetAPI === true) { + if (this.shouldIncludeOwnerUser(options)) { + this.includeOwnerUser() + } + + if (this.shouldIncludeTrackers(options)) { this.includeTrackers() } - this.whereId(options.id) + this.whereId(options) - this.query = this.buildQuery() + this.query = this.buildQuery(options) } - private buildQuery () { - const order = 'ORDER BY "Tags"."name" ASC' + private buildQuery (options: BuildVideoGetQueryOptions) { + const order = this.shouldIncludeTags(options) + ? 'ORDER BY "Tags"."name" ASC' + : '' + const from = `SELECT * FROM "video" ${this.where} LIMIT 1` return `${this.buildSelect()} FROM (${from}) AS "video" ${this.joins} ${order}` } + + private shouldIncludeTrackers (options: BuildVideoGetQueryOptions) { + return options.type === 'api' + } + + private shouldIncludeLive (options: BuildVideoGetQueryOptions) { + return [ 'api', 'full-light' ].includes(options.type) + } + + private shouldIncludeScheduleUpdate (options: BuildVideoGetQueryOptions) { + return [ 'api', 'full-light' ].includes(options.type) + } + + private shouldIncludeTags (options: BuildVideoGetQueryOptions) { + return [ 'api', 'full-light' ].includes(options.type) + } + + private shouldIncludeUserHistory (options: BuildVideoGetQueryOptions) { + return [ 'api', 'full-light' ].includes(options.type) + } + + private shouldIncludeAccount (options: BuildVideoGetQueryOptions) { + return [ 'api', 'full-light', 'account-blacklist-files' ].includes(options.type) + } + + private shouldIncludeBlacklisted (options: BuildVideoGetQueryOptions) { + return [ 'api', 'full-light', 'account-blacklist-files', 'thumbnails-blacklist', 'blacklist-rights' ].includes(options.type) + } + + private shouldIncludeOwnerUser (options: BuildVideoGetQueryOptions) { + return options.type === 'blacklist-rights' + } + + private shouldIncludeThumbnails (options: BuildVideoGetQueryOptions) { + return [ 'api', 'full-light', 'account-blacklist-files', 'thumbnails', 'thumbnails-blacklist' ].includes(options.type) + } } 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 this.buildInnerQuery(options) this.buildListQueryFromIdsQuery(options) - return this.runQuery(undefined).then(rows => this.videoModelBuilder.buildVideosFromRows(rows)) + return this.runQuery() + .then(rows => this.videoModelBuilder.buildVideosFromRows(rows)) } 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 { MVideoFormattableDetails, MVideoForUser, MVideoFullLight, - MVideoIdThumbnail, + MVideoId, MVideoImmutable, MVideoThumbnail, MVideoThumbnailBlacklist, MVideoWithAllFiles, - MVideoWithFile, - MVideoWithRights + MVideoWithFile } from '../../types/models' import { MThumbnail } from '../../types/models/video/thumbnail' import { MVideoFile, MVideoFileStreamingPlaylistVideo } from '../../types/models/video/video-file' @@ -1301,27 +1300,16 @@ export class VideoModel extends Model>> { return VideoModel.count(options) } - static load (id: number | string, t?: Transaction): Promise { - const where = buildWhereIdOrUUID(id) - const options = { - where, - transaction: t - } + static load (id: number | string, transaction?: Transaction): Promise { + const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize) - return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options) + return queryBuilder.queryVideo({ id, transaction, type: 'thumbnails' }) } - static loadWithBlacklist (id: number | string, t?: Transaction): Promise { - const where = buildWhereIdOrUUID(id) - const options = { - where, - transaction: t - } + static loadWithBlacklist (id: number | string, transaction?: Transaction): Promise { + const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize) - return VideoModel.scope([ - ScopeNames.WITH_THUMBNAILS, - ScopeNames.WITH_BLACKLISTED - ]).findOne(options) + return queryBuilder.queryVideo({ id, transaction, type: 'thumbnails-blacklist' }) } static loadImmutableAttributes (id: number | string, t?: Transaction): Promise { @@ -1342,68 +1330,6 @@ export class VideoModel extends Model>> { }) } - static loadWithRights (id: number | string, t?: Transaction): Promise { - const where = buildWhereIdOrUUID(id) - const options = { - where, - transaction: t - } - - return VideoModel.scope([ - ScopeNames.WITH_BLACKLISTED, - ScopeNames.WITH_USER_ID - ]).findOne(options) - } - - static loadOnlyId (id: number | string, t?: Transaction): Promise { - const where = buildWhereIdOrUUID(id) - - const options = { - attributes: [ 'id' ], - where, - transaction: t - } - - return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options) - } - - static loadWithFiles (id: number | string, t?: Transaction, logging?: boolean): Promise { - const where = buildWhereIdOrUUID(id) - - const query = { - where, - transaction: t, - logging - } - - return VideoModel.scope([ - ScopeNames.WITH_WEBTORRENT_FILES, - ScopeNames.WITH_STREAMING_PLAYLISTS, - ScopeNames.WITH_THUMBNAILS - ]).findOne(query) - } - - static loadByUUID (uuid: string): Promise { - const options = { - where: { - uuid - } - } - - return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options) - } - - static loadByUrl (url: string, transaction?: Transaction): Promise { - const query: FindOptions = { - where: { - url - }, - transaction - } - - return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(query) - } - static loadByUrlImmutableAttributes (url: string, transaction?: Transaction): Promise { const fun = () => { const query: FindOptions = { @@ -1424,50 +1350,34 @@ export class VideoModel extends Model>> { }) } - static loadByUrlAndPopulateAccount (url: string, transaction?: Transaction): Promise { - const query: FindOptions = { - where: { - url - }, - transaction - } + static loadOnlyId (id: number | string, transaction?: Transaction): Promise { + const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize) - return VideoModel.scope([ - ScopeNames.WITH_ACCOUNT_DETAILS, - ScopeNames.WITH_WEBTORRENT_FILES, - ScopeNames.WITH_STREAMING_PLAYLISTS, - ScopeNames.WITH_THUMBNAILS, - ScopeNames.WITH_BLACKLISTED - ]).findOne(query) + return queryBuilder.queryVideo({ id, transaction, type: 'id' }) } - static loadAndPopulateAccountAndServerAndTags (id: number | string, t?: Transaction, userId?: number): Promise { - const where = buildWhereIdOrUUID(id) + static loadWithFiles (id: number | string, transaction?: Transaction, logging?: boolean): Promise { + const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize) - const options = { - order: [ [ 'Tags', 'name', 'ASC' ] ] as any, - where, - transaction: t - } + return queryBuilder.queryVideo({ id, transaction, type: 'all-files', logging }) + } - const scopes: (string | ScopeOptions)[] = [ - ScopeNames.WITH_TAGS, - ScopeNames.WITH_BLACKLISTED, - ScopeNames.WITH_ACCOUNT_DETAILS, - ScopeNames.WITH_SCHEDULED_UPDATE, - ScopeNames.WITH_WEBTORRENT_FILES, - ScopeNames.WITH_STREAMING_PLAYLISTS, - ScopeNames.WITH_THUMBNAILS, - ScopeNames.WITH_LIVE - ] + static loadByUrl (url: string, transaction?: Transaction): Promise { + const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize) - if (userId) { - scopes.push({ method: [ ScopeNames.WITH_USER_HISTORY, userId ] }) - } + return queryBuilder.queryVideo({ url, transaction, type: 'thumbnails' }) + } + + static loadByUrlAndPopulateAccount (url: string, transaction?: Transaction): Promise { + const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize) + + return queryBuilder.queryVideo({ url, transaction, type: 'account-blacklist-files' }) + } + + static loadAndPopulateAccountAndServerAndTags (id: number | string, t?: Transaction, userId?: number): Promise { + const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize) - return VideoModel - .scope(scopes) - .findOne(options) + return queryBuilder.queryVideo({ id, transaction: t, type: 'full-light', userId }) } static loadForGetAPI (parameters: { @@ -1478,7 +1388,7 @@ export class VideoModel extends Model>> { const { id, transaction, userId } = parameters const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize) - return queryBuilder.queryVideos({ id, transaction, forGetAPI: true, userId }) + return queryBuilder.queryVideo({ id, transaction, type: 'api', userId }) } 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 { MVideoChangeOwnershipFull, MVideoFile, MVideoFormattableDetails, + MVideoId, MVideoImmutable, MVideoLive, MVideoPlaylistFull, @@ -106,8 +107,7 @@ declare module 'express' { videoAll?: MVideoFullLight onlyImmutableVideo?: MVideoImmutable onlyVideo?: MVideoThumbnail - onlyVideoWithRights?: MVideoWithRights - videoId?: MVideoIdThumbnail + videoId?: MVideoId videoLive?: MVideoLive