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,
|
2019-11-28 09:14:07 +01:00
|
|
|
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,
|
2020-04-24 22:40:31 +02:00
|
|
|
setPlayingUri: (?string) => 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) {
|
2020-02-04 22:14:08 +01:00
|
|
|
const {
|
|
|
|
contentType,
|
|
|
|
source,
|
|
|
|
changeVolume,
|
|
|
|
changeMute,
|
|
|
|
thumbnail,
|
2020-03-19 21:25:37 +01:00
|
|
|
position,
|
2020-02-04 22:14:08 +01:00
|
|
|
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,
|
2020-04-24 22:40:31 +02:00
|
|
|
setPlayingUri,
|
2020-02-04 22:14:08 +01:00
|
|
|
} = props;
|
2020-01-22 18:19:49 +01:00
|
|
|
const claimId = claim && claim.claim_id;
|
2019-11-28 09:14:07 +01:00
|
|
|
const isAudio = contentType.includes('audio');
|
2020-02-04 22:14:08 +01:00
|
|
|
|
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);
|
2019-10-08 10:06:28 +02:00
|
|
|
|
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) {
|
2020-04-17 17:35:37 +02:00
|
|
|
if (!embedded) {
|
2020-04-20 23:07:49 +02:00
|
|
|
this.muted(muted);
|
|
|
|
this.volume(volume);
|
2020-04-17 17:35:37 +02:00
|
|
|
}
|
|
|
|
|
2020-04-16 01:21:17 +02:00
|
|
|
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-08 19:10:33 +02:00
|
|
|
|
2020-04-16 01:21:17 +02:00
|
|
|
function onPlay() {
|
2020-04-24 22:53:24 +02:00
|
|
|
console.log('on play!!!');
|
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-08 19:10:33 +02:00
|
|
|
|
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-24 22:53:24 +02:00
|
|
|
console.log('on player ready!!!');
|
2020-04-24 22:40:31 +02:00
|
|
|
// https://blog.videojs.com/autoplay-best-practices-with-video-js/#Programmatic-Autoplay-and-Success-Failure-Detection
|
|
|
|
if (autoplaySetting || autoplayIfEmbedded) {
|
|
|
|
const promise = player.play();
|
|
|
|
if (promise !== undefined) {
|
|
|
|
promise
|
|
|
|
.then(function() {
|
|
|
|
// Autoplay started
|
|
|
|
})
|
|
|
|
.catch(function(error) {
|
|
|
|
setIsPlaying(false);
|
|
|
|
setPlayingUri(null);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-16 23:43:09 +02:00
|
|
|
setIsLoading(!embedded); // if we are here outside of an embed, we're playing
|
|
|
|
player.on('tracking:buffered', doTrackingBuffered);
|
2020-04-17 17:35:37 +02:00
|
|
|
player.on('tracking:firstplay', doTrackingFirstPlay.bind(player));
|
2020-04-16 18:10:47 +02:00
|
|
|
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-08 19:10:33 +02:00
|
|
|
|
2020-04-16 18:10:47 +02:00
|
|
|
if (position) {
|
|
|
|
player.currentTime(position);
|
|
|
|
}
|
2020-04-16 23:43:09 +02:00
|
|
|
}, []);
|
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}
|
2020-04-16 18:10:47 +02:00
|
|
|
onPlayerReady={onPlayerReady}
|
2020-04-24 22:40:31 +02:00
|
|
|
startMuted={autoplayIfEmbedded}
|
2020-04-16 01:21:17 +02:00
|
|
|
/>
|
2019-08-02 08:28:14 +02:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
export default VideoViewer;
|