maybe ready

This commit is contained in:
Jeremy Kauffman 2020-04-16 17:43:09 -04:00 committed by Sean Yesmunt
parent 9db9363b9f
commit 6c8b0b2d68
7 changed files with 103 additions and 96 deletions

View file

@ -1,11 +1,15 @@
import * as SETTINGS from 'constants/settings';
import { connect } from 'react-redux';
import { makeSelectClaimForUri } from 'lbry-redux';
import { withRouter } from 'react-router';
import { makeSelectIsPlayerFloating, makeSelectNextUnplayedRecommended } from 'redux/selectors/content';
import { makeSelectClientSetting } from 'redux/selectors/settings';
import { doSetPlayingUri } from 'redux/actions/content';
import AutoplayCountdown from './view';
/*
AutoplayCountdown does not fetch it's own next content to play, it relies on <RecommendedContent> being rendered. This is dumb but I'm just the guy who noticed
*/
const select = (state, props) => {
const nextRecommendedUri = makeSelectNextUnplayedRecommended(props.uri)(state);
return {
@ -20,4 +24,4 @@ const perform = dispatch => ({
setPlayingUri: uri => dispatch(doSetPlayingUri(uri)),
});
export default connect(select, perform)(AutoplayCountdown);
export default withRouter(connect(select, perform)(AutoplayCountdown));

View file

@ -1,5 +1,5 @@
// @flow
import React from 'react';
import React, { useCallback } from 'react';
import Button from 'component/button';
import UriIndicator from 'component/uriIndicator';
import I18nMessage from 'component/i18nMessage';
@ -35,20 +35,22 @@ function AutoplayCountdown(props: Props) {
navigateUrl = formatLbryUrlForWeb(nextRecommendedUri);
}
function doNavigate() {
// FIXME: make autoplay continue in floating player
const doNavigate = useCallback(() => {
if (!isFloating) {
// if not floating
setPlayingUri(null);
if (navigateUrl) {
push(navigateUrl);
setPlayingUri(null);
}
} else {
if (nextRecommendedUri) {
setPlayingUri(nextRecommendedUri);
}
}
}, [navigateUrl, nextRecommendedUri, isFloating, setPlayingUri]);
React.useEffect(() => {
let interval;
if (!timerCanceled) {
if (!timerCanceled && nextRecommendedUri) {
interval = setInterval(() => {
const newTime = timer - 1;
if (newTime === 0) {
@ -82,12 +84,12 @@ function AutoplayCountdown(props: Props) {
<Button onClick={doNavigate} iconSize={30} title={__('Play')} className="button--icon button--play" />
</div>
<div className="file-viewer__overlay-secondary autoplay-countdown__counter">
{__('Playing in %seconds_left% seconds', { seconds_left: timer })}
</div>
</div>
{__('Playing in %seconds_left% seconds...', { seconds_left: timer })}{' '}
<Button label={__('Cancel')} button="link" onClick={() => setTimerCanceled(true)} />
</div>
</div>
</div>
</div>
);
}

View file

@ -2,7 +2,6 @@ import * as SETTINGS from 'constants/settings';
import { connect } from 'react-redux';
import { makeSelectFileInfoForUri, makeSelectTitleForUri } from 'lbry-redux';
import {
makeSelectIsPlaying,
makeSelectIsPlayerFloating,
selectPlayingUri,
makeSelectFileRenderModeForUri,
@ -19,7 +18,6 @@ const select = (state, props) => {
uri,
title: makeSelectTitleForUri(uri)(state),
fileInfo: makeSelectFileInfoForUri(uri)(state),
isPlaying: makeSelectIsPlaying(uri)(state),
isFloating: makeSelectIsPlayerFloating(props.location)(state),
streamingUrl: makeSelectStreamingUrlForUriWebProxy(uri)(state),
floatingPlayerEnabled: makeSelectClientSetting(SETTINGS.FLOATING_PLAYER)(state),

View file

@ -15,8 +15,6 @@ import { onFullscreenChange } from 'util/full-screen';
import useIsMobile from 'effects/use-is-mobile';
type Props = {
isLoading: boolean,
isPlaying: boolean,
isFloating: boolean,
fileInfo: FileListItem,
uri: string,
@ -28,17 +26,7 @@ type Props = {
};
export default function FileRenderFloating(props: Props) {
const {
isPlaying,
fileInfo,
uri,
streamingUrl,
title,
isFloating,
clearPlayingUri,
floatingPlayerEnabled,
renderMode,
} = props;
const { fileInfo, uri, streamingUrl, title, isFloating, clearPlayingUri, floatingPlayerEnabled, renderMode } = props;
const isMobile = useIsMobile();
const [fileViewerRect, setFileViewerRect] = usePersistedState('inline-file-viewer:rect');
@ -75,7 +63,7 @@ export default function FileRenderFloating(props: Props) {
};
}, [setFileViewerRect, isFloating]);
if (!isPlayable || !isPlaying || !uri || (isFloating && (isMobile || !floatingPlayerEnabled))) {
if (!isPlayable || !uri || (isFloating && (isMobile || !floatingPlayerEnabled))) {
return null;
}

View file

@ -1,9 +1,10 @@
// @flow
import React, { useContext, useEffect, useRef } from 'react';
import videojs from 'video.js/dist/alt/video.core.novtt.min.js';
import 'video.js/dist/alt/video-js-cdn.min.css';
import eventTracking from 'videojs-event-tracking';
import { EmbedContext } from '../../../../page/embedWrapper/view';
import isUserTyping from '../../../../util/detect-typing';
import { EmbedContext } from 'page/embedWrapper/view';
import isUserTyping from 'util/detect-typing';
type Props = {
source: string,
@ -11,17 +12,10 @@ type Props = {
poster: boolean,
autoplay: boolean,
onPlayerReady: () => null,
onVolumeChange: () => null,
isAudio: boolean,
};
const VIDEO_JS_OPTIONS: VideoJSOptions = {
controls: true,
autoplay: true,
preload: 'auto',
playbackRates: [0.25, 0.5, 0.75, 1, 1.1, 1.25, 1.5, 1.75, 2],
responsive: true,
};
type VideoJSOptions = {
controls: boolean,
autoplay: boolean,
@ -33,6 +27,14 @@ type VideoJSOptions = {
poster?: string,
};
const VIDEO_JS_OPTIONS: VideoJSOptions = {
controls: true,
autoplay: true,
preload: 'auto',
playbackRates: [0.25, 0.5, 0.75, 1, 1.1, 1.25, 1.5, 1.75, 2],
responsive: true,
};
const F11_KEYCODE = 122;
const SPACE_BAR_KEYCODE = 32;
const SMALL_F_KEYCODE = 70;
@ -57,7 +59,7 @@ properties for this component should be kept to ONLY those that if changed shoul
*/
export default React.memo(function VideoJs(props: Props) {
const { autoplay, source, sourceType, poster, isAudio, onPlayerReady } = props;
const videoRef = useRef();
const containerRef = useRef();
const embedded = useContext(EmbedContext);
const videoJsOptions = {
...VIDEO_JS_OPTIONS,
@ -75,7 +77,7 @@ export default React.memo(function VideoJs(props: Props) {
videoJsOptions.muted = autoplay && embedded;
function handleKeyDown(e: KeyboardEvent) {
const { current: videoNode } = videoRef;
const videoNode = containerRef.current && containerRef.current.querySelector('video, audio');
if (!videoNode || isUserTyping()) {
return;
@ -113,27 +115,33 @@ export default React.memo(function VideoJs(props: Props) {
}
let player;
useEffect(() => {
if (videoRef.current) {
console.log('videojs effect to instatiate player');
const { current: videoNode } = videoRef;
player = videojs(videoNode, videoJsOptions);
// Create the video element. Note that a new videojs instantiation will happen on *every* render, so do not add props to this component!
useEffect(() => {
if (containerRef.current) {
const wrapper = document.createElement('div');
wrapper.setAttribute('data-vjs-player', true);
const el = document.createElement(isAudio ? 'audio' : 'video');
el.className = 'video-js';
wrapper.appendChild(el);
containerRef.current.appendChild(wrapper);
player = videojs(el, videoJsOptions);
onPlayerReady(player);
// fixes #3498 (https://github.com/lbryio/lbry-desktop/issues/3498)
// summary: on firefox the focus would stick to the fullscreen button which caused buggy behavior with spacebar
// $FlowFixMe
player.on('fullscreenchange', () => document.activeElement && document.activeElement.blur());
window.addEventListener('keydown', handleKeyDown);
return () => {
console.log('videojs effect cleanup to dispose player');
window.removeEventListener('keydown', handleKeyDown);
player.dispose();
};
}
});
return (
<div data-vjs-player>
{isAudio ? <audio ref={videoRef} className="video-js" /> : <video ref={videoRef} className="video-js" />}
</div>
);
return <div className="video-js-parent" ref={containerRef} />;
});

View file

@ -1,9 +1,8 @@
// @flow
import React, { useRef, useEffect, useState, useContext, useCallback } from 'react';
import React, { useEffect, useState, useContext, useCallback } from 'react';
import { stopContextMenu } from 'util/context-menu';
import VideoJs from './internal/videojs';
import isUserTyping from 'util/detect-typing';
import analytics from 'analytics';
import { EmbedContext } from 'page/embedWrapper/view';
import classnames from 'classnames';
@ -12,18 +11,18 @@ import AutoplayCountdown from 'component/autoplayCountdown';
import usePrevious from 'effects/use-previous';
import FileViewerEmbeddedEnded from 'lbrytv/component/fileViewerEmbeddedEnded';
import FileViewerEmbeddedTitle from 'lbrytv/component/fileViewerEmbeddedTitle';
import LoadingScreen from 'component/common/loading-screen';
type Props = {
position: number,
hasFileInfo: boolean,
changeVolume: number => void,
savePosition: (string, number) => void,
changeMute: boolean => void,
source: string,
contentType: string,
thumbnail: string,
hasFileInfo: boolean,
claim: Claim,
muted: boolean,
volume: number,
uri: string,
autoplaySetting: boolean,
autoplayIfEmbedded: boolean,
@ -46,6 +45,8 @@ function VideoViewer(props: Props) {
position,
claim,
uri,
muted,
volume,
autoplaySetting,
autoplayIfEmbedded,
doAnalyticsView,
@ -58,18 +59,25 @@ function VideoViewer(props: Props) {
const [isPlaying, setIsPlaying] = useState(false);
const [showAutoplayCountdown, setShowAutoplayCountdown] = useState(false);
const [isEndededEmbed, setIsEndededEmbed] = useState(false);
const [player, setPlayer] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const previousUri = usePrevious(uri);
const embedded = useContext(EmbedContext);
// force everything to recent when URI changes, can cause weird corner cases otherwise (e.g. navigate while autoplay is true)
useEffect(() => {
if (uri && previousUri && uri !== previousUri) {
setShowAutoplayCountdown(false);
setIsEndededEmbed(false);
setIsLoading(false);
}
}, [uri, previousUri]);
function doTrackingBuffered(e: Event, data: any) {
analytics.videoBufferEvent(claimId, data.currentTime);
}
function doTrackingFirstPlay(e: Event, data: any) {
console.log('doTrackingFirstPlay: ' + data.secondsToLoad);
analytics.videoStartEvent(claimId, data.secondsToLoad);
doAnalyticsView(uri, data.secondsToLoad).then(() => {
@ -85,14 +93,8 @@ function VideoViewer(props: Props) {
}
}
function onVolumeChange(e: Event) {
const isMuted = player.muted();
const volume = player.volume();
changeVolume(volume);
changeMute(isMuted);
}
function onPlay() {
setIsLoading(false);
setIsPlaying(true);
setShowAutoplayCountdown(false);
setIsEndededEmbed(false);
@ -103,38 +105,50 @@ function VideoViewer(props: Props) {
}
const onPlayerReady = useCallback(player => {
console.log('videoViewer.onPlayerReady attach effects');
setIsLoading(!embedded); // if we are here outside of an embed, we're playing
player.on('tracking:buffered', doTrackingBuffered);
player.on('tracking:firstplay', doTrackingFirstPlay);
player.on('ended', onEnded);
player.on('volumechange', onVolumeChange);
player.on('play', onPlay);
player.on('pause', onPause);
// fixes #3498 (https://github.com/lbryio/lbry-desktop/issues/3498)
// summary: on firefox the focus would stick to the fullscreen button which caused buggy behavior with spacebar
// $FlowFixMe
player.on('fullscreenchange', () => document.activeElement && document.activeElement.blur());
player.on('volumechange', () => {
if (player && player.volume() !== volume) {
changeVolume(player.volume());
}
if (player && player.muted() !== muted) {
changeMute(player.muted());
}
});
if (position) {
player.currentTime(position);
}
}, []);
console.log('VideoViewer render');
// FIXME: below breaks rendering?!
/* if (!embedded) {
if (muted) {
player.muted(muted);
}
if (volume) {
player.volume(volume);
}
} */
}, []);
return (
<div
className={classnames('file-viewer', {
'file-viewer--is-playing': isPlaying,
'file-viewer--ended-embed': isEndededEmbed,
})}
onContextMenu={stopContextMenu}
>
{showAutoplayCountdown && <AutoplayCountdown uri={uri} />}
{isEndededEmbed && <FileViewerEmbeddedEnded uri={uri} />}
{embedded && !isEndededEmbed && <FileViewerEmbeddedTitle uri={uri} />}
{/* change message at any time */}
{isLoading && <LoadingScreen status={__('Loading')} />}
<VideoJs
source={source}
isAudio={isAudio}

View file

@ -164,10 +164,6 @@
}
.content__viewer--floating {
.file-viewer__overlay {
padding: var(--spacing-medium);
}
.file-viewer__overlay-title,
.file-viewer__overlay-secondary {
overflow: hidden;
@ -177,10 +173,6 @@
}
}
@media (max-width: $breakpoint-small) {
.file-viewer__overlay {
padding: var(--spacing-medium);
}
.file-viewer__overlay-title,
.file-viewer__overlay-secondary {
overflow: hidden;
@ -291,16 +283,20 @@
}
}
.video-js {
.video-js-parent {
height: 100%;
width: 100%;
}
// Removing the play button because we have autoplay turned on
// These are classes added by video.js
// By default no video js play button
.vjs-big-play-button {
display: none;
}
.video-js {
height: 100%;
width: 100%;
.vjs-modal-dialog .vjs-modal-dialog-content {
position: relative;
padding-top: 5rem;
@ -321,11 +317,8 @@
}
}
.vjs-paused .vjs-big-play-button,
.vjs-paused.vjs-has-started .vjs-big-play-button {
@media (max-width: $breakpoint-small) {
display: block;
}
.file-viewer--ended-embed .vjs-big-play-button {
display: none;
}
.file-render {