]>
Commit | Line | Data |
---|---|---|
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' | |
5 | ||
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 | ||
24 | const lTags = loggerTagsFactory('views') | |
25 | ||
26 | export class VideoViewsManager { | |
27 | ||
28 | private static instance: VideoViewsManager | |
29 | ||
30 | private videoViewers: VideoViewers | |
31 | private videoViews: VideoViews | |
32 | ||
33 | private constructor () { | |
34 | } | |
35 | ||
36 | init () { | |
37 | this.videoViewers = new VideoViewers() | |
38 | this.videoViews = new VideoViews() | |
39 | } | |
40 | ||
41 | async processLocalView (options: { | |
42 | video: MVideo | |
43 | currentTime: number | |
44 | ip: string | null | |
45 | viewEvent?: VideoViewEvent | |
46 | }) { | |
47 | const { video, ip, viewEvent, currentTime } = options | |
48 | ||
49 | logger.debug('Processing local view for %s and ip %s.', video.url, ip, lTags()) | |
50 | ||
51 | const successViewer = await this.videoViewers.addLocalViewer({ video, ip, viewEvent, currentTime }) | |
52 | ||
53 | // Do it after added local viewer to fetch updated information | |
54 | const watchTime = await this.videoViewers.getWatchTime(video.id, ip) | |
55 | ||
56 | const successView = await this.videoViews.addLocalView({ video, watchTime, ip }) | |
57 | ||
58 | return { successView, successViewer } | |
59 | } | |
60 | ||
61 | async processRemoteView (options: { | |
62 | video: MVideo | |
63 | viewerExpires?: Date | |
64 | }) { | |
65 | const { video, viewerExpires } = options | |
66 | ||
67 | logger.debug('Processing remote view for %s.', video.url, { viewerExpires, ...lTags() }) | |
68 | ||
69 | if (viewerExpires) await this.videoViewers.addRemoteViewer({ video, viewerExpires }) | |
70 | else await this.videoViews.addRemoteView({ video }) | |
71 | } | |
72 | ||
73 | getViewers (video: MVideo) { | |
74 | return this.videoViewers.getViewers(video) | |
75 | } | |
76 | ||
77 | buildViewerExpireTime () { | |
78 | return this.videoViewers.buildViewerExpireTime() | |
79 | } | |
80 | ||
81 | processViewers () { | |
82 | return this.videoViewers.processViewerStats() | |
83 | } | |
84 | ||
85 | static get Instance () { | |
86 | return this.instance || (this.instance = new this()) | |
87 | } | |
88 | } |