unified-video-framework 1.4.262 → 1.4.264
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/interfaces/IVideoPlayer.d.ts +0 -1
- package/packages/core/dist/interfaces/IVideoPlayer.d.ts.map +1 -1
- package/packages/core/dist/interfaces.d.ts +0 -1
- package/packages/core/dist/interfaces.d.ts.map +1 -1
- package/packages/core/src/interfaces/IVideoPlayer.ts +0 -3
- package/packages/core/src/interfaces.ts +0 -1
- package/packages/web/dist/WebPlayer.d.ts +0 -11
- package/packages/web/dist/WebPlayer.d.ts.map +1 -1
- package/packages/web/dist/WebPlayer.js +47 -418
- package/packages/web/dist/WebPlayer.js.map +1 -1
- package/packages/web/dist/react/WebPlayerView.d.ts +1 -1
- package/packages/web/dist/react/WebPlayerView.d.ts.map +1 -1
- package/packages/web/dist/react/WebPlayerView.js +1 -2
- package/packages/web/dist/react/WebPlayerView.js.map +1 -1
- package/packages/web/src/WebPlayer.ts +77 -567
- package/packages/web/src/react/WebPlayerView.tsx +2 -5
|
@@ -94,9 +94,6 @@ export class WebPlayer extends BasePlayer {
|
|
|
94
94
|
this.youtubePlayerReady = false;
|
|
95
95
|
this.youtubeIframe = null;
|
|
96
96
|
this.youtubeTimeTrackingInterval = null;
|
|
97
|
-
this.isYouTubeLive = false;
|
|
98
|
-
this.useYouTubeNativeControls = false;
|
|
99
|
-
this.currentYouTubeControlsState = null;
|
|
100
97
|
this.clickToUnmuteHandler = null;
|
|
101
98
|
}
|
|
102
99
|
debugLog(message, ...args) {
|
|
@@ -118,11 +115,11 @@ export class WebPlayer extends BasePlayer {
|
|
|
118
115
|
console.log('WebPlayer.initialize called with config:', config);
|
|
119
116
|
if (config && config.customControls !== undefined) {
|
|
120
117
|
this.useCustomControls = config.customControls;
|
|
121
|
-
console.log('Custom controls set via customControls
|
|
118
|
+
console.log('Custom controls set via customControls:', this.useCustomControls);
|
|
122
119
|
}
|
|
123
120
|
else if (config && config.controls !== undefined) {
|
|
124
121
|
this.useCustomControls = config.controls;
|
|
125
|
-
console.log('Custom controls set via controls
|
|
122
|
+
console.log('Custom controls set via controls prop:', this.useCustomControls);
|
|
126
123
|
}
|
|
127
124
|
if (config && config.settings) {
|
|
128
125
|
console.log('Settings config found:', config.settings);
|
|
@@ -202,6 +199,13 @@ export class WebPlayer extends BasePlayer {
|
|
|
202
199
|
if (this.useCustomControls) {
|
|
203
200
|
this.createCustomControls(videoContainer);
|
|
204
201
|
}
|
|
202
|
+
else {
|
|
203
|
+
this.debugLog('Controls disabled - not creating custom controls UI');
|
|
204
|
+
}
|
|
205
|
+
if (!this.useCustomControls) {
|
|
206
|
+
wrapper.classList.add('controls-disabled');
|
|
207
|
+
this.debugLog('🚫 controls-disabled class applied to player wrapper');
|
|
208
|
+
}
|
|
205
209
|
wrapper.appendChild(videoContainer);
|
|
206
210
|
this.container.innerHTML = '';
|
|
207
211
|
this.container.appendChild(wrapper);
|
|
@@ -856,13 +860,8 @@ export class WebPlayer extends BasePlayer {
|
|
|
856
860
|
if (this.video && metadata.thumbnail) {
|
|
857
861
|
this.video.poster = metadata.thumbnail;
|
|
858
862
|
}
|
|
859
|
-
this.updateMetadataUI();
|
|
860
863
|
await this.createYouTubePlayer(videoId);
|
|
861
|
-
setTimeout(() => {
|
|
862
|
-
this.updateMetadataUI();
|
|
863
|
-
}, 1000);
|
|
864
864
|
this.debugLog('✅ YouTube video loaded successfully');
|
|
865
|
-
this.debugLog('YouTube video title:', metadata.title);
|
|
866
865
|
}
|
|
867
866
|
catch (error) {
|
|
868
867
|
this.debugError('Failed to load YouTube video:', error);
|
|
@@ -879,15 +878,13 @@ export class WebPlayer extends BasePlayer {
|
|
|
879
878
|
}
|
|
880
879
|
const iframeContainer = document.createElement('div');
|
|
881
880
|
iframeContainer.id = `youtube-player-${videoId}`;
|
|
882
|
-
const useNativeControls = this.config.youtubeNativeControls === true;
|
|
883
881
|
iframeContainer.style.cssText = `
|
|
884
882
|
position: absolute;
|
|
885
883
|
top: 0;
|
|
886
884
|
left: 0;
|
|
887
885
|
width: 100%;
|
|
888
886
|
height: 100%;
|
|
889
|
-
z-index:
|
|
890
|
-
pointer-events: ${useNativeControls ? 'auto' : 'none'};
|
|
887
|
+
z-index: 1;
|
|
891
888
|
`;
|
|
892
889
|
const existingPlayer = container.querySelector(`#youtube-player-${videoId}`);
|
|
893
890
|
if (existingPlayer) {
|
|
@@ -903,7 +900,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
903
900
|
width: '100%',
|
|
904
901
|
height: '100%',
|
|
905
902
|
playerVars: {
|
|
906
|
-
controls:
|
|
903
|
+
controls: 0,
|
|
907
904
|
disablekb: 0,
|
|
908
905
|
fs: 0,
|
|
909
906
|
iv_load_policy: 3,
|
|
@@ -920,8 +917,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
920
917
|
onError: (event) => this.onYouTubePlayerError(event)
|
|
921
918
|
}
|
|
922
919
|
});
|
|
923
|
-
this.
|
|
924
|
-
this.debugLog('YouTube player created with controls:', this.currentYouTubeControlsState);
|
|
920
|
+
this.debugLog('YouTube player created');
|
|
925
921
|
}
|
|
926
922
|
async loadYouTubeAPI() {
|
|
927
923
|
return new Promise((resolve) => {
|
|
@@ -961,13 +957,6 @@ export class WebPlayer extends BasePlayer {
|
|
|
961
957
|
if (this.config.muted) {
|
|
962
958
|
this.youtubePlayer.mute();
|
|
963
959
|
}
|
|
964
|
-
this.detectYouTubeLiveStatus();
|
|
965
|
-
this.getYouTubeVideoTitle();
|
|
966
|
-
setTimeout(() => {
|
|
967
|
-
this.updateMetadataUI();
|
|
968
|
-
this.updateControlsVisibility();
|
|
969
|
-
this.ensureUILayering();
|
|
970
|
-
}, 500);
|
|
971
960
|
}
|
|
972
961
|
this.startYouTubeTimeTracking();
|
|
973
962
|
this.emit('onReady');
|
|
@@ -1004,10 +993,6 @@ export class WebPlayer extends BasePlayer {
|
|
|
1004
993
|
case window.YT.PlayerState.CUED:
|
|
1005
994
|
this.state.duration = this.youtubePlayer.getDuration();
|
|
1006
995
|
this.updateYouTubeUI('cued');
|
|
1007
|
-
setTimeout(() => {
|
|
1008
|
-
this.detectYouTubeLiveStatus();
|
|
1009
|
-
this.updateControlsVisibility();
|
|
1010
|
-
}, 500);
|
|
1011
996
|
break;
|
|
1012
997
|
}
|
|
1013
998
|
}
|
|
@@ -1058,323 +1043,6 @@ export class WebPlayer extends BasePlayer {
|
|
|
1058
1043
|
details: { errorCode }
|
|
1059
1044
|
});
|
|
1060
1045
|
}
|
|
1061
|
-
getYouTubeVideoTitle() {
|
|
1062
|
-
if (!this.youtubePlayer || !this.youtubePlayerReady)
|
|
1063
|
-
return;
|
|
1064
|
-
try {
|
|
1065
|
-
const videoData = this.youtubePlayer.getVideoData();
|
|
1066
|
-
if (videoData && videoData.title) {
|
|
1067
|
-
this.debugLog('Got YouTube title from player API:', videoData.title);
|
|
1068
|
-
if (this.source && this.source.metadata) {
|
|
1069
|
-
this.source.metadata.title = videoData.title;
|
|
1070
|
-
}
|
|
1071
|
-
this.updateMetadataUI();
|
|
1072
|
-
}
|
|
1073
|
-
}
|
|
1074
|
-
catch (error) {
|
|
1075
|
-
this.debugWarn('Could not get YouTube video title from API:', error);
|
|
1076
|
-
this.getYouTubeVideoTitleFromOEmbed();
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
detectYouTubeLiveStatus() {
|
|
1080
|
-
if (!this.youtubePlayer || !this.youtubePlayerReady)
|
|
1081
|
-
return;
|
|
1082
|
-
try {
|
|
1083
|
-
const videoData = this.youtubePlayer.getVideoData();
|
|
1084
|
-
this.isYouTubeLive = videoData?.isLive || false;
|
|
1085
|
-
this.useYouTubeNativeControls = this.config.youtubeNativeControls === true;
|
|
1086
|
-
this.debugLog('YouTube Live status:', {
|
|
1087
|
-
isLive: this.isYouTubeLive,
|
|
1088
|
-
useNativeControls: this.useYouTubeNativeControls,
|
|
1089
|
-
videoId: videoData?.video_id
|
|
1090
|
-
});
|
|
1091
|
-
}
|
|
1092
|
-
catch (error) {
|
|
1093
|
-
this.debugWarn('Could not detect YouTube Live status:', error);
|
|
1094
|
-
try {
|
|
1095
|
-
const duration = this.youtubePlayer.getDuration();
|
|
1096
|
-
this.isYouTubeLive = !duration || duration === 0;
|
|
1097
|
-
this.useYouTubeNativeControls = this.config.youtubeNativeControls === true;
|
|
1098
|
-
this.debugLog('YouTube Live detected via duration check:', {
|
|
1099
|
-
duration,
|
|
1100
|
-
isLive: this.isYouTubeLive,
|
|
1101
|
-
useNativeControls: this.useYouTubeNativeControls
|
|
1102
|
-
});
|
|
1103
|
-
}
|
|
1104
|
-
catch (e) {
|
|
1105
|
-
this.debugWarn('Could not check YouTube duration for Live detection:', e);
|
|
1106
|
-
}
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1109
|
-
ensureUILayering() {
|
|
1110
|
-
if (!this.youtubePlayer)
|
|
1111
|
-
return;
|
|
1112
|
-
const videoContainer = this.playerWrapper?.querySelector('.uvf-video-container');
|
|
1113
|
-
if (!videoContainer)
|
|
1114
|
-
return;
|
|
1115
|
-
const uiElements = videoContainer.querySelectorAll('.uvf-top-gradient, .uvf-controls-gradient, .uvf-top-bar, .uvf-center-play-container, .uvf-shortcut-indicator, .uvf-controls-bar');
|
|
1116
|
-
uiElements.forEach(el => {
|
|
1117
|
-
const element = el;
|
|
1118
|
-
element.style.zIndex = '2';
|
|
1119
|
-
element.style.position = 'relative';
|
|
1120
|
-
});
|
|
1121
|
-
this.debugLog('UI layering ensured for YouTube player');
|
|
1122
|
-
}
|
|
1123
|
-
updateControlsVisibility() {
|
|
1124
|
-
const controlsContainer = document.getElementById('uvf-controls');
|
|
1125
|
-
if (!controlsContainer) {
|
|
1126
|
-
this.debugWarn('Controls container not found, looking for .uvf-controls-bar');
|
|
1127
|
-
const controlsBar = this.playerWrapper?.querySelector('.uvf-controls-bar');
|
|
1128
|
-
if (!controlsBar) {
|
|
1129
|
-
this.debugWarn('Controls bar not found either, cannot update controls visibility');
|
|
1130
|
-
return;
|
|
1131
|
-
}
|
|
1132
|
-
const controlsContainerFallback = controlsBar;
|
|
1133
|
-
if (this.youtubePlayer && this.useYouTubeNativeControls) {
|
|
1134
|
-
controlsContainerFallback.style.display = 'none';
|
|
1135
|
-
const videoId = this.source?.metadata?.videoId;
|
|
1136
|
-
if (videoId) {
|
|
1137
|
-
const ytWrapper = this.playerWrapper?.querySelector(`#youtube-player-${videoId}`);
|
|
1138
|
-
if (ytWrapper) {
|
|
1139
|
-
ytWrapper.style.zIndex = '1';
|
|
1140
|
-
ytWrapper.style.pointerEvents = 'auto';
|
|
1141
|
-
ytWrapper.style.position = 'absolute';
|
|
1142
|
-
}
|
|
1143
|
-
}
|
|
1144
|
-
const videoContainer = this.playerWrapper?.querySelector('.uvf-video-container');
|
|
1145
|
-
if (videoContainer) {
|
|
1146
|
-
const allControls = videoContainer.querySelectorAll('.uvf-top-gradient, .uvf-controls-gradient, .uvf-top-bar, .uvf-center-play-container, .uvf-shortcut-indicator');
|
|
1147
|
-
allControls.forEach(el => el.style.display = 'none');
|
|
1148
|
-
}
|
|
1149
|
-
if (this.currentYouTubeControlsState !== true) {
|
|
1150
|
-
this.recreateYouTubePlayerWithNativeControls();
|
|
1151
|
-
this.currentYouTubeControlsState = true;
|
|
1152
|
-
}
|
|
1153
|
-
this.debugLog('✅ YouTube native controls enabled', {
|
|
1154
|
-
isLive: this.isYouTubeLive,
|
|
1155
|
-
reason: this.config.youtubeNativeControls === true ? 'Explicitly enabled in config' : 'Live stream detected'
|
|
1156
|
-
});
|
|
1157
|
-
}
|
|
1158
|
-
else {
|
|
1159
|
-
controlsContainerFallback.style.display = 'flex';
|
|
1160
|
-
controlsContainerFallback.style.zIndex = '2';
|
|
1161
|
-
const videoId = this.source?.metadata?.videoId;
|
|
1162
|
-
if (videoId) {
|
|
1163
|
-
const ytWrapper = this.playerWrapper?.querySelector(`#youtube-player-${videoId}`);
|
|
1164
|
-
if (ytWrapper) {
|
|
1165
|
-
ytWrapper.style.zIndex = '0';
|
|
1166
|
-
ytWrapper.style.pointerEvents = 'none';
|
|
1167
|
-
ytWrapper.style.position = 'absolute';
|
|
1168
|
-
}
|
|
1169
|
-
}
|
|
1170
|
-
const videoContainer = this.playerWrapper?.querySelector('.uvf-video-container');
|
|
1171
|
-
if (videoContainer) {
|
|
1172
|
-
const allControls = videoContainer.querySelectorAll('.uvf-top-gradient, .uvf-controls-gradient, .uvf-top-bar, .uvf-center-play-container, .uvf-shortcut-indicator');
|
|
1173
|
-
allControls.forEach(el => {
|
|
1174
|
-
const elh = el;
|
|
1175
|
-
elh.style.display = '';
|
|
1176
|
-
elh.style.zIndex = '2';
|
|
1177
|
-
elh.style.position = 'relative';
|
|
1178
|
-
});
|
|
1179
|
-
}
|
|
1180
|
-
if (this.currentYouTubeControlsState !== false) {
|
|
1181
|
-
this.recreateYouTubePlayerWithoutNativeControls();
|
|
1182
|
-
this.currentYouTubeControlsState = false;
|
|
1183
|
-
}
|
|
1184
|
-
this.debugLog('✅ Custom controls enabled for YouTube video');
|
|
1185
|
-
}
|
|
1186
|
-
return;
|
|
1187
|
-
}
|
|
1188
|
-
if (this.youtubePlayer && this.useYouTubeNativeControls) {
|
|
1189
|
-
controlsContainer.style.display = 'none';
|
|
1190
|
-
const videoId = this.source?.metadata?.videoId;
|
|
1191
|
-
if (videoId) {
|
|
1192
|
-
const ytWrapper = this.playerWrapper?.querySelector(`#youtube-player-${videoId}`);
|
|
1193
|
-
if (ytWrapper) {
|
|
1194
|
-
ytWrapper.style.zIndex = '1';
|
|
1195
|
-
ytWrapper.style.pointerEvents = 'auto';
|
|
1196
|
-
ytWrapper.style.position = 'absolute';
|
|
1197
|
-
}
|
|
1198
|
-
}
|
|
1199
|
-
if (this.currentYouTubeControlsState !== true) {
|
|
1200
|
-
this.recreateYouTubePlayerWithNativeControls();
|
|
1201
|
-
this.currentYouTubeControlsState = true;
|
|
1202
|
-
}
|
|
1203
|
-
this.debugLog('✅ YouTube native controls enabled', {
|
|
1204
|
-
isLive: this.isYouTubeLive,
|
|
1205
|
-
reason: this.config.youtubeNativeControls === true ? 'Explicitly enabled in config' : 'Live stream detected'
|
|
1206
|
-
});
|
|
1207
|
-
}
|
|
1208
|
-
else {
|
|
1209
|
-
controlsContainer.style.display = 'flex';
|
|
1210
|
-
controlsContainer.style.zIndex = '2';
|
|
1211
|
-
controlsContainer.style.position = 'relative';
|
|
1212
|
-
const videoId = this.source?.metadata?.videoId;
|
|
1213
|
-
if (videoId) {
|
|
1214
|
-
const ytWrapper = this.playerWrapper?.querySelector(`#youtube-player-${videoId}`);
|
|
1215
|
-
if (ytWrapper) {
|
|
1216
|
-
ytWrapper.style.zIndex = '0';
|
|
1217
|
-
ytWrapper.style.pointerEvents = 'none';
|
|
1218
|
-
ytWrapper.style.position = 'absolute';
|
|
1219
|
-
}
|
|
1220
|
-
}
|
|
1221
|
-
const videoContainer = this.playerWrapper?.querySelector('.uvf-video-container');
|
|
1222
|
-
if (videoContainer) {
|
|
1223
|
-
const allControls = videoContainer.querySelectorAll('.uvf-top-gradient, .uvf-controls-gradient, .uvf-top-bar, .uvf-center-play-container, .uvf-shortcut-indicator');
|
|
1224
|
-
allControls.forEach(el => {
|
|
1225
|
-
const elh = el;
|
|
1226
|
-
elh.style.zIndex = '2';
|
|
1227
|
-
elh.style.position = 'relative';
|
|
1228
|
-
});
|
|
1229
|
-
}
|
|
1230
|
-
if (this.currentYouTubeControlsState !== false) {
|
|
1231
|
-
this.recreateYouTubePlayerWithoutNativeControls();
|
|
1232
|
-
this.currentYouTubeControlsState = false;
|
|
1233
|
-
}
|
|
1234
|
-
this.debugLog('✅ Custom controls enabled for YouTube video');
|
|
1235
|
-
}
|
|
1236
|
-
}
|
|
1237
|
-
recreateYouTubePlayerWithNativeControls() {
|
|
1238
|
-
if (!this.source?.metadata?.videoId)
|
|
1239
|
-
return;
|
|
1240
|
-
const videoId = this.source.metadata.videoId;
|
|
1241
|
-
const currentTime = this.youtubePlayer?.getCurrentTime() || 0;
|
|
1242
|
-
const container = this.playerWrapper || this.video?.parentElement;
|
|
1243
|
-
if (!container)
|
|
1244
|
-
return;
|
|
1245
|
-
if (this.youtubePlayer) {
|
|
1246
|
-
this.youtubePlayer.destroy();
|
|
1247
|
-
}
|
|
1248
|
-
const existingContainer = container.querySelector(`#youtube-player-${videoId}`);
|
|
1249
|
-
if (existingContainer) {
|
|
1250
|
-
existingContainer.remove();
|
|
1251
|
-
}
|
|
1252
|
-
const iframeContainer = document.createElement('div');
|
|
1253
|
-
iframeContainer.id = `youtube-player-${videoId}`;
|
|
1254
|
-
iframeContainer.style.cssText = `
|
|
1255
|
-
position: absolute;
|
|
1256
|
-
top: 0;
|
|
1257
|
-
left: 0;
|
|
1258
|
-
width: 100%;
|
|
1259
|
-
height: 100%;
|
|
1260
|
-
z-index: 1;
|
|
1261
|
-
`;
|
|
1262
|
-
container.appendChild(iframeContainer);
|
|
1263
|
-
this.youtubePlayer = new window.YT.Player(iframeContainer.id, {
|
|
1264
|
-
videoId: videoId,
|
|
1265
|
-
width: '100%',
|
|
1266
|
-
height: '100%',
|
|
1267
|
-
playerVars: {
|
|
1268
|
-
autoplay: this.config.autoPlay ? 1 : 0,
|
|
1269
|
-
controls: 1,
|
|
1270
|
-
modestbranding: 1,
|
|
1271
|
-
rel: 0,
|
|
1272
|
-
showinfo: 0,
|
|
1273
|
-
iv_load_policy: 3,
|
|
1274
|
-
playsinline: 1,
|
|
1275
|
-
start: Math.floor(currentTime)
|
|
1276
|
-
},
|
|
1277
|
-
events: {
|
|
1278
|
-
onReady: () => {
|
|
1279
|
-
this.youtubePlayerReady = true;
|
|
1280
|
-
this.debugLog('YouTube player with native controls ready');
|
|
1281
|
-
this.emit('onReady');
|
|
1282
|
-
},
|
|
1283
|
-
onStateChange: (event) => this.onYouTubePlayerStateChange(event),
|
|
1284
|
-
onError: (event) => this.onYouTubePlayerError(event)
|
|
1285
|
-
}
|
|
1286
|
-
});
|
|
1287
|
-
}
|
|
1288
|
-
recreateYouTubePlayerWithoutNativeControls() {
|
|
1289
|
-
if (!this.source?.metadata?.videoId)
|
|
1290
|
-
return;
|
|
1291
|
-
const videoId = this.source.metadata.videoId;
|
|
1292
|
-
const currentTime = this.youtubePlayer?.getCurrentTime() || 0;
|
|
1293
|
-
const container = this.playerWrapper || this.video?.parentElement;
|
|
1294
|
-
if (!container)
|
|
1295
|
-
return;
|
|
1296
|
-
if (this.youtubePlayer) {
|
|
1297
|
-
this.youtubePlayer.destroy();
|
|
1298
|
-
}
|
|
1299
|
-
const existingContainer = container.querySelector(`#youtube-player-${videoId}`);
|
|
1300
|
-
if (existingContainer) {
|
|
1301
|
-
existingContainer.remove();
|
|
1302
|
-
}
|
|
1303
|
-
const iframeContainer = document.createElement('div');
|
|
1304
|
-
iframeContainer.id = `youtube-player-${videoId}`;
|
|
1305
|
-
iframeContainer.style.cssText = `
|
|
1306
|
-
position: absolute;
|
|
1307
|
-
top: 0;
|
|
1308
|
-
left: 0;
|
|
1309
|
-
width: 100%;
|
|
1310
|
-
height: 100%;
|
|
1311
|
-
z-index: 0;
|
|
1312
|
-
pointer-events: none;
|
|
1313
|
-
`;
|
|
1314
|
-
container.appendChild(iframeContainer);
|
|
1315
|
-
this.youtubePlayer = new window.YT.Player(iframeContainer.id, {
|
|
1316
|
-
videoId: videoId,
|
|
1317
|
-
width: '100%',
|
|
1318
|
-
height: '100%',
|
|
1319
|
-
playerVars: {
|
|
1320
|
-
autoplay: this.config.autoPlay ? 1 : 0,
|
|
1321
|
-
controls: 0,
|
|
1322
|
-
disablekb: 0,
|
|
1323
|
-
fs: 0,
|
|
1324
|
-
iv_load_policy: 3,
|
|
1325
|
-
modestbranding: 1,
|
|
1326
|
-
rel: 0,
|
|
1327
|
-
showinfo: 0,
|
|
1328
|
-
playsinline: 1,
|
|
1329
|
-
start: Math.floor(currentTime)
|
|
1330
|
-
},
|
|
1331
|
-
events: {
|
|
1332
|
-
onReady: () => {
|
|
1333
|
-
this.youtubePlayerReady = true;
|
|
1334
|
-
this.debugLog('YouTube player without native controls ready');
|
|
1335
|
-
this.emit('onReady');
|
|
1336
|
-
},
|
|
1337
|
-
onStateChange: (event) => this.onYouTubePlayerStateChange(event),
|
|
1338
|
-
onError: (event) => this.onYouTubePlayerError(event)
|
|
1339
|
-
}
|
|
1340
|
-
});
|
|
1341
|
-
}
|
|
1342
|
-
toggleYouTubeControls(useNative = !this.useYouTubeNativeControls) {
|
|
1343
|
-
if (!this.youtubePlayer) {
|
|
1344
|
-
this.debugWarn('Cannot toggle YouTube controls - no YouTube player active');
|
|
1345
|
-
return;
|
|
1346
|
-
}
|
|
1347
|
-
this.useYouTubeNativeControls = useNative;
|
|
1348
|
-
this.config.youtubeNativeControls = useNative;
|
|
1349
|
-
this.updateControlsVisibility();
|
|
1350
|
-
this.debugLog('YouTube controls toggled:', {
|
|
1351
|
-
useNative: this.useYouTubeNativeControls,
|
|
1352
|
-
isLive: this.isYouTubeLive
|
|
1353
|
-
});
|
|
1354
|
-
this.showNotification(`YouTube Controls: ${this.useYouTubeNativeControls ? 'Native' : 'Custom'}`);
|
|
1355
|
-
}
|
|
1356
|
-
async getYouTubeVideoTitleFromOEmbed() {
|
|
1357
|
-
if (!this.source?.metadata?.videoId)
|
|
1358
|
-
return;
|
|
1359
|
-
try {
|
|
1360
|
-
const videoId = this.source.metadata.videoId;
|
|
1361
|
-
const oembedUrl = `https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v=${videoId}&format=json`;
|
|
1362
|
-
const response = await fetch(oembedUrl);
|
|
1363
|
-
if (response.ok) {
|
|
1364
|
-
const data = await response.json();
|
|
1365
|
-
if (data.title) {
|
|
1366
|
-
this.debugLog('Got YouTube title from oembed API:', data.title);
|
|
1367
|
-
if (this.source && this.source.metadata) {
|
|
1368
|
-
this.source.metadata.title = data.title;
|
|
1369
|
-
}
|
|
1370
|
-
this.updateMetadataUI();
|
|
1371
|
-
}
|
|
1372
|
-
}
|
|
1373
|
-
}
|
|
1374
|
-
catch (error) {
|
|
1375
|
-
this.debugWarn('Could not get YouTube title from oembed API:', error);
|
|
1376
|
-
}
|
|
1377
|
-
}
|
|
1378
1046
|
startYouTubeTimeTracking() {
|
|
1379
1047
|
if (this.youtubeTimeTrackingInterval) {
|
|
1380
1048
|
clearInterval(this.youtubeTimeTrackingInterval);
|
|
@@ -1408,18 +1076,12 @@ export class WebPlayer extends BasePlayer {
|
|
|
1408
1076
|
const progressHandle = document.getElementById('uvf-progress-handle');
|
|
1409
1077
|
if (progressHandle && !this.isDragging) {
|
|
1410
1078
|
progressHandle.style.left = percent + '%';
|
|
1411
|
-
progressHandle.classList.remove('dragging');
|
|
1412
1079
|
}
|
|
1413
1080
|
const progressBuffered = document.getElementById('uvf-progress-buffered');
|
|
1414
1081
|
if (progressBuffered) {
|
|
1415
1082
|
progressBuffered.style.width = buffered + '%';
|
|
1416
1083
|
}
|
|
1417
|
-
|
|
1418
|
-
if (timeDisplay) {
|
|
1419
|
-
const currentTimeStr = this.formatTime(currentTime);
|
|
1420
|
-
const durationStr = this.formatTime(duration);
|
|
1421
|
-
timeDisplay.textContent = `${currentTimeStr} / ${durationStr}`;
|
|
1422
|
-
}
|
|
1084
|
+
this.updateTimeDisplay();
|
|
1423
1085
|
}
|
|
1424
1086
|
loadScript(src) {
|
|
1425
1087
|
return new Promise((resolve, reject) => {
|
|
@@ -1754,27 +1416,12 @@ export class WebPlayer extends BasePlayer {
|
|
|
1754
1416
|
updateTimeTooltip(e) {
|
|
1755
1417
|
const progressBar = document.getElementById('uvf-progress-bar');
|
|
1756
1418
|
const tooltip = document.getElementById('uvf-time-tooltip');
|
|
1757
|
-
if (!progressBar || !tooltip)
|
|
1758
|
-
return;
|
|
1759
|
-
let duration = 0;
|
|
1760
|
-
if (this.youtubePlayer && this.youtubePlayerReady) {
|
|
1761
|
-
try {
|
|
1762
|
-
duration = this.youtubePlayer.getDuration() || 0;
|
|
1763
|
-
}
|
|
1764
|
-
catch (error) {
|
|
1765
|
-
this.debugWarn('Error getting YouTube duration for tooltip:', error);
|
|
1766
|
-
return;
|
|
1767
|
-
}
|
|
1768
|
-
}
|
|
1769
|
-
else if (this.video) {
|
|
1770
|
-
duration = this.video.duration || 0;
|
|
1771
|
-
}
|
|
1772
|
-
if (!duration || !isFinite(duration))
|
|
1419
|
+
if (!progressBar || !tooltip || !this.video)
|
|
1773
1420
|
return;
|
|
1774
1421
|
const rect = progressBar.getBoundingClientRect();
|
|
1775
1422
|
const x = Math.max(0, Math.min(e.clientX - rect.left, rect.width));
|
|
1776
1423
|
const percent = (x / rect.width);
|
|
1777
|
-
const time = percent * duration;
|
|
1424
|
+
const time = percent * this.video.duration;
|
|
1778
1425
|
tooltip.textContent = this.formatTime(time);
|
|
1779
1426
|
tooltip.style.left = `${x}px`;
|
|
1780
1427
|
tooltip.classList.add('visible');
|
|
@@ -4183,29 +3830,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
4183
3830
|
}
|
|
4184
3831
|
|
|
4185
3832
|
.uvf-accordion-item.expanded .uvf-accordion-content {
|
|
4186
|
-
max-height:
|
|
4187
|
-
overflow-y: auto;
|
|
4188
|
-
-webkit-overflow-scrolling: touch;
|
|
4189
|
-
}
|
|
4190
|
-
|
|
4191
|
-
/* Special handling for quality accordion with many options */
|
|
4192
|
-
.uvf-accordion-item.expanded .uvf-accordion-content[data-section="quality"] {
|
|
4193
|
-
max-height: 400px;
|
|
4194
|
-
}
|
|
4195
|
-
|
|
4196
|
-
/* Scrollbar styling for accordion content */
|
|
4197
|
-
.uvf-accordion-content::-webkit-scrollbar {
|
|
4198
|
-
width: 4px;
|
|
4199
|
-
}
|
|
4200
|
-
.uvf-accordion-content::-webkit-scrollbar-track {
|
|
4201
|
-
background: transparent;
|
|
4202
|
-
}
|
|
4203
|
-
.uvf-accordion-content::-webkit-scrollbar-thumb {
|
|
4204
|
-
background: rgba(255,255,255,0.3);
|
|
4205
|
-
border-radius: 2px;
|
|
4206
|
-
}
|
|
4207
|
-
.uvf-accordion-content::-webkit-scrollbar-thumb:hover {
|
|
4208
|
-
background: rgba(255,255,255,0.5);
|
|
3833
|
+
max-height: 250px;
|
|
4209
3834
|
}
|
|
4210
3835
|
|
|
4211
3836
|
/* Settings options within accordion */
|
|
@@ -5933,6 +5558,25 @@ export class WebPlayer extends BasePlayer {
|
|
|
5933
5558
|
}
|
|
5934
5559
|
}
|
|
5935
5560
|
|
|
5561
|
+
/* Controls visibility */
|
|
5562
|
+
.uvf-controls-bar {
|
|
5563
|
+
display: flex !important;
|
|
5564
|
+
}
|
|
5565
|
+
|
|
5566
|
+
.uvf-top-bar {
|
|
5567
|
+
display: flex !important;
|
|
5568
|
+
}
|
|
5569
|
+
|
|
5570
|
+
/* Hide all controls if controls prop is false */
|
|
5571
|
+
.uvf-player-wrapper.controls-disabled .uvf-controls-bar,
|
|
5572
|
+
.uvf-player-wrapper.controls-disabled .uvf-top-bar,
|
|
5573
|
+
.uvf-player-wrapper.controls-disabled .uvf-top-gradient,
|
|
5574
|
+
.uvf-player-wrapper.controls-disabled .uvf-controls-gradient {
|
|
5575
|
+
display: none !important;
|
|
5576
|
+
visibility: hidden !important;
|
|
5577
|
+
pointer-events: none !important;
|
|
5578
|
+
}
|
|
5579
|
+
|
|
5936
5580
|
/* Hide YouTube UI elements */
|
|
5937
5581
|
iframe[src*="youtube.com"] {
|
|
5938
5582
|
pointer-events: auto !important;
|
|
@@ -6271,7 +5915,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
6271
5915
|
const qualityBadge = document.createElement('div');
|
|
6272
5916
|
qualityBadge.className = 'uvf-quality-badge';
|
|
6273
5917
|
qualityBadge.id = 'uvf-quality-badge';
|
|
6274
|
-
qualityBadge.textContent = '
|
|
5918
|
+
qualityBadge.textContent = 'HD';
|
|
6275
5919
|
rightControls.appendChild(qualityBadge);
|
|
6276
5920
|
this.debugLog('Settings config check:', this.settingsConfig);
|
|
6277
5921
|
this.debugLog('Settings enabled:', this.settingsConfig.enabled);
|
|
@@ -7385,27 +7029,11 @@ export class WebPlayer extends BasePlayer {
|
|
|
7385
7029
|
const progressBar = document.querySelector('.uvf-progress-bar');
|
|
7386
7030
|
const progressFilled = document.getElementById('uvf-progress-filled');
|
|
7387
7031
|
const progressHandle = document.getElementById('uvf-progress-handle');
|
|
7388
|
-
if (!progressBar)
|
|
7389
|
-
return;
|
|
7390
|
-
let duration = 0;
|
|
7391
|
-
if (this.youtubePlayer && this.youtubePlayerReady) {
|
|
7392
|
-
try {
|
|
7393
|
-
duration = this.youtubePlayer.getDuration() || 0;
|
|
7394
|
-
}
|
|
7395
|
-
catch (error) {
|
|
7396
|
-
this.debugWarn('Error getting YouTube duration for seeking:', error);
|
|
7397
|
-
return;
|
|
7398
|
-
}
|
|
7399
|
-
}
|
|
7400
|
-
else if (this.video) {
|
|
7401
|
-
duration = this.video.duration;
|
|
7402
|
-
}
|
|
7403
|
-
else {
|
|
7404
|
-
this.debugWarn('No video source available for seeking');
|
|
7032
|
+
if (!progressBar || !this.video)
|
|
7405
7033
|
return;
|
|
7406
|
-
|
|
7034
|
+
const duration = this.video.duration;
|
|
7407
7035
|
if (!isFinite(duration) || isNaN(duration) || duration <= 0) {
|
|
7408
|
-
this.debugWarn('Invalid video duration, cannot seek via progress bar
|
|
7036
|
+
this.debugWarn('Invalid video duration, cannot seek via progress bar');
|
|
7409
7037
|
return;
|
|
7410
7038
|
}
|
|
7411
7039
|
const rect = progressBar.getBoundingClientRect();
|
|
@@ -7416,18 +7044,19 @@ export class WebPlayer extends BasePlayer {
|
|
|
7416
7044
|
this.debugWarn('Calculated seek time is invalid:', time);
|
|
7417
7045
|
return;
|
|
7418
7046
|
}
|
|
7419
|
-
|
|
7420
|
-
if (progressFilled && !this.isDragging) {
|
|
7047
|
+
if (progressFilled) {
|
|
7421
7048
|
progressFilled.style.width = percent + '%';
|
|
7422
7049
|
}
|
|
7423
|
-
if (progressHandle
|
|
7050
|
+
if (progressHandle) {
|
|
7424
7051
|
progressHandle.style.left = percent + '%';
|
|
7425
|
-
|
|
7052
|
+
if (this.isDragging) {
|
|
7053
|
+
progressHandle.classList.add('dragging');
|
|
7054
|
+
}
|
|
7055
|
+
else {
|
|
7056
|
+
progressHandle.classList.remove('dragging');
|
|
7057
|
+
}
|
|
7426
7058
|
}
|
|
7427
7059
|
this.seek(time);
|
|
7428
|
-
if (this.youtubePlayer && this.youtubePlayerReady) {
|
|
7429
|
-
this.emit('onSeeking');
|
|
7430
|
-
}
|
|
7431
7060
|
}
|
|
7432
7061
|
formatTime(seconds) {
|
|
7433
7062
|
if (!seconds || isNaN(seconds))
|