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

123 lines
3.2 KiB
React
Raw Normal View History

2019-08-02 08:28:14 +02:00
// @flow
2019-08-13 07:35:13 +02:00
import React, { useRef, useEffect, useState } from 'react';
2019-08-02 08:28:14 +02:00
import { stopContextMenu } from 'util/context-menu';
import videojs from 'video.js';
import 'video.js/dist/video-js.css';
import isUserTyping from 'util/detect-typing';
const SPACE_BAR_KEYCODE = 32;
const VIDEO_JS_OPTIONS = {
autoplay: true,
controls: true,
preload: 'auto',
2019-08-13 07:35:13 +02:00
playbackRates: [0.25, 0.5, 0.75, 1, 1.1, 1.25, 1.5, 2],
2019-08-02 08:28:14 +02:00
};
type Props = {
2019-09-06 02:26:03 +02:00
volume: number,
position: number,
muted: boolean,
hasFileInfo: boolean,
changeVolume: number => void,
savePosition: (string, number) => void,
changeMute: boolean => void,
setPlayingUri: (string | null) => void,
2019-08-02 08:28:14 +02:00
source: string,
contentType: string,
2019-08-13 07:35:13 +02:00
hasFileInfo: boolean,
2019-09-06 02:26:03 +02:00
onEndedCB: any,
2019-08-02 08:28:14 +02:00
};
function VideoViewer(props: Props) {
2019-09-06 02:26:03 +02:00
const { contentType, source, setPlayingUri, onEndedCB } = props;
2019-08-13 07:35:13 +02:00
const videoRef = useRef();
const [requireRedraw, setRequireRedraw] = useState(false);
2019-08-02 08:28:14 +02:00
2019-09-06 02:26:03 +02:00
useEffect(() => {
const currentVideo: HTMLVideoElement | null = document.querySelector('video');
function doEnded() {
setPlayingUri(null);
onEndedCB();
}
if (currentVideo) {
currentVideo.addEventListener('ended', doEnded);
}
// cleanup function:
return () => {
if (currentVideo) {
currentVideo.removeEventListener('ended', doEnded);
}
};
}, []);
2019-08-02 08:28:14 +02:00
useEffect(() => {
2019-08-06 05:25:33 +02:00
const videoNode = videoRef.current;
const videoJsOptions = {
...VIDEO_JS_OPTIONS,
sources: [
{
src: source,
type: contentType,
},
],
};
2019-08-02 08:28:14 +02:00
2019-08-13 07:35:13 +02:00
let player;
if (!requireRedraw) {
player = videojs(videoNode, videoJsOptions);
}
2019-08-06 05:25:33 +02:00
return () => {
2019-08-13 07:35:13 +02:00
if (!player) {
return;
}
// Video.js has a player.dispose() function that is meant to cleanup a previous video
// We can't use this because it does some weird stuff to remove the video element from the page
// This makes it really hard to use because the ref we keep still thinks it's on the page
// requireRedraw just makes it so the video component is removed from the page _by react_
// Then it's set to false immediately after so we can re-mount a new player
setRequireRedraw(true);
2019-08-06 05:25:33 +02:00
};
2019-08-13 07:35:13 +02:00
}, [videoRef, source, contentType, setRequireRedraw, requireRedraw]);
useEffect(() => {
if (requireRedraw) {
setRequireRedraw(false);
}
}, [requireRedraw]);
2019-08-02 08:28:14 +02:00
useEffect(() => {
function handleKeyDown(e: KeyboardEvent) {
2019-08-13 07:35:13 +02:00
const videoNode = videoRef.current;
2019-08-02 08:28:14 +02:00
2019-08-13 07:35:13 +02:00
if (videoNode && !isUserTyping() && e.keyCode === SPACE_BAR_KEYCODE) {
2019-08-02 08:28:14 +02:00
e.preventDefault();
2019-08-13 07:35:13 +02:00
videoNode.paused ? videoNode.play() : videoNode.pause();
2019-08-02 08:28:14 +02:00
}
}
window.addEventListener('keydown', handleKeyDown);
return () => {
window.removeEventListener('keydown', handleKeyDown);
};
2019-08-13 07:35:13 +02:00
// include requireRedraw here so the event listener is re-added when we need to manually remove/add the video player
}, [videoRef, requireRedraw]);
2019-08-02 08:28:14 +02:00
return (
<div className="file-render__viewer" onContextMenu={stopContextMenu}>
2019-08-13 07:35:13 +02:00
{!requireRedraw && (
<div data-vjs-player>
<video ref={videoRef} className="video-js" />
</div>
)}
2019-08-02 08:28:14 +02:00
</div>
);
}
export default VideoViewer;