X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Fmodels%2Fvideo%2Fvideo-channel.ts;h=03a3cdf81da8c7c7f6d84cc89666bbc67936cbbe;hb=4f32032fed8587ea97d45e235b167e8958efd81f;hp=128915af31a9d7d0b727c55946f9e7d7105313b6;hpb=8165d00ac6263cf3c0d61d450960ef36635084ff;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts index 128915af3..03a3cdf81 100644 --- a/server/models/video/video-channel.ts +++ b/server/models/video/video-channel.ts @@ -41,7 +41,7 @@ import { MChannelAP, MChannelFormattable, MChannelSummaryFormattable -} from '../../typings/models/video' +} from '../../types/models/video' export enum ScopeNames { FOR_API = 'FOR_API', @@ -61,6 +61,7 @@ type AvailableWithStatsOptions = { } export type SummaryOptions = { + actorRequired?: boolean // Default: true withAccount?: boolean // Default: false withAccountBlockerIds?: number[] } @@ -121,7 +122,7 @@ export type SummaryOptions = { { attributes: [ 'id', 'preferredUsername', 'url', 'serverId', 'avatarId' ], model: ActorModel.unscoped(), - required: true, + required: options.actorRequired ?? true, include: [ { attributes: [ 'host' ], @@ -166,42 +167,43 @@ export type SummaryOptions = { VideoModel ] }, - [ScopeNames.WITH_STATS]: (options: AvailableWithStatsOptions = { daysPrior: 30 }) => ({ - attributes: { - include: [ - [ - literal( - '(' + - `SELECT string_agg(concat_ws('|', t.day, t.views), ',') ` + - 'FROM ( ' + - 'WITH ' + - 'days AS ( ' + - `SELECT generate_series(date_trunc('day', now()) - '${options.daysPrior} day'::interval, ` + - `date_trunc('day', now()), '1 day'::interval) AS day ` + - '), ' + - 'views AS ( ' + - 'SELECT * ' + - 'FROM "videoView" ' + - 'WHERE "videoView"."videoId" IN ( ' + - 'SELECT "video"."id" ' + - 'FROM "video" ' + - 'WHERE "video"."channelId" = "VideoChannelModel"."id" ' + + [ScopeNames.WITH_STATS]: (options: AvailableWithStatsOptions = { daysPrior: 30 }) => { + const daysPrior = parseInt(options.daysPrior + '', 10) + + return { + attributes: { + include: [ + [ + literal('(SELECT COUNT(*) FROM "video" WHERE "channelId" = "VideoChannelModel"."id")'), + 'videosCount' + ], + [ + literal( + '(' + + `SELECT string_agg(concat_ws('|', t.day, t.views), ',') ` + + 'FROM ( ' + + 'WITH ' + + 'days AS ( ' + + `SELECT generate_series(date_trunc('day', now()) - '${daysPrior} day'::interval, ` + + `date_trunc('day', now()), '1 day'::interval) AS day ` + ') ' + - ') ' + - 'SELECT days.day AS day, ' + - 'COALESCE(SUM(views.views), 0) AS views ' + - 'FROM days ' + - `LEFT JOIN views ON date_trunc('day', "views"."createdAt") = days.day ` + - 'GROUP BY 1 ' + - 'ORDER BY day ' + - ') t' + - ')' - ), - 'viewsPerDay' + 'SELECT days.day AS day, COALESCE(SUM("videoView".views), 0) AS views ' + + 'FROM days ' + + 'LEFT JOIN (' + + '"videoView" INNER JOIN "video" ON "videoView"."videoId" = "video"."id" ' + + 'AND "video"."channelId" = "VideoChannelModel"."id"' + + `) ON date_trunc('day', "videoView"."startDate") = date_trunc('day', days.day) ` + + 'GROUP BY day ' + + 'ORDER BY day ' + + ') t' + + ')' + ), + 'viewsPerDay' + ] ] - ] + } } - }) + } })) @Table({ tableName: 'videoChannel', @@ -412,8 +414,7 @@ export class VideoChannelModel extends Model { const scopes: string | ScopeOptions | (string | ScopeOptions)[] = [ ScopeNames.WITH_ACTOR ] - options.withStats = true // TODO: remove beyond after initial tests - if (options.withStats) { + if (options.withStats === true) { scopes.push({ method: [ ScopeNames.WITH_STATS, { daysPrior: 30 } as AvailableWithStatsOptions ] }) @@ -548,7 +549,22 @@ export class VideoChannelModel extends Model { } toFormattedJSON (this: MChannelFormattable): VideoChannel { - const viewsPerDay = this.get('viewsPerDay') as string + const viewsPerDayString = this.get('viewsPerDay') as string + const videosCount = this.get('videosCount') as number + + let viewsPerDay: { date: Date, views: number }[] + + if (viewsPerDayString) { + viewsPerDay = viewsPerDayString.split(',') + .map(v => { + const [ dateString, amount ] = v.split('|') + + return { + date: new Date(dateString), + views: +amount + } + }) + } const actor = this.Actor.toFormattedJSON() const videoChannel = { @@ -560,15 +576,8 @@ export class VideoChannelModel extends Model { createdAt: this.createdAt, updatedAt: this.updatedAt, ownerAccount: undefined, - viewsPerDay: viewsPerDay !== undefined - ? viewsPerDay.split(',').map(v => { - const o = v.split('|') - return { - date: new Date(o[0]), - views: +o[1] - } - }) - : undefined + videosCount, + viewsPerDay } if (this.Account) videoChannel.ownerAccount = this.Account.toFormattedJSON()