From 6e46de095d7169355dd83030f6ce4a582304153a Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 5 Oct 2018 11:15:06 +0200 Subject: Add user history and resume videos --- server/models/video/video-format-utils.ts | 9 +++- server/models/video/video.ts | 80 ++++++++++++++++++++++++------- 2 files changed, 72 insertions(+), 17 deletions(-) (limited to 'server/models/video') diff --git a/server/models/video/video-format-utils.ts b/server/models/video/video-format-utils.ts index f23dde9b8..78972b199 100644 --- a/server/models/video/video-format-utils.ts +++ b/server/models/video/video-format-utils.ts @@ -10,6 +10,7 @@ import { getVideoLikesActivityPubUrl, getVideoSharesActivityPubUrl } from '../../lib/activitypub' +import { isArray } from 'util' export type VideoFormattingJSONOptions = { completeDescription?: boolean @@ -24,6 +25,8 @@ function videoModelToFormattedJSON (video: VideoModel, options?: VideoFormatting const formattedAccount = video.VideoChannel.Account.toFormattedJSON() const formattedVideoChannel = video.VideoChannel.toFormattedJSON() + const userHistory = isArray(video.UserVideoHistories) ? video.UserVideoHistories[0] : undefined + const videoObject: Video = { id: video.id, uuid: video.uuid, @@ -74,7 +77,11 @@ function videoModelToFormattedJSON (video: VideoModel, options?: VideoFormatting url: formattedVideoChannel.url, host: formattedVideoChannel.host, avatar: formattedVideoChannel.avatar - } + }, + + userHistory: userHistory ? { + currentTime: userHistory.currentTime + } : undefined } if (options) { diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 6c89c16bf..0a2d7e6de 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts @@ -92,6 +92,8 @@ import { videoModelToFormattedJSON } from './video-format-utils' import * as validator from 'validator' +import { UserVideoHistoryModel } from '../account/user-video-history' + // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation const indexes: Sequelize.DefineIndexesOptions[] = [ @@ -127,7 +129,8 @@ export enum ScopeNames { WITH_TAGS = 'WITH_TAGS', WITH_FILES = 'WITH_FILES', WITH_SCHEDULED_UPDATE = 'WITH_SCHEDULED_UPDATE', - WITH_BLACKLISTED = 'WITH_BLACKLISTED' + WITH_BLACKLISTED = 'WITH_BLACKLISTED', + WITH_USER_HISTORY = 'WITH_USER_HISTORY' } type ForAPIOptions = { @@ -464,6 +467,8 @@ type AvailableForListIDsOptions = { include: [ { model: () => VideoFileModel.unscoped(), + // FIXME: typings + [ 'separate' as any ]: true, // We may have multiple files, having multiple redundancies so let's separate this join required: false, include: [ { @@ -482,6 +487,20 @@ type AvailableForListIDsOptions = { required: false } ] + }, + [ ScopeNames.WITH_USER_HISTORY ]: (userId: number) => { + return { + include: [ + { + attributes: [ 'currentTime' ], + model: UserVideoHistoryModel.unscoped(), + required: false, + where: { + userId + } + } + ] + } } }) @Table({ @@ -672,11 +691,19 @@ export class VideoModel extends Model { name: 'videoId', allowNull: false }, - onDelete: 'cascade', - hooks: true + onDelete: 'cascade' }) VideoViews: VideoViewModel[] + @HasMany(() => UserVideoHistoryModel, { + foreignKey: { + name: 'videoId', + allowNull: false + }, + onDelete: 'cascade' + }) + UserVideoHistories: UserVideoHistoryModel[] + @HasOne(() => ScheduleVideoUpdateModel, { foreignKey: { name: 'videoId', @@ -930,7 +957,8 @@ export class VideoModel extends Model { accountId?: number, videoChannelId?: number, actorId?: number - trendingDays?: number + trendingDays?: number, + userId?: number }, countVideos = true) { const query: IFindOptions = { offset: options.start, @@ -961,6 +989,7 @@ export class VideoModel extends Model { accountId: options.accountId, videoChannelId: options.videoChannelId, includeLocalVideos: options.includeLocalVideos, + userId: options.userId, trendingDays } @@ -983,6 +1012,7 @@ export class VideoModel extends Model { tagsAllOf?: string[] durationMin?: number // seconds durationMax?: number // seconds + userId?: number }) { const whereAnd = [] @@ -1058,7 +1088,8 @@ export class VideoModel extends Model { licenceOneOf: options.licenceOneOf, languageOneOf: options.languageOneOf, tagsOneOf: options.tagsOneOf, - tagsAllOf: options.tagsAllOf + tagsAllOf: options.tagsAllOf, + userId: options.userId } return VideoModel.getAvailableForApi(query, queryOptions) @@ -1125,7 +1156,7 @@ export class VideoModel extends Model { return VideoModel.scope([ ScopeNames.WITH_ACCOUNT_DETAILS, ScopeNames.WITH_FILES ]).findOne(query) } - static loadAndPopulateAccountAndServerAndTags (id: number | string, t?: Sequelize.Transaction) { + static loadAndPopulateAccountAndServerAndTags (id: number | string, t?: Sequelize.Transaction, userId?: number) { const where = VideoModel.buildWhereIdOrUUID(id) const options = { @@ -1134,14 +1165,20 @@ export class VideoModel extends Model { transaction: t } + const scopes = [ + ScopeNames.WITH_TAGS, + ScopeNames.WITH_BLACKLISTED, + ScopeNames.WITH_FILES, + ScopeNames.WITH_ACCOUNT_DETAILS, + ScopeNames.WITH_SCHEDULED_UPDATE + ] + + if (userId) { + scopes.push({ method: [ ScopeNames.WITH_USER_HISTORY, userId ] } as any) // FIXME: typings + } + return VideoModel - .scope([ - ScopeNames.WITH_TAGS, - ScopeNames.WITH_BLACKLISTED, - ScopeNames.WITH_FILES, - ScopeNames.WITH_ACCOUNT_DETAILS, - ScopeNames.WITH_SCHEDULED_UPDATE - ]) + .scope(scopes) .findOne(options) } @@ -1225,7 +1262,11 @@ export class VideoModel extends Model { return {} } - private static async getAvailableForApi (query: IFindOptions, options: AvailableForListIDsOptions, countVideos = true) { + private static async getAvailableForApi ( + query: IFindOptions, + options: AvailableForListIDsOptions & { userId?: number}, + countVideos = true + ) { const idsScope = { method: [ ScopeNames.AVAILABLE_FOR_LIST_IDS, options @@ -1249,8 +1290,15 @@ export class VideoModel extends Model { if (ids.length === 0) return { data: [], total: count } - const apiScope = { - method: [ ScopeNames.FOR_API, { ids, withFiles: options.withFiles } as ForAPIOptions ] + // FIXME: typings + const apiScope: any[] = [ + { + method: [ ScopeNames.FOR_API, { ids, withFiles: options.withFiles } as ForAPIOptions ] + } + ] + + if (options.userId) { + apiScope.push({ method: [ ScopeNames.WITH_USER_HISTORY, options.userId ] }) } const secondQuery = { -- cgit v1.2.3