unified-video-framework 1.4.135 → 1.4.137

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.
@@ -2402,6 +2402,87 @@ export class WebPlayer extends BasePlayer {
2402
2402
  transform: translateY(0);
2403
2403
  }
2404
2404
 
2405
+ /* Accordion Styles */
2406
+ .uvf-settings-accordion {
2407
+ padding: 0;
2408
+ }
2409
+
2410
+ .uvf-accordion-item {
2411
+ border-bottom: 1px solid rgba(255,255,255,0.08);
2412
+ }
2413
+
2414
+ .uvf-accordion-item:last-child {
2415
+ border-bottom: none;
2416
+ }
2417
+
2418
+ .uvf-accordion-header {
2419
+ display: flex;
2420
+ align-items: center;
2421
+ justify-content: space-between;
2422
+ padding: 14px 18px;
2423
+ cursor: pointer;
2424
+ transition: all 0.2s ease;
2425
+ border-radius: 8px;
2426
+ margin: 4px 8px;
2427
+ }
2428
+
2429
+ .uvf-accordion-header:hover {
2430
+ background: rgba(255,255,255,0.08);
2431
+ transform: translateX(2px);
2432
+ }
2433
+
2434
+ .uvf-accordion-title {
2435
+ display: flex;
2436
+ align-items: center;
2437
+ gap: 10px;
2438
+ font-size: 14px;
2439
+ font-weight: 500;
2440
+ color: #fff;
2441
+ }
2442
+
2443
+ .uvf-accordion-icon {
2444
+ font-size: 16px;
2445
+ opacity: 0.8;
2446
+ }
2447
+
2448
+ .uvf-accordion-current {
2449
+ font-size: 12px;
2450
+ color: rgba(255,255,255,0.7);
2451
+ background: rgba(255,255,255,0.1);
2452
+ padding: 4px 8px;
2453
+ border-radius: 12px;
2454
+ font-weight: 500;
2455
+ }
2456
+
2457
+ .uvf-accordion-arrow {
2458
+ font-size: 12px;
2459
+ color: rgba(255,255,255,0.6);
2460
+ transition: transform 0.3s ease;
2461
+ }
2462
+
2463
+ .uvf-accordion-item.expanded .uvf-accordion-arrow {
2464
+ transform: rotate(180deg);
2465
+ }
2466
+
2467
+ .uvf-accordion-content {
2468
+ max-height: 0;
2469
+ overflow: hidden;
2470
+ transition: max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1), padding 0.3s ease;
2471
+ padding: 0 18px;
2472
+ }
2473
+
2474
+ .uvf-accordion-item.expanded .uvf-accordion-content {
2475
+ max-height: 300px;
2476
+ padding: 8px 18px 16px;
2477
+ }
2478
+
2479
+ .uvf-settings-empty {
2480
+ padding: 20px;
2481
+ text-align: center;
2482
+ color: rgba(255,255,255,0.6);
2483
+ font-size: 14px;
2484
+ }
2485
+
2405
2486
  .uvf-settings-group {
2406
2487
  padding: 10px 0;
2407
2488
  border-bottom: 1px solid rgba(255,255,255,0.1);
@@ -5029,11 +5110,44 @@ export class WebPlayer extends BasePlayer {
5029
5110
 
5030
5111
  // Settings menu - dynamically populated
5031
5112
  const settingsMenu = document.getElementById('uvf-settings-menu');
5113
+ this.debugLog('Settings menu element found:', !!settingsMenu);
5114
+ this.debugLog('Settings button found:', !!settingsBtn);
5115
+
5032
5116
  settingsBtn?.addEventListener('click', (e) => {
5033
5117
  e.stopPropagation();
5118
+ this.debugLog('Settings button clicked!');
5119
+ this.debugLog('Settings menu before update:', settingsMenu?.innerHTML?.length || 0, 'characters');
5120
+
5034
5121
  // Update the menu content before showing it
5035
5122
  this.updateSettingsMenu();
5123
+
5124
+ this.debugLog('Settings menu after update:', settingsMenu?.innerHTML?.length || 0, 'characters');
5125
+ this.debugLog('Settings menu classes before toggle:', Array.from(settingsMenu?.classList || []).join(' '));
5126
+
5036
5127
  settingsMenu?.classList.toggle('active');
5128
+
5129
+ // Force visibility if menu is not showing properly
5130
+ if (settingsMenu && settingsMenu.classList.contains('active')) {
5131
+ settingsMenu.style.display = 'block';
5132
+ settingsMenu.style.visibility = 'visible';
5133
+ settingsMenu.style.opacity = '1';
5134
+ settingsMenu.style.transform = 'translateY(0)';
5135
+ settingsMenu.style.zIndex = '9999';
5136
+ settingsMenu.style.position = 'absolute';
5137
+ settingsMenu.style.bottom = '50px';
5138
+ settingsMenu.style.right = '0';
5139
+ settingsMenu.style.background = 'rgba(0,0,0,0.9)';
5140
+ settingsMenu.style.border = '1px solid rgba(255,255,255,0.2)';
5141
+ settingsMenu.style.borderRadius = '8px';
5142
+ settingsMenu.style.minWidth = '200px';
5143
+ settingsMenu.style.padding = '10px 0';
5144
+ this.debugLog('Applied fallback styles to force menu visibility');
5145
+ }
5146
+
5147
+ this.debugLog('Settings menu classes after toggle:', Array.from(settingsMenu?.classList || []).join(' '));
5148
+ this.debugLog('Settings menu computed display:', window.getComputedStyle(settingsMenu || document.body).display);
5149
+ this.debugLog('Settings menu computed visibility:', window.getComputedStyle(settingsMenu || document.body).visibility);
5150
+ this.debugLog('Settings menu computed opacity:', window.getComputedStyle(settingsMenu || document.body).opacity);
5037
5151
  });
5038
5152
 
5039
5153
  // EPG button
@@ -6288,67 +6402,129 @@ export class WebPlayer extends BasePlayer {
6288
6402
  * Dynamically populate settings menu based on video capabilities
6289
6403
  */
6290
6404
  private updateSettingsMenu(): void {
6405
+ this.debugLog('updateSettingsMenu called');
6291
6406
  const settingsMenu = document.getElementById('uvf-settings-menu');
6292
- if (!settingsMenu) return;
6407
+ if (!settingsMenu) {
6408
+ this.debugError('Settings menu element not found!');
6409
+ return;
6410
+ }
6293
6411
 
6412
+ this.debugLog('Settings menu element found, updating content...');
6294
6413
  // Detect available qualities from video
6295
6414
  this.detectAvailableQualities();
6296
6415
  // Detect available subtitles
6297
6416
  this.detectAvailableSubtitles();
6298
6417
 
6299
- let menuHTML = '';
6418
+ this.debugLog('Available qualities:', this.availableQualities);
6419
+ this.debugLog('Available subtitles:', this.availableSubtitles);
6420
+ this.debugLog('Settings config:', this.settingsConfig);
6300
6421
 
6301
- // Playback Speed Section (only if enabled in config)
6422
+ // Generate accordion-style menu
6423
+ this.generateAccordionMenu();
6424
+ }
6425
+
6426
+ /**
6427
+ * Generate accordion-style settings menu
6428
+ */
6429
+ private generateAccordionMenu(): void {
6430
+ const settingsMenu = document.getElementById('uvf-settings-menu');
6431
+ if (!settingsMenu) return;
6432
+
6433
+ let menuHTML = '<div class="uvf-settings-accordion">';
6434
+
6435
+ // Playback Speed Accordion Section (only if enabled in config)
6302
6436
  if (this.settingsConfig.speed) {
6437
+ const currentSpeedLabel = this.currentPlaybackRate === 1 ? 'Normal' : `${this.currentPlaybackRate}x`;
6303
6438
  menuHTML += `
6304
- <div class="uvf-settings-group">
6305
- <div class="uvf-settings-label">Playback Speed</div>
6306
- <div class="uvf-settings-option speed-option" data-speed="0.25">0.25x</div>
6307
- <div class="uvf-settings-option speed-option" data-speed="0.5">0.5x</div>
6308
- <div class="uvf-settings-option speed-option" data-speed="0.75">0.75x</div>
6309
- <div class="uvf-settings-option speed-option ${this.currentPlaybackRate === 1 ? 'active' : ''}" data-speed="1">Normal</div>
6310
- <div class="uvf-settings-option speed-option" data-speed="1.25">1.25x</div>
6311
- <div class="uvf-settings-option speed-option" data-speed="1.5">1.5x</div>
6312
- <div class="uvf-settings-option speed-option" data-speed="1.75">1.75x</div>
6313
- <div class="uvf-settings-option speed-option" data-speed="2">2x</div>
6439
+ <div class="uvf-accordion-item">
6440
+ <div class="uvf-accordion-header" data-section="speed">
6441
+ <div class="uvf-accordion-title">
6442
+ <span class="uvf-accordion-icon">⚡</span>
6443
+ <span>Playback Speed</span>
6444
+ </div>
6445
+ <div class="uvf-accordion-current">${currentSpeedLabel}</div>
6446
+ <div class="uvf-accordion-arrow">▼</div>
6447
+ </div>
6448
+ <div class="uvf-accordion-content" data-section="speed">
6449
+ <div class="uvf-settings-option speed-option ${this.currentPlaybackRate === 0.25 ? 'active' : ''}" data-speed="0.25">0.25x</div>
6450
+ <div class="uvf-settings-option speed-option ${this.currentPlaybackRate === 0.5 ? 'active' : ''}" data-speed="0.5">0.5x</div>
6451
+ <div class="uvf-settings-option speed-option ${this.currentPlaybackRate === 0.75 ? 'active' : ''}" data-speed="0.75">0.75x</div>
6452
+ <div class="uvf-settings-option speed-option ${this.currentPlaybackRate === 1 ? 'active' : ''}" data-speed="1">Normal</div>
6453
+ <div class="uvf-settings-option speed-option ${this.currentPlaybackRate === 1.25 ? 'active' : ''}" data-speed="1.25">1.25x</div>
6454
+ <div class="uvf-settings-option speed-option ${this.currentPlaybackRate === 1.5 ? 'active' : ''}" data-speed="1.5">1.5x</div>
6455
+ <div class="uvf-settings-option speed-option ${this.currentPlaybackRate === 1.75 ? 'active' : ''}" data-speed="1.75">1.75x</div>
6456
+ <div class="uvf-settings-option speed-option ${this.currentPlaybackRate === 2 ? 'active' : ''}" data-speed="2">2x</div>
6457
+ </div>
6314
6458
  </div>`;
6315
6459
  }
6316
6460
 
6317
- // Quality Section (only if enabled in config and qualities detected)
6461
+ // Quality Accordion Section (only if enabled in config and qualities detected)
6318
6462
  if (this.settingsConfig.quality && this.availableQualities.length > 0) {
6319
- menuHTML += `<div class="uvf-settings-group">
6320
- <div class="uvf-settings-label">Quality</div>`;
6463
+ const currentQuality = this.availableQualities.find(q => q.value === this.currentQuality);
6464
+ const currentQualityLabel = currentQuality ? currentQuality.label : 'Auto';
6465
+
6466
+ menuHTML += `
6467
+ <div class="uvf-accordion-item">
6468
+ <div class="uvf-accordion-header" data-section="quality">
6469
+ <div class="uvf-accordion-title">
6470
+ <span class="uvf-accordion-icon">🎬</span>
6471
+ <span>Quality</span>
6472
+ </div>
6473
+ <div class="uvf-accordion-current">${currentQualityLabel}</div>
6474
+ <div class="uvf-accordion-arrow">▼</div>
6475
+ </div>
6476
+ <div class="uvf-accordion-content" data-section="quality">`;
6321
6477
 
6322
6478
  this.availableQualities.forEach(quality => {
6323
6479
  const isActive = quality.value === this.currentQuality ? 'active' : '';
6324
6480
  menuHTML += `<div class="uvf-settings-option quality-option ${isActive}" data-quality="${quality.value}">${quality.label}</div>`;
6325
6481
  });
6326
6482
 
6327
- menuHTML += `</div>`;
6483
+ menuHTML += `</div></div>`;
6328
6484
  }
6329
6485
 
6330
- // Subtitles Section (only if enabled in config and subtitles available)
6486
+ // Subtitles Accordion Section (only if enabled in config and subtitles available)
6331
6487
  if (this.settingsConfig.subtitles && this.availableSubtitles.length > 0) {
6332
- menuHTML += `<div class="uvf-settings-group">
6333
- <div class="uvf-settings-label">Subtitles/Captions</div>`;
6488
+ const currentSubtitle = this.availableSubtitles.find(s => s.value === this.currentSubtitle);
6489
+ const currentSubtitleLabel = currentSubtitle ? currentSubtitle.label : 'Off';
6490
+
6491
+ menuHTML += `
6492
+ <div class="uvf-accordion-item">
6493
+ <div class="uvf-accordion-header" data-section="subtitles">
6494
+ <div class="uvf-accordion-title">
6495
+ <span class="uvf-accordion-icon">💬</span>
6496
+ <span>Subtitles</span>
6497
+ </div>
6498
+ <div class="uvf-accordion-current">${currentSubtitleLabel}</div>
6499
+ <div class="uvf-accordion-arrow">▼</div>
6500
+ </div>
6501
+ <div class="uvf-accordion-content" data-section="subtitles">`;
6334
6502
 
6335
6503
  this.availableSubtitles.forEach(subtitle => {
6336
6504
  const isActive = subtitle.value === this.currentSubtitle ? 'active' : '';
6337
6505
  menuHTML += `<div class="uvf-settings-option subtitle-option ${isActive}" data-subtitle="${subtitle.value}">${subtitle.label}</div>`;
6338
6506
  });
6339
6507
 
6340
- menuHTML += `</div>`;
6508
+ menuHTML += `</div></div>`;
6341
6509
  }
6342
6510
 
6511
+ // Close accordion container
6512
+ menuHTML += '</div>';
6513
+
6343
6514
  // If no sections are enabled or available, show a message
6344
- if (!menuHTML.trim()) {
6345
- menuHTML = '<div class="uvf-settings-group"><div class="uvf-settings-label">No settings available</div></div>';
6515
+ if (menuHTML === '<div class="uvf-settings-accordion"></div>') {
6516
+ menuHTML = '<div class="uvf-settings-accordion"><div class="uvf-settings-empty">No settings available</div></div>';
6346
6517
  }
6347
6518
 
6519
+ this.debugLog('Generated menu HTML length:', menuHTML.length);
6520
+ this.debugLog('Generated menu HTML content:', menuHTML.substring(0, 200) + (menuHTML.length > 200 ? '...' : ''));
6521
+
6348
6522
  settingsMenu.innerHTML = menuHTML;
6523
+ this.debugLog('Settings menu HTML set successfully');
6349
6524
 
6350
6525
  // Add event listeners for settings options
6351
6526
  this.setupSettingsEventListeners();
6527
+ this.debugLog('Settings event listeners setup complete');
6352
6528
  }
6353
6529
 
6354
6530
  /**
@@ -6428,18 +6604,33 @@ export class WebPlayer extends BasePlayer {
6428
6604
  }
6429
6605
 
6430
6606
  /**
6431
- * Setup event listeners for settings menu options
6607
+ * Setup event listeners for accordion-style settings menu
6432
6608
  */
6433
6609
  private setupSettingsEventListeners(): void {
6434
6610
  const settingsMenu = document.getElementById('uvf-settings-menu');
6435
6611
  if (!settingsMenu) return;
6436
6612
 
6613
+ // Accordion header click handlers
6614
+ settingsMenu.querySelectorAll('.uvf-accordion-header').forEach(header => {
6615
+ header.addEventListener('click', (e) => {
6616
+ e.preventDefault();
6617
+ e.stopPropagation();
6618
+
6619
+ const accordionItem = header.parentElement;
6620
+ const section = header.getAttribute('data-section');
6621
+
6622
+ if (accordionItem && section) {
6623
+ this.toggleAccordionSection(accordionItem, section);
6624
+ }
6625
+ });
6626
+ });
6627
+
6437
6628
  // Speed options
6438
6629
  settingsMenu.querySelectorAll('.speed-option').forEach(option => {
6439
6630
  option.addEventListener('click', (e) => {
6440
6631
  const speed = parseFloat((e.target as HTMLElement).dataset.speed || '1');
6441
6632
  this.setPlaybackRateFromSettings(speed);
6442
- this.updateSettingsActiveStates('speed-option', e.target as HTMLElement);
6633
+ this.updateAccordionAfterSelection('speed');
6443
6634
  });
6444
6635
  });
6445
6636
 
@@ -6448,7 +6639,7 @@ export class WebPlayer extends BasePlayer {
6448
6639
  option.addEventListener('click', (e) => {
6449
6640
  const quality = (e.target as HTMLElement).dataset.quality || 'auto';
6450
6641
  this.setQualityFromSettings(quality);
6451
- this.updateSettingsActiveStates('quality-option', e.target as HTMLElement);
6642
+ this.updateAccordionAfterSelection('quality');
6452
6643
  });
6453
6644
  });
6454
6645
 
@@ -6457,10 +6648,53 @@ export class WebPlayer extends BasePlayer {
6457
6648
  option.addEventListener('click', (e) => {
6458
6649
  const subtitle = (e.target as HTMLElement).dataset.subtitle || 'off';
6459
6650
  this.setSubtitle(subtitle);
6460
- this.updateSettingsActiveStates('subtitle-option', e.target as HTMLElement);
6651
+ this.updateAccordionAfterSelection('subtitles');
6461
6652
  });
6462
6653
  });
6463
6654
  }
6655
+
6656
+ /**
6657
+ * Toggle accordion section
6658
+ */
6659
+ private toggleAccordionSection(accordionItem: Element, section: string): void {
6660
+ const isExpanded = accordionItem.classList.contains('expanded');
6661
+
6662
+ // Close all other sections
6663
+ const settingsMenu = document.getElementById('uvf-settings-menu');
6664
+ if (settingsMenu) {
6665
+ settingsMenu.querySelectorAll('.uvf-accordion-item.expanded').forEach(item => {
6666
+ if (item !== accordionItem) {
6667
+ item.classList.remove('expanded');
6668
+ }
6669
+ });
6670
+ }
6671
+
6672
+ // Toggle current section
6673
+ if (isExpanded) {
6674
+ accordionItem.classList.remove('expanded');
6675
+ } else {
6676
+ accordionItem.classList.add('expanded');
6677
+ }
6678
+ }
6679
+
6680
+ /**
6681
+ * Update accordion after user makes a selection
6682
+ */
6683
+ private updateAccordionAfterSelection(section: string): void {
6684
+ // Close the accordion section after selection
6685
+ setTimeout(() => {
6686
+ const settingsMenu = document.getElementById('uvf-settings-menu');
6687
+ const accordionItem = settingsMenu?.querySelector(`[data-section="${section}"]`)?.parentElement;
6688
+
6689
+ if (accordionItem) {
6690
+ accordionItem.classList.remove('expanded');
6691
+ }
6692
+
6693
+ // Refresh the menu to update current values
6694
+ this.generateAccordionMenu();
6695
+ this.setupSettingsEventListeners();
6696
+ }, 300);
6697
+ }
6464
6698
 
6465
6699
  /**
6466
6700
  * Update active states in settings menu