aboutsummaryrefslogtreecommitdiffhomepage
path: root/shared/server-commands
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2022-03-24 13:36:47 +0100
committerChocobozzz <chocobozzz@cpy.re>2022-04-15 09:49:35 +0200
commitb211106695bb82f6c32e53306081b5262c3d109d (patch)
treefa187de1c33b0956665f5362e29af6b0f6d8bb57 /shared/server-commands
parent69d48ee30c9d47cddf0c3c047dc99a99dcb6e894 (diff)
downloadPeerTube-b211106695bb82f6c32e53306081b5262c3d109d.tar.gz
PeerTube-b211106695bb82f6c32e53306081b5262c3d109d.tar.zst
PeerTube-b211106695bb82f6c32e53306081b5262c3d109d.zip
Support video views/viewers stats in server
* Add "currentTime" and "event" body params to view endpoint * Merge watching and view endpoints * Introduce WatchAction AP activity * Add tables to store viewer information of local videos * Add endpoints to fetch video views/viewers stats of local videos * Refactor views/viewers handlers * Support "views" and "viewers" counters for both VOD and live videos
Diffstat (limited to 'shared/server-commands')
-rw-r--r--shared/server-commands/server/server.ts8
-rw-r--r--shared/server-commands/videos/history-command.ts19
-rw-r--r--shared/server-commands/videos/index.ts1
-rw-r--r--shared/server-commands/videos/video-stats-command.ts48
-rw-r--r--shared/server-commands/videos/videos-command.ts17
-rw-r--r--shared/server-commands/videos/views-command.ts51
6 files changed, 107 insertions, 37 deletions
diff --git a/shared/server-commands/server/server.ts b/shared/server-commands/server/server.ts
index 2bf31b5a4..0ad818a11 100644
--- a/shared/server-commands/server/server.ts
+++ b/shared/server-commands/server/server.ts
@@ -25,10 +25,12 @@ import {
25 PlaylistsCommand, 25 PlaylistsCommand,
26 ServicesCommand, 26 ServicesCommand,
27 StreamingPlaylistsCommand, 27 StreamingPlaylistsCommand,
28 VideosCommand,
28 VideoStudioCommand, 29 VideoStudioCommand,
29 VideosCommand 30 ViewsCommand
30} from '../videos' 31} from '../videos'
31import { CommentsCommand } from '../videos/comments-command' 32import { CommentsCommand } from '../videos/comments-command'
33import { VideoStatsCommand } from '../videos/video-stats-command'
32import { ConfigCommand } from './config-command' 34import { ConfigCommand } from './config-command'
33import { ContactFormCommand } from './contact-form-command' 35import { ContactFormCommand } from './contact-form-command'
34import { DebugCommand } from './debug-command' 36import { DebugCommand } from './debug-command'
@@ -127,6 +129,8 @@ export class PeerTubeServer {
127 objectStorage?: ObjectStorageCommand 129 objectStorage?: ObjectStorageCommand
128 videoStudio?: VideoStudioCommand 130 videoStudio?: VideoStudioCommand
129 videos?: VideosCommand 131 videos?: VideosCommand
132 videoStats?: VideoStatsCommand
133 views?: ViewsCommand
130 134
131 constructor (options: { serverNumber: number } | { url: string }) { 135 constructor (options: { serverNumber: number } | { url: string }) {
132 if ((options as any).url) { 136 if ((options as any).url) {
@@ -397,5 +401,7 @@ export class PeerTubeServer {
397 this.videos = new VideosCommand(this) 401 this.videos = new VideosCommand(this)
398 this.objectStorage = new ObjectStorageCommand(this) 402 this.objectStorage = new ObjectStorageCommand(this)
399 this.videoStudio = new VideoStudioCommand(this) 403 this.videoStudio = new VideoStudioCommand(this)
404 this.videoStats = new VideoStatsCommand(this)
405 this.views = new ViewsCommand(this)
400 } 406 }
401} 407}
diff --git a/shared/server-commands/videos/history-command.ts b/shared/server-commands/videos/history-command.ts
index e9dc63462..d27afcff2 100644
--- a/shared/server-commands/videos/history-command.ts
+++ b/shared/server-commands/videos/history-command.ts
@@ -3,25 +3,6 @@ import { AbstractCommand, OverrideCommandOptions } from '../shared'
3 3
4export class HistoryCommand extends AbstractCommand { 4export class HistoryCommand extends AbstractCommand {
5 5
6 watchVideo (options: OverrideCommandOptions & {
7 videoId: number | string
8 currentTime: number
9 }) {
10 const { videoId, currentTime } = options
11
12 const path = '/api/v1/videos/' + videoId + '/watching'
13 const fields = { currentTime }
14
15 return this.putBodyRequest({
16 ...options,
17
18 path,
19 fields,
20 implicitToken: true,
21 defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204
22 })
23 }
24
25 list (options: OverrideCommandOptions & { 6 list (options: OverrideCommandOptions & {
26 search?: string 7 search?: string
27 } = {}) { 8 } = {}) {
diff --git a/shared/server-commands/videos/index.ts b/shared/server-commands/videos/index.ts
index c9ef6134d..b861731fb 100644
--- a/shared/server-commands/videos/index.ts
+++ b/shared/server-commands/videos/index.ts
@@ -13,4 +13,5 @@ export * from './services-command'
13export * from './streaming-playlists-command' 13export * from './streaming-playlists-command'
14export * from './comments-command' 14export * from './comments-command'
15export * from './video-studio-command' 15export * from './video-studio-command'
16export * from './views-command'
16export * from './videos-command' 17export * from './videos-command'
diff --git a/shared/server-commands/videos/video-stats-command.ts b/shared/server-commands/videos/video-stats-command.ts
new file mode 100644
index 000000000..90f7ffeaf
--- /dev/null
+++ b/shared/server-commands/videos/video-stats-command.ts
@@ -0,0 +1,48 @@
1import { HttpStatusCode, VideoStatsOverall, VideoStatsRetention, VideoStatsTimeserie, VideoStatsTimeserieMetric } from '@shared/models'
2import { AbstractCommand, OverrideCommandOptions } from '../shared'
3
4export class VideoStatsCommand extends AbstractCommand {
5
6 getOverallStats (options: OverrideCommandOptions & {
7 videoId: number | string
8 }) {
9 const path = '/api/v1/videos/' + options.videoId + '/stats/overall'
10
11 return this.getRequestBody<VideoStatsOverall>({
12 ...options,
13 path,
14
15 implicitToken: true,
16 defaultExpectedStatus: HttpStatusCode.OK_200
17 })
18 }
19
20 getTimeserieStats (options: OverrideCommandOptions & {
21 videoId: number | string
22 metric: VideoStatsTimeserieMetric
23 }) {
24 const path = '/api/v1/videos/' + options.videoId + '/stats/timeseries/' + options.metric
25
26 return this.getRequestBody<VideoStatsTimeserie>({
27 ...options,
28 path,
29
30 implicitToken: true,
31 defaultExpectedStatus: HttpStatusCode.OK_200
32 })
33 }
34
35 getRetentionStats (options: OverrideCommandOptions & {
36 videoId: number | string
37 }) {
38 const path = '/api/v1/videos/' + options.videoId + '/stats/retention'
39
40 return this.getRequestBody<VideoStatsRetention>({
41 ...options,
42 path,
43
44 implicitToken: true,
45 defaultExpectedStatus: HttpStatusCode.OK_200
46 })
47 }
48}
diff --git a/shared/server-commands/videos/videos-command.ts b/shared/server-commands/videos/videos-command.ts
index 21753ddc4..2ac426f76 100644
--- a/shared/server-commands/videos/videos-command.ts
+++ b/shared/server-commands/videos/videos-command.ts
@@ -107,23 +107,6 @@ export class VideosCommand extends AbstractCommand {
107 107
108 // --------------------------------------------------------------------------- 108 // ---------------------------------------------------------------------------
109 109
110 view (options: OverrideCommandOptions & {
111 id: number | string
112 xForwardedFor?: string
113 }) {
114 const { id, xForwardedFor } = options
115 const path = '/api/v1/videos/' + id + '/views'
116
117 return this.postBodyRequest({
118 ...options,
119
120 path,
121 xForwardedFor,
122 implicitToken: false,
123 defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204
124 })
125 }
126
127 rate (options: OverrideCommandOptions & { 110 rate (options: OverrideCommandOptions & {
128 id: number | string 111 id: number | string
129 rating: UserVideoRateType 112 rating: UserVideoRateType
diff --git a/shared/server-commands/videos/views-command.ts b/shared/server-commands/videos/views-command.ts
new file mode 100644
index 000000000..01113f798
--- /dev/null
+++ b/shared/server-commands/videos/views-command.ts
@@ -0,0 +1,51 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */
2import { HttpStatusCode, VideoViewEvent } from '@shared/models'
3import { AbstractCommand, OverrideCommandOptions } from '../shared'
4
5export class ViewsCommand extends AbstractCommand {
6
7 view (options: OverrideCommandOptions & {
8 id: number | string
9 currentTime?: number
10 viewEvent?: VideoViewEvent
11 xForwardedFor?: string
12 }) {
13 const { id, xForwardedFor, viewEvent, currentTime } = options
14 const path = '/api/v1/videos/' + id + '/views'
15
16 return this.postBodyRequest({
17 ...options,
18
19 path,
20 xForwardedFor,
21 fields: {
22 currentTime: currentTime ?? 1,
23 viewEvent
24 },
25 implicitToken: false,
26 defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204
27 })
28 }
29
30 async simulateView (options: OverrideCommandOptions & {
31 id: number | string
32 xForwardedFor?: string
33 }) {
34 await this.view({ ...options, currentTime: 0 })
35 await this.view({ ...options, currentTime: 5 })
36 }
37
38 async simulateViewer (options: OverrideCommandOptions & {
39 id: number | string
40 currentTimes: number[]
41 xForwardedFor?: string
42 }) {
43 let viewEvent: VideoViewEvent = 'seek'
44
45 for (const currentTime of options.currentTimes) {
46 await this.view({ ...options, currentTime, viewEvent })
47
48 viewEvent = undefined
49 }
50 }
51}