attempt to persist a single video.js instance
Continually recreating video.js instance on render is bad. Instead, persist a single instance, and simply update the source and poster on the existing instance.
This commit is contained in:
parent
912489cce0
commit
7c8383f2dc
1 changed files with 108 additions and 41 deletions
|
@ -325,50 +325,79 @@ export default React.memo<Props>(function VideoJs(props: Props) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the video element. Note that a new videojs instantiation will happen on *every* render, so do not add props to this component!
|
// Create the video DOM element and wrapper
|
||||||
useEffect(() => {
|
function createVideoPlayerDOM(container) {
|
||||||
if (containerRef.current) {
|
if (!container) {
|
||||||
|
console.error(`VideoPlayer Error: missing ref to container!`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This seems like a poor way to generate the DOM for video.js
|
||||||
const wrapper = document.createElement('div');
|
const wrapper = document.createElement('div');
|
||||||
wrapper.setAttribute('data-vjs-player', 'true');
|
wrapper.setAttribute('data-vjs-player', 'true');
|
||||||
const el = document.createElement(isAudio ? 'audio' : 'video');
|
const el = document.createElement(isAudio ? 'audio' : 'video');
|
||||||
el.className = 'video-js';
|
el.className = 'video-js';
|
||||||
wrapper.appendChild(el);
|
wrapper.appendChild(el);
|
||||||
|
|
||||||
// $FlowFixMe
|
container.appendChild(wrapper);
|
||||||
containerRef.current.appendChild(wrapper);
|
|
||||||
|
|
||||||
fetch(source, { method: 'HEAD' }).then(response => {
|
return el;
|
||||||
if (response && response.redirected && response.url && response.url.endsWith('m3u8')) {
|
}
|
||||||
videoJsOptions.sources[0].type = 'application/x-mpegURL';
|
|
||||||
|
// Initialize video.js
|
||||||
|
function initializeVideoPlayer(el) {
|
||||||
|
if (!el) {
|
||||||
|
console.error(`Failed to initialize video player: Missing element to attach to`);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
player = videojs(el, videoJsOptions, () => {
|
player = videojs(el, videoJsOptions, () => {
|
||||||
if (player) {
|
// this seems like a weird thing to have to check for here
|
||||||
|
if (!player) {
|
||||||
|
console.error(`Failed to create videojs player!`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add various event listeners to player
|
||||||
player.one('play', onInitialPlay);
|
player.one('play', onInitialPlay);
|
||||||
player.on('volumechange', onVolumeChange);
|
player.on('volumechange', onVolumeChange);
|
||||||
player.on('error', onError);
|
player.on('error', onError);
|
||||||
player.on('ended', onEnded);
|
player.on('ended', onEnded);
|
||||||
|
|
||||||
|
// Replace volume bar with custom LBRY volume bar
|
||||||
LbryVolumeBarClass.replaceExisting(player);
|
LbryVolumeBarClass.replaceExisting(player);
|
||||||
|
|
||||||
|
// initialize mobile UI
|
||||||
player.mobileUi(); // Inits mobile version. No-op if Desktop.
|
player.mobileUi(); // Inits mobile version. No-op if Desktop.
|
||||||
|
|
||||||
|
// I think this is a callback function
|
||||||
onPlayerReady(player);
|
onPlayerReady(player);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add quality selector to player
|
||||||
player.hlsQualitySelector({
|
player.hlsQualitySelector({
|
||||||
displayCurrentQuality: true,
|
displayCurrentQuality: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add reference to player to global scope
|
||||||
window.player = player;
|
window.player = player;
|
||||||
|
|
||||||
// fixes #3498 (https://github.com/lbryio/lbry-desktop/issues/3498)
|
// 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
|
// 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('fullscreenchange', () => document.activeElement && document.activeElement.blur());
|
||||||
|
|
||||||
window.addEventListener('keydown', handleKeyDown);
|
return player;
|
||||||
});
|
}
|
||||||
|
|
||||||
|
// This lifecycle hook is only called once (on mount)
|
||||||
|
useEffect(() => {
|
||||||
|
const vjsElement = createVideoPlayerDOM(containerRef.current);
|
||||||
|
const vjsPlayer = initializeVideoPlayer(vjsElement);
|
||||||
|
|
||||||
|
// Add event listener for keyboard shortcuts
|
||||||
|
window.addEventListener('keydown', handleKeyDown);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener('keydown', handleKeyDown);
|
window.removeEventListener('keydown', handleKeyDown);
|
||||||
|
|
||||||
|
@ -376,8 +405,46 @@ export default React.memo<Props>(function VideoJs(props: Props) {
|
||||||
player.dispose();
|
player.dispose();
|
||||||
window.player = undefined;
|
window.player = undefined;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Update video player settings and reload it when props change
|
||||||
|
useEffect(() => {
|
||||||
|
// For some reason the video player is responsible for detecting content type this way
|
||||||
|
fetch(source, { method: 'HEAD' }).then(response => {
|
||||||
|
if (!player) {
|
||||||
|
console.log(`Our player was disposed, we should disregard the fetch result.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let type = sourceType;
|
||||||
|
|
||||||
|
// override type if we receive an .m3u8 (transcoded mp4)
|
||||||
|
if (
|
||||||
|
response &&
|
||||||
|
response.redirected &&
|
||||||
|
response.url &&
|
||||||
|
response.url.endsWith('m3u8')
|
||||||
|
) {
|
||||||
|
type = 'application/x-mpegURL';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update player poster
|
||||||
|
// note: the poster prop seems to return null usually.
|
||||||
|
if ( poster ) player.poster(poster);
|
||||||
|
|
||||||
|
// Update player source
|
||||||
|
player.src({
|
||||||
|
src: source,
|
||||||
|
type: type,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`Updated Player: ${source} (${type}) Poster: ${poster}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
console.log('Guess we could clean up something here if needed');
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
Loading…
Reference in a new issue