Patch to restore position upon returning to video until more fully fleshed out fix can be introduced (#817)
* Patch to restore position upon returning to video until more fully fleshed out fix can be introduced * Add code to notify other open tabs of position saving * Fix typo * Wrap localStorage access in try/catch in event browser settings make it unavailable * Remove formatting changes * Move constant from 'pages' to 'player' * Move dispatch out of try/catch * Fixed typo
This commit is contained in:
parent
65ad2df643
commit
ce903c9280
6 changed files with 36 additions and 4 deletions
|
@ -32,6 +32,7 @@ export type Player = {
|
||||||
chromecast: (any) => void,
|
chromecast: (any) => void,
|
||||||
currentTime: (?number) => number,
|
currentTime: (?number) => number,
|
||||||
dispose: () => void,
|
dispose: () => void,
|
||||||
|
duration: () => number,
|
||||||
ended: () => boolean,
|
ended: () => boolean,
|
||||||
error: () => any,
|
error: () => any,
|
||||||
exitFullscreen: () => boolean,
|
exitFullscreen: () => boolean,
|
||||||
|
@ -292,7 +293,7 @@ export default React.memo<Props>(function VideoJs(props: Props) {
|
||||||
/** instantiate videoJS and dispose of it when done with code **/
|
/** instantiate videoJS and dispose of it when done with code **/
|
||||||
// This lifecycle hook is only called once (on mount), or when `isAudio` or `source` changes.
|
// This lifecycle hook is only called once (on mount), or when `isAudio` or `source` changes.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async function() {
|
(async function () {
|
||||||
// test if perms to play video are available
|
// test if perms to play video are available
|
||||||
let canAutoplayVideo = await canAutoplay.video({ timeout: 2000, inline: true });
|
let canAutoplayVideo = await canAutoplay.video({ timeout: 2000, inline: true });
|
||||||
|
|
||||||
|
@ -351,7 +352,7 @@ export default React.memo<Props>(function VideoJs(props: Props) {
|
||||||
const adsClaimParentDiv = adsClaimDiv.parentNode;
|
const adsClaimParentDiv = adsClaimDiv.parentNode;
|
||||||
|
|
||||||
// watch parent div for when it is on viewport
|
// watch parent div for when it is on viewport
|
||||||
const observer = new IntersectionObserver(function(entries) {
|
const observer = new IntersectionObserver(function (entries) {
|
||||||
// when ad div parent becomes visible by 1px, show the ad video
|
// when ad div parent becomes visible by 1px, show the ad video
|
||||||
if (entries[0].isIntersecting === true) {
|
if (entries[0].isIntersecting === true) {
|
||||||
adsClaimDiv.style.display = 'block';
|
adsClaimDiv.style.display = 'block';
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { ENABLE_PREROLL_ADS } from 'config';
|
import { ENABLE_PREROLL_ADS } from 'config';
|
||||||
import * as PAGES from 'constants/pages';
|
import * as PAGES from 'constants/pages';
|
||||||
|
import { VIDEO_ALMOST_FINISHED_THRESHOLD } from 'constants/player';
|
||||||
import * as ICONS from 'constants/icons';
|
import * as ICONS from 'constants/icons';
|
||||||
import React, { useEffect, useState, useContext, useCallback } from 'react';
|
import React, { useEffect, useState, useContext, useCallback } from 'react';
|
||||||
import { stopContextMenu } from 'util/context-menu';
|
import { stopContextMenu } from 'util/context-menu';
|
||||||
|
@ -265,6 +266,12 @@ function VideoViewer(props: Props) {
|
||||||
function onDispose(event, player) {
|
function onDispose(event, player) {
|
||||||
handlePosition(player);
|
handlePosition(player);
|
||||||
analytics.videoIsPlaying(false, player);
|
analytics.videoIsPlaying(false, player);
|
||||||
|
|
||||||
|
const almostFinished = player.currentTime() / player.duration() >= VIDEO_ALMOST_FINISHED_THRESHOLD;
|
||||||
|
|
||||||
|
if (player.ended() || almostFinished) {
|
||||||
|
clearPosition(permanentUrl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePosition(player) {
|
function handlePosition(player) {
|
||||||
|
|
1
ui/constants/player.js
Normal file
1
ui/constants/player.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export const VIDEO_ALMOST_FINISHED_THRESHOLD = 0.8;
|
|
@ -1,5 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import * as PAGES from 'constants/pages';
|
import * as PAGES from 'constants/pages';
|
||||||
|
import { VIDEO_ALMOST_FINISHED_THRESHOLD } from 'constants/player';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { lazyImport } from 'util/lazyImport';
|
import { lazyImport } from 'util/lazyImport';
|
||||||
|
@ -72,9 +73,9 @@ function FilePage(props: Props) {
|
||||||
const durationInSecs =
|
const durationInSecs =
|
||||||
fileInfo && fileInfo.metadata && fileInfo.metadata.video ? fileInfo.metadata.video.duration : 0;
|
fileInfo && fileInfo.metadata && fileInfo.metadata.video ? fileInfo.metadata.video.duration : 0;
|
||||||
const isVideoTooShort = durationInSecs <= 45;
|
const isVideoTooShort = durationInSecs <= 45;
|
||||||
const almostFinishedPlaying = position / durationInSecs >= 0.8;
|
const almostFinishedPlaying = position / durationInSecs >= VIDEO_ALMOST_FINISHED_THRESHOLD;
|
||||||
|
|
||||||
return isVideoTooShort || almostFinishedPlaying;
|
return durationInSecs ? isVideoTooShort || almostFinishedPlaying : false;
|
||||||
}, [fileInfo, position]);
|
}, [fileInfo, position]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
|
|
@ -220,6 +220,19 @@ export function savePosition(uri: string, position: number) {
|
||||||
const { claim_id: claimId, txid, nout } = claim;
|
const { claim_id: claimId, txid, nout } = claim;
|
||||||
const outpoint = `${txid}:${nout}`;
|
const outpoint = `${txid}:${nout}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
localStorage.setItem(
|
||||||
|
ACTIONS.SET_CONTENT_POSITION,
|
||||||
|
JSON.stringify({
|
||||||
|
claimId,
|
||||||
|
outpoint,
|
||||||
|
position,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('localStorage not available');
|
||||||
|
}
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ACTIONS.SET_CONTENT_POSITION,
|
type: ACTIONS.SET_CONTENT_POSITION,
|
||||||
data: { claimId, outpoint, position },
|
data: { claimId, outpoint, position },
|
||||||
|
|
|
@ -230,4 +230,13 @@ const store = createStore(
|
||||||
const persistor = persistStore(store);
|
const persistor = persistStore(store);
|
||||||
window.persistor = persistor;
|
window.persistor = persistor;
|
||||||
|
|
||||||
|
window.addEventListener('storage', (e) => {
|
||||||
|
if (e.key === ACTIONS.SET_CONTENT_POSITION) {
|
||||||
|
store.dispatch({
|
||||||
|
type: ACTIONS.SET_CONTENT_POSITION,
|
||||||
|
data: JSON.parse(e.newValue),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export { store, persistor, history, whiteListedReducers };
|
export { store, persistor, history, whiteListedReducers };
|
||||||
|
|
Loading…
Reference in a new issue