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;
|
analyticsEnabled = enabled;
|
||||||
},
|
},
|
||||||
apiLogView: (uri: string, outpoint: string, claimId: string): void => {
|
apiLogView: (uri: string, outpoint: string, claimId: string, timeToStart?: number): void => {
|
||||||
if (analyticsEnabled) {
|
if (analyticsEnabled) {
|
||||||
Lbryio.call('file', 'view', {
|
const params = {
|
||||||
uri,
|
uri,
|
||||||
outpoint,
|
outpoint,
|
||||||
claim_id: claimId,
|
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() {
|
componentDidMount() {
|
||||||
const container = this.media;
|
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 = () => {
|
const loadedMetadata = () => {
|
||||||
this.setState({ hasMetadata: true, startedPlaying: true });
|
this.setState({ hasMetadata: true, startedPlaying: true });
|
||||||
|
if (startedPlayingCb) {
|
||||||
|
startedPlayingCb();
|
||||||
|
}
|
||||||
this.media.children[0].play();
|
this.media.children[0].play();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
import analytics from 'analytics';
|
||||||
import type { Claim } from 'types/claim';
|
import type { Claim } from 'types/claim';
|
||||||
import LoadingScreen from 'component/common/loading-screen';
|
import LoadingScreen from 'component/common/loading-screen';
|
||||||
import Player from './internal/player';
|
import Player from './internal/player';
|
||||||
|
@ -48,17 +49,48 @@ type Props = {
|
||||||
class FileViewer extends React.PureComponent<Props> {
|
class FileViewer extends React.PureComponent<Props> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
(this: any).playContent = this.playContent.bind(this);
|
(this: any).playContent = this.playContent.bind(this);
|
||||||
(this: any).handleKeyDown = this.handleKeyDown.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() {
|
componentDidMount() {
|
||||||
|
const { fileInfo } = this.props;
|
||||||
|
if (!fileInfo) {
|
||||||
|
this.startedPlayingCb = this.logTimeToStart;
|
||||||
|
}
|
||||||
|
|
||||||
this.handleAutoplay(this.props);
|
this.handleAutoplay(this.props);
|
||||||
window.addEventListener('keydown', this.handleKeyDown);
|
window.addEventListener('keydown', this.handleKeyDown);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prev: Props) {
|
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 (
|
if (
|
||||||
this.props.autoplay !== prev.autoplay ||
|
this.props.autoplay !== prev.autoplay ||
|
||||||
this.props.fileInfo !== prev.fileInfo ||
|
this.props.fileInfo !== prev.fileInfo ||
|
||||||
|
@ -73,6 +105,14 @@ class FileViewer extends React.PureComponent<Props> {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
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();
|
this.props.cancelPlay();
|
||||||
window.removeEventListener('keydown', this.handleKeyDown);
|
window.removeEventListener('keydown', this.handleKeyDown);
|
||||||
}
|
}
|
||||||
|
@ -107,9 +147,42 @@ class FileViewer extends React.PureComponent<Props> {
|
||||||
|
|
||||||
playContent() {
|
playContent() {
|
||||||
const { play, uri } = this.props;
|
const { play, uri } = this.props;
|
||||||
|
|
||||||
|
if (this.startedPlayingCb) {
|
||||||
|
this.startTime = Date.now();
|
||||||
|
}
|
||||||
|
|
||||||
play(uri);
|
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() {
|
render() {
|
||||||
const {
|
const {
|
||||||
metadata,
|
metadata,
|
||||||
|
@ -178,6 +251,7 @@ class FileViewer extends React.PureComponent<Props> {
|
||||||
uri={uri}
|
uri={uri}
|
||||||
paused={mediaPaused}
|
paused={mediaPaused}
|
||||||
position={mediaPosition}
|
position={mediaPosition}
|
||||||
|
startedPlayingCb={this.startedPlayingCb}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -31,7 +31,6 @@ import {
|
||||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||||
import setBadge from 'util/setBadge';
|
import setBadge from 'util/setBadge';
|
||||||
import setProgressBar from 'util/setProgressBar';
|
import setProgressBar from 'util/setProgressBar';
|
||||||
import analytics from 'analytics';
|
|
||||||
|
|
||||||
const DOWNLOAD_POLL_INTERVAL = 250;
|
const DOWNLOAD_POLL_INTERVAL = 250;
|
||||||
|
|
||||||
|
@ -224,13 +223,6 @@ export function doStartDownload(uri, outpoint) {
|
||||||
export function doDownloadFile(uri, streamInfo) {
|
export function doDownloadFile(uri, streamInfo) {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
dispatch(doStartDownload(uri, streamInfo.outpoint));
|
dispatch(doStartDownload(uri, streamInfo.outpoint));
|
||||||
|
|
||||||
analytics.apiLogView(
|
|
||||||
`${streamInfo.claim_name}#${streamInfo.claim_id}`,
|
|
||||||
streamInfo.outpoint,
|
|
||||||
streamInfo.claim_id
|
|
||||||
);
|
|
||||||
|
|
||||||
dispatch(doClaimEligiblePurchaseRewards());
|
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) {
|
export function doLoadVideo(uri) {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
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) {
|
export function doPurchaseUri(uri, specificCostInfo) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
|
Loading…
Reference in a new issue