diff options
| author | Astounds <kirito@disroot.org> | 2026-05-03 13:45:00 -0500 |
|---|---|---|
| committer | Astounds <kirito@disroot.org> | 2026-05-03 13:45:00 -0500 |
| commit | b9248cfe2da65c58fc65c09855d609dce8a903a3 (patch) | |
| tree | 1e9d4b75e8b3c175c7c6942168d93bda6b60cf74 /youtube/static | |
| parent | 07ca635a8409943783a2914a5f979b8350f44cd3 (diff) | |
| download | yt-local-b9248cfe2da65c58fc65c09855d609dce8a903a3.tar.lz yt-local-b9248cfe2da65c58fc65c09855d609dce8a903a3.tar.xz yt-local-b9248cfe2da65c58fc65c09855d609dce8a903a3.zip | |
fix: init Plyr before HLS manifest loads to avoid bare video flash
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.
Diffstat (limited to 'youtube/static')
| -rw-r--r-- | youtube/static/js/plyr.hls.start.js | 193 |
1 files changed, 90 insertions, 103 deletions
diff --git a/youtube/static/js/plyr.hls.start.js b/youtube/static/js/plyr.hls.start.js index bc8ec23..69e24bd 100644 --- a/youtube/static/js/plyr.hls.start.js +++ b/youtube/static/js/plyr.hls.start.js @@ -150,7 +150,7 @@ * Create custom quality control in Plyr controls */ function addCustomQualityControl(player, qualityLabels) { - player.on('ready', () => { + function doAdd() { console.log('Adding custom quality control...'); const controls = player.elements.container.querySelector('.plyr__controls'); @@ -238,14 +238,21 @@ } 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 */ function addCustomAudioTracksControl(player, hlsInstance) { - player.on('ready', () => { + function doAdd() { console.log('Adding custom audio tracks control...'); const controls = player.elements.container.querySelector('.plyr__controls'); @@ -397,137 +404,117 @@ }); 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) { - const video = document.getElementById('js-video-player'); - - if (!hlsInstance || !hlsInstance.levels || hlsInstance.levels.length === 0) { - console.error('HLS not ready'); - return; - } + async function start() { + console.log('Starting Plyr with HLS...'); - if (!video) { - console.error('Video element not found'); + if (typeof hls_manifest_url === 'undefined' || !hls_manifest_url) { + console.error('No HLS manifest URL available'); 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, - disableContextMenu: false, - captions: { - active: captionsActive, - language: typeof data !== 'undefined' ? data.settings.subtitles_language : 'en', - }, - controls: [ - 'play-large', - 'play', - 'progress', - 'current-time', - 'duration', - 'mute', - 'volume', - 'captions', - 'settings', - 'pip', - 'airplay', - 'fullscreen', - ], - iconUrl: '/youtube.com/static/modules/plyr/plyr.svg', - blankVideo: '/youtube.com/static/modules/plyr/blank.webm', - debug: false, - storage: { enabled: false }, - previewThumbnails: { - enabled: typeof storyboard_url !== 'undefined' && storyboard_url !== null, - src: typeof storyboard_url !== 'undefined' && storyboard_url !== null ? [storyboard_url] : [], - }, - settings: ['captions', 'speed', 'loop'], - tooltips: { - controls: true, - }, - }; - - console.log('Creating Plyr...'); - - try { - plyrInstance = new Plyr(video, playerOptions); - console.log('Plyr instance created'); - + // 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'); + if (video) { + plyrInstance = new Plyr(video, { + autoplay: autoplayActive, + disableContextMenu: false, + captions: { + active: captionsActive, + language: typeof data !== 'undefined' ? data.settings.subtitles_language : 'en', + }, + controls: [ + 'play-large', + 'play', + 'progress', + 'current-time', + 'duration', + 'mute', + 'volume', + 'captions', + 'settings', + 'pip', + 'airplay', + 'fullscreen', + ], + iconUrl: '/youtube.com/static/modules/plyr/plyr.svg', + blankVideo: '/youtube.com/static/modules/plyr/blank.webm', + debug: false, + storage: { enabled: false }, + previewThumbnails: { + enabled: typeof storyboard_url !== 'undefined' && storyboard_url !== null, + src: typeof storyboard_url !== 'undefined' && storyboard_url !== null ? [storyboard_url] : [], + }, + settings: ['captions', 'speed', 'loop'], + tooltips: { controls: true }, + }); window.plyrInstance = plyrInstance; - addCustomQualityControl(plyrInstance, qualityLabels); - addCustomAudioTracksControl(plyrInstance, hlsInstance); - if (plyrInstance.eventListeners) { plyrInstance.eventListeners.forEach(function(eventListener) { - if(eventListener.type === 'dblclick') { - eventListener.element.removeEventListener(eventListener.type, eventListener.callback, eventListener.options); + if (eventListener.type === 'dblclick') { + eventListener.element.removeEventListener( + eventListener.type, eventListener.callback, eventListener.options); } }); } 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) { video.addEventListener('loadedmetadata', function() { video.currentTime = data.time_start; }); } + } - console.log('Plyr init complete'); - } catch (e) { - console.error('Failed to initialize Plyr:', e); + try { + const hlsInstance = await initHLS(hls_manifest_url); + // Manifest is ready — add quality and audio controls + addCustomQualityControl(plyrInstance, buildQualityLabels(hlsInstance)); + addCustomAudioTracksControl(plyrInstance, hlsInstance); + } catch (error) { + console.error('Failed to initialize HLS:', error); } } /** - * Main initialization + * Build quality labels from HLS levels */ - async function start() { - console.log('Starting Plyr with HLS...'); + function buildQualityLabels(hlsInstance) { + const qualityLabels = ['auto']; + if (!hlsInstance || !hlsInstance.levels) return qualityLabels; - if (typeof hls_manifest_url === 'undefined' || !hls_manifest_url) { - console.error('No HLS manifest URL available'); - return; - } + const sortedLevels = [...hlsInstance.levels].sort((a, b) => b.height - a.height); + const seenHeights = new Set(); - try { - const hlsInstance = await initHLS(hls_manifest_url); - initPlyrWithQuality(hlsInstance); - } catch (error) { - console.error('Failed to initialize:', error); - } + 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') { |
