Video component reimplemented with hooks

This commit is contained in:
NikolaBorislavovHristov 2019-09-25 17:56:34 +03:00
parent c6a29f5692
commit 7c6fb5a631
2 changed files with 67 additions and 58 deletions

View file

@ -1,77 +1,67 @@
const React = require('react'); const React = require('react');
const PropTypes = require('prop-types'); const PropTypes = require('prop-types');
const hat = require('hat'); const hat = require('hat');
const { HTMLVideo, YouTubeVideo, MPVVideo } = require('stremio-video'); const useVideoImplementation = require('./useVideoImplementation');
class Video extends React.Component { const Video = React.forwardRef(({ className, ...props }, ref) => {
constructor(props) { const [onEnded, onError, onPropValue, onPropChanged, onImplementationChanged] = React.useMemo(() => [
super(props); props.onEnded,
props.onError,
this.containerRef = React.createRef(); props.onPropValue,
this.id = `video-${hat()}`; props.onPropChanged,
this.video = null; props.onImplementationChanged
} ], []);
const containerElementRef = React.useRef(null);
shouldComponentUpdate() { const videoRef = React.useRef(null);
return false; const id = React.useMemo(() => `video-${hat()}`, []);
} const dispatch = React.useCallback((args) => {
if (args && args.commandName === 'load' && args.commandArgs) {
componentWillUnmount() { const Video = useVideoImplementation(args.commandArgs.shell, args.commandArgs.stream);
this.dispatch({ commandName: 'destroy' }); if (typeof Video !== 'function') {
} videoRef.current = null;
} else if (videoRef.current === null || videoRef.current.constructor !== Video) {
selectVideoImplementation = (args) => { dispatch({ commandName: 'destroy' });
if (args.ipc) { videoRef.current = new Video({
return MPVVideo; id: id,
} else if (args.stream.ytId) { containerElement: containerElementRef.current,
return YouTubeVideo; shell: args.commandArgs.shell
} else {
return HTMLVideo;
}
}
dispatch = (args = {}) => {
if (args.commandName === 'load') {
const { commandArgs = {} } = args;
const Video = this.selectVideoImplementation(commandArgs);
if (this.video === null || this.video.constructor !== Video) {
this.dispatch({ commandName: 'destroy' });
this.video = new Video({
id: this.id,
containerElement: this.containerRef.current,
ipc: commandArgs.ipc
}); });
this.video.on('ended', this.props.onEnded); videoRef.current.on('ended', onEnded);
this.video.on('error', this.props.onError); videoRef.current.on('error', onError);
this.video.on('propValue', this.props.onPropValue); videoRef.current.on('propValue', onPropValue);
this.video.on('propChanged', this.props.onPropChanged); videoRef.current.on('propChanged', onPropChanged);
this.props.onImplementationChanged(this.video.constructor.manifest); onImplementationChanged(videoRef.current.constructor.manifest);
} }
} }
if (this.video !== null) { if (videoRef.current !== null) {
try { try {
this.video.dispatch(args); videoRef.current.dispatch(args);
} catch (e) { } catch (e) {
console.error(this.video.constructor.manifest.name, e); console.error(videoRef.current.constructor.manifest.name, e);
} }
} }
} }, []);
React.useImperativeHandle(ref, () => ({ dispatch }));
React.useEffect(() => {
return () => {
dispatch({ commandName: 'destroy' });
};
}, []);
return (
<div ref={containerElementRef} id={id} className={className} />
);
});
render() { Video.displayName = 'Video';
return (
<div ref={this.containerRef} id={this.id} className={this.props.className} />
);
}
}
Video.propTypes = { Video.propTypes = {
className: PropTypes.string, className: PropTypes.string,
onEnded: PropTypes.func.isRequired, onEnded: PropTypes.func,
onError: PropTypes.func.isRequired, onError: PropTypes.func,
onPropValue: PropTypes.func.isRequired, onPropValue: PropTypes.func,
onPropChanged: PropTypes.func.isRequired, onPropChanged: PropTypes.func,
onImplementationChanged: PropTypes.func.isRequired onImplementationChanged: PropTypes.func
}; };
module.exports = Video; module.exports = Video;

View file

@ -0,0 +1,19 @@
const { HTMLVideo, YouTubeVideo, MPVVideo } = require('stremio-video');
const useVideoImplementation = (shell, stream) => {
if (shell) {
return MPVVideo;
}
if (stream) {
if (stream.ytId) {
return YouTubeVideo;
} else {
return HTMLVideo;
}
}
return null;
};
module.exports = useVideoImplementation;