unified-video-framework 1.4.136 → 1.4.138
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,141 @@ export class WebPlayer extends BasePlayer {
|
|
|
2402
2402
|
transform: translateY(0);
|
|
2403
2403
|
}
|
|
2404
2404
|
|
|
2405
|
+
/* Improved Accordion Styles */
|
|
2406
|
+
.uvf-settings-accordion {
|
|
2407
|
+
padding: 8px 0;
|
|
2408
|
+
}
|
|
2409
|
+
|
|
2410
|
+
.uvf-accordion-item {
|
|
2411
|
+
margin-bottom: 2px;
|
|
2412
|
+
border-radius: 8px;
|
|
2413
|
+
overflow: hidden;
|
|
2414
|
+
background: rgba(255,255,255,0.03);
|
|
2415
|
+
}
|
|
2416
|
+
|
|
2417
|
+
.uvf-accordion-item:last-child {
|
|
2418
|
+
margin-bottom: 0;
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2421
|
+
.uvf-accordion-header {
|
|
2422
|
+
display: flex;
|
|
2423
|
+
align-items: center;
|
|
2424
|
+
justify-content: space-between;
|
|
2425
|
+
padding: 12px 16px;
|
|
2426
|
+
cursor: pointer;
|
|
2427
|
+
transition: all 0.2s ease;
|
|
2428
|
+
background: rgba(255,255,255,0.05);
|
|
2429
|
+
border-bottom: 1px solid rgba(255,255,255,0.08);
|
|
2430
|
+
}
|
|
2431
|
+
|
|
2432
|
+
.uvf-accordion-header:hover {
|
|
2433
|
+
background: rgba(255,255,255,0.1);
|
|
2434
|
+
}
|
|
2435
|
+
|
|
2436
|
+
.uvf-accordion-item.expanded .uvf-accordion-header {
|
|
2437
|
+
background: rgba(255,255,255,0.08);
|
|
2438
|
+
border-bottom-color: rgba(255,255,255,0.12);
|
|
2439
|
+
}
|
|
2440
|
+
|
|
2441
|
+
.uvf-accordion-title {
|
|
2442
|
+
display: flex;
|
|
2443
|
+
align-items: center;
|
|
2444
|
+
gap: 8px;
|
|
2445
|
+
font-size: 13px;
|
|
2446
|
+
font-weight: 500;
|
|
2447
|
+
color: #fff;
|
|
2448
|
+
flex: 1;
|
|
2449
|
+
}
|
|
2450
|
+
|
|
2451
|
+
.uvf-accordion-icon {
|
|
2452
|
+
display: flex;
|
|
2453
|
+
align-items: center;
|
|
2454
|
+
justify-content: center;
|
|
2455
|
+
opacity: 0.9;
|
|
2456
|
+
width: 16px;
|
|
2457
|
+
height: 16px;
|
|
2458
|
+
}
|
|
2459
|
+
|
|
2460
|
+
.uvf-accordion-icon svg {
|
|
2461
|
+
width: 14px;
|
|
2462
|
+
height: 14px;
|
|
2463
|
+
fill: currentColor;
|
|
2464
|
+
}
|
|
2465
|
+
|
|
2466
|
+
.uvf-accordion-current {
|
|
2467
|
+
font-size: 11px;
|
|
2468
|
+
color: var(--uvf-accent-1);
|
|
2469
|
+
background: rgba(255,255,255,0.08);
|
|
2470
|
+
padding: 2px 8px;
|
|
2471
|
+
border-radius: 8px;
|
|
2472
|
+
font-weight: 600;
|
|
2473
|
+
margin-right: 8px;
|
|
2474
|
+
}
|
|
2475
|
+
|
|
2476
|
+
.uvf-accordion-arrow {
|
|
2477
|
+
font-size: 10px;
|
|
2478
|
+
color: rgba(255,255,255,0.7);
|
|
2479
|
+
transition: transform 0.25s ease;
|
|
2480
|
+
width: 16px;
|
|
2481
|
+
text-align: center;
|
|
2482
|
+
}
|
|
2483
|
+
|
|
2484
|
+
.uvf-accordion-item.expanded .uvf-accordion-arrow {
|
|
2485
|
+
transform: rotate(180deg);
|
|
2486
|
+
}
|
|
2487
|
+
|
|
2488
|
+
.uvf-accordion-content {
|
|
2489
|
+
max-height: 0;
|
|
2490
|
+
overflow: hidden;
|
|
2491
|
+
transition: max-height 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
|
2492
|
+
background: rgba(0,0,0,0.2);
|
|
2493
|
+
}
|
|
2494
|
+
|
|
2495
|
+
.uvf-accordion-item.expanded .uvf-accordion-content {
|
|
2496
|
+
max-height: 250px;
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2499
|
+
/* Settings options within accordion */
|
|
2500
|
+
.uvf-accordion-content .uvf-settings-option {
|
|
2501
|
+
color: #fff;
|
|
2502
|
+
font-size: 13px;
|
|
2503
|
+
padding: 10px 16px;
|
|
2504
|
+
cursor: pointer;
|
|
2505
|
+
transition: all 0.2s ease;
|
|
2506
|
+
border-bottom: 1px solid rgba(255,255,255,0.05);
|
|
2507
|
+
display: flex;
|
|
2508
|
+
align-items: center;
|
|
2509
|
+
justify-content: space-between;
|
|
2510
|
+
}
|
|
2511
|
+
|
|
2512
|
+
.uvf-accordion-content .uvf-settings-option:last-child {
|
|
2513
|
+
border-bottom: none;
|
|
2514
|
+
}
|
|
2515
|
+
|
|
2516
|
+
.uvf-accordion-content .uvf-settings-option:hover {
|
|
2517
|
+
background: rgba(255,255,255,0.06);
|
|
2518
|
+
padding-left: 20px;
|
|
2519
|
+
}
|
|
2520
|
+
|
|
2521
|
+
.uvf-accordion-content .uvf-settings-option.active {
|
|
2522
|
+
color: var(--uvf-accent-1);
|
|
2523
|
+
background: rgba(255,255,255,0.08);
|
|
2524
|
+
font-weight: 600;
|
|
2525
|
+
}
|
|
2526
|
+
|
|
2527
|
+
.uvf-accordion-content .uvf-settings-option.active::after {
|
|
2528
|
+
content: '✓';
|
|
2529
|
+
font-size: 12px;
|
|
2530
|
+
opacity: 0.8;
|
|
2531
|
+
}
|
|
2532
|
+
|
|
2533
|
+
.uvf-settings-empty {
|
|
2534
|
+
padding: 20px;
|
|
2535
|
+
text-align: center;
|
|
2536
|
+
color: rgba(255,255,255,0.6);
|
|
2537
|
+
font-size: 14px;
|
|
2538
|
+
}
|
|
2539
|
+
|
|
2405
2540
|
.uvf-settings-group {
|
|
2406
2541
|
padding: 10px 0;
|
|
2407
2542
|
border-bottom: 1px solid rgba(255,255,255,0.1);
|
|
@@ -5091,11 +5226,26 @@ export class WebPlayer extends BasePlayer {
|
|
|
5091
5226
|
stopCastBtn?.addEventListener('click', () => this.stopCasting());
|
|
5092
5227
|
shareBtn?.addEventListener('click', () => this.shareVideo());
|
|
5093
5228
|
|
|
5094
|
-
// Hide settings menu when clicking outside
|
|
5229
|
+
// Hide settings menu when clicking outside or pressing Escape
|
|
5095
5230
|
document.addEventListener('click', (e) => {
|
|
5096
5231
|
if (!(e.target as HTMLElement).closest('#uvf-settings-btn') &&
|
|
5097
5232
|
!(e.target as HTMLElement).closest('#uvf-settings-menu')) {
|
|
5098
5233
|
settingsMenu?.classList.remove('active');
|
|
5234
|
+
// Also close any expanded accordions
|
|
5235
|
+
settingsMenu?.querySelectorAll('.uvf-accordion-item.expanded').forEach(item => {
|
|
5236
|
+
item.classList.remove('expanded');
|
|
5237
|
+
});
|
|
5238
|
+
}
|
|
5239
|
+
});
|
|
5240
|
+
|
|
5241
|
+
// Add Escape key handler for settings menu
|
|
5242
|
+
document.addEventListener('keydown', (e) => {
|
|
5243
|
+
if (e.key === 'Escape' && settingsMenu?.classList.contains('active')) {
|
|
5244
|
+
settingsMenu.classList.remove('active');
|
|
5245
|
+
// Also close any expanded accordions
|
|
5246
|
+
settingsMenu.querySelectorAll('.uvf-accordion-item.expanded').forEach(item => {
|
|
5247
|
+
item.classList.remove('expanded');
|
|
5248
|
+
});
|
|
5099
5249
|
}
|
|
5100
5250
|
});
|
|
5101
5251
|
}
|
|
@@ -6338,53 +6488,113 @@ export class WebPlayer extends BasePlayer {
|
|
|
6338
6488
|
this.debugLog('Available subtitles:', this.availableSubtitles);
|
|
6339
6489
|
this.debugLog('Settings config:', this.settingsConfig);
|
|
6340
6490
|
|
|
6341
|
-
|
|
6491
|
+
// Generate accordion-style menu
|
|
6492
|
+
this.generateAccordionMenu();
|
|
6493
|
+
}
|
|
6494
|
+
|
|
6495
|
+
/**
|
|
6496
|
+
* Generate accordion-style settings menu
|
|
6497
|
+
*/
|
|
6498
|
+
private generateAccordionMenu(): void {
|
|
6499
|
+
const settingsMenu = document.getElementById('uvf-settings-menu');
|
|
6500
|
+
if (!settingsMenu) return;
|
|
6342
6501
|
|
|
6343
|
-
|
|
6502
|
+
let menuHTML = '<div class="uvf-settings-accordion">';
|
|
6503
|
+
|
|
6504
|
+
// Playback Speed Accordion Section (only if enabled in config)
|
|
6344
6505
|
if (this.settingsConfig.speed) {
|
|
6506
|
+
const currentSpeedLabel = this.currentPlaybackRate === 1 ? 'Normal' : `${this.currentPlaybackRate}x`;
|
|
6345
6507
|
menuHTML += `
|
|
6346
|
-
<div class="uvf-
|
|
6347
|
-
<div class="uvf-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
|
|
6351
|
-
|
|
6352
|
-
|
|
6353
|
-
|
|
6354
|
-
|
|
6355
|
-
|
|
6508
|
+
<div class="uvf-accordion-item">
|
|
6509
|
+
<div class="uvf-accordion-header" data-section="speed">
|
|
6510
|
+
<div class="uvf-accordion-title">
|
|
6511
|
+
<span class="uvf-accordion-icon">
|
|
6512
|
+
<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor">
|
|
6513
|
+
<path d="M13,24l11-12L13,0V7.5C5.7,7.5,0,13.2,0,20.5C0,22.4,0.6,24.2,1.6,25.7C4.8,21.8,8.7,19.5,13,19.5V24z"/>
|
|
6514
|
+
</svg>
|
|
6515
|
+
</span>
|
|
6516
|
+
<span>Playback Speed</span>
|
|
6517
|
+
</div>
|
|
6518
|
+
<div class="uvf-accordion-current">${currentSpeedLabel}</div>
|
|
6519
|
+
<div class="uvf-accordion-arrow">▼</div>
|
|
6520
|
+
</div>
|
|
6521
|
+
<div class="uvf-accordion-content" data-section="speed">
|
|
6522
|
+
<div class="uvf-settings-option speed-option ${this.currentPlaybackRate === 0.25 ? 'active' : ''}" data-speed="0.25">0.25x</div>
|
|
6523
|
+
<div class="uvf-settings-option speed-option ${this.currentPlaybackRate === 0.5 ? 'active' : ''}" data-speed="0.5">0.5x</div>
|
|
6524
|
+
<div class="uvf-settings-option speed-option ${this.currentPlaybackRate === 0.75 ? 'active' : ''}" data-speed="0.75">0.75x</div>
|
|
6525
|
+
<div class="uvf-settings-option speed-option ${this.currentPlaybackRate === 1 ? 'active' : ''}" data-speed="1">Normal</div>
|
|
6526
|
+
<div class="uvf-settings-option speed-option ${this.currentPlaybackRate === 1.25 ? 'active' : ''}" data-speed="1.25">1.25x</div>
|
|
6527
|
+
<div class="uvf-settings-option speed-option ${this.currentPlaybackRate === 1.5 ? 'active' : ''}" data-speed="1.5">1.5x</div>
|
|
6528
|
+
<div class="uvf-settings-option speed-option ${this.currentPlaybackRate === 1.75 ? 'active' : ''}" data-speed="1.75">1.75x</div>
|
|
6529
|
+
<div class="uvf-settings-option speed-option ${this.currentPlaybackRate === 2 ? 'active' : ''}" data-speed="2">2x</div>
|
|
6530
|
+
</div>
|
|
6356
6531
|
</div>`;
|
|
6357
6532
|
}
|
|
6358
6533
|
|
|
6359
|
-
// Quality Section (only if enabled in config and qualities detected)
|
|
6534
|
+
// Quality Accordion Section (only if enabled in config and qualities detected)
|
|
6360
6535
|
if (this.settingsConfig.quality && this.availableQualities.length > 0) {
|
|
6361
|
-
|
|
6362
|
-
|
|
6536
|
+
const currentQuality = this.availableQualities.find(q => q.value === this.currentQuality);
|
|
6537
|
+
const currentQualityLabel = currentQuality ? currentQuality.label : 'Auto';
|
|
6538
|
+
|
|
6539
|
+
menuHTML += `
|
|
6540
|
+
<div class="uvf-accordion-item">
|
|
6541
|
+
<div class="uvf-accordion-header" data-section="quality">
|
|
6542
|
+
<div class="uvf-accordion-title">
|
|
6543
|
+
<span class="uvf-accordion-icon">
|
|
6544
|
+
<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor">
|
|
6545
|
+
<path d="M9,4v3h5V4h4V16H15v-3H9v3H5V4H9z M8,5H6v10h2V11h6v4h2V5h-2v4H8V5z"/>
|
|
6546
|
+
</svg>
|
|
6547
|
+
</span>
|
|
6548
|
+
<span>Quality</span>
|
|
6549
|
+
</div>
|
|
6550
|
+
<div class="uvf-accordion-current">${currentQualityLabel}</div>
|
|
6551
|
+
<div class="uvf-accordion-arrow">▼</div>
|
|
6552
|
+
</div>
|
|
6553
|
+
<div class="uvf-accordion-content" data-section="quality">`;
|
|
6363
6554
|
|
|
6364
6555
|
this.availableQualities.forEach(quality => {
|
|
6365
6556
|
const isActive = quality.value === this.currentQuality ? 'active' : '';
|
|
6366
6557
|
menuHTML += `<div class="uvf-settings-option quality-option ${isActive}" data-quality="${quality.value}">${quality.label}</div>`;
|
|
6367
6558
|
});
|
|
6368
6559
|
|
|
6369
|
-
menuHTML += `</div>`;
|
|
6560
|
+
menuHTML += `</div></div>`;
|
|
6370
6561
|
}
|
|
6371
6562
|
|
|
6372
|
-
// Subtitles Section (only if enabled in config and subtitles available)
|
|
6563
|
+
// Subtitles Accordion Section (only if enabled in config and subtitles available)
|
|
6373
6564
|
if (this.settingsConfig.subtitles && this.availableSubtitles.length > 0) {
|
|
6374
|
-
|
|
6375
|
-
|
|
6565
|
+
const currentSubtitle = this.availableSubtitles.find(s => s.value === this.currentSubtitle);
|
|
6566
|
+
const currentSubtitleLabel = currentSubtitle ? currentSubtitle.label : 'Off';
|
|
6567
|
+
|
|
6568
|
+
menuHTML += `
|
|
6569
|
+
<div class="uvf-accordion-item">
|
|
6570
|
+
<div class="uvf-accordion-header" data-section="subtitles">
|
|
6571
|
+
<div class="uvf-accordion-title">
|
|
6572
|
+
<span class="uvf-accordion-icon">
|
|
6573
|
+
<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor">
|
|
6574
|
+
<path d="M20,4H4C2.89,4 2,4.89 2,6V18C2,19.11 2.89,20 4,20H20C21.11,20 22,19.11 22,18V6C22,4.89 21.11,4 20,4M20,18H4V6H20V18M6,10H8V12H6V10M6,14H14V16H6V14M16,14H18V16H16V14M10,10H18V12H10V10Z"/>
|
|
6575
|
+
</svg>
|
|
6576
|
+
</span>
|
|
6577
|
+
<span>Subtitles</span>
|
|
6578
|
+
</div>
|
|
6579
|
+
<div class="uvf-accordion-current">${currentSubtitleLabel}</div>
|
|
6580
|
+
<div class="uvf-accordion-arrow">▼</div>
|
|
6581
|
+
</div>
|
|
6582
|
+
<div class="uvf-accordion-content" data-section="subtitles">`;
|
|
6376
6583
|
|
|
6377
6584
|
this.availableSubtitles.forEach(subtitle => {
|
|
6378
6585
|
const isActive = subtitle.value === this.currentSubtitle ? 'active' : '';
|
|
6379
6586
|
menuHTML += `<div class="uvf-settings-option subtitle-option ${isActive}" data-subtitle="${subtitle.value}">${subtitle.label}</div>`;
|
|
6380
6587
|
});
|
|
6381
6588
|
|
|
6382
|
-
menuHTML += `</div>`;
|
|
6589
|
+
menuHTML += `</div></div>`;
|
|
6383
6590
|
}
|
|
6384
6591
|
|
|
6592
|
+
// Close accordion container
|
|
6593
|
+
menuHTML += '</div>';
|
|
6594
|
+
|
|
6385
6595
|
// If no sections are enabled or available, show a message
|
|
6386
|
-
if (
|
|
6387
|
-
menuHTML = '<div class="uvf-settings-
|
|
6596
|
+
if (menuHTML === '<div class="uvf-settings-accordion"></div>') {
|
|
6597
|
+
menuHTML = '<div class="uvf-settings-accordion"><div class="uvf-settings-empty">No settings available</div></div>';
|
|
6388
6598
|
}
|
|
6389
6599
|
|
|
6390
6600
|
this.debugLog('Generated menu HTML length:', menuHTML.length);
|
|
@@ -6475,18 +6685,33 @@ export class WebPlayer extends BasePlayer {
|
|
|
6475
6685
|
}
|
|
6476
6686
|
|
|
6477
6687
|
/**
|
|
6478
|
-
* Setup event listeners for settings menu
|
|
6688
|
+
* Setup event listeners for accordion-style settings menu
|
|
6479
6689
|
*/
|
|
6480
6690
|
private setupSettingsEventListeners(): void {
|
|
6481
6691
|
const settingsMenu = document.getElementById('uvf-settings-menu');
|
|
6482
6692
|
if (!settingsMenu) return;
|
|
6483
6693
|
|
|
6694
|
+
// Accordion header click handlers
|
|
6695
|
+
settingsMenu.querySelectorAll('.uvf-accordion-header').forEach(header => {
|
|
6696
|
+
header.addEventListener('click', (e) => {
|
|
6697
|
+
e.preventDefault();
|
|
6698
|
+
e.stopPropagation();
|
|
6699
|
+
|
|
6700
|
+
const accordionItem = header.parentElement;
|
|
6701
|
+
const section = header.getAttribute('data-section');
|
|
6702
|
+
|
|
6703
|
+
if (accordionItem && section) {
|
|
6704
|
+
this.toggleAccordionSection(accordionItem, section);
|
|
6705
|
+
}
|
|
6706
|
+
});
|
|
6707
|
+
});
|
|
6708
|
+
|
|
6484
6709
|
// Speed options
|
|
6485
6710
|
settingsMenu.querySelectorAll('.speed-option').forEach(option => {
|
|
6486
6711
|
option.addEventListener('click', (e) => {
|
|
6487
6712
|
const speed = parseFloat((e.target as HTMLElement).dataset.speed || '1');
|
|
6488
6713
|
this.setPlaybackRateFromSettings(speed);
|
|
6489
|
-
this.
|
|
6714
|
+
this.updateAccordionAfterSelection('speed');
|
|
6490
6715
|
});
|
|
6491
6716
|
});
|
|
6492
6717
|
|
|
@@ -6495,7 +6720,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
6495
6720
|
option.addEventListener('click', (e) => {
|
|
6496
6721
|
const quality = (e.target as HTMLElement).dataset.quality || 'auto';
|
|
6497
6722
|
this.setQualityFromSettings(quality);
|
|
6498
|
-
this.
|
|
6723
|
+
this.updateAccordionAfterSelection('quality');
|
|
6499
6724
|
});
|
|
6500
6725
|
});
|
|
6501
6726
|
|
|
@@ -6504,10 +6729,47 @@ export class WebPlayer extends BasePlayer {
|
|
|
6504
6729
|
option.addEventListener('click', (e) => {
|
|
6505
6730
|
const subtitle = (e.target as HTMLElement).dataset.subtitle || 'off';
|
|
6506
6731
|
this.setSubtitle(subtitle);
|
|
6507
|
-
this.
|
|
6732
|
+
this.updateAccordionAfterSelection('subtitles');
|
|
6508
6733
|
});
|
|
6509
6734
|
});
|
|
6510
6735
|
}
|
|
6736
|
+
|
|
6737
|
+
/**
|
|
6738
|
+
* Toggle accordion section
|
|
6739
|
+
*/
|
|
6740
|
+
private toggleAccordionSection(accordionItem: Element, section: string): void {
|
|
6741
|
+
const isExpanded = accordionItem.classList.contains('expanded');
|
|
6742
|
+
|
|
6743
|
+
// If clicking the same section that's already expanded, just close it
|
|
6744
|
+
if (isExpanded) {
|
|
6745
|
+
accordionItem.classList.remove('expanded');
|
|
6746
|
+
return;
|
|
6747
|
+
}
|
|
6748
|
+
|
|
6749
|
+
// Otherwise, close all sections and open the clicked one
|
|
6750
|
+
const settingsMenu = document.getElementById('uvf-settings-menu');
|
|
6751
|
+
if (settingsMenu) {
|
|
6752
|
+
settingsMenu.querySelectorAll('.uvf-accordion-item.expanded').forEach(item => {
|
|
6753
|
+
item.classList.remove('expanded');
|
|
6754
|
+
});
|
|
6755
|
+
}
|
|
6756
|
+
|
|
6757
|
+
// Open the clicked section
|
|
6758
|
+
accordionItem.classList.add('expanded');
|
|
6759
|
+
}
|
|
6760
|
+
|
|
6761
|
+
/**
|
|
6762
|
+
* Update accordion after user makes a selection
|
|
6763
|
+
*/
|
|
6764
|
+
private updateAccordionAfterSelection(section: string): void {
|
|
6765
|
+
// Just update the current values without closing
|
|
6766
|
+
// User can manually close or it will close when they click outside
|
|
6767
|
+
setTimeout(() => {
|
|
6768
|
+
// Refresh the menu to update current values
|
|
6769
|
+
this.generateAccordionMenu();
|
|
6770
|
+
this.setupSettingsEventListeners();
|
|
6771
|
+
}, 100);
|
|
6772
|
+
}
|
|
6511
6773
|
|
|
6512
6774
|
/**
|
|
6513
6775
|
* Update active states in settings menu
|