const VIEW_LIFETIME = {
VIEW: CONFIG.VIEWS.VIDEOS.IP_VIEW_EXPIRATION,
- VIEWER: 60000 * 5, // 5 minutes
+ VIEWER_COUNTER: 60000 * 5, // 5 minutes
VIEWER_STATS: 60000 * 60 // 1 hour
}
REDUNDANCY.VIDEOS.RANDOMIZED_FACTOR = 1
- VIEW_LIFETIME.VIEWER = 1000 * 5 // 5 second
+ VIEW_LIFETIME.VIEWER_COUNTER = 1000 * 5 // 5 second
VIEW_LIFETIME.VIEWER_STATS = 1000 * 5 // 5 second
CONTACT_FORM_LIFETIME = 1000 // 1 second
}
setIPVideoViewer (ip: string, videoUUID: string) {
- return this.setValue(this.generateIPViewerKey(ip, videoUUID), '1', VIEW_LIFETIME.VIEWER)
+ return this.setValue(this.generateIPViewerKey(ip, videoUUID), '1', VIEW_LIFETIME.VIEWER_COUNTER)
}
async doesVideoIPViewExist (ip: string, videoUUID: string) {
private processingViewerStats = false
constructor () {
- setInterval(() => this.cleanViewerCounters(), VIEW_LIFETIME.VIEWER)
+ setInterval(() => this.cleanViewerCounters(), VIEW_LIFETIME.VIEWER_COUNTER)
setInterval(() => this.processViewerStats(), VIEW_LIFETIME.VIEWER_STATS)
}
}
buildViewerExpireTime () {
- return new Date().getTime() + VIEW_LIFETIME.VIEWER
+ return new Date().getTime() + VIEW_LIFETIME.VIEWER_COUNTER
}
async getWatchTime (videoId: number, ip: string) {
if (this.processingViewerStats) return
this.processingViewerStats = true
- if (!isTestInstance()) logger.info('Processing viewers.', lTags())
+ if (!isTestInstance()) logger.info('Processing viewer statistics.', lTags())
const now = new Date().getTime()
for (const key of allKeys) {
const stats: LocalViewerStats = await Redis.Instance.getLocalVideoViewer({ key })
+ // Process expired stats
if (stats.lastUpdated > now - VIEW_LIFETIME.VIEWER_STATS) {
continue
}
import { VideoViewEvent } from '@shared/models'
import { VideoViewers, VideoViews } from './shared'
+/**
+ * If processing a local view:
+ * - We update viewer information (segments watched, watch time etc)
+ * - We add +1 to video viewers counter if this is a new viewer
+ * - We add +1 to video views counter if this is a new view and if the user watched enough seconds
+ * - We send AP message to notify about this viewer and this view
+ * - We update last video time for the user if authenticated
+ *
+ * If processing a remote view:
+ * - We add +1 to video viewers counter
+ * - We add +1 to video views counter
+ *
+ * A viewer is a someone that watched one or multiple sections of a video
+ * A viewer that watched only a few seconds of a video may not increment the video views counter
+ * Viewers statistics are sent to origin instance using the `WatchAction` ActivityPub object
+ *
+ */
+
const lTags = loggerTagsFactory('views')
export class VideoViewsManager {
import { VideoModel } from '../video/video'
import { LocalVideoViewerWatchSectionModel } from './local-video-viewer-watch-section'
+/**
+ *
+ * Aggregate viewers of local videos only to display statistics to video owners
+ * A viewer is a user that watched one or multiple sections of a specific video inside a time window
+ *
+ */
+
@Table({
tableName: 'localVideoViewer',
updatedAt: false,
import { AttributesOnly } from '@shared/typescript-utils'
import { VideoModel } from '../video/video'
+/**
+ *
+ * Aggregate views of all videos federated with our instance
+ * Mainly used by the trending/hot algorithms
+ *
+ */
+
@Table({
tableName: 'videoView',
updatedAt: false,