unified-video-framework 1.4.261 → 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.
@@ -179,13 +179,9 @@ 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
- // Check both customControls (specific) and controls (standard) options
183
182
  if (config && config.customControls !== undefined) {
184
183
  this.useCustomControls = config.customControls;
185
- console.log('Custom controls set via customControls to:', this.useCustomControls);
186
- } else if (config && config.controls !== undefined) {
187
- this.useCustomControls = config.controls;
188
- console.log('Custom controls set via controls to:', this.useCustomControls);
184
+ console.log('Custom controls set to:', this.useCustomControls);
189
185
  }
190
186
 
191
187
  // Configure settings menu options
@@ -1119,20 +1115,11 @@ export class WebPlayer extends BasePlayer {
1119
1115
  if (this.video && metadata.thumbnail) {
1120
1116
  this.video.poster = metadata.thumbnail;
1121
1117
  }
1122
-
1123
- // Update metadata UI immediately with YouTube title and thumbnail
1124
- this.updateMetadataUI();
1125
1118
 
1126
1119
  // Create YouTube iframe player with custom controls integration
1127
1120
  await this.createYouTubePlayer(videoId);
1128
1121
 
1129
- // Force another metadata update after player creation
1130
- setTimeout(() => {
1131
- this.updateMetadataUI();
1132
- }, 1000);
1133
-
1134
1122
  this.debugLog('✅ YouTube video loaded successfully');
1135
- this.debugLog('YouTube video title:', metadata.title);
1136
1123
  } catch (error) {
1137
1124
  this.debugError('Failed to load YouTube video:', error);
1138
1125
  throw new Error(`YouTube video loading failed: ${error}`);
@@ -1188,7 +1175,7 @@ export class WebPlayer extends BasePlayer {
1188
1175
  width: '100%',
1189
1176
  height: '100%',
1190
1177
  playerVars: {
1191
- controls: this.config.youtubeNativeControls === true ? 1 : 0, // Native controls disabled by default for custom controls
1178
+ controls: 0, // Hide YouTube controls
1192
1179
  disablekb: 0, // Allow keyboard controls
1193
1180
  fs: 0, // Hide fullscreen button
1194
1181
  iv_load_policy: 3, // Hide annotations
@@ -1206,10 +1193,7 @@ export class WebPlayer extends BasePlayer {
1206
1193
  }
1207
1194
  });
1208
1195
 
1209
- // Track the initial controls state
1210
- this.currentYouTubeControlsState = this.config.youtubeNativeControls === true;
1211
-
1212
- this.debugLog('YouTube player created with controls:', this.currentYouTubeControlsState);
1196
+ this.debugLog('YouTube player created');
1213
1197
  }
1214
1198
 
