diff options
author | Rigel Kent <sendmemail@rigelk.eu> | 2021-04-12 11:19:07 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-12 11:19:07 +0200 |
commit | fe19f600dab0f6b00a7aa146ba4bd4bb96536155 (patch) | |
tree | be388f89a41cbc257fc9a642a9205b4910b7a6b7 /server/models | |
parent | a472cf033003cf96b69a80808b2dce1fe382e09b (diff) | |
download | PeerTube-fe19f600dab0f6b00a7aa146ba4bd4bb96536155.tar.gz PeerTube-fe19f600dab0f6b00a7aa146ba4bd4bb96536155.tar.zst PeerTube-fe19f600dab0f6b00a7aa146ba4bd4bb96536155.zip |
add channel and playlist stats to server stats endpoint (#3747)
* add channel and playlist stats to nodeinfo
* add tests for active video channels stats
* fix tests for active channel stats
Diffstat (limited to 'server/models')
-rw-r--r-- | server/models/video/video-channel.ts | 43 | ||||
-rw-r--r-- | server/models/video/video-playlist.ts | 60 |
2 files changed, 89 insertions, 14 deletions
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts index d2a055f5b..b7ffbd3b1 100644 --- a/server/models/video/video-channel.ts +++ b/server/models/video/video-channel.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { FindOptions, Includeable, literal, Op, ScopeOptions } from 'sequelize' | 1 | import { FindOptions, Includeable, literal, Op, QueryTypes, ScopeOptions } from 'sequelize' |
2 | import { | 2 | import { |
3 | AllowNull, | 3 | AllowNull, |
4 | BeforeDestroy, | 4 | BeforeDestroy, |
@@ -338,6 +338,47 @@ export class VideoChannelModel extends Model { | |||
338 | return VideoChannelModel.count(query) | 338 | return VideoChannelModel.count(query) |
339 | } | 339 | } |
340 | 340 | ||
341 | static async getStats () { | ||
342 | |||
343 | function getActiveVideoChannels (days: number) { | ||
344 | const options = { | ||
345 | type: QueryTypes.SELECT as QueryTypes.SELECT, | ||
346 | raw: true | ||
347 | } | ||
348 | |||
349 | const query = ` | ||
350 | SELECT COUNT(DISTINCT("VideoChannelModel"."id")) AS "count" | ||
351 | FROM "videoChannel" AS "VideoChannelModel" | ||
352 | INNER JOIN "video" AS "Videos" | ||
353 | ON "VideoChannelModel"."id" = "Videos"."channelId" | ||
354 | AND ("Videos"."publishedAt" > Now() - interval '${days}d') | ||
355 | INNER JOIN "account" AS "Account" | ||
356 | ON "VideoChannelModel"."accountId" = "Account"."id" | ||
357 | INNER JOIN "actor" AS "Account->Actor" | ||
358 | ON "Account"."actorId" = "Account->Actor"."id" | ||
359 | AND "Account->Actor"."serverId" IS NULL | ||
360 | LEFT OUTER JOIN "server" AS "Account->Actor->Server" | ||
361 | ON "Account->Actor"."serverId" = "Account->Actor->Server"."id"` | ||
362 | |||
363 | return VideoChannelModel.sequelize.query<{ count: string }>(query, options) | ||
364 | .then(r => parseInt(r[0].count, 10)) | ||
365 | } | ||
366 | |||
367 | const totalLocalVideoChannels = await VideoChannelModel.count() | ||
368 | const totalLocalDailyActiveVideoChannels = await getActiveVideoChannels(1) | ||
369 | const totalLocalWeeklyActiveVideoChannels = await getActiveVideoChannels(7) | ||
370 | const totalLocalMonthlyActiveVideoChannels = await getActiveVideoChannels(30) | ||
371 | const totalHalfYearActiveVideoChannels = await getActiveVideoChannels(180) | ||
372 | |||
373 | return { | ||
374 | totalLocalVideoChannels, | ||
375 | totalLocalDailyActiveVideoChannels, | ||
376 | totalLocalWeeklyActiveVideoChannels, | ||
377 | totalLocalMonthlyActiveVideoChannels, | ||
378 | totalHalfYearActiveVideoChannels | ||
379 | } | ||
380 | } | ||
381 | |||
341 | static listForApi (parameters: { | 382 | static listForApi (parameters: { |
342 | actorId: number | 383 | actorId: number |
343 | start: number | 384 | start: number |
diff --git a/server/models/video/video-playlist.ts b/server/models/video/video-playlist.ts index 49a406608..efe5be36d 100644 --- a/server/models/video/video-playlist.ts +++ b/server/models/video/video-playlist.ts | |||
@@ -54,6 +54,7 @@ import { buildServerIdsFollowedBy, buildWhereIdOrUUID, getPlaylistSort, isOutdat | |||
54 | import { ThumbnailModel } from './thumbnail' | 54 | import { ThumbnailModel } from './thumbnail' |
55 | import { ScopeNames as VideoChannelScopeNames, VideoChannelModel } from './video-channel' | 55 | import { ScopeNames as VideoChannelScopeNames, VideoChannelModel } from './video-channel' |
56 | import { VideoPlaylistElementModel } from './video-playlist-element' | 56 | import { VideoPlaylistElementModel } from './video-playlist-element' |
57 | import { ActorModel } from '../activitypub/actor' | ||
57 | 58 | ||
58 | enum ScopeNames { | 59 | enum ScopeNames { |
59 | AVAILABLE_FOR_LIST = 'AVAILABLE_FOR_LIST', | 60 | AVAILABLE_FOR_LIST = 'AVAILABLE_FOR_LIST', |
@@ -65,7 +66,7 @@ enum ScopeNames { | |||
65 | } | 66 | } |
66 | 67 | ||
67 | type AvailableForListOptions = { | 68 | type AvailableForListOptions = { |
68 | followerActorId: number | 69 | followerActorId?: number |
69 | type?: VideoPlaylistType | 70 | type?: VideoPlaylistType |
70 | accountId?: number | 71 | accountId?: number |
71 | videoChannelId?: number | 72 | videoChannelId?: number |
@@ -134,20 +135,26 @@ type AvailableForListOptions = { | |||
134 | privacy: VideoPlaylistPrivacy.PUBLIC | 135 | privacy: VideoPlaylistPrivacy.PUBLIC |
135 | }) | 136 | }) |
136 | 137 | ||
137 | // Only list local playlists OR playlists that are on an instance followed by actorId | 138 | // Only list local playlists |
138 | const inQueryInstanceFollow = buildServerIdsFollowedBy(options.followerActorId) | 139 | const whereActorOr: WhereOptions[] = [ |
140 | { | ||
141 | serverId: null | ||
142 | } | ||
143 | ] | ||
139 | 144 | ||
140 | whereActor = { | 145 | // … OR playlists that are on an instance followed by actorId |
141 | [Op.or]: [ | 146 | if (options.followerActorId) { |
142 | { | 147 | const inQueryInstanceFollow = buildServerIdsFollowedBy(options.followerActorId) |
143 | serverId: null | 148 | |
144 | }, | 149 | whereActorOr.push({ |
145 | { | 150 | serverId: { |
146 | serverId: { | 151 | [Op.in]: literal(inQueryInstanceFollow) |
147 | [Op.in]: literal(inQueryInstanceFollow) | ||
148 | } | ||
149 | } | 152 | } |
150 | ] | 153 | }) |
154 | } | ||
155 | |||
156 | whereActor = { | ||
157 | [Op.or]: whereActorOr | ||
151 | } | 158 | } |
152 | } | 159 | } |
153 | 160 | ||
@@ -495,6 +502,33 @@ export class VideoPlaylistModel extends Model { | |||
495 | return '/video-playlists/embed/' + this.uuid | 502 | return '/video-playlists/embed/' + this.uuid |
496 | } | 503 | } |
497 | 504 | ||
505 | static async getStats () { | ||
506 | const totalLocalPlaylists = await VideoPlaylistModel.count({ | ||
507 | include: [ | ||
508 | { | ||
509 | model: AccountModel, | ||
510 | required: true, | ||
511 | include: [ | ||
512 | { | ||
513 | model: ActorModel, | ||
514 | required: true, | ||
515 | where: { | ||
516 | serverId: null | ||
517 | } | ||
518 | } | ||
519 | ] | ||
520 | } | ||
521 | ], | ||
522 | where: { | ||
523 | privacy: VideoPlaylistPrivacy.PUBLIC | ||
524 | } | ||
525 | }) | ||
526 | |||
527 | return { | ||
528 | totalLocalPlaylists | ||
529 | } | ||
530 | } | ||
531 | |||
498 | setAsRefreshed () { | 532 | setAsRefreshed () { |
499 | this.changed('updatedAt', true) | 533 | this.changed('updatedAt', true) |
500 | 534 | ||