Clear media position if video has played to the end.

Closes #4174
This commit is contained in:
Jeffrey Fisher 2020-05-14 18:18:54 -07:00 committed by Sean Yesmunt
parent f6431ac235
commit 394fad5754
6 changed files with 62 additions and 3 deletions

View file

@ -2,7 +2,7 @@ import { connect } from 'react-redux';
import { makeSelectClaimForUri, makeSelectFileInfoForUri, makeSelectThumbnailForUri } from 'lbry-redux'; import { makeSelectClaimForUri, makeSelectFileInfoForUri, makeSelectThumbnailForUri } from 'lbry-redux';
import { doChangeVolume, doChangeMute, doAnalyticsView } from 'redux/actions/app'; import { doChangeVolume, doChangeMute, doAnalyticsView } from 'redux/actions/app';
import { selectVolume, selectMute } from 'redux/selectors/app'; import { selectVolume, selectMute } from 'redux/selectors/app';
import { savePosition } from 'redux/actions/content'; import { savePosition, clearPosition } from 'redux/actions/content';
import { makeSelectContentPositionForUri } from 'redux/selectors/content'; import { makeSelectContentPositionForUri } from 'redux/selectors/content';
import VideoViewer from './view'; import VideoViewer from './view';
import { withRouter } from 'react-router'; import { withRouter } from 'react-router';
@ -31,6 +31,7 @@ const select = (state, props) => {
const perform = dispatch => ({ const perform = dispatch => ({
changeVolume: volume => dispatch(doChangeVolume(volume)), changeVolume: volume => dispatch(doChangeVolume(volume)),
savePosition: (uri, position) => dispatch(savePosition(uri, position)), savePosition: (uri, position) => dispatch(savePosition(uri, position)),
clearPosition: uri => dispatch(clearPosition(uri)),
changeMute: muted => dispatch(doChangeMute(muted)), changeMute: muted => dispatch(doChangeMute(muted)),
doAnalyticsView: (uri, timeToStart) => dispatch(doAnalyticsView(uri, timeToStart)), doAnalyticsView: (uri, timeToStart) => dispatch(doAnalyticsView(uri, timeToStart)),
claimRewards: () => dispatch(doClaimEligiblePurchaseRewards()), claimRewards: () => dispatch(doClaimEligiblePurchaseRewards()),

View file

@ -16,6 +16,7 @@ export type Player = {
muted: (?boolean) => boolean, muted: (?boolean) => boolean,
dispose: () => void, dispose: () => void,
currentTime: (?number) => number, currentTime: (?number) => number,
ended: () => boolean,
}; };
type Props = { type Props = {

View file

@ -33,6 +33,7 @@ type Props = {
doAnalyticsView: (string, number) => Promise<any>, doAnalyticsView: (string, number) => Promise<any>,
claimRewards: () => void, claimRewards: () => void,
savePosition: (string, number) => void, savePosition: (string, number) => void,
clearPosition: string => void,
}; };
/* /*
@ -57,6 +58,7 @@ function VideoViewer(props: Props) {
doAnalyticsView, doAnalyticsView,
claimRewards, claimRewards,
savePosition, savePosition,
clearPosition,
desktopPlayStartTime, desktopPlayStartTime,
} = props; } = props;
const claimId = claim && claim.claim_id; const claimId = claim && claim.claim_id;
@ -115,6 +117,14 @@ function VideoViewer(props: Props) {
setIsEndededEmbed(false); setIsEndededEmbed(false);
} }
function handlePosition(player) {
if (player.ended()) {
clearPosition(uri);
} else {
savePosition(uri, player.currentTime());
}
}
const onPlayerReady = useCallback( const onPlayerReady = useCallback(
(player: Player) => { (player: Player) => {
if (!embedded) { if (!embedded) {
@ -151,7 +161,7 @@ function VideoViewer(props: Props) {
player.on('play', onPlay); player.on('play', onPlay);
player.on('pause', () => { player.on('pause', () => {
setIsPlaying(false); setIsPlaying(false);
savePosition(uri, player.currentTime()); handlePosition(player);
}); });
player.on('volumechange', () => { player.on('volumechange', () => {
if (player && player.volume() !== volume) { if (player && player.volume() !== volume) {
@ -165,7 +175,9 @@ function VideoViewer(props: Props) {
if (position) { if (position) {
player.currentTime(position); player.currentTime(position);
} }
player.on('dispose', () => savePosition(uri, player.currentTime())); player.on('dispose', () => {
handlePosition(player);
});
}, },
IS_WEB ? [uri] : [uri, desktopPlayStartTime] IS_WEB ? [uri] : [uri, desktopPlayStartTime]
); );

View file

@ -84,6 +84,7 @@ export const PUBLISH_FAILED = 'PUBLISH_FAILED';
export const SET_PLAYING_URI = 'SET_PLAYING_URI'; export const SET_PLAYING_URI = 'SET_PLAYING_URI';
export const SET_FLOATING_URI = 'SET_FLOATING_URI'; export const SET_FLOATING_URI = 'SET_FLOATING_URI';
export const SET_CONTENT_POSITION = 'SET_CONTENT_POSITION'; export const SET_CONTENT_POSITION = 'SET_CONTENT_POSITION';
export const CLEAR_CONTENT_POSITION = 'CLEAR_CONTENT_POSITION';
export const SET_CONTENT_LAST_VIEWED = 'SET_CONTENT_LAST_VIEWED'; export const SET_CONTENT_LAST_VIEWED = 'SET_CONTENT_LAST_VIEWED';
export const CLEAR_CONTENT_HISTORY_URI = 'CLEAR_CONTENT_HISTORY_URI'; export const CLEAR_CONTENT_HISTORY_URI = 'CLEAR_CONTENT_HISTORY_URI';
export const CLEAR_CONTENT_HISTORY_ALL = 'CLEAR_CONTENT_HISTORY_ALL'; export const CLEAR_CONTENT_HISTORY_ALL = 'CLEAR_CONTENT_HISTORY_ALL';

View file

@ -249,6 +249,20 @@ export function savePosition(uri: string, position: number) {
}; };
} }
export function clearPosition(uri: string) {
return (dispatch: Dispatch, getState: () => any) => {
const state = getState();
const claim = makeSelectClaimForUri(uri)(state);
const { claim_id: claimId, txid, nout } = claim;
const outpoint = `${txid}:${nout}`;
dispatch({
type: ACTIONS.CLEAR_CONTENT_POSITION,
data: { claimId, outpoint },
});
};
}
export function doSetContentHistoryItem(uri: string) { export function doSetContentHistoryItem(uri: string) {
return (dispatch: Dispatch) => { return (dispatch: Dispatch) => {
dispatch({ dispatch({

View file

@ -33,6 +33,36 @@ reducers[ACTIONS.SET_CONTENT_POSITION] = (state, action) => {
}; };
}; };
reducers[ACTIONS.CLEAR_CONTENT_POSITION] = (state, action) => {
const { claimId, outpoint } = action.data;
if (state.positions[claimId]) {
const numOutpoints = Object.keys(state.positions[claimId]).length;
if (numOutpoints <= 1) {
let positions = { ...state.positions };
delete positions[claimId];
return {
...state,
positions: positions,
};
} else {
let outpoints = { ...state.positions[claimId] };
delete outpoints[outpoint];
return {
...state,
positions: {
...state.positions,
[claimId]: outpoints,
},
};
}
} else {
return state;
}
};
reducers[ACTIONS.SET_CONTENT_LAST_VIEWED] = (state, action) => { reducers[ACTIONS.SET_CONTENT_LAST_VIEWED] = (state, action) => {
const { uri, lastViewed } = action.data; const { uri, lastViewed } = action.data;
const { history } = state; const { history } = state;