unified-video-framework 1.4.448 → 1.4.450
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/packages/core/dist/version.d.ts +1 -1
- package/packages/core/dist/version.js +1 -1
- package/packages/core/src/version.ts +1 -1
- package/packages/web/dist/WebPlayer.d.ts.map +1 -1
- package/packages/web/dist/WebPlayer.js +77 -5
- package/packages/web/dist/WebPlayer.js.map +1 -1
- package/packages/web/src/WebPlayer.ts +88 -6
|
@@ -1725,8 +1725,44 @@ export class WebPlayer extends BasePlayer {
|
|
|
1725
1725
|
existingPlayer.remove();
|
|
1726
1726
|
}
|
|
1727
1727
|
|
|
1728
|
+
// Remove existing overlay if any
|
|
1729
|
+
const existingOverlay = container.querySelector('.uvf-youtube-overlay');
|
|
1730
|
+
if (existingOverlay) {
|
|
1731
|
+
existingOverlay.remove();
|
|
1732
|
+
}
|
|
1733
|
+
|
|
1728
1734
|
container.appendChild(iframeContainer);
|
|
1729
1735
|
|
|
1736
|
+
// Create transparent overlay to block YouTube's native controls (when custom controls are enabled)
|
|
1737
|
+
if (!this.youtubeNativeControls) {
|
|
1738
|
+
const overlay = document.createElement('div');
|
|
1739
|
+
overlay.className = 'uvf-youtube-overlay';
|
|
1740
|
+
// Styles are handled in CSS, just set essentials here
|
|
1741
|
+
overlay.style.cssText = `
|
|
1742
|
+
position: absolute;
|
|
1743
|
+
top: 0;
|
|
1744
|
+
left: 0;
|
|
1745
|
+
width: 100%;
|
|
1746
|
+
z-index: 2;
|
|
1747
|
+
`;
|
|
1748
|
+
|
|
1749
|
+
// Handle click to toggle play/pause
|
|
1750
|
+
overlay.addEventListener('click', () => {
|
|
1751
|
+
this.togglePlayPause();
|
|
1752
|
+
});
|
|
1753
|
+
|
|
1754
|
+
// Handle double-click for fullscreen
|
|
1755
|
+
overlay.addEventListener('dblclick', () => {
|
|
1756
|
+
if (this.isFullscreen()) {
|
|
1757
|
+
this.exitFullscreen();
|
|
1758
|
+
} else {
|
|
1759
|
+
this.enterFullscreen();
|
|
1760
|
+
}
|
|
1761
|
+
});
|
|
1762
|
+
|
|
1763
|
+
container.appendChild(overlay);
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1730
1766
|
// Load YouTube IFrame API if not loaded
|
|
1731
1767
|
if (!window.YT) {
|
|
1732
1768
|
await this.loadYouTubeAPI();
|
|
@@ -1802,12 +1838,19 @@ export class WebPlayer extends BasePlayer {
|
|
|
1802
1838
|
this.youtubePlayerReady = true;
|
|
1803
1839
|
this.debugLog('YouTube player ready');
|
|
1804
1840
|
|
|
1805
|
-
//
|
|
1806
|
-
|
|
1807
|
-
|
|
1841
|
+
// Hide loading spinner when YouTube player is ready
|
|
1842
|
+
const loading = document.getElementById('uvf-loading');
|
|
1843
|
+
if (loading) loading.classList.remove('active');
|
|
1844
|
+
|
|
1845
|
+
// If YouTube native controls are enabled AND custom controls are disabled, hide custom controls
|
|
1846
|
+
// This allows hybrid mode where both YouTube native controls and custom controls can be shown
|
|
1847
|
+
if (this.youtubeNativeControls && !this.useCustomControls && this.playerWrapper) {
|
|
1848
|
+
this.debugLog('[YouTube] Native controls enabled & custom controls disabled - hiding custom controls');
|
|
1808
1849
|
this.playerWrapper.classList.add('youtube-native-controls-mode');
|
|
1809
1850
|
// Also hide center play button and custom controls
|
|
1810
1851
|
this.hideCustomControls();
|
|
1852
|
+
} else if (this.youtubeNativeControls && this.useCustomControls) {
|
|
1853
|
+
this.debugLog('[YouTube] Hybrid mode - both YouTube native controls and custom controls enabled');
|
|
1811
1854
|
}
|
|
1812
1855
|
|
|
1813
1856
|
// Set initial volume
|
|
@@ -1851,6 +1894,10 @@ export class WebPlayer extends BasePlayer {
|
|
|
1851
1894
|
const state = event.data;
|
|
1852
1895
|
|
|
1853
1896
|
switch (state) {
|
|
1897
|
+
case window.YT.PlayerState.UNSTARTED: // -1: Video is loaded but not started
|
|
1898
|
+
this.updateYouTubeUI('unstarted');
|
|
1899
|
+
break;
|
|
1900
|
+
|
|
1854
1901
|
case window.YT.PlayerState.PLAYING:
|
|
1855
1902
|
this.state.isPlaying = true;
|
|
1856
1903
|
this.state.isPaused = false;
|
|
@@ -1903,12 +1950,20 @@ export class WebPlayer extends BasePlayer {
|
|
|
1903
1950
|
const playIcon = document.getElementById('uvf-play-icon');
|
|
1904
1951
|
const pauseIcon = document.getElementById('uvf-pause-icon');
|
|
1905
1952
|
const centerPlay = document.getElementById('uvf-center-play');
|
|
1953
|
+
const loading = document.getElementById('uvf-loading');
|
|
1954
|
+
|
|
1955
|
+
// Handle loading spinner for YouTube
|
|
1956
|
+
if (state === 'buffering') {
|
|
1957
|
+
if (loading) loading.classList.add('active');
|
|
1958
|
+
} else if (state === 'playing' || state === 'paused' || state === 'cued' || state === 'ended' || state === 'unstarted') {
|
|
1959
|
+
if (loading) loading.classList.remove('active');
|
|
1960
|
+
}
|
|
1906
1961
|
|
|
1907
1962
|
if (state === 'playing' || state === 'buffering') {
|
|
1908
1963
|
if (playIcon) playIcon.style.display = 'none';
|
|
1909
1964
|
if (pauseIcon) pauseIcon.style.display = 'block';
|
|
1910
1965
|
if (centerPlay) centerPlay.classList.add('hidden');
|
|
1911
|
-
} else if (state === 'paused' || state === 'cued' || state === 'ended') {
|
|
1966
|
+
} else if (state === 'paused' || state === 'cued' || state === 'ended' || state === 'unstarted') {
|
|
1912
1967
|
if (playIcon) playIcon.style.display = 'block';
|
|
1913
1968
|
if (pauseIcon) pauseIcon.style.display = 'none';
|
|
1914
1969
|
if (centerPlay) centerPlay.classList.remove('hidden');
|
|
@@ -5804,7 +5859,8 @@ export class WebPlayer extends BasePlayer {
|
|
|
5804
5859
|
z-index: 25;
|
|
5805
5860
|
opacity: 0;
|
|
5806
5861
|
transform: translateX(-50%) translateY(8px);
|
|
5807
|
-
transition: opacity 0.15s ease, transform 0.15s ease;
|
|
5862
|
+
transition: opacity 0.15s ease, transform 0.15s ease, left 0.05s ease-out;
|
|
5863
|
+
will-change: left, transform, opacity;
|
|
5808
5864
|
}
|
|
5809
5865
|
|
|
5810
5866
|
.uvf-thumbnail-preview.visible {
|
|
@@ -5820,6 +5876,8 @@ export class WebPlayer extends BasePlayer {
|
|
|
5820
5876
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.1);
|
|
5821
5877
|
backdrop-filter: blur(12px);
|
|
5822
5878
|
-webkit-backdrop-filter: blur(12px);
|
|
5879
|
+
/* Prevent container size changes */
|
|
5880
|
+
flex-shrink: 0;
|
|
5823
5881
|
}
|
|
5824
5882
|
|
|
5825
5883
|
.uvf-thumbnail-preview-image-wrapper {
|
|
@@ -5829,6 +5887,8 @@ export class WebPlayer extends BasePlayer {
|
|
|
5829
5887
|
border-radius: 6px;
|
|
5830
5888
|
overflow: hidden;
|
|
5831
5889
|
background: rgba(30, 30, 30, 0.95);
|
|
5890
|
+
/* Prevent layout shifts during image loading */
|
|
5891
|
+
flex-shrink: 0;
|
|
5832
5892
|
}
|
|
5833
5893
|
|
|
5834
5894
|
.uvf-thumbnail-preview-image {
|
|
@@ -5838,6 +5898,10 @@ export class WebPlayer extends BasePlayer {
|
|
|
5838
5898
|
display: block;
|
|
5839
5899
|
opacity: 0;
|
|
5840
5900
|
transition: opacity 0.2s ease;
|
|
5901
|
+
/* Prevent reflow/repaint jitter during load */
|
|
5902
|
+
will-change: opacity;
|
|
5903
|
+
backface-visibility: hidden;
|
|
5904
|
+
-webkit-backface-visibility: hidden;
|
|
5841
5905
|
}
|
|
5842
5906
|
|
|
5843
5907
|
.uvf-thumbnail-preview-image.loaded {
|
|
@@ -8588,7 +8652,25 @@ export class WebPlayer extends BasePlayer {
|
|
|
8588
8652
|
opacity: 0 !important;
|
|
8589
8653
|
pointer-events: none !important;
|
|
8590
8654
|
}
|
|
8591
|
-
|
|
8655
|
+
|
|
8656
|
+
/* YouTube overlay to block native controls */
|
|
8657
|
+
.uvf-youtube-overlay {
|
|
8658
|
+
position: absolute;
|
|
8659
|
+
top: 0;
|
|
8660
|
+
left: 0;
|
|
8661
|
+
width: 100%;
|
|
8662
|
+
height: calc(100% - 60px); /* Leave bottom area for our controls */
|
|
8663
|
+
z-index: 2;
|
|
8664
|
+
cursor: pointer;
|
|
8665
|
+
background: transparent;
|
|
8666
|
+
pointer-events: auto;
|
|
8667
|
+
}
|
|
8668
|
+
|
|
8669
|
+
/* When controls are hidden, cover entire video */
|
|
8670
|
+
.uvf-player-wrapper:not(:hover) .uvf-youtube-overlay {
|
|
8671
|
+
height: 100%;
|
|
8672
|
+
}
|
|
8673
|
+
|
|
8592
8674
|
/* Ultra-wide screens */
|
|
8593
8675
|
@media screen and (min-width: 1440px) {
|
|
8594
8676
|
.uvf-video-title {
|