unified-video-framework 1.4.459 → 1.4.461
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 +122 -6
- package/packages/web/dist/WebPlayer.js.map +1 -1
- package/packages/web/src/WebPlayer.ts +131 -7
|
@@ -1838,12 +1838,17 @@ export class WebPlayer extends BasePlayer {
|
|
|
1838
1838
|
iv_load_policy: 3, // Hide annotations
|
|
1839
1839
|
modestbranding: 1, // Minimal YouTube branding
|
|
1840
1840
|
rel: 0, // Don't show related videos
|
|
1841
|
-
showinfo: 0, // Hide video info
|
|
1841
|
+
showinfo: 0, // Hide video info (deprecated but keep for older players)
|
|
1842
|
+
autohide: 1, // Auto-hide controls after delay
|
|
1843
|
+
cc_load_policy: 0, // Don't show captions by default
|
|
1844
|
+
playsinline: 1, // Play inline on mobile
|
|
1842
1845
|
autoplay: this.config.autoPlay ? 1 : 0,
|
|
1843
1846
|
mute: this.config.muted ? 1 : 0,
|
|
1844
1847
|
loop: this.config.loop ? 1 : 0, // Enable/disable loop
|
|
1845
1848
|
playlist: this.config.loop ? videoId : undefined, // Required for loop to work with single video
|
|
1846
|
-
widget_referrer: window.location.href
|
|
1849
|
+
widget_referrer: window.location.href, // Hide YouTube recommendations
|
|
1850
|
+
origin: window.location.origin, // Required for security
|
|
1851
|
+
enablejsapi: 1 // Enable JavaScript API
|
|
1847
1852
|
},
|
|
1848
1853
|
events: {
|
|
1849
1854
|
onReady: () => this.onYouTubePlayerReady(),
|
|
@@ -2688,12 +2693,27 @@ export class WebPlayer extends BasePlayer {
|
|
|
2688
2693
|
private updateTimeTooltip(e: MouseEvent): void {
|
|
2689
2694
|
const progressBar = document.getElementById('uvf-progress-bar');
|
|
2690
2695
|
const tooltip = document.getElementById('uvf-time-tooltip');
|
|
2691
|
-
if (!progressBar || !tooltip
|
|
2696
|
+
if (!progressBar || !tooltip) return;
|
|
2697
|
+
|
|
2698
|
+
// Get duration from YouTube player or regular video
|
|
2699
|
+
let duration: number;
|
|
2700
|
+
if (this.youtubePlayer && this.youtubePlayerReady) {
|
|
2701
|
+
duration = this.youtubePlayer.getDuration();
|
|
2702
|
+
} else if (this.video) {
|
|
2703
|
+
duration = this.video.duration;
|
|
2704
|
+
} else {
|
|
2705
|
+
return; // No video source available
|
|
2706
|
+
}
|
|
2707
|
+
|
|
2708
|
+
// Validate duration
|
|
2709
|
+
if (!isFinite(duration) || isNaN(duration) || duration <= 0) {
|
|
2710
|
+
return;
|
|
2711
|
+
}
|
|
2692
2712
|
|
|
2693
2713
|
const rect = progressBar.getBoundingClientRect();
|
|
2694
2714
|
const x = Math.max(0, Math.min(e.clientX - rect.left, rect.width));
|
|
2695
2715
|
const percent = (x / rect.width);
|
|
2696
|
-
const time = percent *
|
|
2716
|
+
const time = percent * duration;
|
|
2697
2717
|
|
|
2698
2718
|
// Update tooltip content and position
|
|
2699
2719
|
tooltip.textContent = this.formatTime(time);
|
|
@@ -4596,6 +4616,42 @@ export class WebPlayer extends BasePlayer {
|
|
|
4596
4616
|
this.playerWrapper.classList.add('uvf-fullscreen');
|
|
4597
4617
|
this.emit('onFullscreenChanged', true);
|
|
4598
4618
|
|
|
4619
|
+
// Force YouTube custom controls to be visible in fullscreen
|
|
4620
|
+
if (this.isYouTubeCustomControlsMode) {
|
|
4621
|
+
const controlsBar = document.getElementById('uvf-controls') as HTMLElement;
|
|
4622
|
+
const topBar = document.querySelector('.uvf-top-bar') as HTMLElement;
|
|
4623
|
+
|
|
4624
|
+
if (controlsBar) {
|
|
4625
|
+
controlsBar.style.position = 'fixed';
|
|
4626
|
+
controlsBar.style.bottom = '0';
|
|
4627
|
+
controlsBar.style.left = '0';
|
|
4628
|
+
controlsBar.style.right = '0';
|
|
4629
|
+
controlsBar.style.zIndex = '2147483645';
|
|
4630
|
+
controlsBar.style.display = 'flex';
|
|
4631
|
+
controlsBar.style.flexDirection = 'column';
|
|
4632
|
+
controlsBar.style.visibility = 'visible';
|
|
4633
|
+
controlsBar.style.opacity = '1';
|
|
4634
|
+
controlsBar.style.pointerEvents = 'auto';
|
|
4635
|
+
controlsBar.style.transform = 'translateY(0)';
|
|
4636
|
+
}
|
|
4637
|
+
|
|
4638
|
+
if (topBar) {
|
|
4639
|
+
topBar.style.position = 'fixed';
|
|
4640
|
+
topBar.style.top = '0';
|
|
4641
|
+
topBar.style.left = '0';
|
|
4642
|
+
topBar.style.right = '0';
|
|
4643
|
+
topBar.style.zIndex = '2147483645';
|
|
4644
|
+
topBar.style.display = 'flex';
|
|
4645
|
+
topBar.style.visibility = 'visible';
|
|
4646
|
+
topBar.style.opacity = '1';
|
|
4647
|
+
topBar.style.pointerEvents = 'auto';
|
|
4648
|
+
topBar.style.transform = 'translateY(0)';
|
|
4649
|
+
}
|
|
4650
|
+
|
|
4651
|
+
// Keep controls always visible in YouTube fullscreen
|
|
4652
|
+
this.playerWrapper?.classList.add('controls-visible');
|
|
4653
|
+
}
|
|
4654
|
+
|
|
4599
4655
|
// Lock to landscape orientation on mobile devices
|
|
4600
4656
|
await this.lockOrientationLandscape();
|
|
4601
4657
|
} else {
|
|
@@ -7812,7 +7868,34 @@ export class WebPlayer extends BasePlayer {
|
|
|
7812
7868
|
transform: translateY(-10px) !important;
|
|
7813
7869
|
pointer-events: none;
|
|
7814
7870
|
}
|
|
7815
|
-
|
|
7871
|
+
|
|
7872
|
+
/* YouTube custom controls in fullscreen - CRITICAL FIX for all devices */
|
|
7873
|
+
/* This rule applies regardless of device/orientation */
|
|
7874
|
+
.uvf-player-wrapper.youtube-custom-controls-mode.uvf-fullscreen .uvf-controls-bar,
|
|
7875
|
+
.uvf-player-wrapper.youtube-custom-controls-mode.uvf-fullscreen .uvf-top-bar {
|
|
7876
|
+
position: fixed !important;
|
|
7877
|
+
z-index: 2147483645 !important;
|
|
7878
|
+
visibility: visible !important;
|
|
7879
|
+
opacity: 1 !important;
|
|
7880
|
+
pointer-events: auto !important;
|
|
7881
|
+
transform: translateY(0) !important;
|
|
7882
|
+
}
|
|
7883
|
+
|
|
7884
|
+
.uvf-player-wrapper.youtube-custom-controls-mode.uvf-fullscreen .uvf-controls-bar {
|
|
7885
|
+
bottom: 0 !important;
|
|
7886
|
+
left: 0 !important;
|
|
7887
|
+
right: 0 !important;
|
|
7888
|
+
display: flex !important;
|
|
7889
|
+
flex-direction: column !important;
|
|
7890
|
+
}
|
|
7891
|
+
|
|
7892
|
+
.uvf-player-wrapper.youtube-custom-controls-mode.uvf-fullscreen .uvf-top-bar {
|
|
7893
|
+
top: 0 !important;
|
|
7894
|
+
left: 0 !important;
|
|
7895
|
+
right: 0 !important;
|
|
7896
|
+
display: flex !important;
|
|
7897
|
+
}
|
|
7898
|
+
|
|
7816
7899
|
/* Fullscreen specific styles - DESKTOP AND LANDSCAPE ONLY */
|
|
7817
7900
|
/* Mobile portrait uses Material You layout in fullscreen */
|
|
7818
7901
|
@media not all and (max-width: 767px) and (orientation: portrait) {
|
|
@@ -7923,6 +8006,38 @@ export class WebPlayer extends BasePlayer {
|
|
|
7923
8006
|
opacity: 1;
|
|
7924
8007
|
transform: translateY(0);
|
|
7925
8008
|
}
|
|
8009
|
+
|
|
8010
|
+
/* Ensure YouTube custom controls are visible in fullscreen */
|
|
8011
|
+
.uvf-player-wrapper.youtube-custom-controls-mode.uvf-fullscreen .uvf-controls-bar {
|
|
8012
|
+
position: fixed !important;
|
|
8013
|
+
bottom: 0 !important;
|
|
8014
|
+
left: 0 !important;
|
|
8015
|
+
right: 0 !important;
|
|
8016
|
+
z-index: 2147483645 !important;
|
|
8017
|
+
display: flex !important;
|
|
8018
|
+
flex-direction: column !important;
|
|
8019
|
+
visibility: visible !important;
|
|
8020
|
+
opacity: 1 !important;
|
|
8021
|
+
pointer-events: auto !important;
|
|
8022
|
+
}
|
|
8023
|
+
|
|
8024
|
+
.uvf-player-wrapper.youtube-custom-controls-mode.uvf-fullscreen .uvf-top-bar {
|
|
8025
|
+
position: fixed !important;
|
|
8026
|
+
top: 0 !important;
|
|
8027
|
+
left: 0 !important;
|
|
8028
|
+
right: 0 !important;
|
|
8029
|
+
z-index: 2147483645 !important;
|
|
8030
|
+
display: flex !important;
|
|
8031
|
+
visibility: visible !important;
|
|
8032
|
+
opacity: 1 !important;
|
|
8033
|
+
pointer-events: auto !important;
|
|
8034
|
+
}
|
|
8035
|
+
|
|
8036
|
+
/* Keep controls always visible in fullscreen for YouTube */
|
|
8037
|
+
.uvf-player-wrapper.youtube-custom-controls-mode.uvf-fullscreen .uvf-controls-bar,
|
|
8038
|
+
.uvf-player-wrapper.youtube-custom-controls-mode.uvf-fullscreen .uvf-top-bar {
|
|
8039
|
+
transform: translateY(0) !important;
|
|
8040
|
+
}
|
|
7926
8041
|
}
|
|
7927
8042
|
|
|
7928
8043
|
/* Safe Area Variables - Support for modern mobile devices */
|
|
@@ -10810,9 +10925,18 @@ export class WebPlayer extends BasePlayer {
|
|
|
10810
10925
|
const progressBar = document.querySelector('.uvf-progress-bar') as HTMLElement;
|
|
10811
10926
|
const progressFilled = document.getElementById('uvf-progress-filled') as HTMLElement;
|
|
10812
10927
|
const progressHandle = document.getElementById('uvf-progress-handle') as HTMLElement;
|
|
10813
|
-
if (!progressBar
|
|
10928
|
+
if (!progressBar) return;
|
|
10929
|
+
|
|
10930
|
+
// Get duration from YouTube player or regular video
|
|
10931
|
+
let duration: number;
|
|
10932
|
+
if (this.youtubePlayer && this.youtubePlayerReady) {
|
|
10933
|
+
duration = this.youtubePlayer.getDuration();
|
|
10934
|
+
} else if (this.video) {
|
|
10935
|
+
duration = this.video.duration;
|
|
10936
|
+
} else {
|
|
10937
|
+
return; // No video source available
|
|
10938
|
+
}
|
|
10814
10939
|
|
|
10815
|
-
const duration = this.video.duration;
|
|
10816
10940
|
// Validate duration before calculating seek time
|
|
10817
10941
|
if (!isFinite(duration) || isNaN(duration) || duration <= 0) {
|
|
10818
10942
|
this.debugWarn('Invalid video duration, cannot seek via progress bar');
|