UNPKG

@aller/blink

Version:

A library for tracking user behaviour.

133 lines (112 loc) 3.37 kB
import { PlayerStateEvent, PlayerShownEvent, PlayerHiddenEvent, PlayerState, } from '../reducers/player'; export interface GeneralVideoEvent { time: Date; videoId: string; playerId: string; muted: boolean; volume: number; position: number; sticky?: boolean; streamingMode?: string; channelId?: string; } export interface VideoPlayEvent extends GeneralVideoEvent { type: 'start'; reason: 'interaction' | 'autostart' | 'viewable'; } export interface VideoStopEvent extends GeneralVideoEvent { type: 'stop'; reason: 'pause' | 'complete' | 'exit' | 'viewable' | 'stickyClosed'; } export type VideoTimeEvent = VideoPlayEvent | VideoStopEvent; export type VideoEvent = PlayerStateEvent | VideoTimeEvent; export enum PLAYER_TIMER_STATES { RUNNING = 'RUNNING', STOPPED = 'STOPPED', } export enum PLAYER_VISIBILITY_STATES { VISIBLE = 'VISIBLE', HIDDEN = 'HIDDEN', } export interface VideoWatchEvent { watchTime: number; startEvent: VideoTimeEvent | PlayerShownEvent; stopEvent: VideoTimeEvent | PlayerHiddenEvent; } export function calculateVideoEventTime( times: VideoTimeEvent[], videoId: string, players: PlayerState, playerId: string, time?: Date, ): VideoWatchEvent[] { if (!times || times.length === 0) { return []; } const forSpecificVideo = times.filter( t => t.videoId === videoId && t.playerId === playerId, ); const playerEvents = players[playerId] || []; const events: VideoEvent[] = [...playerEvents, ...forSpecificVideo]; const filtered = filterValidEvents(events); const result = filtered.reduce((all: any, curr, i, source) => { // When a stop occurs, create a new event, and calculate time from start if (curr.type === 'stop' || curr.type === 'hidden') { const timestamp = i > 0 ? curr.time.getTime() - source[i - 1].time.getTime() : 0; all.push({ watchTime: timestamp, startEvent: source[i - 1], stopEvent: curr, }); } return all; }, []); return result; } function filterValidEvents(times: VideoEvent[]) { let currentState = PLAYER_TIMER_STATES.STOPPED; let currentVisibility = PLAYER_VISIBILITY_STATES.HIDDEN; const sorted = times.sort((a, b) => a.time.getTime() - b.time.getTime()); return sorted.filter(t => { if (currentState === PLAYER_TIMER_STATES.RUNNING) { if (currentVisibility === PLAYER_VISIBILITY_STATES.VISIBLE) { if (t.type === 'hidden') { currentVisibility = PLAYER_VISIBILITY_STATES.HIDDEN; return true; } if (t.type === 'stop') { currentState = PLAYER_TIMER_STATES.STOPPED; return true; } } else { if (t.type === 'shown') { currentVisibility = PLAYER_VISIBILITY_STATES.VISIBLE; return true; } } } if (currentState === PLAYER_TIMER_STATES.STOPPED) { if (currentVisibility === PLAYER_VISIBILITY_STATES.VISIBLE) { if (t.type === 'start') { currentState = PLAYER_TIMER_STATES.RUNNING; return true; } } else { if (t.type === 'shown') { currentVisibility = PLAYER_VISIBILITY_STATES.VISIBLE; return false; } if (t.type === 'start') { currentState = PLAYER_TIMER_STATES.RUNNING; return false; } } } }); }