unified-video-framework 1.4.254 → 1.4.256

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.
@@ -1550,40 +1550,162 @@ export class WebPlayer extends BasePlayer {
1550
1550
 
1551
1551
  this.debugLog('📊 Attempting to set YouTube quality to:', qualityLevel);
1552
1552
 
1553
- // Try to set the quality
1554
- this.youtubePlayer.setPlaybackQuality(qualityLevel);
1555
- this.debugLog('✅ setPlaybackQuality called for:', qualityLevel);
1556
-
1557
- // Verify quality was changed after a delay
1558
- setTimeout(() => {
1553
+ // Multiple approaches to force YouTube quality change
1554
+ if (qualityLevel === 'auto') {
1555
+ // For auto, just use setPlaybackQuality
1556
+ this.youtubePlayer.setPlaybackQuality(qualityLevel);
1557
+ } else {
1558
+ // For specific qualities, try multiple methods
1559
+ try {
1560
+ // Method 1: Set quality range (most effective for forcing specific quality)
1561
+ if (typeof this.youtubePlayer.setPlaybackQualityRange === 'function') {
1562
+ this.youtubePlayer.setPlaybackQualityRange(qualityLevel, qualityLevel);
1563
+ this.debugLog('✅ setPlaybackQualityRange called for:', qualityLevel);
1564
+ }
1565
+ } catch (e) {
1566
+ this.debugWarn('setPlaybackQualityRange failed:', e);
1567
+ }
1568
+
1559
1569
  try {
1560
- const currentQuality = this.youtubePlayer.getPlaybackQuality();
1561
- this.youtubeCurrentQuality = qualityMap[currentQuality] || qualityMap['auto'];
1570
+ // Method 2: Standard quality setting
1571
+ this.youtubePlayer.setPlaybackQuality(qualityLevel);
1572
+ this.debugLog('✅ setPlaybackQuality called for:', qualityLevel);
1573
+ } catch (e) {
1574
+ this.debugWarn('setPlaybackQuality failed:', e);
1575
+ }
1576
+
1577
+ // Method 3: Force quality with seekTo trick (most aggressive)
1578
+ try {
1579
+ const currentTime = this.youtubePlayer.getCurrentTime();
1580
+ const wasPlaying = this.youtubePlayer.getPlayerState() === window.YT.PlayerState.PLAYING;
1562
1581
 
1563
- this.debugLog('📊 Current quality after set:', currentQuality, '(', this.youtubeCurrentQuality?.label, ')');
1582
+ // Seek to current time + 0.1 seconds to force reload with new quality
1583
+ this.youtubePlayer.seekTo(currentTime + 0.1, true);
1564
1584
 
1565
- // Show notification with result
1566
- if (currentQuality === qualityLevel) {
1567
- this.showNotification(`Quality changed to ${qualityMap[currentQuality]?.label || 'requested quality'}`);
1568
- this.debugLog('✅ Quality successfully changed to:', qualityLevel);
1585
+ // Set quality immediately after seek
1586
+ setTimeout(() => {
1587
+ this.youtubePlayer.setPlaybackQuality(qualityLevel);
1588
+
1589
+ // Seek back to original time
1590
+ setTimeout(() => {
1591
+ this.youtubePlayer.seekTo(currentTime, true);
1592
+ if (!wasPlaying) {
1593
+ this.youtubePlayer.pauseVideo();
1594
+ }
1595
+ }, 100);
1596
+ }, 50);
1597
+
1598
+ this.debugLog('🔄 Applied seekTo trick for quality change');
1599
+ } catch (e) {
1600
+ this.debugWarn('Force quality change with seekTo trick failed:', e);
1601
+ }
1602
+ }
1603
+
1604
+ // Verify quality was changed after multiple delays with retry logic
1605
+ this.verifyYouTubeQualityChange(qualityLevel, qualityMap, 0);
1606
+ } catch (error) {
1607
+ this.debugWarn('❌ Could not set YouTube quality:', error);
1608
+ this.showNotification('Quality control limited on YouTube');
1609
+ }
1610
+ }
1611
+
1612
+ /**
1613
+ * Verify YouTube quality change with retry logic
1614
+ */
1615
+ private verifyYouTubeQualityChange(requestedQuality: string, qualityMap: Record<string, any>, attempt: number): void {
1616
+ const maxAttempts = 3;
1617
+ const delays = [500, 1500, 3000]; // Progressive delays
1618
+
1619
+ setTimeout(() => {
1620
+ try {
1621
+ const currentQuality = this.youtubePlayer.getPlaybackQuality();
1622
+ this.youtubeCurrentQuality = qualityMap[currentQuality] || qualityMap['auto'];
1623
+
1624
+ this.debugLog('🔍 Quality verification attempt', attempt + 1, '- Requested:', requestedQuality, '| Current:', currentQuality);
1625
+
1626
+ if (currentQuality === requestedQuality || attempt >= maxAttempts - 1) {
1627
+ // Success or final attempt
1628
+ if (currentQuality === requestedQuality) {
1629
+ this.showNotification(`Quality: ${qualityMap[currentQuality]?.label || 'requested quality'}`);
1630
+ this.debugLog('✅ Quality successfully changed to:', requestedQuality);
1569
1631
  } else {
1570
- this.showNotification(`Quality set to ${qualityMap[currentQuality]?.label || currentQuality} (YouTube optimized)`);
1571
- this.debugLog('⚠️ Requested quality:', qualityLevel, '| Actual quality:', currentQuality, '(YouTube may have optimized)');
1632
+ // Try one more aggressive method on final attempt
1633
+ if (attempt === maxAttempts - 1) {
1634
+ this.debugLog('🔥 Final attempt: Trying loadVideoById method');
1635
+ try {
1636
+ const videoData = this.youtubePlayer.getVideoData();
1637
+ const currentTime = this.youtubePlayer.getCurrentTime();
1638
+
1639
+ // Reload video at current time with suggested quality
1640
+ this.youtubePlayer.loadVideoById({
1641
+ videoId: videoData.video_id,
1642
+ startSeconds: currentTime,
1643
+ suggestedQuality: requestedQuality
1644
+ });
1645
+
1646
+ this.debugLog('🔄 Video reloaded with suggested quality:', requestedQuality);
1647
+ } catch (e) {
1648
+ this.debugWarn('loadVideoById method failed:', e);
1649
+ }
1650
+ }
1651
+
1652
+ this.showNotification(`Quality: ${qualityMap[currentQuality]?.label || currentQuality}`);
1653
+ this.debugLog('⚠️ Quality change may not have worked. Requested:', requestedQuality, '| Current:', currentQuality);
1572
1654
  }
1573
1655
 
1574
- // Update quality badge
1656
+ // Update UI regardless
1575
1657
  this.updateQualityBadge();
1658
+ this.updateSettingsMenu();
1659
+ } else {
1660
+ // Retry with more aggressive method
1661
+ this.debugLog('🔁 Quality not changed, retrying with method', attempt + 2);
1662
+ this.retryYouTubeQualityChange(requestedQuality, qualityMap, attempt + 1);
1576
1663
 
1577
- // Update settings menu UI
1664
+ // Still verify after delay
1665
+ this.verifyYouTubeQualityChange(requestedQuality, qualityMap, attempt + 1);
1666
+ }
1667
+ } catch (verifyError) {
1668
+ this.debugWarn('Could not verify YouTube quality:', verifyError);
1669
+ if (attempt === maxAttempts - 1) {
1670
+ this.showNotification('Quality change attempted');
1671
+ this.updateQualityBadge();
1578
1672
  this.updateSettingsMenu();
1579
- } catch (verifyError) {
1580
- this.debugWarn('Could not verify YouTube quality:', verifyError);
1581
1673
  }
1582
- }, 1000);
1583
-
1584
- } catch (error) {
1585
- this.debugWarn('❌ Could not set YouTube quality:', error);
1586
- this.showNotification('Quality control limited on YouTube');
1674
+ }
1675
+ }, delays[attempt] || 1000);
1676
+ }
1677
+
1678
+ /**
1679
+ * Retry YouTube quality change with alternative methods
1680
+ */
1681
+ private retryYouTubeQualityChange(qualityLevel: string, qualityMap: Record<string, any>, attempt: number): void {
1682
+ try {
1683
+ if (attempt === 1) {
1684
+ // Second attempt: Try with video restart
1685
+ this.debugLog('🔄 Retry attempt 1: Using cueVideoById');
1686
+ const videoData = this.youtubePlayer.getVideoData();
1687
+ const currentTime = this.youtubePlayer.getCurrentTime();
1688
+
1689
+ this.youtubePlayer.cueVideoById({
1690
+ videoId: videoData.video_id,
1691
+ startSeconds: currentTime,
1692
+ suggestedQuality: qualityLevel
1693
+ });
1694
+
1695
+ setTimeout(() => this.youtubePlayer.playVideo(), 100);
1696
+
1697
+ } else if (attempt === 2) {
1698
+ // Third attempt: Multiple sequential calls
1699
+ this.debugLog('🔄 Retry attempt 2: Multiple sequential calls');
1700
+
1701
+ for (let i = 0; i < 3; i++) {
1702
+ setTimeout(() => {
1703
+ this.youtubePlayer.setPlaybackQuality(qualityLevel);
1704
+ }, i * 100);
1705
+ }
1706
+ }
1707
+ } catch (e) {
1708
+ this.debugWarn('Retry attempt', attempt, 'failed:', e);
1587
1709
  }
1588
1710
  }
