1 import { logger, loggerTagsFactory } from '@server/helpers/logger'
2 import { MVideo } from '@server/types/models'
3 import { VideoViewEvent } from '@shared/models'
4 import { VideoViewers, VideoViews } from './shared'
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
14 * If processing a remote view:
15 * - We add +1 to video viewers counter
16 * - We add +1 to video views counter
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
24 const lTags = loggerTagsFactory('views')
26 export class VideoViewsManager {
28 private static instance: VideoViewsManager
30 private videoViewers: VideoViewers
31 private videoViews: VideoViews
33 private constructor () {
37 this.videoViewers = new VideoViewers()
38 this.videoViews = new VideoViews()
41 async processLocalView (options: {
45 viewEvent?: VideoViewEvent
47 const { video, ip, viewEvent, currentTime } = options
49 logger.debug('Processing local view for %s and ip %s.', video.url, ip, lTags())
51 const successViewer = await this.videoViewers.addLocalViewer({ video, ip, viewEvent, currentTime })
53 // Do it after added local viewer to fetch updated information
54 const watchTime = await this.videoViewers.getWatchTime(video.id, ip)
56 const successView = await this.videoViews.addLocalView({ video, watchTime, ip })
58 return { successView, successViewer }
61 async processRemoteView (options: {
65 const { video, viewerExpires } = options
67 logger.debug('Processing remote view for %s.', video.url, { viewerExpires, ...lTags() })
69 if (viewerExpires) await this.videoViewers.addRemoteViewer({ video, viewerExpires })
70 else await this.videoViews.addRemoteView({ video })
73 getViewers (video: MVideo) {
74 return this.videoViewers.getViewers(video)
77 buildViewerExpireTime () {
78 return this.videoViewers.buildViewerExpireTime()
82 return this.videoViewers.processViewerStats()
85 static get Instance () {
86 return this.instance || (this.instance = new this())