Merge pull request #1853 from lbryio/log-time-to-play

log time to play
This commit is contained in:
Sean Yesmunt 2018-08-13 14:36:18 -04:00 committed by GitHub
commit cb004e34f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 119 additions and 36 deletions

View file

@ -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(() => {});
}
},
};

View file

@ -34,10 +34,21 @@ class MediaPlayer 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();
};

View file

@ -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>

View file

@ -31,7 +31,6 @@ import {
import { makeSelectClientSetting, selectosNotificationsEnabled } from 'redux/selectors/settings';
import setBadge from 'util/setBadge';
import setProgressBar from 'util/setProgressBar';
import analytics from 'analytics';
const DOWNLOAD_POLL_INTERVAL = 250;
@ -228,13 +227,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());
};
}
@ -248,6 +240,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({
@ -274,29 +289,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();