1589
1711
 
@@ -4798,7 +4920,29 @@ export class WebPlayer extends BasePlayer {
4798
4920
  }
4799
4921
 
4800
4922
  .uvf-accordion-item.expanded .uvf-accordion-content {
4801
- max-height: 250px;
4923
+ max-height: 350px;
4924
+ overflow-y: auto;
4925
+ -webkit-overflow-scrolling: touch;
4926
+ }
4927
+
4928
+ /* Special handling for quality accordion with many options */
4929
+ .uvf-accordion-item.expanded .uvf-accordion-content[data-section="quality"] {
4930
+ max-height: 400px;
4931
+ }
4932
+
4933
+ /* Scrollbar styling for accordion content */
4934
+ .uvf-accordion-content::-webkit-scrollbar {
4935
+ width: 4px;
4936
+ }
4937
+ .uvf-accordion-content::-webkit-scrollbar-track {
4938
+ background: transparent;
4939
+ }
4940
+ .uvf-accordion-content::-webkit-scrollbar-thumb {
4941
+ background: rgba(255,255,255,0.3);
4942
+ border-radius: 2px;
4943
+ }
4944
+ .uvf-accordion-content::-webkit-scrollbar-thumb:hover {
4945
+ background: rgba(255,255,255,0.5);
4802
4946
  }
4803
4947
 
4804
4948
  /* Settings options within accordion */