From b36f41ca09e92ecb30d367d91d1089a23d10d585 Mon Sep 17 00:00:00 2001 From: Chocobozzz <me@florianbigard.com> Date: Fri, 14 Sep 2018 09:57:21 +0200 Subject: Add trending videos strategy --- server/models/redundancy/video-redundancy.ts | 115 ++++++++++++++++++--------- server/models/video/video.ts | 32 +++++--- 2 files changed, 96 insertions(+), 51 deletions(-) (limited to 'server/models') diff --git a/server/models/redundancy/video-redundancy.ts b/server/models/redundancy/video-redundancy.ts index 48ec77206..b13ade0f4 100644 --- a/server/models/redundancy/video-redundancy.ts +++ b/server/models/redundancy/video-redundancy.ts @@ -14,11 +14,10 @@ import { UpdatedAt } from 'sequelize-typescript' import { ActorModel } from '../activitypub/actor' -import { throwIfNotValid } from '../utils' +import { getVideoSort, throwIfNotValid } from '../utils' import { isActivityPubUrlValid, isUrlValid } from '../../helpers/custom-validators/activitypub/misc' -import { CONSTRAINTS_FIELDS, VIDEO_EXT_MIMETYPE } from '../../initializers' +import { CONFIG, CONSTRAINTS_FIELDS, VIDEO_EXT_MIMETYPE } from '../../initializers' import { VideoFileModel } from '../video/video-file' -import { isDateValid } from '../../helpers/custom-validators/misc' import { getServerActor } from '../../helpers/utils' import { VideoModel } from '../video/video' import { VideoRedundancyStrategy } from '../../../shared/models/redundancy' @@ -145,50 +144,51 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { return VideoRedundancyModel.findOne(query) } + static getVideoSample (rows: { id: number }[]) { + const ids = rows.map(r => r.id) + const id = sample(ids) + + return VideoModel.loadWithFile(id, undefined, !isTestInstance()) + } + static async findMostViewToDuplicate (randomizedFactor: number) { // On VideoModel! const query = { + attributes: [ 'id', 'views' ], logging: !isTestInstance(), limit: randomizedFactor, - order: [ [ 'views', 'DESC' ] ], + order: getVideoSort('-views'), include: [ - { - model: VideoFileModel.unscoped(), - required: true, - where: { - id: { - [ Sequelize.Op.notIn ]: await VideoRedundancyModel.buildExcludeIn() - } - } - }, - { - attributes: [], - model: VideoChannelModel.unscoped(), - required: true, - include: [ - { - attributes: [], - model: ActorModel.unscoped(), - required: true, - include: [ - { - attributes: [], - model: ServerModel.unscoped(), - required: true, - where: { - redundancyAllowed: true - } - } - ] - } - ] - } + await VideoRedundancyModel.buildVideoFileForDuplication(), + VideoRedundancyModel.buildServerRedundancyInclude() + ] + } + + const rows = await VideoModel.unscoped().findAll(query) + + return VideoRedundancyModel.getVideoSample(rows as { id: number }[]) + } + + static async findTrendingToDuplicate (randomizedFactor: number) { + // On VideoModel! + const query = { + attributes: [ 'id', 'views' ], + subQuery: false, + logging: !isTestInstance(), + group: 'VideoModel.id', + limit: randomizedFactor, + order: getVideoSort('-trending'), + include: [ + await VideoRedundancyModel.buildVideoFileForDuplication(), + VideoRedundancyModel.buildServerRedundancyInclude(), + + VideoModel.buildTrendingQuery(CONFIG.TRENDING.VIDEOS.INTERVAL_DAYS) ] } const rows = await VideoModel.unscoped().findAll(query) - return sample(rows) + return VideoRedundancyModel.getVideoSample(rows as { id: number }[]) } static async getVideoFiles (strategy: VideoRedundancyStrategy) { @@ -211,7 +211,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { logging: !isTestInstance(), where: { expiresOn: { - [Sequelize.Op.lt]: new Date() + [ Sequelize.Op.lt ]: new Date() } } } @@ -237,13 +237,50 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { } } - private static async buildExcludeIn () { + // Don't include video files we already duplicated + private static async buildVideoFileForDuplication () { const actor = await getServerActor() - return Sequelize.literal( + const notIn = Sequelize.literal( '(' + `SELECT "videoFileId" FROM "videoRedundancy" WHERE "actorId" = ${actor.id} AND "expiresOn" >= NOW()` + ')' ) + + return { + attributes: [], + model: VideoFileModel.unscoped(), + required: true, + where: { + id: { + [ Sequelize.Op.notIn ]: notIn + } + } + } + } + + private static buildServerRedundancyInclude () { + return { + attributes: [], + model: VideoChannelModel.unscoped(), + required: true, + include: [ + { + attributes: [], + model: ActorModel.unscoped(), + required: true, + include: [ + { + attributes: [], + model: ServerModel.unscoped(), + required: true, + where: { + redundancyAllowed: true + } + } + ] + } + ] + } } } diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 27c631dcd..ef8be7c86 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts @@ -387,16 +387,7 @@ type AvailableForListIDsOptions = { } if (options.trendingDays) { - query.include.push({ - attributes: [], - model: VideoViewModel, - required: false, - where: { - startDate: { - [ Sequelize.Op.gte ]: new Date(new Date().getTime() - (24 * 3600 * 1000) * options.trendingDays) - } - } - }) + query.include.push(VideoModel.buildTrendingQuery(options.trendingDays)) query.subQuery = false } @@ -1071,9 +1062,12 @@ export class VideoModel extends Model<VideoModel> { } static load (id: number, t?: Sequelize.Transaction) { - const options = t ? { transaction: t } : undefined + return VideoModel.findById(id, { transaction: t }) + } - return VideoModel.findById(id, options) + static loadWithFile (id: number, t?: Sequelize.Transaction, logging?: boolean) { + return VideoModel.scope(ScopeNames.WITH_FILES) + .findById(id, { transaction: t, logging }) } static loadByUrlAndPopulateAccount (url: string, t?: Sequelize.Transaction) { @@ -1191,6 +1185,20 @@ export class VideoModel extends Model<VideoModel> { .then(rows => rows.map(r => r[ field ])) } + static buildTrendingQuery (trendingDays: number) { + return { + attributes: [], + subQuery: false, + model: VideoViewModel, + required: false, + where: { + startDate: { + [ Sequelize.Op.gte ]: new Date(new Date().getTime() - (24 * 3600 * 1000) * trendingDays) + } + } + } + } + private static buildActorWhereWithFilter (filter?: VideoFilter) { if (filter && filter === 'local') { return { -- cgit v1.2.3