unified-video-framework 1.4.263 → 1.4.265
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.
|
@@ -179,9 +179,14 @@ export class WebPlayer extends BasePlayer {
|
|
|
179
179
|
console.log('WebPlayer.initialize called with config:', config);
|
|
180
180
|
|
|
181
181
|
// Set useCustomControls based on config before calling parent initialize
|
|
182
|
+
// Priority: customControls > controls (for backward compatibility)
|
|
182
183
|
if (config && config.customControls !== undefined) {
|
|
183
184
|
this.useCustomControls = config.customControls;
|
|
184
|
-
console.log('Custom controls set
|
|
185
|
+
console.log('Custom controls set via customControls:', this.useCustomControls);
|
|
186
|
+
} else if (config && config.controls !== undefined) {
|
|
187
|
+
// Use 'controls' prop if customControls is not defined
|
|
188
|
+
this.useCustomControls = config.controls;
|
|
189
|
+
console.log('Custom controls set via controls prop:', this.useCustomControls);
|
|
185
190
|
}
|
|
186
191
|
|
|
187
192
|
// Configure settings menu options
|
|
@@ -288,9 +293,18 @@ export class WebPlayer extends BasePlayer {
|
|
|
288
293
|
// Create custom controls if enabled
|
|
289
294
|
if (this.useCustomControls) {
|
|
290
295
|
this.createCustomControls(videoContainer);
|
|
296
|
+
} else {
|
|
297
|
+
// Hide controls if disabled
|
|
298
|
+
this.debugLog('Controls disabled - not creating custom controls UI');
|
|
291
299
|
}
|
|
292
300
|
|
|
293
301
|
|
|
302
|
+
// Apply controls-disabled class if controls are disabled
|
|
303
|
+
if (!this.useCustomControls) {
|
|
304
|
+
wrapper.classList.add('controls-disabled');
|
|
305
|
+
this.debugLog('🚫 controls-disabled class applied to player wrapper');
|
|
306
|
+
}
|
|
307
|
+
|
|
294
308
|
// Assemble the player
|
|
295
309
|
wrapper.appendChild(videoContainer);
|
|
296
310
|
|
|
@@ -1234,6 +1248,9 @@ export class WebPlayer extends BasePlayer {
|
|
|
1234
1248
|
this.youtubePlayerReady = true;
|
|
1235
1249
|
this.debugLog('YouTube player ready');
|
|
1236
1250
|
|
|
1251
|
+
// Hide custom controls immediately for YouTube
|
|
1252
|
+
this.hideCustomControls();
|
|
1253
|
+
|
|
1237
1254
|
// Set initial volume
|
|
1238
1255
|
if (this.youtubePlayer) {
|
|
1239
1256
|
const volume = this.config.volume ? this.config.volume * 100 : 100;
|
|
@@ -1242,6 +1259,17 @@ export class WebPlayer extends BasePlayer {
|
|
|
1242
1259
|
if (this.config.muted) {
|
|
1243
1260
|
this.youtubePlayer.mute();
|
|
1244
1261
|
}
|
|
1262
|
+
|
|
1263
|
+
// Detect if YouTube video is Live and handle controls
|
|
1264
|
+
this.detectYouTubeLiveStatus();
|
|
1265
|
+
|
|
1266
|
+
// Try to get video title from YouTube API
|
|
1267
|
+
this.getYouTubeVideoTitle();
|
|
1268
|
+
|
|
1269
|
+
// Update metadata UI after player is ready
|
|
1270
|
+
setTimeout(() => {
|
|
1271
|
+
this.updateMetadataUI();
|
|
1272
|
+
}, 500);
|
|
1245
1273
|
}
|
|
1246
1274
|
|
|
1247
1275
|
// Start time tracking
|
|
@@ -1249,6 +1277,36 @@ export class WebPlayer extends BasePlayer {
|
|
|
1249
1277
|
|
|
1250
1278
|
this.emit('onReady');
|
|
1251
1279
|
}
|
|
1280
|
+
|
|
1281
|
+
/**
|
|
1282
|
+
* Hide custom controls when YouTube is active
|
|
1283
|
+
*/
|
|
1284
|
+
private hideCustomControls(): void {
|
|
1285
|
+
const controlsBar = document.getElementById('uvf-controls');
|
|
1286
|
+
const topBar = document.querySelector('.uvf-top-bar');
|
|
1287
|
+
const topGradient = document.querySelector('.uvf-top-gradient');
|
|
1288
|
+
const controlsGradient = document.querySelector('.uvf-controls-gradient');
|
|
1289
|
+
|
|
1290
|
+
if (controlsBar) {
|
|
1291
|
+
controlsBar.style.display = 'none !important';
|
|
1292
|
+
controlsBar.style.visibility = 'hidden';
|
|
1293
|
+
controlsBar.style.pointerEvents = 'none';
|
|
1294
|
+
}
|
|
1295
|
+
if (topBar) {
|
|
1296
|
+
(topBar as HTMLElement).style.display = 'none';
|
|
1297
|
+
(topBar as HTMLElement).style.visibility = 'hidden';
|
|
1298
|
+
}
|
|
1299
|
+
if (topGradient) {
|
|
1300
|
+
(topGradient as HTMLElement).style.display = 'none';
|
|
1301
|
+
(topGradient as HTMLElement).style.visibility = 'hidden';
|
|
1302
|
+
}
|
|
1303
|
+
if (controlsGradient) {
|
|
1304
|
+
(controlsGradient as HTMLElement).style.display = 'none';
|
|
1305
|
+
(controlsGradient as HTMLElement).style.visibility = 'hidden';
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
this.debugLog('🎬 Custom controls hidden for YouTube player');
|
|
1309
|
+
}
|
|
1252
1310
|
|
|
1253
1311
|
private onYouTubePlayerStateChange(event: any): void {
|
|
1254
1312
|
const state = event.data;
|
|
@@ -1256,10 +1314,10 @@ export class WebPlayer extends BasePlayer {
|
|
|
1256
1314
|
switch (state) {
|
|
1257
1315
|
case window.YT.PlayerState.PLAYING:
|
|
1258
1316
|
this.state.isPlaying = true;
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1317
|
+
this.state.isPaused = false;
|
|
1318
|
+
this.state.isBuffering = false;
|
|
1319
|
+
this.updateYouTubeUI('playing');
|
|
1320
|
+
this.emit('onPlay');
|
|
1263
1321
|
break;
|
|
1264
1322
|
|
|
1265
1323
|
case window.YT.PlayerState.PAUSED:
|
|
@@ -1336,7 +1394,66 @@ export class WebPlayer extends BasePlayer {
|
|
|
1336
1394
|
});
|
|
1337
1395
|
}
|
|
1338
1396
|
|
|
1397
|
+
/**
|
|
1398
|
+
* Get YouTube video title from the player API
|
|
1399
|
+
*/
|
|
1400
|
+
private getYouTubeVideoTitle(): void {
|
|
1401
|
+
if (!this.youtubePlayer || !this.youtubePlayerReady) return;
|
|
1402
|
+
|
|
1403
|
+
try {
|
|
1404
|
+
// Try to get video data from YouTube player
|
|
1405
|
+
const videoData = this.youtubePlayer.getVideoData();
|
|
1406
|
+
if (videoData && videoData.title) {
|
|
1407
|
+
this.debugLog('Got YouTube title from player API:', videoData.title);
|
|
1408
|
+
|
|
1409
|
+
// Update source metadata with the correct title
|
|
1410
|
+
if (this.source && this.source.metadata) {
|
|
1411
|
+
this.source.metadata.title = videoData.title;
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
// Update UI immediately
|
|
1415
|
+
this.updateMetadataUI();
|
|
1416
|
+
}
|
|
1417
|
+
} catch (error) {
|
|
1418
|
+
this.debugWarn('Could not get YouTube video title from API:', error);
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
/**
|
|
1423
|
+
* Detect if YouTube video is Live
|
|
1424
|
+
*/
|
|
1425
|
+
private detectYouTubeLiveStatus(): void {
|
|
1426
|
+
if (!this.youtubePlayer || !this.youtubePlayerReady) return;
|
|
1427
|
+
|
|
1428
|
+
try {
|
|
1429
|
+
const videoData = this.youtubePlayer.getVideoData();
|
|
1430
|
+
this.isYouTubeLive = videoData?.isLive || false;
|
|
1431
|
+
|
|
1432
|
+
this.debugLog('YouTube Live status:', {
|
|
1433
|
+
isLive: this.isYouTubeLive,
|
|
1434
|
+
videoId: videoData?.video_id
|
|
1435
|
+
});
|
|
1436
|
+
|
|
1437
|
+
} catch (error) {
|
|
1438
|
+
this.debugWarn('Could not detect YouTube Live status:', error);
|
|
1439
|
+
// Fallback: check duration - Live videos typically have duration = 0
|
|
1440
|
+
try {
|
|
1441
|
+
const duration = this.youtubePlayer.getDuration();
|
|
1442
|
+
this.isYouTubeLive = !duration || duration === 0;
|
|
1443
|
+
|
|
1444
|
+
this.debugLog('YouTube Live detected via duration check:', {
|
|
1445
|
+
duration,
|
|
1446
|
+
isLive: this.isYouTubeLive
|
|
1447
|
+
});
|
|
1448
|
+
} catch (e) {
|
|
1449
|
+
this.debugWarn('Could not check YouTube duration for Live detection:', e);
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1339
1454
|
private youtubeTimeTrackingInterval: NodeJS.Timeout | null = null;
|
|
1455
|
+
private isYouTubeLive: boolean = false;
|
|
1456
|
+
private useYouTubeNativeControls: boolean = false;
|
|
1340
1457
|
|
|
1341
1458
|
private startYouTubeTimeTracking(): void {
|
|
1342
1459
|
if (this.youtubeTimeTrackingInterval) {
|
|
@@ -6223,6 +6340,25 @@ export class WebPlayer extends BasePlayer {
|
|
|
6223
6340
|
}
|
|
6224
6341
|
}
|
|
6225
6342
|
|
|
6343
|
+
/* Controls visibility */
|
|
6344
|
+
.uvf-controls-bar {
|
|
6345
|
+
display: flex !important;
|
|
6346
|
+
}
|
|
6347
|
+
|
|
6348
|
+
.uvf-top-bar {
|
|
6349
|
+
display: flex !important;
|
|
6350
|
+
}
|
|
6351
|
+
|
|
6352
|
+
/* Hide all controls if controls prop is false */
|
|
6353
|
+
.uvf-player-wrapper.controls-disabled .uvf-controls-bar,
|
|
6354
|
+
.uvf-player-wrapper.controls-disabled .uvf-top-bar,
|
|
6355
|
+
.uvf-player-wrapper.controls-disabled .uvf-top-gradient,
|
|
6356
|
+
.uvf-player-wrapper.controls-disabled .uvf-controls-gradient {
|
|
6357
|
+
display: none !important;
|
|
6358
|
+
visibility: hidden !important;
|
|
6359
|
+
pointer-events: none !important;
|
|
6360
|
+
}
|
|
6361
|
+
|
|
6226
6362
|
/* Hide YouTube UI elements */
|
|
6227
6363
|
iframe[src*="youtube.com"] {
|
|
6228
6364
|
pointer-events: auto !important;
|