include time to start if available in file_view analytics
This commit is contained in:
parent
2b1a6ce3e3
commit
c5c62a2698
4 changed files with 119 additions and 36 deletions
|
@ -44,13 +44,19 @@ const analytics: Analytics = {
|
|||
}
|
||||
analyticsEnabled = enabled;
|
||||
},
|
||||
apiLogView: (uri: string, outpoint: string, claimId: string): void => {
|
||||
apiLogView: (uri: string, outpoint: string, claimId: string, timeToStart?: number): void => {
|
||||
if (analyticsEnabled) {
|
||||
Lbryio.call('file', 'view', {
|
||||
const params = {
|
||||
uri,
|
||||
outpoint,
|
||||
claim_id: claimId,
|
||||
}).catch(() => {});
|
||||
};
|
||||
|
||||
if (timeToStart) {
|
||||
params.time_to_start = timeToStart;
|
||||
}
|
||||
|
||||
Lbryio.call('file', 'view', params).catch(() => {});
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -34,10 +34,21 @@ class VideoPlayer extends React.PureComponent {
|
|||
|
||||
componentDidMount() {
|
||||
const container = this.media;
|
||||
const { downloadCompleted, contentType, changeVolume, volume, position, claim } = this.props;
|
||||
const {
|
||||
downloadCompleted,
|
||||
contentType,
|
||||
changeVolume,
|
||||
volume,
|
||||
position,
|
||||
claim,
|
||||
startedPlayingCb,
|
||||
} = this.props;
|
||||
|
||||
const loadedMetadata = () => {
|
||||
this.setState({ hasMetadata: true, startedPlaying: true });
|
||||
if (startedPlayingCb) {
|
||||
startedPlayingCb();
|
||||
}
|
||||
this.media.children[0].play();
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
import analytics from 'analytics';
|
||||
import type { Claim } from 'types/claim';
|
||||
import LoadingScreen from 'component/common/loading-screen';
|
||||
import Player from './internal/player';
|
||||
|
@ -48,17 +49,48 @@ type Props = {
|
|||
class FileViewer extends React.PureComponent<Props> {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
(this: any).playContent = this.playContent.bind(this);
|
||||
(this: any).handleKeyDown = this.handleKeyDown.bind(this);
|
||||
(this: any).logTimeToStart = this.logTimeToStart.bind(this);
|
||||
(this: any).startedPlayingCb = undefined;
|
||||
|
||||
// Don't add these variables to state because we don't need to re-render when their values change
|
||||
(this: any).startTime = undefined;
|
||||
(this: any).playTime = undefined;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { fileInfo } = this.props;
|
||||
if (!fileInfo) {
|
||||
this.startedPlayingCb = this.logTimeToStart;
|
||||
}
|
||||
|
||||
this.handleAutoplay(this.props);
|
||||
window.addEventListener('keydown', this.handleKeyDown);
|
||||
}
|
||||
|
||||
componentDidUpdate(prev: Props) {
|
||||
const { fileInfo } = this.props;
|
||||
|
||||
if (this.props.uri !== prev.uri) {
|
||||
// User just directly navigated to another piece of content
|
||||
if (this.startTime && !this.playTime) {
|
||||
// They started playing a file but it didn't start streaming
|
||||
// Fire the analytics event with the previous file
|
||||
this.fireAnalyticsEvent(prev.claim);
|
||||
}
|
||||
|
||||
this.startTime = null;
|
||||
this.playTime = null;
|
||||
|
||||
// If this new file is already downloaded, remove the startedPlayingCallback
|
||||
if (fileInfo && this.startedPlayingCb) {
|
||||
this.startedPlayingCb = null;
|
||||
} else if (!fileInfo && !this.startedPlayingCb) {
|
||||
this.startedPlayingCb = this.logTimeToStart;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
this.props.autoplay !== prev.autoplay ||
|
||||
this.props.fileInfo !== prev.fileInfo ||
|
||||
|
@ -73,6 +105,14 @@ class FileViewer extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const { claim } = this.props;
|
||||
|
||||
if (this.startTime && !this.playTime) {
|
||||
// The user is navigating away before the file started playing, or a play time was never set
|
||||
// Currently will not be set for files that don't use render-media
|
||||
this.fireAnalyticsEvent(claim);
|
||||
}
|
||||
|
||||
this.props.cancelPlay();
|
||||
window.removeEventListener('keydown', this.handleKeyDown);
|
||||
}
|
||||
|
@ -107,9 +147,42 @@ class FileViewer extends React.PureComponent<Props> {
|
|||
|
||||
playContent() {
|
||||
const { play, uri } = this.props;
|
||||
|
||||
if (this.startedPlayingCb) {
|
||||
this.startTime = Date.now();
|
||||
}
|
||||
|
||||
play(uri);
|
||||
}
|
||||
|
||||
logTimeToStart() {
|
||||
const { claim } = this.props;
|
||||
|
||||
if (this.startTime) {
|
||||
this.playTime = Date.now();
|
||||
this.fireAnalyticsEvent(claim, this.startTime, this.playTime);
|
||||
}
|
||||
}
|
||||
|
||||
fireAnalyticsEvent = (claim, startTime, playTime) => {
|
||||
const { name, claim_id: claimId, txid, nout } = claim;
|
||||
|
||||
// ideally outpoint would exist inside of claim information
|
||||
// we can use it after https://github.com/lbryio/lbry/issues/1306 is addressed
|
||||
const outpoint = `${txid}:${nout}`;
|
||||
|
||||
let timeToStart;
|
||||
if (playTime && startTime) {
|
||||
timeToStart = playTime - startTime;
|
||||
}
|
||||
|
||||
analytics.apiLogView(`${name}#${claimId}`, outpoint, claimId, timeToStart);
|
||||
};
|
||||
|
||||
startedPlayingCb: ?() => void;
|
||||
startTime: ?number;
|
||||
playTime: ?number;
|
||||
|
||||
render() {
|
||||
const {
|
||||
metadata,
|
||||
|
@ -178,6 +251,7 @@ class FileViewer extends React.PureComponent<Props> {
|
|||
uri={uri}
|
||||
paused={mediaPaused}
|
||||
position={mediaPosition}
|
||||
startedPlayingCb={this.startedPlayingCb}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -31,7 +31,6 @@ import {
|
|||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||
import setBadge from 'util/setBadge';
|
||||
import setProgressBar from 'util/setProgressBar';
|
||||
import analytics from 'analytics';
|
||||
|
||||
const DOWNLOAD_POLL_INTERVAL = 250;
|
||||
|
||||
|
@ -224,13 +223,6 @@ export function doStartDownload(uri, outpoint) {
|
|||
export function doDownloadFile(uri, streamInfo) {
|
||||
return dispatch => {
|
||||
dispatch(doStartDownload(uri, streamInfo.outpoint));
|
||||
|
||||
analytics.apiLogView(
|
||||
`${streamInfo.claim_name}#${streamInfo.claim_id}`,
|
||||
streamInfo.outpoint,
|
||||
streamInfo.claim_id
|
||||
);
|
||||
|
||||
dispatch(doClaimEligiblePurchaseRewards());
|
||||
};
|
||||
}
|
||||
|
@ -244,6 +236,29 @@ export function doSetPlayingUri(uri) {
|
|||
};
|
||||
}
|
||||
|
||||
function handleLoadVideoError(uri, errorType = '') {
|
||||
return (dispatch, getState) => {
|
||||
// suppress error when another media is playing
|
||||
const { playingUri } = getState().content;
|
||||
if (playingUri && playingUri === uri) {
|
||||
dispatch({
|
||||
type: ACTIONS.LOADING_VIDEO_FAILED,
|
||||
data: { uri },
|
||||
});
|
||||
dispatch(doSetPlayingUri(null));
|
||||
if (errorType === 'timeout') {
|
||||
doNotify({ id: MODALS.FILE_TIMEOUT }, { uri });
|
||||
} else {
|
||||
dispatch(
|
||||
doAlertError(
|
||||
`Failed to download ${uri}, please try again. If this problem persists, visit https://lbry.io/faq/support for support.`
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function doLoadVideo(uri) {
|
||||
return dispatch => {
|
||||
dispatch({
|
||||
|
@ -270,29 +285,6 @@ export function doLoadVideo(uri) {
|
|||
};
|
||||
}
|
||||
|
||||
function handleLoadVideoError(uri, errorType = '') {
|
||||
return (dispatch, getState) => {
|
||||
// suppress error when another media is playing
|
||||
const { playingUri } = getState().content;
|
||||
if (playingUri && playingUri === uri) {
|
||||
dispatch({
|
||||
type: ACTIONS.LOADING_VIDEO_FAILED,
|
||||
data: { uri },
|
||||
});
|
||||
dispatch(doSetPlayingUri(null));
|
||||
if (errorType === 'timeout') {
|
||||
doNotify({ id: MODALS.FILE_TIMEOUT }, { uri });
|
||||
} else {
|
||||
dispatch(
|
||||
doAlertError(
|
||||
`Failed to download ${uri}, please try again. If this problem persists, visit https://lbry.io/faq/support for support.`
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function doPurchaseUri(uri, specificCostInfo) {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
|
|
Loading…
Reference in a new issue