diff options
6 files changed, 41 insertions, 1 deletions
diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html index e7003f1e4..f17f62bba 100644 --- a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html +++ b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html | |||
@@ -36,6 +36,8 @@ | |||
36 | 36 | ||
37 | <div i18n class="video-channel-videos">{videoChannel.videosCount, plural, =0 {No videos} =1 {1 video} other {{{ videoChannel.videosCount }} videos}}</div> | 37 | <div i18n class="video-channel-videos">{videoChannel.videosCount, plural, =0 {No videos} =1 {1 video} other {{{ videoChannel.videosCount }} videos}}</div> |
38 | 38 | ||
39 | <div i18n class="video-channel-views">{videoChannel.totalViews, plural, =0 {No views} =1 {1 view} other {{{ videoChannel.totalViews }} views}}</div> | ||
40 | |||
39 | <div class="video-channel-buttons"> | 41 | <div class="video-channel-buttons"> |
40 | <my-edit-button label [routerLink]="[ '/manage/update', videoChannel.nameWithHost ]"></my-edit-button> | 42 | <my-edit-button label [routerLink]="[ '/manage/update', videoChannel.nameWithHost ]"></my-edit-button> |
41 | <my-delete-button label (click)="deleteVideoChannel(videoChannel)"></my-delete-button> | 43 | <my-delete-button label (click)="deleteVideoChannel(videoChannel)"></my-delete-button> |
diff --git a/client/src/app/shared/shared-main/video-channel/video-channel.model.ts b/client/src/app/shared/shared-main/video-channel/video-channel.model.ts index 32376bf62..62bd94349 100644 --- a/client/src/app/shared/shared-main/video-channel/video-channel.model.ts +++ b/client/src/app/shared/shared-main/video-channel/video-channel.model.ts | |||
@@ -27,6 +27,7 @@ export class VideoChannel extends Actor implements ServerVideoChannel { | |||
27 | videosCount?: number | 27 | videosCount?: number |
28 | 28 | ||
29 | viewsPerDay?: ViewsPerDate[] | 29 | viewsPerDay?: ViewsPerDate[] |
30 | totalViews?: number | ||
30 | 31 | ||
31 | static GET_ACTOR_AVATAR_URL (actor: { avatars: { width: number, url?: string, path: string }[] }, size: number) { | 32 | static GET_ACTOR_AVATAR_URL (actor: { avatars: { width: number, url?: string, path: string }[] }, size: number) { |
32 | return Actor.GET_ACTOR_AVATAR_URL(actor, size) | 33 | return Actor.GET_ACTOR_AVATAR_URL(actor, size) |
@@ -74,6 +75,10 @@ export class VideoChannel extends Actor implements ServerVideoChannel { | |||
74 | this.viewsPerDay = hash.viewsPerDay.map(v => ({ ...v, date: new Date(v.date) })) | 75 | this.viewsPerDay = hash.viewsPerDay.map(v => ({ ...v, date: new Date(v.date) })) |
75 | } | 76 | } |
76 | 77 | ||
78 | if (hash.totalViews !== null && hash.totalViews !== undefined) { | ||
79 | this.totalViews = hash.totalViews | ||
80 | } | ||
81 | |||
77 | if (hash.ownerAccount) { | 82 | if (hash.ownerAccount) { |
78 | this.ownerAccount = hash.ownerAccount | 83 | this.ownerAccount = hash.ownerAccount |
79 | this.ownerBy = Actor.CREATE_BY_STRING(hash.ownerAccount.name, hash.ownerAccount.host) | 84 | this.ownerBy = Actor.CREATE_BY_STRING(hash.ownerAccount.name, hash.ownerAccount.host) |
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts index d6dd1b8bb..91dafbcf1 100644 --- a/server/models/video/video-channel.ts +++ b/server/models/video/video-channel.ts | |||
@@ -311,6 +311,16 @@ export type SummaryOptions = { | |||
311 | ')' | 311 | ')' |
312 | ), | 312 | ), |
313 | 'viewsPerDay' | 313 | 'viewsPerDay' |
314 | ], | ||
315 | [ | ||
316 | literal( | ||
317 | '(' + | ||
318 | 'SELECT COALESCE(SUM("video".views), 0) AS totalViews ' + | ||
319 | 'FROM "video" ' + | ||
320 | 'WHERE "video"."channelId" = "VideoChannelModel"."id"' + | ||
321 | ')' | ||
322 | ), | ||
323 | 'totalViews' | ||
314 | ] | 324 | ] |
315 | ] | 325 | ] |
316 | } | 326 | } |
@@ -766,6 +776,8 @@ ON "Account->Actor"."serverId" = "Account->Actor->Server"."id"` | |||
766 | }) | 776 | }) |
767 | } | 777 | } |
768 | 778 | ||
779 | const totalViews = this.get('totalViews') as number | ||
780 | |||
769 | const actor = this.Actor.toFormattedJSON() | 781 | const actor = this.Actor.toFormattedJSON() |
770 | const videoChannel = { | 782 | const videoChannel = { |
771 | id: this.id, | 783 | id: this.id, |
@@ -779,6 +791,7 @@ ON "Account->Actor"."serverId" = "Account->Actor->Server"."id"` | |||
779 | 791 | ||
780 | videosCount, | 792 | videosCount, |
781 | viewsPerDay, | 793 | viewsPerDay, |
794 | totalViews, | ||
782 | 795 | ||
783 | avatars: actor.avatars, | 796 | avatars: actor.avatars, |
784 | 797 | ||
diff --git a/server/tests/api/videos/video-channels.ts b/server/tests/api/videos/video-channels.ts index 6f495c42d..42e0cf431 100644 --- a/server/tests/api/videos/video-channels.ts +++ b/server/tests/api/videos/video-channels.ts | |||
@@ -478,6 +478,25 @@ describe('Test video channels', function () { | |||
478 | } | 478 | } |
479 | }) | 479 | }) |
480 | 480 | ||
481 | it('Should report correct total views count', async function () { | ||
482 | // check if there's the property | ||
483 | { | ||
484 | const { data } = await servers[0].channels.listByAccount({ accountName, withStats: true }) | ||
485 | |||
486 | for (const channel of data) { | ||
487 | expect(channel).to.haveOwnProperty('totalViews') | ||
488 | expect(channel.totalViews).to.be.a('number') | ||
489 | } | ||
490 | } | ||
491 | |||
492 | // Check if the totalViews count can be updated | ||
493 | { | ||
494 | const { data } = await servers[0].channels.listByAccount({ accountName, withStats: true }) | ||
495 | const channelWithView = data.find(channel => channel.id === servers[0].store.channel.id) | ||
496 | expect(channelWithView.totalViews).to.equal(2) | ||
497 | } | ||
498 | }) | ||
499 | |||
481 | it('Should report correct videos count', async function () { | 500 | it('Should report correct videos count', async function () { |
482 | const { data } = await servers[0].channels.listByAccount({ accountName, withStats: true }) | 501 | const { data } = await servers[0].channels.listByAccount({ accountName, withStats: true }) |
483 | 502 | ||
diff --git a/shared/models/videos/channel/video-channel.model.ts b/shared/models/videos/channel/video-channel.model.ts index 58b60c177..68e2f9c4c 100644 --- a/shared/models/videos/channel/video-channel.model.ts +++ b/shared/models/videos/channel/video-channel.model.ts | |||
@@ -18,6 +18,7 @@ export interface VideoChannel extends Actor { | |||
18 | 18 | ||
19 | videosCount?: number | 19 | videosCount?: number |
20 | viewsPerDay?: ViewsPerDate[] // chronologically ordered | 20 | viewsPerDay?: ViewsPerDate[] // chronologically ordered |
21 | totalViews?: number | ||
21 | 22 | ||
22 | banners: ActorImage[] | 23 | banners: ActorImage[] |
23 | 24 | ||
diff --git a/support/doc/api/openapi.yaml b/support/doc/api/openapi.yaml index 294aa50ab..8521f684e 100644 --- a/support/doc/api/openapi.yaml +++ b/support/doc/api/openapi.yaml | |||
@@ -3602,7 +3602,7 @@ paths: | |||
3602 | - $ref: '#/components/parameters/name' | 3602 | - $ref: '#/components/parameters/name' |
3603 | - name: withStats | 3603 | - name: withStats |
3604 | in: query | 3604 | in: query |
3605 | description: include view statistics for the last 30 days (only if authentified as the account user) | 3605 | description: include daily view statistics for the last 30 days and total views (only if authentified as the account user) |
3606 | schema: | 3606 | schema: |
3607 | type: boolean | 3607 | type: boolean |
3608 | - $ref: '#/components/parameters/start' | 3608 | - $ref: '#/components/parameters/start' |