X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Fmodels%2Fvideo%2Fvideo-playlist-element.ts;h=4ba16f5fd4ee56cacc3010437e2bcdf055e714f5;hb=f409f0c3b91d85c66b4841d72ea65b5fbe1483d8;hp=3396b11367902557073a87ef4f36698388836fbf;hpb=74dc3bca2b14f5fd3fe80c394dfc34177a46db77;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/models/video/video-playlist-element.ts b/server/models/video/video-playlist-element.ts index 3396b1136..4ba16f5fd 100644 --- a/server/models/video/video-playlist-element.ts +++ b/server/models/video/video-playlist-element.ts @@ -13,14 +13,26 @@ import { Table, UpdatedAt } from 'sequelize-typescript' -import { VideoModel } from './video' +import { ForAPIOptions, ScopeNames as VideoScopeNames, VideoModel } from './video' import { VideoPlaylistModel } from './video-playlist' -import * as Sequelize from 'sequelize' import { getSort, throwIfNotValid } from '../utils' import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' import { CONSTRAINTS_FIELDS } from '../../initializers/constants' import { PlaylistElementObject } from '../../../shared/models/activitypub/objects/playlist-element-object' -import * as validator from 'validator' +import validator from 'validator' +import { AggregateOptions, Op, ScopeOptions, Sequelize, Transaction } from 'sequelize' +import { VideoPlaylistElement, VideoPlaylistElementType } from '../../../shared/models/videos/playlist/video-playlist-element.model' +import { AccountModel } from '../account/account' +import { VideoPrivacy } from '../../../shared/models/videos' +import * as Bluebird from 'bluebird' +import { + MVideoPlaylistElement, + MVideoPlaylistElementAP, + MVideoPlaylistElementFormattable, + MVideoPlaylistElementVideoUrlPlaylistPrivacy, + MVideoPlaylistVideoThumbnail +} from '@server/typings/models/video/video-playlist-element' +import { MUserAccountId } from '@server/typings/models' @Table({ tableName: 'videoPlaylistElement', @@ -90,13 +102,13 @@ export class VideoPlaylistElementModel extends Model @BelongsTo(() => VideoModel, { foreignKey: { - allowNull: false + allowNull: true }, - onDelete: 'CASCADE' + onDelete: 'set null' }) Video: VideoModel - static deleteAllOf (videoPlaylistId: number, transaction?: Sequelize.Transaction) { + static deleteAllOf (videoPlaylistId: number, transaction?: Transaction) { const query = { where: { videoPlaylistId @@ -107,7 +119,58 @@ export class VideoPlaylistElementModel extends Model return VideoPlaylistElementModel.destroy(query) } - static loadByPlaylistAndVideo (videoPlaylistId: number, videoId: number) { + static listForApi (options: { + start: number + count: number + videoPlaylistId: number + serverAccount: AccountModel + user?: MUserAccountId + }) { + const accountIds = [ options.serverAccount.id ] + const videoScope: (ScopeOptions | string)[] = [ + VideoScopeNames.WITH_BLACKLISTED + ] + + if (options.user) { + accountIds.push(options.user.Account.id) + videoScope.push({ method: [ VideoScopeNames.WITH_USER_HISTORY, options.user.id ] }) + } + + const forApiOptions: ForAPIOptions = { withAccountBlockerIds: accountIds } + videoScope.push({ + method: [ + VideoScopeNames.FOR_API, forApiOptions + ] + }) + + const findQuery = { + offset: options.start, + limit: options.count, + order: getSort('position'), + where: { + videoPlaylistId: options.videoPlaylistId + }, + include: [ + { + model: VideoModel.scope(videoScope), + required: false + } + ] + } + + const countQuery = { + where: { + videoPlaylistId: options.videoPlaylistId + } + } + + return Promise.all([ + VideoPlaylistElementModel.count(countQuery), + VideoPlaylistElementModel.findAll(findQuery) + ]).then(([ total, data ]) => ({ total, data })) + } + + static loadByPlaylistAndVideo (videoPlaylistId: number, videoId: number): Bluebird { const query = { where: { videoPlaylistId, @@ -118,7 +181,14 @@ export class VideoPlaylistElementModel extends Model return VideoPlaylistElementModel.findOne(query) } - static loadByPlaylistAndVideoForAP (playlistId: number | string, videoId: number | string) { + static loadById (playlistElementId: number | string): Bluebird { + return VideoPlaylistElementModel.findByPk(playlistElementId) + } + + static loadByPlaylistAndVideoForAP ( + playlistId: number | string, + videoId: number | string + ): Bluebird { const playlistWhere = validator.isUUID('' + playlistId) ? { uuid: playlistId } : { id: playlistId } const videoWhere = validator.isUUID('' + videoId) ? { uuid: videoId } : { id: videoId } @@ -140,7 +210,7 @@ export class VideoPlaylistElementModel extends Model return VideoPlaylistElementModel.findOne(query) } - static listUrlsOfForAP (videoPlaylistId: number, start: number, count: number, t?: Sequelize.Transaction) { + static listUrlsOfForAP (videoPlaylistId: number, start: number, count: number, t?: Transaction) { const query = { attributes: [ 'url' ], offset: start, @@ -159,8 +229,26 @@ export class VideoPlaylistElementModel extends Model }) } - static getNextPositionOf (videoPlaylistId: number, transaction?: Sequelize.Transaction) { + static loadFirstElementWithVideoThumbnail (videoPlaylistId: number): Bluebird { const query = { + order: getSort('position'), + where: { + videoPlaylistId + }, + include: [ + { + model: VideoModel.scope(VideoScopeNames.WITH_THUMBNAILS), + required: true + } + ] + } + + return VideoPlaylistElementModel + .findOne(query) + } + + static getNextPositionOf (videoPlaylistId: number, transaction?: Transaction) { + const query: AggregateOptions = { where: { videoPlaylistId }, @@ -176,14 +264,14 @@ export class VideoPlaylistElementModel extends Model firstPosition: number, endPosition: number, newPosition: number, - transaction?: Sequelize.Transaction + transaction?: Transaction ) { const query = { where: { videoPlaylistId, position: { - [Sequelize.Op.gte]: firstPosition, - [Sequelize.Op.lte]: endPosition + [Op.gte]: firstPosition, + [Op.lte]: endPosition } }, transaction, @@ -198,13 +286,13 @@ export class VideoPlaylistElementModel extends Model fromPosition: number, toPosition?: number, by = 1, - transaction?: Sequelize.Transaction + transaction?: Transaction ) { const query = { where: { videoPlaylistId, position: { - [Sequelize.Op.gte]: fromPosition + [Op.gte]: fromPosition } }, transaction @@ -213,7 +301,46 @@ export class VideoPlaylistElementModel extends Model return VideoPlaylistElementModel.increment({ position: by }, query) } - toActivityPubObject (): PlaylistElementObject { + getType (this: MVideoPlaylistElementFormattable, displayNSFW?: boolean, accountId?: number) { + const video = this.Video + + if (!video) return VideoPlaylistElementType.DELETED + + // Owned video, don't filter it + if (accountId && video.VideoChannel.Account.id === accountId) return VideoPlaylistElementType.REGULAR + + if (video.privacy === VideoPrivacy.PRIVATE) return VideoPlaylistElementType.PRIVATE + + if (video.isBlacklisted() || video.isBlocked()) return VideoPlaylistElementType.UNAVAILABLE + if (video.nsfw === true && displayNSFW === false) return VideoPlaylistElementType.UNAVAILABLE + + return VideoPlaylistElementType.REGULAR + } + + getVideoElement (this: MVideoPlaylistElementFormattable, displayNSFW?: boolean, accountId?: number) { + if (!this.Video) return null + if (this.getType(displayNSFW, accountId) !== VideoPlaylistElementType.REGULAR) return null + + return this.Video.toFormattedJSON() + } + + toFormattedJSON ( + this: MVideoPlaylistElementFormattable, + options: { displayNSFW?: boolean, accountId?: number } = {} + ): VideoPlaylistElement { + return { + id: this.id, + position: this.position, + startTimestamp: this.startTimestamp, + stopTimestamp: this.stopTimestamp, + + type: this.getType(options.displayNSFW, options.accountId), + + video: this.getVideoElement(options.displayNSFW, options.accountId) + } + } + + toActivityPubObject (this: MVideoPlaylistElementAP): PlaylistElementObject { const base: PlaylistElementObject = { id: this.url, type: 'PlaylistElement',