unified-video-framework 1.4.262 → 1.4.263
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 +20 -421
- 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 +46 -569
- 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,7 @@ 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
|
|
122
|
-
}
|
|
123
|
-
else if (config && config.controls !== undefined) {
|
|
124
|
-
this.useCustomControls = config.controls;
|
|
125
|
-
console.log('Custom controls set via controls to:', this.useCustomControls);
|
|
118
|
+
console.log('Custom controls set to:', this.useCustomControls);
|
|
126
119
|
}
|
|
127
120
|
if (config && config.settings) {
|
|
128
121
|
console.log('Settings config found:', config.settings);
|
|
@@ -856,13 +849,8 @@ export class WebPlayer extends BasePlayer {
|
|
|
856
849
|
if (this.video && metadata.thumbnail) {
|
|
857
850
|
this.video.poster = metadata.thumbnail;
|
|
858
851
|
}
|
|
859
|
-
this.updateMetadataUI();
|
|
860
852
|
await this.createYouTubePlayer(videoId);
|
|
861
|
-
setTimeout(() => {
|
|
862
|
-
this.updateMetadataUI();
|
|
863
|
-
}, 1000);
|
|
864
853
|
this.debugLog('✅ YouTube video loaded successfully');
|
|
865
|
-
this.debugLog('YouTube video title:', metadata.title);
|
|
866
854
|
}
|
|
867
855
|
catch (error) {
|
|
868
856
|
this.debugError('Failed to load YouTube video:', error);
|
|
@@ -879,15 +867,13 @@ export class WebPlayer extends BasePlayer {
|
|
|
879
867
|
}
|
|
880
868
|
const iframeContainer = document.createElement('div');
|
|
881
869
|
iframeContainer.id = `youtube-player-${videoId}`;
|
|
882
|
-
const useNativeControls = this.config.youtubeNativeControls === true;
|
|
883
870
|
iframeContainer.style.cssText = `
|
|
884
871
|
position: absolute;
|
|
885
872
|
top: 0;
|
|
886
873
|
left: 0;
|
|
887
874
|
width: 100%;
|
|
888
875
|
height: 100%;
|
|
889
|
-
z-index:
|
|
890
|
-
pointer-events: ${useNativeControls ? 'auto' : 'none'};
|
|
876
|
+
z-index: 1;
|
|
891
877
|
`;
|
|
892
878
|
const existingPlayer = container.querySelector(`#youtube-player-${videoId}`);
|
|
893
879
|
if (existingPlayer) {
|
|
@@ -903,7 +889,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
903
889
|
width: '100%',
|
|
904
890
|
height: '100%',
|
|
905
891
|
playerVars: {
|
|
906
|
-
controls:
|
|
892
|
+
controls: 0,
|
|
907
893
|
disablekb: 0,
|
|
908
894
|
fs: 0,
|
|
909
895
|
iv_load_policy: 3,
|
|
@@ -920,8 +906,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
920
906
|
onError: (event) => this.onYouTubePlayerError(event)
|
|
921
907
|
}
|
|
922
908
|
});
|
|
923
|
-
this.
|
|
924
|
-
this.debugLog('YouTube player created with controls:', this.currentYouTubeControlsState);
|
|
909
|
+
this.debugLog('YouTube player created');
|
|
925
910
|
}
|
|
926
911
|
async loadYouTubeAPI() {
|
|
927
912
|
return new Promise((resolve) => {
|
|
@@ -961,13 +946,6 @@ export class WebPlayer extends BasePlayer {
|
|
|
961
946
|
if (this.config.muted) {
|
|
962
947
|
this.youtubePlayer.mute();
|
|
963
948
|
}
|
|
964
|
-
this.detectYouTubeLiveStatus();
|
|
965
|
-
this.getYouTubeVideoTitle();
|
|
966
|
-
setTimeout(() => {
|
|
967
|
-
this.updateMetadataUI();
|
|
968
|
-
this.updateControlsVisibility();
|
|
969
|
-
this.ensureUILayering();
|
|
970
|
-
}, 500);
|
|
971
949
|
}
|
|
972
950
|
this.startYouTubeTimeTracking();
|
|
973
951
|
this.emit('onReady');
|
|
@@ -1004,10 +982,6 @@ export class WebPlayer extends BasePlayer {
|
|
|
1004
982
|
case window.YT.PlayerState.CUED:
|
|
1005
983
|
this.state.duration = this.youtubePlayer.getDuration();
|
|
1006
984
|
this.updateYouTubeUI('cued');
|
|
1007
|
-
setTimeout(() => {
|
|
1008
|
-
this.detectYouTubeLiveStatus();
|
|
1009
|
-
this.updateControlsVisibility();
|
|
1010
|
-
}, 500);
|
|
1011
985
|
break;
|
|
1012
986
|
}
|
|
1013
987
|
}
|
|
@@ -1058,323 +1032,6 @@ export class WebPlayer extends BasePlayer {
|
|
|
1058
1032
|
details: { errorCode }
|
|
1059
1033
|
});
|
|
1060
1034
|
}
|
|
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
1035
|
startYouTubeTimeTracking() {
|
|
1379
1036
|
if (this.youtubeTimeTrackingInterval) {
|
|
1380
1037
|
clearInterval(this.youtubeTimeTrackingInterval);
|
|
@@ -1408,18 +1065,12 @@ export class WebPlayer extends BasePlayer {
|
|
|
1408
1065
|
const progressHandle = document.getElementById('uvf-progress-handle');
|
|
1409
1066
|
if (progressHandle && !this.isDragging) {
|
|
1410
1067
|
progressHandle.style.left = percent + '%';
|
|
1411
|
-
progressHandle.classList.remove('dragging');
|
|
1412
1068
|
}
|
|
1413
1069
|
const progressBuffered = document.getElementById('uvf-progress-buffered');
|
|
1414
1070
|
if (progressBuffered) {
|
|
1415
1071
|
progressBuffered.style.width = buffered + '%';
|
|
1416
1072
|
}
|
|
1417
|
-
|
|
1418
|
-
if (timeDisplay) {
|
|
1419
|
-
const currentTimeStr = this.formatTime(currentTime);
|
|
1420
|
-
const durationStr = this.formatTime(duration);
|
|
1421
|
-
timeDisplay.textContent = `${currentTimeStr} / ${durationStr}`;
|
|
1422
|
-
}
|
|
1073
|
+
this.updateTimeDisplay();
|
|
1423
1074
|
}
|
|
1424
1075
|
loadScript(src) {
|
|
1425
1076
|
return new Promise((resolve, reject) => {
|
|
@@ -1754,27 +1405,12 @@ export class WebPlayer extends BasePlayer {
|
|
|
1754
1405
|
updateTimeTooltip(e) {
|
|
1755
1406
|
const progressBar = document.getElementById('uvf-progress-bar');
|
|
1756
1407
|
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))
|
|
1408
|
+
if (!progressBar || !tooltip || !this.video)
|
|
1773
1409
|
return;
|
|
1774
1410
|
const rect = progressBar.getBoundingClientRect();
|
|
1775
1411
|
const x = Math.max(0, Math.min(e.clientX - rect.left, rect.width));
|
|
1776
1412
|
const percent = (x / rect.width);
|
|
1777
|
-
const time = percent * duration;
|
|
1413
|
+
const time = percent * this.video.duration;
|
|
1778
1414
|
tooltip.textContent = this.formatTime(time);
|
|
1779
1415
|
tooltip.style.left = `${x}px`;
|
|
1780
1416
|
tooltip.classList.add('visible');
|
|
@@ -4183,29 +3819,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
4183
3819
|
}
|
|
4184
3820
|
|
|
4185
3821
|
.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);
|
|
3822
|
+
max-height: 250px;
|
|
4209
3823
|
}
|
|
4210
3824
|
|
|
4211
3825
|
/* Settings options within accordion */
|
|
@@ -6271,7 +5885,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
6271
5885
|
const qualityBadge = document.createElement('div');
|
|
6272
5886
|
qualityBadge.className = 'uvf-quality-badge';
|
|
6273
5887
|
qualityBadge.id = 'uvf-quality-badge';
|
|
6274
|
-
qualityBadge.textContent = '
|
|
5888
|
+
qualityBadge.textContent = 'HD';
|
|
6275
5889
|
rightControls.appendChild(qualityBadge);
|
|
6276
5890
|
this.debugLog('Settings config check:', this.settingsConfig);
|
|
6277
5891
|
this.debugLog('Settings enabled:', this.settingsConfig.enabled);
|
|
@@ -7385,27 +6999,11 @@ export class WebPlayer extends BasePlayer {
|
|
|
7385
6999
|
const progressBar = document.querySelector('.uvf-progress-bar');
|
|
7386
7000
|
const progressFilled = document.getElementById('uvf-progress-filled');
|
|
7387
7001
|
const progressHandle = document.getElementById('uvf-progress-handle');
|
|
7388
|
-
if (!progressBar)
|
|
7002
|
+
if (!progressBar || !this.video)
|
|
7389
7003
|
return;
|
|
7390
|
-
|
|
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');
|
|
7405
|
-
return;
|
|
7406
|
-
}
|
|
7004
|
+
const duration = this.video.duration;
|
|
7407
7005
|
if (!isFinite(duration) || isNaN(duration) || duration <= 0) {
|
|
7408
|
-
this.debugWarn('Invalid video duration, cannot seek via progress bar
|
|
7006
|
+
this.debugWarn('Invalid video duration, cannot seek via progress bar');
|
|
7409
7007
|
return;
|
|
7410
7008
|
}
|
|
7411
7009
|
const rect = progressBar.getBoundingClientRect();
|
|
@@ -7416,18 +7014,19 @@ export class WebPlayer extends BasePlayer {
|
|
|
7416
7014
|
this.debugWarn('Calculated seek time is invalid:', time);
|
|
7417
7015
|
return;
|
|
7418
7016
|
}
|
|
7419
|
-
|
|
7420
|
-
if (progressFilled && !this.isDragging) {
|
|
7017
|
+
if (progressFilled) {
|
|
7421
7018
|
progressFilled.style.width = percent + '%';
|
|
7422
7019
|
}
|
|
7423
|
-
if (progressHandle
|
|
7020
|
+
if (progressHandle) {
|
|
7424
7021
|
progressHandle.style.left = percent + '%';
|
|
7425
|
-
|
|
7022
|
+
if (this.isDragging) {
|
|
7023
|
+
progressHandle.classList.add('dragging');
|
|
7024
|
+
}
|
|
7025
|
+
else {
|
|
7026
|
+
progressHandle.classList.remove('dragging');
|
|
7027
|
+
}
|
|
7426
7028
|
}
|
|
7427
7029
|
this.seek(time);
|
|
7428
|
-
if (this.youtubePlayer && this.youtubePlayerReady) {
|
|
7429
|
-
this.emit('onSeeking');
|
|
7430
|
-
}
|
|
7431
7030
|
}
|
|
7432
7031
|
formatTime(seconds) {
|
|
7433
7032
|
if (!seconds || isNaN(seconds))
|