unified-video-framework 1.4.158 → 1.4.159
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 +12 -2
- package/packages/core/dist/analytics/adapters/PlayerAnalyticsAdapter.d.ts +18 -0
- package/packages/core/dist/analytics/adapters/PlayerAnalyticsAdapter.d.ts.map +1 -0
- package/packages/core/dist/analytics/adapters/PlayerAnalyticsAdapter.js +117 -0
- package/packages/core/dist/analytics/adapters/PlayerAnalyticsAdapter.js.map +1 -0
- package/packages/core/dist/analytics/core/AnalyticsProvider.d.ts +18 -0
- package/packages/core/dist/analytics/core/AnalyticsProvider.d.ts.map +1 -0
- package/packages/core/dist/analytics/core/AnalyticsProvider.js +99 -0
- package/packages/core/dist/analytics/core/AnalyticsProvider.js.map +1 -0
- package/packages/core/dist/analytics/core/DynamicAnalyticsManager.d.ts +20 -0
- package/packages/core/dist/analytics/core/DynamicAnalyticsManager.d.ts.map +1 -0
- package/packages/core/dist/analytics/core/DynamicAnalyticsManager.js +161 -0
- package/packages/core/dist/analytics/core/DynamicAnalyticsManager.js.map +1 -0
- package/packages/core/dist/analytics/core/EventBatcher.d.ts +32 -0
- package/packages/core/dist/analytics/core/EventBatcher.d.ts.map +1 -0
- package/packages/core/dist/analytics/core/EventBatcher.js +98 -0
- package/packages/core/dist/analytics/core/EventBatcher.js.map +1 -0
- package/packages/core/dist/analytics/core/PlayerAnalytics.d.ts +19 -0
- package/packages/core/dist/analytics/core/PlayerAnalytics.d.ts.map +1 -0
- package/packages/core/dist/analytics/core/PlayerAnalytics.js +80 -0
- package/packages/core/dist/analytics/core/PlayerAnalytics.js.map +1 -0
- package/packages/core/dist/analytics/examples/DynamicAnalyticsExample.d.ts +32 -0
- package/packages/core/dist/analytics/examples/DynamicAnalyticsExample.d.ts.map +1 -0
- package/packages/core/dist/analytics/examples/DynamicAnalyticsExample.js +220 -0
- package/packages/core/dist/analytics/examples/DynamicAnalyticsExample.js.map +1 -0
- package/packages/core/dist/analytics/index.d.ts +13 -0
- package/packages/core/dist/analytics/index.d.ts.map +1 -0
- package/packages/core/dist/analytics/index.js +13 -0
- package/packages/core/dist/analytics/index.js.map +1 -0
- package/packages/core/dist/analytics/types/AnalyticsTypes.d.ts +239 -0
- package/packages/core/dist/analytics/types/AnalyticsTypes.d.ts.map +1 -0
- package/packages/core/dist/analytics/types/AnalyticsTypes.js +8 -0
- package/packages/core/dist/analytics/types/AnalyticsTypes.js.map +1 -0
- package/packages/core/dist/analytics/utils/DeviceDetection.d.ts +27 -0
- package/packages/core/dist/analytics/utils/DeviceDetection.d.ts.map +1 -0
- package/packages/core/dist/analytics/utils/DeviceDetection.js +184 -0
- package/packages/core/dist/analytics/utils/DeviceDetection.js.map +1 -0
- package/packages/core/dist/chapter-manager.d.ts +39 -0
- package/packages/core/dist/index.d.ts +1 -0
- package/packages/core/dist/index.d.ts.map +1 -1
- package/packages/core/dist/index.js +1 -0
- package/packages/core/dist/index.js.map +1 -1
- package/packages/core/src/analytics/README.md +902 -0
- package/packages/core/src/analytics/adapters/PlayerAnalyticsAdapter.ts +156 -0
- package/packages/core/src/analytics/core/AnalyticsProvider.ts +169 -0
- package/packages/core/src/analytics/core/DynamicAnalyticsManager.ts +199 -0
- package/packages/core/src/analytics/core/EventBatcher.ts +160 -0
- package/packages/core/src/analytics/core/PlayerAnalytics.ts +147 -0
- package/packages/core/src/analytics/index.ts +51 -0
- package/packages/core/src/analytics/types/AnalyticsTypes.ts +315 -0
- package/packages/core/src/analytics/utils/DeviceDetection.ts +220 -0
- package/packages/core/src/index.ts +3 -0
- package/packages/ios/README.md +84 -0
- package/packages/web/dist/WebPlayer.d.ts +5 -0
- package/packages/web/dist/WebPlayer.d.ts.map +1 -1
- package/packages/web/dist/WebPlayer.js +255 -63
- package/packages/web/dist/WebPlayer.js.map +1 -1
- package/packages/web/dist/epg/EPGController.d.ts +78 -0
- package/packages/web/dist/epg/EPGController.d.ts.map +1 -0
- package/packages/web/dist/epg/EPGController.js +476 -0
- package/packages/web/dist/epg/EPGController.js.map +1 -0
- package/packages/web/src/WebPlayer.ts +303 -79
- package/src/analytics/README.md +902 -0
- package/src/analytics/adapters/PlayerAnalyticsAdapter.ts +572 -0
- package/src/analytics/core/DynamicAnalyticsManager.ts +526 -0
- package/src/analytics/examples/DynamicAnalyticsExample.ts +324 -0
- package/src/analytics/index.ts +60 -0
|
@@ -1050,47 +1050,96 @@ export class WebPlayer extends BasePlayer {
|
|
|
1050
1050
|
if (!this.playerWrapper)
|
|
1051
1051
|
return;
|
|
1052
1052
|
try {
|
|
1053
|
-
if (
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1053
|
+
if (this.isIOSDevice() && this.video) {
|
|
1054
|
+
this.debugLog('iOS device detected - using video element fullscreen');
|
|
1055
|
+
try {
|
|
1056
|
+
if (this.video.webkitEnterFullscreen) {
|
|
1057
|
+
await this.video.webkitEnterFullscreen();
|
|
1058
|
+
this.playerWrapper.classList.add('uvf-fullscreen');
|
|
1059
|
+
this.emit('onFullscreenChanged', true);
|
|
1060
|
+
return;
|
|
1061
|
+
}
|
|
1062
|
+
else if (this.video.webkitRequestFullscreen) {
|
|
1063
|
+
await this.video.webkitRequestFullscreen();
|
|
1064
|
+
this.playerWrapper.classList.add('uvf-fullscreen');
|
|
1065
|
+
this.emit('onFullscreenChanged', true);
|
|
1066
|
+
return;
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
catch (iosError) {
|
|
1070
|
+
this.debugWarn('iOS video fullscreen failed:', iosError.message);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
if (!this.isFullscreenSupported()) {
|
|
1057
1074
|
this.debugWarn('Fullscreen not supported by browser');
|
|
1075
|
+
if (this.isMobileDevice()) {
|
|
1076
|
+
this.showShortcutIndicator('Rotate device for fullscreen experience');
|
|
1077
|
+
}
|
|
1058
1078
|
return;
|
|
1059
1079
|
}
|
|
1060
|
-
if (
|
|
1061
|
-
document.webkitFullscreenElement ||
|
|
1062
|
-
document.mozFullScreenElement ||
|
|
1063
|
-
document.msFullscreenElement) {
|
|
1080
|
+
if (this.isFullscreen()) {
|
|
1064
1081
|
this.debugLog('Already in fullscreen mode');
|
|
1065
1082
|
return;
|
|
1066
1083
|
}
|
|
1067
1084
|
const element = this.playerWrapper;
|
|
1085
|
+
let fullscreenSuccess = false;
|
|
1068
1086
|
if (element.requestFullscreen) {
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1087
|
+
try {
|
|
1088
|
+
await element.requestFullscreen();
|
|
1089
|
+
fullscreenSuccess = true;
|
|
1090
|
+
}
|
|
1091
|
+
catch (err) {
|
|
1092
|
+
this.debugWarn('Standard fullscreen request failed:', err.message);
|
|
1093
|
+
}
|
|
1072
1094
|
}
|
|
1073
1095
|
else if (element.webkitRequestFullscreen) {
|
|
1074
|
-
|
|
1096
|
+
try {
|
|
1097
|
+
await element.webkitRequestFullscreen();
|
|
1098
|
+
fullscreenSuccess = true;
|
|
1099
|
+
}
|
|
1100
|
+
catch (err) {
|
|
1075
1101
|
this.debugWarn('WebKit fullscreen request failed:', err.message);
|
|
1076
|
-
}
|
|
1102
|
+
}
|
|
1077
1103
|
}
|
|
1078
1104
|
else if (element.mozRequestFullScreen) {
|
|
1079
|
-
|
|
1105
|
+
try {
|
|
1106
|
+
await element.mozRequestFullScreen();
|
|
1107
|
+
fullscreenSuccess = true;
|
|
1108
|
+
}
|
|
1109
|
+
catch (err) {
|
|
1080
1110
|
this.debugWarn('Mozilla fullscreen request failed:', err.message);
|
|
1081
|
-
}
|
|
1111
|
+
}
|
|
1082
1112
|
}
|
|
1083
1113
|
else if (element.msRequestFullscreen) {
|
|
1084
|
-
|
|
1114
|
+
try {
|
|
1115
|
+
await element.msRequestFullscreen();
|
|
1116
|
+
fullscreenSuccess = true;
|
|
1117
|
+
}
|
|
1118
|
+
catch (err) {
|
|
1085
1119
|
this.debugWarn('MS fullscreen request failed:', err.message);
|
|
1086
|
-
}
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
if (fullscreenSuccess) {
|
|
1123
|
+
this.playerWrapper.classList.add('uvf-fullscreen');
|
|
1124
|
+
this.emit('onFullscreenChanged', true);
|
|
1125
|
+
if (this.isAndroidDevice()) {
|
|
1126
|
+
setTimeout(() => {
|
|
1127
|
+
this.showShortcutIndicator('Rotate device to landscape for best experience');
|
|
1128
|
+
}, 1000);
|
|
1129
|
+
}
|
|
1087
1130
|
}
|
|
1088
1131
|
else {
|
|
1089
|
-
this.debugWarn('
|
|
1090
|
-
|
|
1132
|
+
this.debugWarn('All fullscreen methods failed');
|
|
1133
|
+
if (this.isIOSDevice()) {
|
|
1134
|
+
this.showShortcutIndicator('Fullscreen not available - use device controls');
|
|
1135
|
+
}
|
|
1136
|
+
else if (this.isAndroidDevice()) {
|
|
1137
|
+
this.showShortcutIndicator('Try rotating device to landscape');
|
|
1138
|
+
}
|
|
1139
|
+
else {
|
|
1140
|
+
this.showShortcutIndicator('Fullscreen not supported in this browser');
|
|
1141
|
+
}
|
|
1091
1142
|
}
|
|
1092
|
-
this.playerWrapper.classList.add('uvf-fullscreen');
|
|
1093
|
-
this.emit('onFullscreenChanged', true);
|
|
1094
1143
|
}
|
|
1095
1144
|
catch (error) {
|
|
1096
1145
|
this.debugWarn('Failed to enter fullscreen:', error.message);
|
|
@@ -1098,37 +1147,74 @@ export class WebPlayer extends BasePlayer {
|
|
|
1098
1147
|
}
|
|
1099
1148
|
async exitFullscreen() {
|
|
1100
1149
|
try {
|
|
1101
|
-
if (
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1150
|
+
if (this.isIOSDevice() && this.video) {
|
|
1151
|
+
try {
|
|
1152
|
+
if (this.video.webkitExitFullscreen) {
|
|
1153
|
+
await this.video.webkitExitFullscreen();
|
|
1154
|
+
if (this.playerWrapper) {
|
|
1155
|
+
this.playerWrapper.classList.remove('uvf-fullscreen');
|
|
1156
|
+
}
|
|
1157
|
+
this.emit('onFullscreenChanged', false);
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
catch (iosError) {
|
|
1162
|
+
this.debugWarn('iOS video exit fullscreen failed:', iosError.message);
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
if (!this.isFullscreen()) {
|
|
1105
1166
|
this.debugLog('Not in fullscreen mode');
|
|
1106
1167
|
return;
|
|
1107
1168
|
}
|
|
1169
|
+
let exitSuccess = false;
|
|
1108
1170
|
if (document.exitFullscreen) {
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1171
|
+
try {
|
|
1172
|
+
await document.exitFullscreen();
|
|
1173
|
+
exitSuccess = true;
|
|
1174
|
+
}
|
|
1175
|
+
catch (err) {
|
|
1176
|
+
this.debugWarn('Standard exit fullscreen failed:', err.message);
|
|
1177
|
+
}
|
|
1112
1178
|
}
|
|
1113
1179
|
else if (document.webkitExitFullscreen) {
|
|
1114
|
-
|
|
1180
|
+
try {
|
|
1181
|
+
await document.webkitExitFullscreen();
|
|
1182
|
+
exitSuccess = true;
|
|
1183
|
+
}
|
|
1184
|
+
catch (err) {
|
|
1115
1185
|
this.debugWarn('WebKit exit fullscreen failed:', err.message);
|
|
1116
|
-
}
|
|
1186
|
+
}
|
|
1117
1187
|
}
|
|
1118
1188
|
else if (document.mozCancelFullScreen) {
|
|
1119
|
-
|
|
1189
|
+
try {
|
|
1190
|
+
await document.mozCancelFullScreen();
|
|
1191
|
+
exitSuccess = true;
|
|
1192
|
+
}
|
|
1193
|
+
catch (err) {
|
|
1120
1194
|
this.debugWarn('Mozilla exit fullscreen failed:', err.message);
|
|
1121
|
-
}
|
|
1195
|
+
}
|
|
1122
1196
|
}
|
|
1123
1197
|
else if (document.msExitFullscreen) {
|
|
1124
|
-
|
|
1198
|
+
try {
|
|
1199
|
+
await document.msExitFullscreen();
|
|
1200
|
+
exitSuccess = true;
|
|
1201
|
+
}
|
|
1202
|
+
catch (err) {
|
|
1125
1203
|
this.debugWarn('MS exit fullscreen failed:', err.message);
|
|
1126
|
-
}
|
|
1204
|
+
}
|
|
1127
1205
|
}
|
|
1128
|
-
if (this.
|
|
1129
|
-
this.playerWrapper
|
|
1206
|
+
if (exitSuccess || !this.isFullscreen()) {
|
|
1207
|
+
if (this.playerWrapper) {
|
|
1208
|
+
this.playerWrapper.classList.remove('uvf-fullscreen');
|
|
1209
|
+
}
|
|
1210
|
+
this.emit('onFullscreenChanged', false);
|
|
1211
|
+
}
|
|
1212
|
+
else {
|
|
1213
|
+
this.debugWarn('All exit fullscreen methods failed');
|
|
1214
|
+
if (this.playerWrapper) {
|
|
1215
|
+
this.playerWrapper.classList.remove('uvf-fullscreen');
|
|
1216
|
+
}
|
|
1130
1217
|
}
|
|
1131
|
-
this.emit('onFullscreenChanged', false);
|
|
1132
1218
|
}
|
|
1133
1219
|
catch (error) {
|
|
1134
1220
|
this.debugWarn('Failed to exit fullscreen:', error.message);
|
|
@@ -3697,7 +3783,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
3697
3783
|
}
|
|
3698
3784
|
}
|
|
3699
3785
|
|
|
3700
|
-
/* iOS Safari specific fixes - address bar handling */
|
|
3786
|
+
/* iOS Safari specific fixes - address bar handling and control positioning */
|
|
3701
3787
|
@supports (-webkit-appearance: none) {
|
|
3702
3788
|
.uvf-player-wrapper.uvf-fullscreen,
|
|
3703
3789
|
.uvf-video-container.uvf-fullscreen {
|
|
@@ -3715,6 +3801,31 @@ export class WebPlayer extends BasePlayer {
|
|
|
3715
3801
|
.uvf-player-wrapper {
|
|
3716
3802
|
height: -webkit-fill-available;
|
|
3717
3803
|
min-height: 100vh;
|
|
3804
|
+
/* Fix for iOS Safari control overlay positioning */
|
|
3805
|
+
position: relative;
|
|
3806
|
+
overflow: hidden;
|
|
3807
|
+
}
|
|
3808
|
+
|
|
3809
|
+
/* iOS Safari specific fixes for control positioning */
|
|
3810
|
+
.uvf-controls-bar {
|
|
3811
|
+
position: absolute !important;
|
|
3812
|
+
bottom: 0 !important;
|
|
3813
|
+
left: 0 !important;
|
|
3814
|
+
right: 0 !important;
|
|
3815
|
+
/* Ensure hardware acceleration */
|
|
3816
|
+
-webkit-transform: translate3d(0,0,0);
|
|
3817
|
+
transform: translate3d(0,0,0);
|
|
3818
|
+
/* Prevent any webkit transforms that could cause positioning issues */
|
|
3819
|
+
-webkit-perspective: 1000;
|
|
3820
|
+
perspective: 1000;
|
|
3821
|
+
}
|
|
3822
|
+
|
|
3823
|
+
/* Ensure all control elements use hardware acceleration */
|
|
3824
|
+
.uvf-control-btn,
|
|
3825
|
+
.uvf-progress-bar,
|
|
3826
|
+
.uvf-progress-section {
|
|
3827
|
+
-webkit-transform: translateZ(0);
|
|
3828
|
+
transform: translateZ(0);
|
|
3718
3829
|
}
|
|
3719
3830
|
}
|
|
3720
3831
|
}
|
|
@@ -3775,14 +3886,45 @@ export class WebPlayer extends BasePlayer {
|
|
|
3775
3886
|
|
|
3776
3887
|
/* Fix for controls being cut off by virtual keyboard */
|
|
3777
3888
|
.uvf-controls-bar {
|
|
3778
|
-
position:
|
|
3779
|
-
bottom:
|
|
3889
|
+
position: absolute !important;
|
|
3890
|
+
bottom: 0 !important;
|
|
3891
|
+
left: 0 !important;
|
|
3892
|
+
right: 0 !important;
|
|
3893
|
+
/* Remove fixed positioning that causes issues on iOS Safari */
|
|
3894
|
+
z-index: 1000 !important;
|
|
3895
|
+
transform: translateZ(0); /* Force hardware acceleration */
|
|
3780
3896
|
}
|
|
3781
3897
|
|
|
3782
3898
|
/* Ensure controls stay above virtual keyboards */
|
|
3783
3899
|
@supports (bottom: env(keyboard-inset-height)) {
|
|
3784
3900
|
.uvf-controls-bar {
|
|
3785
|
-
bottom: max(
|
|
3901
|
+
bottom: max(0px, env(keyboard-inset-height, 0)) !important;
|
|
3902
|
+
padding-bottom: calc(16px + max(var(--uvf-safe-area-bottom, 0), env(keyboard-inset-height, 0))) !important;
|
|
3903
|
+
}
|
|
3904
|
+
}
|
|
3905
|
+
|
|
3906
|
+
/* Hide PiP button on mobile - not supported on most mobile browsers */
|
|
3907
|
+
#uvf-pip-btn {
|
|
3908
|
+
display: none !important;
|
|
3909
|
+
}
|
|
3910
|
+
|
|
3911
|
+
/* Mobile fullscreen enhancements */
|
|
3912
|
+
.uvf-player-wrapper.uvf-fullscreen {
|
|
3913
|
+
/* Ensure fullscreen covers entire viewport on mobile */
|
|
3914
|
+
position: fixed !important;
|
|
3915
|
+
top: 0 !important;
|
|
3916
|
+
left: 0 !important;
|
|
3917
|
+
width: 100vw !important;
|
|
3918
|
+
height: 100vh !important;
|
|
3919
|
+
z-index: 2147483647 !important;
|
|
3920
|
+
background: #000 !important;
|
|
3921
|
+
}
|
|
3922
|
+
|
|
3923
|
+
/* iOS Safari specific fullscreen fixes */
|
|
3924
|
+
@supports (-webkit-appearance: none) {
|
|
3925
|
+
.uvf-player-wrapper.uvf-fullscreen {
|
|
3926
|
+
/* Use viewport units that work better with iOS Safari */
|
|
3927
|
+
height: -webkit-fill-available !important;
|
|
3786
3928
|
}
|
|
3787
3929
|
}
|
|
3788
3930
|
}
|
|
@@ -3824,19 +3966,25 @@ export class WebPlayer extends BasePlayer {
|
|
|
3824
3966
|
min-height: inherit;
|
|
3825
3967
|
}
|
|
3826
3968
|
|
|
3827
|
-
/* Enhanced mobile controls bar with safe area padding */
|
|
3969
|
+
/* Enhanced mobile controls bar with safe area padding - iOS Safari specific fixes */
|
|
3828
3970
|
.uvf-controls-bar {
|
|
3829
|
-
position: absolute;
|
|
3830
|
-
bottom: 0;
|
|
3831
|
-
left: 0;
|
|
3832
|
-
right: 0;
|
|
3971
|
+
position: absolute !important;
|
|
3972
|
+
bottom: 0 !important;
|
|
3973
|
+
left: 0 !important;
|
|
3974
|
+
right: 0 !important;
|
|
3833
3975
|
padding: 16px 12px;
|
|
3834
|
-
padding-bottom: calc(16px + var(--uvf-safe-area-bottom));
|
|
3835
|
-
padding-left: calc(12px + var(--uvf-safe-area-left));
|
|
3836
|
-
padding-right: calc(12px + var(--uvf-safe-area-right));
|
|
3976
|
+
padding-bottom: calc(16px + var(--uvf-safe-area-bottom, 0px));
|
|
3977
|
+
padding-left: calc(12px + var(--uvf-safe-area-left, 0px));
|
|
3978
|
+
padding-right: calc(12px + var(--uvf-safe-area-right, 0px));
|
|
3837
3979
|
background: linear-gradient(to top, var(--uvf-overlay-strong) 0%, var(--uvf-overlay-medium) 80%, var(--uvf-overlay-transparent) 100%);
|
|
3838
3980
|
box-sizing: border-box;
|
|
3839
|
-
z-index: 1000;
|
|
3981
|
+
z-index: 1000 !important;
|
|
3982
|
+
/* iOS Safari specific fixes */
|
|
3983
|
+
transform: translateZ(0);
|
|
3984
|
+
-webkit-transform: translateZ(0);
|
|
3985
|
+
will-change: transform;
|
|
3986
|
+
/* Ensure proper stacking */
|
|
3987
|
+
isolation: isolate;
|
|
3840
3988
|
}
|
|
3841
3989
|
|
|
3842
3990
|
.uvf-progress-section {
|
|
@@ -5268,6 +5416,9 @@ export class WebPlayer extends BasePlayer {
|
|
|
5268
5416
|
pipBtn.id = 'uvf-pip-btn';
|
|
5269
5417
|
pipBtn.title = 'Picture-in-Picture';
|
|
5270
5418
|
pipBtn.innerHTML = '<svg viewBox="0 0 24 24"><path d="M19 7h-8v6h8V7zm2-4H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H3V5h18v14z" stroke="currentColor" stroke-width="0.5" fill="currentColor"/></svg>';
|
|
5419
|
+
if (this.isMobileDevice() || !this.isPipSupported()) {
|
|
5420
|
+
pipBtn.style.display = 'none';
|
|
5421
|
+
}
|
|
5271
5422
|
rightControls.appendChild(pipBtn);
|
|
5272
5423
|
const fullscreenBtn = document.createElement('button');
|
|
5273
5424
|
fullscreenBtn.className = 'uvf-control-btn';
|
|
@@ -5506,13 +5657,20 @@ export class WebPlayer extends BasePlayer {
|
|
|
5506
5657
|
fullscreenBtn?.addEventListener('click', (event) => {
|
|
5507
5658
|
const isBrave = this.isBraveBrowser();
|
|
5508
5659
|
const isPrivate = this.isPrivateWindow();
|
|
5660
|
+
const isIOS = this.isIOSDevice();
|
|
5661
|
+
const isAndroid = this.isAndroidDevice();
|
|
5662
|
+
const isMobile = this.isMobileDevice();
|
|
5509
5663
|
this.debugLog('Fullscreen button clicked:', {
|
|
5510
5664
|
isBrave,
|
|
5511
5665
|
isPrivate,
|
|
5666
|
+
isIOS,
|
|
5667
|
+
isAndroid,
|
|
5668
|
+
isMobile,
|
|
5512
5669
|
isFullscreen: this.isFullscreen(),
|
|
5513
5670
|
eventTrusted: event.isTrusted,
|
|
5514
5671
|
eventType: event.type,
|
|
5515
|
-
timestamp: Date.now()
|
|
5672
|
+
timestamp: Date.now(),
|
|
5673
|
+
fullscreenSupported: this.isFullscreenSupported()
|
|
5516
5674
|
});
|
|
5517
5675
|
this.lastUserInteraction = Date.now();
|
|
5518
5676
|
this.checkFullscreenPermissions();
|
|
@@ -5524,20 +5682,27 @@ export class WebPlayer extends BasePlayer {
|
|
|
5524
5682
|
}
|
|
5525
5683
|
else {
|
|
5526
5684
|
this.debugLog('Entering fullscreen via button');
|
|
5527
|
-
if (
|
|
5528
|
-
this.
|
|
5529
|
-
this.debugWarn('Brave fullscreen button failed:', err.message);
|
|
5530
|
-
this.showTemporaryMessage('Brave Browser: Please allow fullscreen in site settings');
|
|
5531
|
-
});
|
|
5685
|
+
if (isIOS) {
|
|
5686
|
+
this.showShortcutIndicator('Using iOS video fullscreen');
|
|
5532
5687
|
}
|
|
5533
|
-
else {
|
|
5534
|
-
this.
|
|
5535
|
-
this.debugWarn('Fullscreen button failed:', err.message);
|
|
5536
|
-
if (isBrave) {
|
|
5537
|
-
this.showTemporaryMessage('Try refreshing the page or check Brave shields settings');
|
|
5538
|
-
}
|
|
5539
|
-
});
|
|
5688
|
+
else if (isAndroid) {
|
|
5689
|
+
this.showShortcutIndicator('Entering fullscreen - rotate to landscape');
|
|
5540
5690
|
}
|
|
5691
|
+
this.enterFullscreen().catch(err => {
|
|
5692
|
+
this.debugWarn('Fullscreen button failed:', err.message);
|
|
5693
|
+
if (isIOS) {
|
|
5694
|
+
this.showTemporaryMessage('iOS: Use device rotation or video controls for fullscreen');
|
|
5695
|
+
}
|
|
5696
|
+
else if (isAndroid) {
|
|
5697
|
+
this.showTemporaryMessage('Android: Try rotating device to landscape mode');
|
|
5698
|
+
}
|
|
5699
|
+
else if (isBrave) {
|
|
5700
|
+
this.showTemporaryMessage('Brave Browser: Please allow fullscreen in site settings');
|
|
5701
|
+
}
|
|
5702
|
+
else {
|
|
5703
|
+
this.showTemporaryMessage('Fullscreen not supported in this browser');
|
|
5704
|
+
}
|
|
5705
|
+
});
|
|
5541
5706
|
}
|
|
5542
5707
|
});
|
|
5543
5708
|
const updateFullscreenIcon = () => {
|
|
@@ -6072,6 +6237,33 @@ export class WebPlayer extends BasePlayer {
|
|
|
6072
6237
|
this.mute();
|
|
6073
6238
|
}
|
|
6074
6239
|
}
|
|
6240
|
+
isMobileDevice() {
|
|
6241
|
+
const userAgent = navigator.userAgent.toLowerCase();
|
|
6242
|
+
const mobileKeywords = ['android', 'iphone', 'ipad', 'ipod', 'blackberry', 'windows phone', 'mobile'];
|
|
6243
|
+
const isMobileUserAgent = mobileKeywords.some(keyword => userAgent.includes(keyword));
|
|
6244
|
+
const isSmallScreen = window.innerWidth <= 768;
|
|
6245
|
+
const hasTouchScreen = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
|
|
6246
|
+
return isMobileUserAgent || (isSmallScreen && hasTouchScreen);
|
|
6247
|
+
}
|
|
6248
|
+
isPipSupported() {
|
|
6249
|
+
return !!(document.pictureInPictureEnabled &&
|
|
6250
|
+
HTMLVideoElement.prototype.requestPictureInPicture &&
|
|
6251
|
+
typeof HTMLVideoElement.prototype.requestPictureInPicture === 'function');
|
|
6252
|
+
}
|
|
6253
|
+
isIOSDevice() {
|
|
6254
|
+
const userAgent = navigator.userAgent.toLowerCase();
|
|
6255
|
+
return /iphone|ipad|ipod/.test(userAgent);
|
|
6256
|
+
}
|
|
6257
|
+
isAndroidDevice() {
|
|
6258
|
+
const userAgent = navigator.userAgent.toLowerCase();
|
|
6259
|
+
return /android/.test(userAgent);
|
|
6260
|
+
}
|
|
6261
|
+
isFullscreenSupported() {
|
|
6262
|
+
return !!(document.fullscreenEnabled ||
|
|
6263
|
+
document.webkitFullscreenEnabled ||
|
|
6264
|
+
document.mozFullScreenEnabled ||
|
|
6265
|
+
document.msFullscreenEnabled);
|
|
6266
|
+
}
|
|
6075
6267
|
handleVolumeChange(e) {
|
|
6076
6268
|
const slider = document.getElementById('uvf-volume-slider');
|
|
6077
6269
|
if (!slider)
|