]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/lib/views/video-views-manager.ts
Optimize view endpoint
[github/Chocobozzz/PeerTube.git] / server / lib / views / video-views-manager.ts
CommitLineData
b2111066 1import { logger, loggerTagsFactory } from '@server/helpers/logger'
aa2ce188 2import { MVideo, MVideoImmutable } from '@server/types/models'
b2111066 3import { VideoViewEvent } from '@shared/models'
ac907dc7 4import { VideoViewerCounters, VideoViewerStats, VideoViews } from './shared'
b2111066 5
dfbcefc2
C
6/**
7 * If processing a local view:
8 * - We update viewer information (segments watched, watch time etc)
9 * - We add +1 to video viewers counter if this is a new viewer
10 * - We add +1 to video views counter if this is a new view and if the user watched enough seconds
11 * - We send AP message to notify about this viewer and this view
12 * - We update last video time for the user if authenticated
13 *
14 * If processing a remote view:
15 * - We add +1 to video viewers counter
16 * - We add +1 to video views counter
17 *
18 * A viewer is a someone that watched one or multiple sections of a video
19 * A viewer that watched only a few seconds of a video may not increment the video views counter
20 * Viewers statistics are sent to origin instance using the `WatchAction` ActivityPub object
21 *
22 */
23
b2111066
C
24const lTags = loggerTagsFactory('views')
25
26export class VideoViewsManager {
27
28 private static instance: VideoViewsManager
29
ac907dc7
C
30 private videoViewerStats: VideoViewerStats
31 private videoViewerCounters: VideoViewerCounters
b2111066
C
32 private videoViews: VideoViews
33
34 private constructor () {
35 }
36
37 init () {
ac907dc7
C
38 this.videoViewerStats = new VideoViewerStats()
39 this.videoViewerCounters = new VideoViewerCounters()
b2111066
C
40 this.videoViews = new VideoViews()
41 }
42
43 async processLocalView (options: {
aa2ce188 44 video: MVideoImmutable
b2111066
C
45 currentTime: number
46 ip: string | null
47 viewEvent?: VideoViewEvent
48 }) {
49 const { video, ip, viewEvent, currentTime } = options
50
51 logger.debug('Processing local view for %s and ip %s.', video.url, ip, lTags())
52
ac907dc7
C
53 await this.videoViewerStats.addLocalViewer({ video, ip, viewEvent, currentTime })
54
55 const successViewer = await this.videoViewerCounters.addLocalViewer({ video, ip })
b2111066
C
56
57 // Do it after added local viewer to fetch updated information
ac907dc7 58 const watchTime = await this.videoViewerStats.getWatchTime(video.id, ip)
b2111066
C
59
60 const successView = await this.videoViews.addLocalView({ video, watchTime, ip })
61
62 return { successView, successViewer }
63 }
64
65 async processRemoteView (options: {
66 video: MVideo
ac907dc7 67 viewerId: string | null
b2111066
C
68 viewerExpires?: Date
69 }) {
ac907dc7 70 const { video, viewerId, viewerExpires } = options
b2111066 71
ac907dc7 72 logger.debug('Processing remote view for %s.', video.url, { viewerExpires, viewerId, ...lTags() })
b2111066 73
ac907dc7 74 if (viewerExpires) await this.videoViewerCounters.addRemoteViewer({ video, viewerId, viewerExpires })
b2111066
C
75 else await this.videoViews.addRemoteView({ video })
76 }
77
78 getViewers (video: MVideo) {
ac907dc7 79 return this.videoViewerCounters.getViewers(video)
b2111066
C
80 }
81
82 buildViewerExpireTime () {
ac907dc7 83 return this.videoViewerCounters.buildViewerExpireTime()
b2111066
C
84 }
85
ac907dc7
C
86 processViewerStats () {
87 return this.videoViewerStats.processViewerStats()
b2111066
C
88 }
89
90 static get Instance () {
91 return this.instance || (this.instance = new this())
92 }
93}