fix: init Plyr before HLS manifest loads to avoid bare video flash
All checks were successful
CI / test (push) Successful in 45s
All checks were successful
CI / test (push) Successful in 45s
Create Plyr instance immediately in start() so the styled player UI appears right away. Quality and audio controls are injected once the HLS manifest is ready, running doAdd() directly when player.ready is already true instead of waiting on the 'ready' event that already fired.
This commit is contained in:
@@ -150,7 +150,7 @@
|
|||||||
* Create custom quality control in Plyr controls
|
* Create custom quality control in Plyr controls
|
||||||
*/
|
*/
|
||||||
function addCustomQualityControl(player, qualityLabels) {
|
function addCustomQualityControl(player, qualityLabels) {
|
||||||
player.on('ready', () => {
|
function doAdd() {
|
||||||
console.log('Adding custom quality control...');
|
console.log('Adding custom quality control...');
|
||||||
|
|
||||||
const controls = player.elements.container.querySelector('.plyr__controls');
|
const controls = player.elements.container.querySelector('.plyr__controls');
|
||||||
@@ -238,14 +238,21 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log('Custom quality control added');
|
console.log('Custom quality control added');
|
||||||
});
|
}
|
||||||
|
|
||||||
|
// Run immediately if Plyr is already ready, otherwise wait
|
||||||
|
if (player.ready) {
|
||||||
|
doAdd();
|
||||||
|
} else {
|
||||||
|
player.on('ready', doAdd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create custom audio tracks control in Plyr controls
|
* Create custom audio tracks control in Plyr controls
|
||||||
*/
|
*/
|
||||||
function addCustomAudioTracksControl(player, hlsInstance) {
|
function addCustomAudioTracksControl(player, hlsInstance) {
|
||||||
player.on('ready', () => {
|
function doAdd() {
|
||||||
console.log('Adding custom audio tracks control...');
|
console.log('Adding custom audio tracks control...');
|
||||||
|
|
||||||
const controls = player.elements.container.querySelector('.plyr__controls');
|
const controls = player.elements.container.querySelector('.plyr__controls');
|
||||||
@@ -397,52 +404,32 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
console.log('Custom audio tracks control added');
|
console.log('Custom audio tracks control added');
|
||||||
});
|
}
|
||||||
|
|
||||||
|
// Run immediately if Plyr is already ready, otherwise wait
|
||||||
|
if (player.ready) {
|
||||||
|
doAdd();
|
||||||
|
} else {
|
||||||
|
player.on('ready', doAdd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize Plyr with HLS quality options
|
* Main initialization
|
||||||
*/
|
*/
|
||||||
function initPlyrWithQuality(hlsInstance) {
|
async function start() {
|
||||||
|
console.log('Starting Plyr with HLS...');
|
||||||
|
|
||||||
|
if (typeof hls_manifest_url === 'undefined' || !hls_manifest_url) {
|
||||||
|
console.error('No HLS manifest URL available');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize Plyr immediately so the player UI shows right away
|
||||||
|
// instead of a bare <video> element while the manifest loads.
|
||||||
const video = document.getElementById('js-video-player');
|
const video = document.getElementById('js-video-player');
|
||||||
|
if (video) {
|
||||||
if (!hlsInstance || !hlsInstance.levels || hlsInstance.levels.length === 0) {
|
plyrInstance = new Plyr(video, {
|
||||||
console.error('HLS not ready');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!video) {
|
|
||||||
console.error('Video element not found');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('HLS levels available:', hlsInstance.levels.length);
|
|
||||||
|
|
||||||
const sortedLevels = [...hlsInstance.levels].sort((a, b) => b.height - a.height);
|
|
||||||
|
|
||||||
const seenHeights = new Set();
|
|
||||||
const uniqueLevels = [];
|
|
||||||
|
|
||||||
sortedLevels.forEach((level) => {
|
|
||||||
if (!seenHeights.has(level.height)) {
|
|
||||||
seenHeights.add(level.height);
|
|
||||||
uniqueLevels.push(level);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const qualityLabels = ['auto'];
|
|
||||||
uniqueLevels.forEach((level) => {
|
|
||||||
const originalIndex = hlsInstance.levels.indexOf(level);
|
|
||||||
const label = level.height + 'p';
|
|
||||||
if (!window.hlsQualityMap[label]) {
|
|
||||||
qualityLabels.push(label);
|
|
||||||
window.hlsQualityMap[label] = originalIndex;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('Quality labels:', qualityLabels);
|
|
||||||
|
|
||||||
const playerOptions = {
|
|
||||||
autoplay: autoplayActive,
|
autoplay: autoplayActive,
|
||||||
disableContextMenu: false,
|
disableContextMenu: false,
|
||||||
captions: {
|
captions: {
|
||||||
@@ -472,64 +459,64 @@
|
|||||||
src: typeof storyboard_url !== 'undefined' && storyboard_url !== null ? [storyboard_url] : [],
|
src: typeof storyboard_url !== 'undefined' && storyboard_url !== null ? [storyboard_url] : [],
|
||||||
},
|
},
|
||||||
settings: ['captions', 'speed', 'loop'],
|
settings: ['captions', 'speed', 'loop'],
|
||||||
tooltips: {
|
tooltips: { controls: true },
|
||||||
controls: true,
|
});
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('Creating Plyr...');
|
|
||||||
|
|
||||||
try {
|
|
||||||
plyrInstance = new Plyr(video, playerOptions);
|
|
||||||
console.log('Plyr instance created');
|
|
||||||
|
|
||||||
window.plyrInstance = plyrInstance;
|
window.plyrInstance = plyrInstance;
|
||||||
|
|
||||||
addCustomQualityControl(plyrInstance, qualityLabels);
|
|
||||||
addCustomAudioTracksControl(plyrInstance, hlsInstance);
|
|
||||||
|
|
||||||
if (plyrInstance.eventListeners) {
|
if (plyrInstance.eventListeners) {
|
||||||
plyrInstance.eventListeners.forEach(function(eventListener) {
|
plyrInstance.eventListeners.forEach(function(eventListener) {
|
||||||
if (eventListener.type === 'dblclick') {
|
if (eventListener.type === 'dblclick') {
|
||||||
eventListener.element.removeEventListener(eventListener.type, eventListener.callback, eventListener.options);
|
eventListener.element.removeEventListener(
|
||||||
|
eventListener.type, eventListener.callback, eventListener.options);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
plyrInstance.started = false;
|
plyrInstance.started = false;
|
||||||
plyrInstance.once('playing', function(){this.started = true});
|
plyrInstance.once('playing', function(){ this.started = true; });
|
||||||
|
|
||||||
if (typeof data !== 'undefined' && data.time_start != 0) {
|
if (typeof data !== 'undefined' && data.time_start != 0) {
|
||||||
video.addEventListener('loadedmetadata', function() {
|
video.addEventListener('loadedmetadata', function() {
|
||||||
video.currentTime = data.time_start;
|
video.currentTime = data.time_start;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Plyr init complete');
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Failed to initialize Plyr:', e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main initialization
|
|
||||||
*/
|
|
||||||
async function start() {
|
|
||||||
console.log('Starting Plyr with HLS...');
|
|
||||||
|
|
||||||
if (typeof hls_manifest_url === 'undefined' || !hls_manifest_url) {
|
|
||||||
console.error('No HLS manifest URL available');
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const hlsInstance = await initHLS(hls_manifest_url);
|
const hlsInstance = await initHLS(hls_manifest_url);
|
||||||
initPlyrWithQuality(hlsInstance);
|
// Manifest is ready — add quality and audio controls
|
||||||
|
addCustomQualityControl(plyrInstance, buildQualityLabels(hlsInstance));
|
||||||
|
addCustomAudioTracksControl(plyrInstance, hlsInstance);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to initialize:', error);
|
console.error('Failed to initialize HLS:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build quality labels from HLS levels
|
||||||
|
*/
|
||||||
|
function buildQualityLabels(hlsInstance) {
|
||||||
|
const qualityLabels = ['auto'];
|
||||||
|
if (!hlsInstance || !hlsInstance.levels) return qualityLabels;
|
||||||
|
|
||||||
|
const sortedLevels = [...hlsInstance.levels].sort((a, b) => b.height - a.height);
|
||||||
|
const seenHeights = new Set();
|
||||||
|
|
||||||
|
sortedLevels.forEach((level) => {
|
||||||
|
if (!seenHeights.has(level.height)) {
|
||||||
|
seenHeights.add(level.height);
|
||||||
|
const originalIndex = hlsInstance.levels.indexOf(level);
|
||||||
|
const label = level.height + 'p';
|
||||||
|
if (!window.hlsQualityMap[label]) {
|
||||||
|
qualityLabels.push(label);
|
||||||
|
window.hlsQualityMap[label] = originalIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return qualityLabels;
|
||||||
|
}
|
||||||
|
|
||||||
if (document.readyState === 'loading') {
|
if (document.readyState === 'loading') {
|
||||||
document.addEventListener('DOMContentLoaded', start);
|
document.addEventListener('DOMContentLoaded', start);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user