lbry-desktop/ui/component/viewers/videoViewer/view.jsx

165 lines
4.6 KiB
React
Raw Normal View History

2019-08-02 08:28:14 +02:00
// @flow
2020-04-16 23:43:09 +02:00
import React, { useEffect, useState, useContext, useCallback } from 'react';
2019-08-02 08:28:14 +02:00
import { stopContextMenu } from 'util/context-menu';
2020-04-16 01:21:17 +02:00
import VideoJs from './internal/videojs';
2020-01-22 18:19:49 +01:00
import analytics from 'analytics';
2020-01-31 19:25:48 +01:00
import { EmbedContext } from 'page/embedWrapper/view';
2020-04-14 01:48:11 +02:00
import classnames from 'classnames';
2020-03-27 17:49:41 +01:00
import { FORCE_CONTENT_TYPE_PLAYER } from 'constants/claim';
2020-04-14 01:48:11 +02:00
import AutoplayCountdown from 'component/autoplayCountdown';
import usePrevious from 'effects/use-previous';
import FileViewerEmbeddedEnded from 'lbrytv/component/fileViewerEmbeddedEnded';
import FileViewerEmbeddedTitle from 'lbrytv/component/fileViewerEmbeddedTitle';
2020-04-16 23:43:09 +02:00
import LoadingScreen from 'component/common/loading-screen';
2019-08-02 08:28:14 +02:00
type Props = {
2019-09-06 02:26:03 +02:00
position: number,
changeVolume: number => void,
changeMute: boolean => void,
2019-08-02 08:28:14 +02:00
source: string,
contentType: string,
thumbnail: string,
2020-01-22 18:19:49 +01:00
claim: Claim,
2020-04-16 23:43:09 +02:00
muted: boolean,
volume: number,
2020-04-14 01:48:11 +02:00
uri: string,
autoplaySetting: boolean,
autoplayIfEmbedded: boolean,
doAnalyticsView: (string, number) => Promise<any>,
claimRewards: () => void,
2019-08-02 08:28:14 +02:00
};
2020-04-16 01:21:17 +02:00
/*
codesandbox of idealized/clean videojs and react 16+
https://codesandbox.io/s/71z2lm4ko6
*/
2019-08-02 08:28:14 +02:00
function VideoViewer(props: Props) {
const {
contentType,
source,
changeVolume,
changeMute,
thumbnail,
2020-03-19 21:25:37 +01:00
position,
claim,
2020-04-14 01:48:11 +02:00
uri,
2020-04-16 23:43:09 +02:00
muted,
volume,
2020-04-14 01:48:11 +02:00
autoplaySetting,
autoplayIfEmbedded,
doAnalyticsView,
claimRewards,
} = props;
2020-01-22 18:19:49 +01:00
const claimId = claim && claim.claim_id;
const isAudio = contentType.includes('audio');
2020-03-27 17:49:41 +01:00
const forcePlayer = FORCE_CONTENT_TYPE_PLAYER.includes(contentType);
2020-04-14 01:48:11 +02:00
const [isPlaying, setIsPlaying] = useState(false);
const [showAutoplayCountdown, setShowAutoplayCountdown] = useState(false);
const [isEndededEmbed, setIsEndededEmbed] = useState(false);
2020-04-16 23:43:09 +02:00
const [isLoading, setIsLoading] = useState(false);
2020-04-16 01:21:17 +02:00
const previousUri = usePrevious(uri);
const embedded = useContext(EmbedContext);
2019-08-02 08:28:14 +02:00
2020-04-16 23:43:09 +02:00
// 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]);
2020-04-16 01:21:17 +02:00
function doTrackingBuffered(e: Event, data: any) {
analytics.videoBufferEvent(claimId, data.currentTime);
}
2019-08-13 07:35:13 +02:00
2020-04-16 01:21:17 +02:00
function doTrackingFirstPlay(e: Event, data: any) {
analytics.videoStartEvent(claimId, data.secondsToLoad);
2020-04-14 01:48:11 +02:00
2020-04-16 01:21:17 +02:00
doAnalyticsView(uri, data.secondsToLoad).then(() => {
claimRewards();
});
}
2020-04-14 01:48:11 +02:00
2020-04-16 01:21:17 +02:00
function onEnded() {
if (embedded) {
setIsEndededEmbed(true);
} else if (autoplaySetting) {
setShowAutoplayCountdown(true);
2020-01-22 18:19:49 +01:00
}
2020-04-16 01:21:17 +02:00
}
2020-04-16 01:21:17 +02:00
function onPlay() {
2020-04-16 23:43:09 +02:00
setIsLoading(false);
2020-04-16 01:21:17 +02:00
setIsPlaying(true);
setShowAutoplayCountdown(false);
setIsEndededEmbed(false);
}
2020-04-16 01:21:17 +02:00
function onPause() {
setIsPlaying(false);
}
2020-04-14 01:48:11 +02:00
2020-04-16 18:10:47 +02:00
const onPlayerReady = useCallback(player => {
2020-04-16 23:43:09 +02:00
setIsLoading(!embedded); // if we are here outside of an embed, we're playing
2020-04-14 01:48:11 +02:00
2020-04-16 23:43:09 +02:00
player.on('tracking:buffered', doTrackingBuffered);
2020-04-16 18:10:47 +02:00
player.on('tracking:firstplay', doTrackingFirstPlay);
player.on('ended', onEnded);
player.on('play', onPlay);
player.on('pause', onPause);
2020-04-16 23:43:09 +02:00
player.on('volumechange', () => {
if (player && player.volume() !== volume) {
changeVolume(player.volume());
}
if (player && player.muted() !== muted) {
changeMute(player.muted());
}
});
2020-04-16 18:10:47 +02:00
if (position) {
player.currentTime(position);
}
2020-01-22 18:19:49 +01:00
2020-04-16 23:43:09 +02:00
// FIXME: below breaks rendering?!
/* if (!embedded) {
if (muted) {
player.muted(muted);
}
if (volume) {
player.volume(volume);
}
} */
}, []);
2020-03-19 21:25:37 +01:00
2019-08-02 08:28:14 +02:00
return (
2020-04-14 01:48:11 +02:00
<div
className={classnames('file-viewer', {
'file-viewer--is-playing': isPlaying,
2020-04-16 23:43:09 +02:00
'file-viewer--ended-embed': isEndededEmbed,
2020-04-14 01:48:11 +02:00
})}
onContextMenu={stopContextMenu}
>
{showAutoplayCountdown && <AutoplayCountdown uri={uri} />}
{isEndededEmbed && <FileViewerEmbeddedEnded uri={uri} />}
{embedded && !isEndededEmbed && <FileViewerEmbeddedTitle uri={uri} />}
2020-04-16 23:43:09 +02:00
{/* change message at any time */}
{isLoading && <LoadingScreen status={__('Loading')} />}
2020-04-16 01:21:17 +02:00
<VideoJs
source={source}
isAudio={isAudio}
poster={isAudio || (embedded && !autoplayIfEmbedded) ? thumbnail : null}
sourceType={forcePlayer ? 'video/mp4' : contentType}
autoplay={embedded ? autoplayIfEmbedded : true}
2020-04-16 18:10:47 +02:00
onPlayerReady={onPlayerReady}
2020-04-16 01:21:17 +02:00
/>
2019-08-02 08:28:14 +02:00
</div>
);
}
export default VideoViewer;