send events when video buffers

This commit is contained in:
jessop 2020-01-22 12:19:49 -05:00 committed by Sean Yesmunt
parent 9aab2092e6
commit 75410392d8
5 changed files with 127 additions and 5 deletions

View file

@ -51,7 +51,8 @@
"electron-updater": "^4.1.2",
"express": "^4.17.1",
"if-env": "^1.0.4",
"keytar": "^4.4.1"
"keytar": "^4.4.1",
"videojs-event-tracking": "^1.0.1"
},
"devDependencies": {
"@babel/core": "^7.0.0",

View file

@ -28,6 +28,8 @@ type Analytics = {
apiLogView: (string, string, string, ?number, ?() => void) => Promise<any>,
apiLogPublish: (ChannelClaim | StreamClaim) => void,
tagFollowEvent: (string, boolean, string) => void,
videoStartEvent: (string, number) => void,
videoBufferEvent: (string, number) => void,
emailProvidedEvent: () => void,
emailVerifiedEvent: () => void,
rewardEligibleEvent: () => void,
@ -127,6 +129,12 @@ const analytics: Analytics = {
Lbryio.call('feedback', 'search', { query, vote });
}
},
videoStartEvent: (claimId, duration) => {
sendGaEvent('Media', 'StartDelay', claimId, duration);
},
videoBufferEvent: (claimId, currentTime) => {
sendGaEvent('Media', 'BufferTimestamp', claimId, currentTime);
},
tagFollowEvent: (tag, following, location) => {
sendGaEvent(following ? 'Tag-Follow' : 'Tag-Unfollow', tag);
},
@ -154,13 +162,14 @@ const analytics: Analytics = {
},
};
function sendGaEvent(category, action, label) {
function sendGaEvent(category, action, label, value) {
if (analyticsEnabled && isProduction) {
ReactGA.event(
{
category,
action,
...(label ? { label } : {}),
...(value ? { value } : {}),
},
[SECOND_TRACKER_NAME]
);

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux';
import { makeSelectFileInfoForUri, makeSelectThumbnailForUri } from 'lbry-redux';
import { makeSelectClaimForUri, makeSelectFileInfoForUri, makeSelectThumbnailForUri } from 'lbry-redux';
import { doChangeVolume, doChangeMute } from 'redux/actions/app';
import { selectVolume, selectMute } from 'redux/selectors/app';
import { savePosition, doSetPlayingUri } from 'redux/actions/content';
@ -12,6 +12,7 @@ const select = (state, props) => ({
muted: selectMute(state),
hasFileInfo: Boolean(makeSelectFileInfoForUri(props.uri)(state)),
thumbnail: makeSelectThumbnailForUri(props.uri)(state),
claim: makeSelectClaimForUri(props.uri)(state),
});
const perform = dispatch => ({

View file

@ -3,7 +3,9 @@ import React, { useRef, useEffect, useState } from 'react';
import { stopContextMenu } from 'util/context-menu';
import videojs from 'video.js/dist/alt/video.core.novtt.min.js';
import 'video.js/dist/alt/video-js-cdn.min.css';
import eventTracking from 'videojs-event-tracking';
import isUserTyping from 'util/detect-typing';
import analytics from 'analytics';
const F11_KEYCODE = 122;
const SPACE_BAR_KEYCODE = 32;
@ -42,10 +44,23 @@ type Props = {
thumbnail: string,
hasFileInfo: boolean,
onEndedCB: any,
claim: Claim,
};
function VideoViewer(props: Props) {
const { contentType, source, setPlayingUri, onEndedCB, changeVolume, changeMute, volume, muted, thumbnail } = props;
const {
contentType,
source,
setPlayingUri,
onEndedCB,
changeVolume,
changeMute,
volume,
muted,
thumbnail,
claim,
} = props;
const claimId = claim && claim.claim_id;
const videoRef = useRef();
const isAudio = contentType.includes('audio');
let forceTypes = [
@ -65,6 +80,10 @@ function VideoViewer(props: Props) {
useEffect(() => {
const currentVideo: HTMLVideoElement | null = document.querySelector('video');
if (!Object.keys(videojs.getPlugins()).includes('eventTracking')) {
videojs.registerPlugin('eventTracking', eventTracking);
}
function doEnded() {
// clear position
setPlayingUri(null);
@ -105,6 +124,7 @@ function VideoViewer(props: Props) {
type: forceMp4 ? 'video/mp4' : contentType,
},
],
plugins: { eventTracking: true },
};
if (isAudio) {
@ -185,6 +205,30 @@ function VideoViewer(props: Props) {
// include requireRedraw here so the event listener is re-added when we need to manually remove/add the video player
}, [videoRef, requireRedraw]);
// player analytics
useEffect(() => {
function doTrackingBuffered(e: Event, data: any) {
analytics.videoBufferEvent(claimId, data.currentTime);
}
function doTrackingFirstPlay(e: Event, data: any) {
analytics.videoStartEvent(claimId, data.secondsToLoad);
}
function doError(e: Event) {
console.log('ERROR', e);
}
if (player) {
player.on('tracking:buffered', (e, d) => doTrackingBuffered(e, d));
player.on('tracking:firstplay', (e, d) => doTrackingFirstPlay(e, d));
player.on('error', e => doError(e));
}
return () => {
if (player) {
player.off();
}
};
// include requireRedraw here so the event listener is re-added when we need to manually remove/add the video player
}, [player]);
return (
<div className="file-render__viewer" onContextMenu={stopContextMenu}>
{!requireRedraw && (

View file

@ -909,6 +909,13 @@
dependencies:
regenerator-runtime "^0.13.2"
"@babel/runtime@^7.4.5":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.3.tgz#0811944f73a6c926bb2ad35e918dcc1bfab279f1"
integrity sha512-fVHx1rzEmwB130VTkLnxR+HmxcTjGzH12LYQcFFoBwakMd3aOMD4OsRN7tGG/UOYE2ektgFrS8uACAoRk1CY0w==
dependencies:
regenerator-runtime "^0.13.2"
"@babel/runtime@^7.6.3":
version "7.7.4"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.7.4.tgz#b23a856751e4bf099262f867767889c0e3fe175b"
@ -1214,6 +1221,19 @@
resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.14.1.tgz#0d8a53f308f017c53a5ddc3d07f4d6fa76b790d7"
integrity sha512-0Ki9jAAhKDSuLDXOIMADg54Hu60SuBTEsWaJGGy5cV+SSUQ63J2a+RrYYGrErzz39fXzTibhKrAQJAb8M7PNcA==
"@videojs/http-streaming@1.10.6":
version "1.10.6"
resolved "https://registry.yarnpkg.com/@videojs/http-streaming/-/http-streaming-1.10.6.tgz#a9119b1828b354c5cc17b42ea051cc7bcce2dca0"
integrity sha512-uPBuunHnxWeFRYxRX0j6h1IIWv3+QKvSkZGmW9TvqxWBqeNGSrQymR6tm1nVjQ2HhMVxVphQTUhUTTPDVWqmQg==
dependencies:
aes-decrypter "3.0.0"
global "^4.3.0"
m3u8-parser "4.4.0"
mpd-parser "0.8.1"
mux.js "5.2.1"
url-toolkit "^2.1.3"
video.js "^6.8.0 || ^7.0.0"
"@videojs/http-streaming@1.9.3":
version "1.9.3"
resolved "https://registry.yarnpkg.com/@videojs/http-streaming/-/http-streaming-1.9.3.tgz#c971050495fb58d2b4c6ee0246bb03cc750635b1"
@ -7472,6 +7492,13 @@ m3u8-parser@4.3.0:
dependencies:
global "^4.3.2"
m3u8-parser@4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/m3u8-parser/-/m3u8-parser-4.4.0.tgz#adf606c0af6d97f6750095a42006c2ae03dde177"
integrity sha512-iH2AygTFILtato+XAgnoPYzLHM4R3DjATj7Ozbk7EHdB2XoLF2oyOUguM7Kc4UVHbQHHL/QPaw98r7PbWzG0gg==
dependencies:
global "^4.3.2"
macos-release@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.2.0.tgz#ab58d55dd4714f0a05ad4b0e90f4370fef5cdea8"
@ -7909,6 +7936,14 @@ mpd-parser@0.7.0:
global "^4.3.2"
url-toolkit "^2.1.1"
mpd-parser@0.8.1:
version "0.8.1"
resolved "https://registry.yarnpkg.com/mpd-parser/-/mpd-parser-0.8.1.tgz#db299dbec337999fbbbace989d227c7b03dc8ea7"
integrity sha512-WBTJ1bKk8OLUIxBh6s1ju1e2yz/5CzhPbgi6P3F3kJHKhGy1Z+ElvEnuzEbtC/dnbRcJtMXazE3f93N5LLdp9Q==
dependencies:
global "^4.3.2"
url-toolkit "^2.1.1"
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
@ -7947,6 +7982,11 @@ mux.js@5.1.1:
resolved "https://registry.yarnpkg.com/mux.js/-/mux.js-5.1.1.tgz#0e95f048b4ac51d413c9ddc2d78e4cefad8d06de"
integrity sha512-Mf/UYmh5b8jvUP+jmrTbETnyFZprMdbT0RxKm/lJ/4d2Q3xdc5GaHaRPI1zVV5D3+6uxArVPm78QEb1RsrmaQw==
mux.js@5.2.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/mux.js/-/mux.js-5.2.1.tgz#6698761fc88da5acecea0758ac25f11d3a08bee8"
integrity sha512-1t2payD3Y8izfZRq7tfUQlhL2fKzjeLr9v1/2qNCTkEQnd9Abtn1JgzsBgGZubEXh6lM5L8B0iLGoWQiukjtbQ==
nan@2.13.2:
version "2.13.2"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.2.tgz#f51dc7ae66ba7d5d55e1e6d4d8092e802c9aefe7"
@ -12641,12 +12681,39 @@ vfile@^2.0.0:
videojs-vtt.js "0.14.1"
xhr "2.4.0"
video.js@^7.0.0:
version "7.6.6"
resolved "https://registry.yarnpkg.com/video.js/-/video.js-7.6.6.tgz#e7c9163d53f9b0e05ccb5ac0f79d02fa49b4d3ac"
integrity sha512-AXzHwymhvMpS7c7rF29u0j0/3tSs+v2gIk5UY8OkiDHSEHL7T0+t3hid4JHW7aGvTruUUgwyf4C74cX2RDL1Pw==
dependencies:
"@babel/runtime" "^7.4.5"
"@videojs/http-streaming" "1.10.6"
global "4.3.2"
keycode "^2.2.0"
safe-json-parse "4.0.0"
videojs-font "3.2.0"
videojs-vtt.js "^0.14.1"
xhr "2.4.0"
videojs-event-tracking@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/videojs-event-tracking/-/videojs-event-tracking-1.0.1.tgz#382e8b1293d32021f3bac65c4310ee454a659bcf"
integrity sha512-SdL4utk5U3S8PNTXFiJtlZeR4L4DbJxjK+1fv7ugLMw7v20NZbp1S0ag+9fHJCKSQrkc2QkXUqSZHXpqwkw/3Q==
dependencies:
global "^4.3.2"
video.js "^7.0.0"
videojs-font@3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/videojs-font/-/videojs-font-3.1.0.tgz#ac33be9b517fe19299f61cccd2b3c7d75a1c6960"
integrity sha512-rxB68SVgbHD+kSwoNWNCHicKJuR2ga3bGfvGxmB+8fupsiLbnyCwTBVtrZUq4bZnD64mrKP1DxHiutxwrs59pQ==
videojs-vtt.js@0.14.1:
videojs-font@3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/videojs-font/-/videojs-font-3.2.0.tgz#212c9d3f4e4ec3fa7345167d64316add35e92232"
integrity sha512-g8vHMKK2/JGorSfqAZQUmYYNnXmfec4MLhwtEFS+mMs2IDY398GLysy6BH6K+aS1KMNu/xWZ8Sue/X/mdQPliA==
videojs-vtt.js@0.14.1, videojs-vtt.js@^0.14.1:
version "0.14.1"
resolved "https://registry.yarnpkg.com/videojs-vtt.js/-/videojs-vtt.js-0.14.1.tgz#da583eb1fc9c81c826a9432b706040e8dea49911"
integrity sha512-YxOiywx6N9t3J5nqsE5WN2Sw4CSqVe3zV+AZm2T4syOc2buNJaD6ZoexSdeszx2sHLU/RRo2r4BJAXFDQ7Qo2Q==