1215
1199
  private async loadYouTubeAPI(): Promise<void> {
@@ -1258,18 +1242,6 @@ export class WebPlayer extends BasePlayer {
1258
1242
  if (this.config.muted) {
1259
1243
  this.youtubePlayer.mute();
1260
1244
  }
1261
-
1262
- // Detect if YouTube video is Live and handle controls
1263
- this.detectYouTubeLiveStatus();
1264
-
1265
- // Try to get video title from YouTube API
1266
- this.getYouTubeVideoTitle();
1267
-
1268
- // Update metadata UI and controls visibility after player is ready
1269
- setTimeout(() => {
1270
- this.updateMetadataUI();
1271
- this.updateControlsVisibility();
1272
- }, 500);
1273
1245
  }
1274
1246
 
1275
1247
  // Start time tracking
@@ -1284,10 +1256,10 @@ export class WebPlayer extends BasePlayer {
1284
1256
  switch (state) {
1285
1257
  case window.YT.PlayerState.PLAYING:
1286
1258
  this.state.isPlaying = true;
1287
- this.state.isPaused = false;
1288
- this.state.isBuffering = false;
1289
- this.updateYouTubeUI('playing');
1290
- this.emit('onPlay');
1259
+ this.state.isPaused = false;
1260
+ this.state.isBuffering = false;
1261
+ this.updateYouTubeUI('playing');
1262
+ this.emit('onPlay');
1291
1263
  break;
1292
1264
 
1293
1265
  case window.YT.PlayerState.PAUSED:
@@ -1298,10 +1270,10 @@ export class WebPlayer extends BasePlayer {
1298
1270
  this.emit('onPause');
1299
1271
  break;
1300
1272
 
1301
- case window.YT.PlayerState.BUFFERING:
1302
- this.state.isBuffering = true;
1303
- this.updateYouTubeUI('buffering');
1304
- this.emit('onBuffering', true);
1273
+ case window.YT.PlayerState.BUFFERING:
1274
+ this.state.isBuffering = true;
1275
+ this.updateYouTubeUI('buffering');
1276
+ this.emit('onBuffering', true);
1305
1277
  break;
1306
1278
 
1307
1279
  case window.YT.PlayerState.ENDED:
@@ -1312,16 +1284,10 @@ export class WebPlayer extends BasePlayer {
1312
1284
  this.emit('onEnded');
1313
1285
  break;
1314
1286
 
1315
- case window.YT.PlayerState.CUED:
1316
- this.state.duration = this.youtubePlayer.getDuration();
1317
- this.updateYouTubeUI('cued');
1318
-
1319
- // Re-check Live status when video is cued
1320
- setTimeout(() => {
1321
- this.detectYouTubeLiveStatus();
1322
- this.updateControlsVisibility();
1323
- }, 500);
1324
- break;
1287
+ case window.YT.PlayerState.CUED:
1288
+ this.state.duration = this.youtubePlayer.getDuration();
1289
+ this.updateYouTubeUI('cued');
1290
+ break;
1325
1291
  }
1326
1292
  }
1327
1293
 
@@ -1370,360 +1336,23 @@ export class WebPlayer extends BasePlayer {
1370
1336
  });
1371
1337
  }
1372
1338
 
1373
- /**
1374
- * Get YouTube video title from the player API
1375
- */
1376
- private getYouTubeVideoTitle(): void {
1377
- if (!this.youtubePlayer || !this.youtubePlayerReady) return;
1378
-
1379
- try {
1380
- // Try to get video data from YouTube player
1381
- const videoData = this.youtubePlayer.getVideoData();
1382
- if (videoData && videoData.title) {
1383
- this.debugLog('Got YouTube title from player API:', videoData.title);
1384
-
1385
- // Update source metadata with the correct title
1386
- if (this.source && this.source.metadata) {
1387
- this.source.metadata.title = videoData.title;
1388
- }
1389
-
1390
- // Update UI immediately
1391
- this.updateMetadataUI();
1392
- }
1393
- } catch (error) {
1394
- this.debugWarn('Could not get YouTube video title from API:', error);
1395
-
1396
- // Fallback: Try to get from oembed API
1397
- this.getYouTubeVideoTitleFromOEmbed();
1398
- }
1399
- }
1400
-
1401
- /**
1402
- * Detect if YouTube video is Live
1403
- */
1404
- private detectYouTubeLiveStatus(): void {
1405
- if (!this.youtubePlayer || !this.youtubePlayerReady) return;
1406
-
1407
- try {
1408
- const videoData = this.youtubePlayer.getVideoData();
1409
- this.isYouTubeLive = videoData?.isLive || false;
1410
-
1411
- // Use custom controls by default, unless youtubeNativeControls is explicitly set to true
1412
- this.useYouTubeNativeControls = this.config.youtubeNativeControls === true;
1413
-
1414
- this.debugLog('YouTube Live status:', {
1415
- isLive: this.isYouTubeLive,
1416
- useNativeControls: this.useYouTubeNativeControls,
1417
- videoId: videoData?.video_id
1418
- });
1419
-
1420
- } catch (error) {
1421
- this.debugWarn('Could not detect YouTube Live status:', error);
1422
- // Fallback: check duration - Live videos typically have duration = 0
1423
- try {
1424
- const duration = this.youtubePlayer.getDuration();
1425
- this.isYouTubeLive = !duration || duration === 0;
1426
- this.useYouTubeNativeControls = this.config.youtubeNativeControls === true;
1427
-
1428
- this.debugLog('YouTube Live detected via duration check:', {
1429
- duration,
1430
- isLive: this.isYouTubeLive,
1431
- useNativeControls: this.useYouTubeNativeControls
1432
- });
1433
- } catch (e) {
1434
- this.debugWarn('Could not check YouTube duration for Live detection:', e);
1435
- }
1436
- }
1437
- }
1438
-
1439
- /**
1440
- * Update controls visibility based on YouTube Live status and config
1441
- */
1442
- private updateControlsVisibility(): void {
1443
- const controlsContainer = document.getElementById('uvf-controls');
1444
- if (!controlsContainer) {
1445
- this.debugWarn('Controls container not found, looking for .uvf-controls-bar');
1446
- const controlsBar = this.playerWrapper?.querySelector('.uvf-controls-bar') as HTMLElement;
1447
- if (!controlsBar) {
1448
- this.debugWarn('Controls bar not found either, cannot update controls visibility');
1449
- return;
1450
- }
1451
- // Use the controls bar as fallback
1452
- const controlsContainerFallback = controlsBar;
1453
-
1454
- if (this.youtubePlayer && this.useYouTubeNativeControls) {
1455
- // Hide custom controls
1456
- controlsContainerFallback.style.display = 'none';
1457
- // Also hide any other control elements
1458
- const videoContainer = this.playerWrapper?.querySelector('.uvf-video-container') as HTMLElement;
1459
- if (videoContainer) {
1460
- const allControls = videoContainer.querySelectorAll('.uvf-top-gradient, .uvf-controls-gradient, .uvf-top-bar, .uvf-center-play-container, .uvf-shortcut-indicator');
1461
- allControls.forEach(el => (el as HTMLElement).style.display = 'none');
1462
- }
1463
-
1464
- // Only recreate YouTube player if it doesn't currently have native controls
1465
- if (this.currentYouTubeControlsState !== true) {
1466
- this.recreateYouTubePlayerWithNativeControls();
1467
- this.currentYouTubeControlsState = true;
1468
- }
1469
-
1470
- this.debugLog('✅ YouTube native controls enabled', {
1471
- isLive: this.isYouTubeLive,
1472
- reason: this.config.youtubeNativeControls === true ? 'Explicitly enabled in config' : 'Live stream detected'
1473
- });
1474
- } else {
1475
- // Show custom controls
1476
- controlsContainerFallback.style.display = 'flex';
1477
- // Also show other control elements
1478
- const videoContainer = this.playerWrapper?.querySelector('.uvf-video-container') as HTMLElement;
1479
- if (videoContainer) {
1480
- const allControls = videoContainer.querySelectorAll('.uvf-top-gradient, .uvf-controls-gradient, .uvf-top-bar, .uvf-center-play-container, .uvf-shortcut-indicator');
1481
- allControls.forEach(el => (el as HTMLElement).style.display = '');
1482
- }
1483
-
1484
- // Only recreate YouTube player if it currently has native controls
1485
- if (this.currentYouTubeControlsState !== false) {
1486
- this.recreateYouTubePlayerWithoutNativeControls();
1487
- this.currentYouTubeControlsState = false;
1488
- }
1489
-
1490
- this.debugLog('✅ Custom controls enabled for YouTube video');
1491
- }
1492
- return;
1493
- }
1494
-
1495
- if (this.youtubePlayer && this.useYouTubeNativeControls) {
1496
- // Hide custom controls and show YouTube native controls
1497
- controlsContainer.style.display = 'none';
1498
-
1499
- // Only recreate YouTube player if it doesn't currently have native controls
1500
- if (this.currentYouTubeControlsState !== true) {
1501
- this.recreateYouTubePlayerWithNativeControls();
1502
- this.currentYouTubeControlsState = true;
1503
- }
1504
-
1505
- this.debugLog('✅ YouTube native controls enabled', {
1506
- isLive: this.isYouTubeLive,
1507
- reason: this.config.youtubeNativeControls === true ? 'Explicitly enabled in config' : 'Live stream detected'
1508
- });
1509
- } else {
1510
- // Show custom controls and ensure YouTube native controls are disabled
1511
- controlsContainer.style.display = 'flex';
1512
-
1513
- // Only recreate YouTube player if it currently has native controls
1514
- if (this.currentYouTubeControlsState !== false) {
1515
- this.recreateYouTubePlayerWithoutNativeControls();
1516
- this.currentYouTubeControlsState = false;
1517
- }
1518
-
1519
- this.debugLog('✅ Custom controls enabled for YouTube video');
1520
- }
1521
- }
1522
-
1523
- /**
1524
- * Recreate YouTube player with native controls enabled
1525
- */
1526
- private recreateYouTubePlayerWithNativeControls(): void {
1527
- if (!this.source?.metadata?.videoId) return;
1528
-
1529
- const videoId = this.source.metadata.videoId;
1530
- const currentTime = this.youtubePlayer?.getCurrentTime() || 0;
1531
-
1532
- // Find the container
1533
- const container = this.playerWrapper || this.video?.parentElement;
1534
- if (!container) return;
1535
-
1536
- // Destroy current player
1537
- if (this.youtubePlayer) {
1538
- this.youtubePlayer.destroy();
1539
- }
1540
-
1541
- // Remove existing iframe container
1542
- const existingContainer = container.querySelector(`#youtube-player-${videoId}`);
1543
- if (existingContainer) {
1544
- existingContainer.remove();
1545
- }
1546
-
1547
- // Create new iframe container
1548
- const iframeContainer = document.createElement('div');
1549
- iframeContainer.id = `youtube-player-${videoId}`;
1550
- iframeContainer.style.cssText = `
1551
- position: absolute;
1552
- top: 0;
1553
- left: 0;
1554
- width: 100%;
1555
- height: 100%;
1556
- z-index: 1;
1557
- `;
1558
- container.appendChild(iframeContainer);
1559
-
1560
- // Create new player with native controls
1561
- this.youtubePlayer = new window.YT.Player(iframeContainer.id, {
1562
- videoId: videoId,
1563
- width: '100%',
1564
- height: '100%',
1565
- playerVars: {
1566
- autoplay: this.config.autoPlay ? 1 : 0,
1567
- controls: 1, // Enable native controls
1568
- modestbranding: 1,
1569
- rel: 0,
1570
- showinfo: 0,
1571
- iv_load_policy: 3,
1572
- playsinline: 1,
1573
- start: Math.floor(currentTime)
1574
- },
1575
- events: {
1576
- onReady: () => {
1577
- this.youtubePlayerReady = true;
1578
- this.debugLog('YouTube player with native controls ready');
1579
- this.emit('onReady');
1580
- },
1581
- onStateChange: (event: any) => this.onYouTubePlayerStateChange(event),
1582
- onError: (event: any) => this.onYouTubePlayerError(event)
1583
- }
1584
- });
1585
- }
1586
-
1587
- /**
1588
- * Recreate YouTube player without native controls enabled
1589
- */
1590
- private recreateYouTubePlayerWithoutNativeControls(): void {
1591
- if (!this.source?.metadata?.videoId) return;
1592
-
1593
- const videoId = this.source.metadata.videoId;
1594
- const currentTime = this.youtubePlayer?.getCurrentTime() || 0;
1595
-
1596
- // Find the container
1597
- const container = this.playerWrapper || this.video?.parentElement;
1598
- if (!container) return;
1599
-
1600
- // Destroy current player
1601
- if (this.youtubePlayer) {
1602
- this.youtubePlayer.destroy();
1603
- }
1604
-
1605
- // Remove existing iframe container
1606
- const existingContainer = container.querySelector(`#youtube-player-${videoId}`);
1607
- if (existingContainer) {
1608
- existingContainer.remove();
1609
- }
1610
-
1611
- // Create new iframe container
1612
- const iframeContainer = document.createElement('div');
1613
- iframeContainer.id = `youtube-player-${videoId}`;
1614
- iframeContainer.style.cssText = `
1615
- position: absolute;
1616
- top: 0;
1617
- left: 0;
1618
- width: 100%;
1619
- height: 100%;
1620
- z-index: 1;
1621
- `;
1622
- container.appendChild(iframeContainer);
1623
-
1624
- // Create new player without native controls
1625
- this.youtubePlayer = new window.YT.Player(iframeContainer.id, {
1626
- videoId: videoId,
1627
- width: '100%',
1628
- height: '100%',
1629
- playerVars: {
1630
- autoplay: this.config.autoPlay ? 1 : 0,
1631
- controls: 0, // Disable native controls
1632
- disablekb: 0,
1633
- fs: 0,
1634
- iv_load_policy: 3,
1635
- modestbranding: 1,
1636
- rel: 0,
1637
- showinfo: 0,
1638
- playsinline: 1,
1639
- start: Math.floor(currentTime)
1640
- },
1641
- events: {
1642
- onReady: () => {
1643
- this.youtubePlayerReady = true;
1644
- this.debugLog('YouTube player without native controls ready');
1645
- this.emit('onReady');
1646
- },
1647
- onStateChange: (event: any) => this.onYouTubePlayerStateChange(event),
1648
- onError: (event: any) => this.onYouTubePlayerError(event)
1649
- }
1650
- });
1651
- }
1652
-
1653
- /**
1654
- * Toggle between native and custom YouTube controls
1655
- */
1656
- public toggleYouTubeControls(useNative: boolean = !this.useYouTubeNativeControls): void {
1657
- if (!this.youtubePlayer) {
1658
- this.debugWarn('Cannot toggle YouTube controls - no YouTube player active');
1659
- return;
1660
- }
1661
-
1662
- this.useYouTubeNativeControls = useNative;
1663
- this.config.youtubeNativeControls = useNative; // Update config
1664
- this.updateControlsVisibility();
1665
-
1666
- this.debugLog('YouTube controls toggled:', {
1667
- useNative: this.useYouTubeNativeControls,
1668
- isLive: this.isYouTubeLive
1669
- });
1670
-
1671
- // Show notification
1672
- this.showNotification(
1673
- `YouTube Controls: ${this.useYouTubeNativeControls ? 'Native' : 'Custom'}`
1674
- );
1675
- }
1676
-
1677
- /**
1678
- * Fallback method to get title from YouTube oembed API
1679
- */
1680
- private async getYouTubeVideoTitleFromOEmbed(): Promise<void> {
1681
- if (!this.source?.metadata?.videoId) return;
1682
-
1683
- try {
1684
- const videoId = this.source.metadata.videoId;
1685
- const oembedUrl = `https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v=${videoId}&format=json`;
1686
-
1687
- const response = await fetch(oembedUrl);
1688
- if (response.ok) {
1689
- const data = await response.json();
1690
- if (data.title) {
1691
- this.debugLog('Got YouTube title from oembed API:', data.title);
1692
-
1693
- // Update source metadata
1694
- if (this.source && this.source.metadata) {
1695
- this.source.metadata.title = data.title;
1696
- }
1697
-
1698
- // Update UI
1699
- this.updateMetadataUI();
1700
- }
1701
- }
1702
- } catch (error) {
1703
- this.debugWarn('Could not get YouTube title from oembed API:', error);
1704
- }
1705
- }
1706
-
1707
1339
  private youtubeTimeTrackingInterval: NodeJS.Timeout | null = null;
1708
- private isYouTubeLive: boolean = false;
1709
- private useYouTubeNativeControls: boolean = false;
1710
- private currentYouTubeControlsState: boolean | null = null; // Track current YouTube player controls state
1711
1340
 
1712
1341
  private startYouTubeTimeTracking(): void {
1713
1342
  if (this.youtubeTimeTrackingInterval) {
1714
1343
  clearInterval(this.youtubeTimeTrackingInterval);
1715
1344
  }
1716
1345
 
1717
- this.youtubeTimeTrackingInterval = setInterval(() => {
1718
- if (this.youtubePlayer && this.youtubePlayerReady) {
1719
- try {
1720
- const currentTime = this.youtubePlayer.getCurrentTime();
1721
- const duration = this.youtubePlayer.getDuration();
1722
- const buffered = this.youtubePlayer.getVideoLoadedFraction() * 100;
1723
-
1724
- this.state.currentTime = currentTime || 0;
1725
- this.state.duration = duration || 0;
1726
- this.state.bufferedPercentage = buffered || 0;
1346
+ this.youtubeTimeTrackingInterval = setInterval(() => {
1347
+ if (this.youtubePlayer && this.youtubePlayerReady) {
1348
+ try {
1349
+ const currentTime = this.youtubePlayer.getCurrentTime();
1350
+ const duration = this.youtubePlayer.getDuration();
1351
+ const buffered = this.youtubePlayer.getVideoLoadedFraction() * 100;
1352
+
1353
+ this.state.currentTime = currentTime || 0;
1354
+ this.state.duration = duration || 0;
1355
+ this.state.bufferedPercentage = buffered || 0;
1727
1356
 
1728
1357
  // Update UI progress bar
1729
1358
  this.updateYouTubeProgressBar(currentTime, duration, buffered);
@@ -1742,18 +1371,16 @@ export class WebPlayer extends BasePlayer {
1742
1371
 
1743
1372
  const percent = (currentTime / duration) * 100;
1744
1373
 
1745
- // Update progress filled (only if not dragging)
1374
+ // Update progress filled
1746
1375
  const progressFilled = document.getElementById('uvf-progress-filled') as HTMLElement;
1747
1376
  if (progressFilled && !this.isDragging) {
1748
1377
  progressFilled.style.width = percent + '%';
1749
1378
  }
1750
1379
 
1751
- // Update progress handle (only if not dragging)
1380
+ // Update progress handle
1752
1381
  const progressHandle = document.getElementById('uvf-progress-handle') as HTMLElement;
1753
1382
  if (progressHandle && !this.isDragging) {
1754
1383
  progressHandle.style.left = percent + '%';
1755
- // Remove dragging class if it was set
1756
- progressHandle.classList.remove('dragging');
1757
1384
  }
1758
1385
 
1759
1386
  // Update buffered progress
@@ -1762,13 +1389,8 @@ export class WebPlayer extends BasePlayer {
1762
1389
  progressBuffered.style.width = buffered + '%';
1763
1390
  }
1764
1391
 
1765
- // Update time display with YouTube-specific times
1766
- const timeDisplay = document.getElementById('uvf-time-display');
1767
- if (timeDisplay) {
1768
- const currentTimeStr = this.formatTime(currentTime);
1769
- const durationStr = this.formatTime(duration);
1770
- timeDisplay.textContent = `${currentTimeStr} / ${durationStr}`;
1771
- }
1392
+ // Update time display
1393
+ this.updateTimeDisplay();
1772
1394
  }
1773
1395
 
1774
1396
 
@@ -2213,27 +1835,12 @@ export class WebPlayer extends BasePlayer {
2213
1835
  private updateTimeTooltip(e: MouseEvent): void {
2214
1836
  const progressBar = document.getElementById('uvf-progress-bar');
2215
1837
  const tooltip = document.getElementById('uvf-time-tooltip');
2216
- if (!progressBar || !tooltip) return;
2217
-
2218
- // Get duration from appropriate source
2219
- let duration = 0;
2220
- if (this.youtubePlayer && this.youtubePlayerReady) {
2221
- try {
2222
- duration = this.youtubePlayer.getDuration() || 0;
2223
- } catch (error) {
2224
- this.debugWarn('Error getting YouTube duration for tooltip:', error);
2225
- return;
2226
- }
2227
- } else if (this.video) {
2228
- duration = this.video.duration || 0;
2229
- }
2230
-
2231
- if (!duration || !isFinite(duration)) return;
1838
+ if (!progressBar || !tooltip || !this.video) return;
2232
1839
 
2233
1840
  const rect = progressBar.getBoundingClientRect();
2234
1841
  const x = Math.max(0, Math.min(e.clientX - rect.left, rect.width));
2235
1842
  const percent = (x / rect.width);
2236
- const time = percent * duration;
1843
+ const time = percent * this.video.duration;
2237
1844
 
2238
1845
  // Update tooltip content and position
2239
1846
  tooltip.textContent = this.formatTime(time);
@@ -4888,29 +4495,7 @@ export class WebPlayer extends BasePlayer {
4888
4495
  }
4889
4496
 
4890
4497
  .uvf-accordion-item.expanded .uvf-accordion-content {
4891
- max-height: 350px;
4892
- overflow-y: auto;
4893
- -webkit-overflow-scrolling: touch;
4894
- }
4895
-
4896
- /* Special handling for quality accordion with many options */
4897
- .uvf-accordion-item.expanded .uvf-accordion-content[data-section="quality"] {
4898
- max-height: 400px;
4899
- }
4900
-
4901
- /* Scrollbar styling for accordion content */
4902
- .uvf-accordion-content::-webkit-scrollbar {
4903
- width: 4px;
4904
- }
4905
- .uvf-accordion-content::-webkit-scrollbar-track {
4906
- background: transparent;
4907
- }
4908
- .uvf-accordion-content::-webkit-scrollbar-thumb {
4909
- background: rgba(255,255,255,0.3);
4910
- border-radius: 2px;
4911
- }
4912
- .uvf-accordion-content::-webkit-scrollbar-thumb:hover {
4913
- background: rgba(255,255,255,0.5);
4498
+ max-height: 250px;
4914
4499
  }
4915
4500
 
4916
4501
  /* Settings options within accordion */
@@ -7071,7 +6656,7 @@ export class WebPlayer extends BasePlayer {
7071
6656
  const qualityBadge = document.createElement('div');
7072
6657
  qualityBadge.className = 'uvf-quality-badge';
7073
6658
  qualityBadge.id = 'uvf-quality-badge';
7074
- qualityBadge.textContent = 'AUTO'; // Default to AUTO for better UX
6659
+ qualityBadge.textContent = 'HD';
7075
6660
  rightControls.appendChild(qualityBadge);
7076
6661
 
7077
6662
  // Settings button with menu (show only if enabled)
@@ -8428,27 +8013,12 @@ export class WebPlayer extends BasePlayer {
8428
8013
  const progressBar = document.querySelector('.uvf-progress-bar') as HTMLElement;
8429
8014
  const progressFilled = document.getElementById('uvf-progress-filled') as HTMLElement;
8430
8015
  const progressHandle = document.getElementById('uvf-progress-handle') as HTMLElement;
8431
- if (!progressBar) return;
8432
-
8433
- // Get duration from appropriate source
8434
- let duration = 0;
8435
- if (this.youtubePlayer && this.youtubePlayerReady) {
8436
- try {
8437
- duration = this.youtubePlayer.getDuration() || 0;
8438
- } catch (error) {
8439
- this.debugWarn('Error getting YouTube duration for seeking:', error);
8440
- return;
8441
- }
8442
- } else if (this.video) {
8443
- duration = this.video.duration;
8444
- } else {
8445
- this.debugWarn('No video source available for seeking');
8446
- return;
8447
- }
8016
+ if (!progressBar || !this.video) return;
8448
8017
 
8018
+ const duration = this.video.duration;
8449
8019
  // Validate duration before calculating seek time
8450
8020
  if (!isFinite(duration) || isNaN(duration) || duration <= 0) {
8451
- this.debugWarn('Invalid video duration, cannot seek via progress bar:', duration);
8021
+ this.debugWarn('Invalid video duration, cannot seek via progress bar');
8452
8022
  return;
8453
8023
  }
8454
8024
 
@@ -8463,24 +8033,21 @@ export class WebPlayer extends BasePlayer {
8463
8033
  return;
8464
8034
  }
8465
8035
 
8466
- this.debugLog('Seeking to position:', time, 'seconds (', Math.round(percent), '%)');
8467
-
8468
8036
  // Update UI immediately for responsive feedback
8469
- if (progressFilled && !this.isDragging) {
8037
+ if (progressFilled) {
8470
8038
  progressFilled.style.width = percent + '%';
8471
8039
  }
8472
- if (progressHandle && !this.isDragging) {
8040
+ if (progressHandle) {
8473
8041
  progressHandle.style.left = percent + '%';
8474
- progressHandle.classList.add('dragging');
8042
+ // Add dragging class for visual feedback
8043
+ if (this.isDragging) {
8044
+ progressHandle.classList.add('dragging');
8045
+ } else {
8046
+ progressHandle.classList.remove('dragging');
8047
+ }
8475
8048
  }
8476
8049
 
8477
- // Perform the actual seek
8478
8050
  this.seek(time);
8479
-
8480
- // For YouTube, provide immediate visual feedback since API might be delayed
8481
- if (this.youtubePlayer && this.youtubePlayerReady) {
8482
- this.emit('onSeeking');
8483
- }
8484
8051
  }
8485
8052
 
8486
8053
  private formatTime(seconds: number): string {