myetv-player 1.1.3 → 1.1.4
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.
- package/css/myetv-player.css +44 -0
- package/css/myetv-player.min.css +1 -1
- package/dist/myetv-player.js +122 -51
- package/dist/myetv-player.min.js +102 -43
- package/package.json +2 -1
- package/plugins/youtube/myetv-player-youtube-plugin.js +378 -130
- package/scss/_menus.scss +49 -0
- package/src/controls.js +122 -51
package/scss/_menus.scss
CHANGED
|
@@ -381,3 +381,52 @@
|
|
|
381
381
|
display: none !important;
|
|
382
382
|
}
|
|
383
383
|
}
|
|
384
|
+
// Expandable settings menu styles
|
|
385
|
+
.settings-expandable-wrapper {
|
|
386
|
+
position: relative;
|
|
387
|
+
display: block;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.settings-option.expandable-trigger {
|
|
391
|
+
display: flex;
|
|
392
|
+
justify-content: space-between;
|
|
393
|
+
align-items: center;
|
|
394
|
+
cursor: pointer;
|
|
395
|
+
font-size: 10px !important;
|
|
396
|
+
|
|
397
|
+
.settings-option-label {
|
|
398
|
+
font-size: 10px !important;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
.expand-arrow {
|
|
402
|
+
font-size: 8px;
|
|
403
|
+
transition: transform 0.2s ease;
|
|
404
|
+
margin-left: 8px;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.settings-expandable-content {
|
|
409
|
+
padding-left: 15px;
|
|
410
|
+
margin-top: 4px;
|
|
411
|
+
|
|
412
|
+
.settings-suboption {
|
|
413
|
+
padding: 6px 12px;
|
|
414
|
+
cursor: pointer;
|
|
415
|
+
color: white;
|
|
416
|
+
font-size: 10px;
|
|
417
|
+
white-space: normal;
|
|
418
|
+
word-wrap: break-word;
|
|
419
|
+
opacity: 0.8;
|
|
420
|
+
transition: opacity 0.2s;
|
|
421
|
+
|
|
422
|
+
&.active {
|
|
423
|
+
opacity: 1;
|
|
424
|
+
font-weight: bold;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
&:hover {
|
|
428
|
+
opacity: 1;
|
|
429
|
+
background: rgba(255, 255, 255, 0.1);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
package/src/controls.js
CHANGED
|
@@ -600,7 +600,9 @@ updateSettingsMenuVisibility() {
|
|
|
600
600
|
}
|
|
601
601
|
}
|
|
602
602
|
|
|
603
|
-
|
|
603
|
+
/**
|
|
604
|
+
* Populate settings menu with controls
|
|
605
|
+
*/
|
|
604
606
|
populateSettingsMenu() {
|
|
605
607
|
const settingsMenu = this.controls?.querySelector('.settings-menu');
|
|
606
608
|
if (!settingsMenu) return;
|
|
@@ -615,54 +617,104 @@ populateSettingsMenu() {
|
|
|
615
617
|
</div>`;
|
|
616
618
|
}
|
|
617
619
|
|
|
618
|
-
// Speed Control
|
|
620
|
+
// Speed Control - expandable
|
|
619
621
|
if (this.options.showSpeedControl) {
|
|
620
622
|
const speedLabel = this.t('playback_speed') || 'Playback Speed';
|
|
621
623
|
const currentSpeed = this.video ? this.video.playbackRate : 1;
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
<
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
<div class="settings-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
624
|
+
|
|
625
|
+
menuHTML += `
|
|
626
|
+
<div class="settings-expandable-wrapper">
|
|
627
|
+
<div class="settings-option expandable-trigger" data-action="speed-expand">
|
|
628
|
+
<span class="settings-option-label">${speedLabel}: ${currentSpeed}x</span>
|
|
629
|
+
<span class="expand-arrow">▼</span>
|
|
630
|
+
</div>
|
|
631
|
+
<div class="settings-expandable-content" style="display: none;">`;
|
|
632
|
+
|
|
633
|
+
const speeds = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
|
|
634
|
+
speeds.forEach(speed => {
|
|
635
|
+
const isActive = Math.abs(speed - currentSpeed) < 0.01;
|
|
636
|
+
menuHTML += `<div class="settings-suboption ${isActive ? 'active' : ''}" data-speed="${speed}">${speed}x</div>`;
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
menuHTML += `</div></div>`;
|
|
634
640
|
}
|
|
635
641
|
|
|
636
|
-
// Subtitles
|
|
642
|
+
// Subtitles - expandable
|
|
637
643
|
if (this.options.showSubtitles && this.textTracks && this.textTracks.length > 0) {
|
|
638
644
|
const subtitlesLabel = this.t('subtitles') || 'Subtitles';
|
|
639
645
|
const currentTrack = this.currentSubtitleTrack;
|
|
640
|
-
const currentLabel = this.subtitlesEnabled && currentTrack
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
<div class="settings-
|
|
649
|
-
${this.t('subtitlesoff') || 'Off'}
|
|
650
|
-
</div>`;
|
|
646
|
+
const currentLabel = this.subtitlesEnabled && currentTrack ? currentTrack.label : (this.t('subtitlesoff') || 'Off');
|
|
647
|
+
|
|
648
|
+
menuHTML += `
|
|
649
|
+
<div class="settings-expandable-wrapper">
|
|
650
|
+
<div class="settings-option expandable-trigger" data-action="subtitles-expand">
|
|
651
|
+
<span class="settings-option-label">${subtitlesLabel}: ${currentLabel}</span>
|
|
652
|
+
<span class="expand-arrow">▼</span>
|
|
653
|
+
</div>
|
|
654
|
+
<div class="settings-expandable-content" style="display: none;">`;
|
|
651
655
|
|
|
656
|
+
// Off option
|
|
657
|
+
menuHTML += `<div class="settings-suboption ${!this.subtitlesEnabled ? 'active' : ''}" data-track="off">${this.t('subtitlesoff') || 'Off'}</div>`;
|
|
658
|
+
|
|
659
|
+
// Subtitle tracks
|
|
652
660
|
this.textTracks.forEach((trackData, index) => {
|
|
653
661
|
const isActive = this.currentSubtitleTrack === trackData.track;
|
|
654
|
-
menuHTML += `<div class="settings-suboption ${isActive ? 'active' : ''}" data-track="${index}"
|
|
655
|
-
${trackData.label}
|
|
656
|
-
</div>`;
|
|
662
|
+
menuHTML += `<div class="settings-suboption ${isActive ? 'active' : ''}" data-track="${index}">${trackData.label}</div>`;
|
|
657
663
|
});
|
|
658
664
|
|
|
659
|
-
menuHTML +=
|
|
665
|
+
menuHTML += `</div></div>`;
|
|
660
666
|
}
|
|
661
667
|
|
|
662
668
|
settingsMenu.innerHTML = menuHTML;
|
|
669
|
+
|
|
670
|
+
// Add scrollbar if needed
|
|
671
|
+
this.addSettingsMenuScrollbar();
|
|
663
672
|
}
|
|
664
673
|
|
|
665
|
-
|
|
674
|
+
/**
|
|
675
|
+
* Add scrollbar to settings menu on mobile
|
|
676
|
+
*/
|
|
677
|
+
addSettingsMenuScrollbar() {
|
|
678
|
+
const settingsMenu = this.controls?.querySelector('.settings-menu');
|
|
679
|
+
if (!settingsMenu) return;
|
|
680
|
+
|
|
681
|
+
const playerHeight = this.container.offsetHeight;
|
|
682
|
+
const maxMenuHeight = playerHeight - 100;
|
|
683
|
+
|
|
684
|
+
settingsMenu.style.maxHeight = `${maxMenuHeight}px`;
|
|
685
|
+
settingsMenu.style.overflowY = 'auto';
|
|
686
|
+
settingsMenu.style.overflowX = 'hidden';
|
|
687
|
+
|
|
688
|
+
// Add scrollbar styling
|
|
689
|
+
if (!document.getElementById('player-settings-scrollbar-style')) {
|
|
690
|
+
const scrollbarStyle = document.createElement('style');
|
|
691
|
+
scrollbarStyle.id = 'player-settings-scrollbar-style';
|
|
692
|
+
scrollbarStyle.textContent = `
|
|
693
|
+
.settings-menu::-webkit-scrollbar {
|
|
694
|
+
width: 6px;
|
|
695
|
+
}
|
|
696
|
+
.settings-menu::-webkit-scrollbar-track {
|
|
697
|
+
background: rgba(255,255,255,0.05);
|
|
698
|
+
border-radius: 3px;
|
|
699
|
+
}
|
|
700
|
+
.settings-menu::-webkit-scrollbar-thumb {
|
|
701
|
+
background: rgba(255,255,255,0.3);
|
|
702
|
+
border-radius: 3px;
|
|
703
|
+
}
|
|
704
|
+
.settings-menu::-webkit-scrollbar-thumb:hover {
|
|
705
|
+
background: rgba(255,255,255,0.5);
|
|
706
|
+
}
|
|
707
|
+
`;
|
|
708
|
+
document.head.appendChild(scrollbarStyle);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
settingsMenu.style.scrollbarWidth = 'thin';
|
|
712
|
+
settingsMenu.style.scrollbarColor = 'rgba(255,255,255,0.3) transparent';
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* Bind settings menu events
|
|
717
|
+
*/
|
|
666
718
|
bindSettingsMenuEvents() {
|
|
667
719
|
const settingsMenu = this.controls?.querySelector('.settings-menu');
|
|
668
720
|
if (!settingsMenu) return;
|
|
@@ -670,7 +722,26 @@ bindSettingsMenuEvents() {
|
|
|
670
722
|
settingsMenu.addEventListener('click', (e) => {
|
|
671
723
|
e.stopPropagation();
|
|
672
724
|
|
|
673
|
-
// Handle
|
|
725
|
+
// Handle expandable triggers
|
|
726
|
+
if (e.target.classList.contains('expandable-trigger') || e.target.closest('.expandable-trigger')) {
|
|
727
|
+
const trigger = e.target.classList.contains('expandable-trigger') ? e.target : e.target.closest('.expandable-trigger');
|
|
728
|
+
const wrapper = trigger.closest('.settings-expandable-wrapper');
|
|
729
|
+
const content = wrapper.querySelector('.settings-expandable-content');
|
|
730
|
+
const arrow = trigger.querySelector('.expand-arrow');
|
|
731
|
+
|
|
732
|
+
const isExpanded = content.style.display !== 'none';
|
|
733
|
+
|
|
734
|
+
if (isExpanded) {
|
|
735
|
+
content.style.display = 'none';
|
|
736
|
+
arrow.style.transform = 'rotate(0deg)';
|
|
737
|
+
} else {
|
|
738
|
+
content.style.display = 'block';
|
|
739
|
+
arrow.style.transform = 'rotate(180deg)';
|
|
740
|
+
}
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
// Handle direct actions (like PiP)
|
|
674
745
|
if (e.target.classList.contains('settings-option') || e.target.closest('.settings-option')) {
|
|
675
746
|
const option = e.target.classList.contains('settings-option') ? e.target : e.target.closest('.settings-option');
|
|
676
747
|
const action = option.getAttribute('data-action');
|
|
@@ -683,32 +754,31 @@ bindSettingsMenuEvents() {
|
|
|
683
754
|
|
|
684
755
|
// Handle submenu actions
|
|
685
756
|
if (e.target.classList.contains('settings-suboption')) {
|
|
686
|
-
const
|
|
687
|
-
const
|
|
757
|
+
const wrapper = e.target.closest('.settings-expandable-wrapper');
|
|
758
|
+
const trigger = wrapper.querySelector('.expandable-trigger');
|
|
759
|
+
const action = trigger.getAttribute('data-action');
|
|
688
760
|
|
|
689
|
-
if (action === 'speed') {
|
|
761
|
+
if (action === 'speed-expand') {
|
|
690
762
|
const speed = parseFloat(e.target.getAttribute('data-speed'));
|
|
691
763
|
if (speed && speed > 0 && this.video && !this.isChangingQuality) {
|
|
692
764
|
this.video.playbackRate = speed;
|
|
693
765
|
|
|
694
766
|
// Update active states
|
|
695
|
-
|
|
696
|
-
opt.classList.remove('active');
|
|
697
|
-
});
|
|
767
|
+
wrapper.querySelectorAll('.settings-suboption').forEach(opt => opt.classList.remove('active'));
|
|
698
768
|
e.target.classList.add('active');
|
|
699
769
|
|
|
700
|
-
// Update
|
|
701
|
-
const
|
|
702
|
-
if (
|
|
770
|
+
// Update trigger text
|
|
771
|
+
const label = trigger.querySelector('.settings-option-label');
|
|
772
|
+
if (label) {
|
|
773
|
+
const speedLabel = this.t('playback_speed') || 'Playback Speed';
|
|
774
|
+
label.textContent = `${speedLabel}: ${speed}x`;
|
|
775
|
+
}
|
|
703
776
|
|
|
704
777
|
// Trigger event
|
|
705
778
|
this.triggerEvent('speedchange', { speed, previousSpeed: this.video.playbackRate });
|
|
706
779
|
}
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
else if (action === 'subtitles') {
|
|
780
|
+
} else if (action === 'subtitles-expand') {
|
|
710
781
|
const trackData = e.target.getAttribute('data-track');
|
|
711
|
-
|
|
712
782
|
if (trackData === 'off') {
|
|
713
783
|
this.disableSubtitles();
|
|
714
784
|
} else {
|
|
@@ -717,14 +787,15 @@ bindSettingsMenuEvents() {
|
|
|
717
787
|
}
|
|
718
788
|
|
|
719
789
|
// Update active states
|
|
720
|
-
|
|
721
|
-
opt.classList.remove('active');
|
|
722
|
-
});
|
|
790
|
+
wrapper.querySelectorAll('.settings-suboption').forEach(opt => opt.classList.remove('active'));
|
|
723
791
|
e.target.classList.add('active');
|
|
724
792
|
|
|
725
|
-
// Update
|
|
726
|
-
const
|
|
727
|
-
if (
|
|
793
|
+
// Update trigger text
|
|
794
|
+
const label = trigger.querySelector('.settings-option-label');
|
|
795
|
+
if (label) {
|
|
796
|
+
const subtitlesLabel = this.t('subtitles') || 'Subtitles';
|
|
797
|
+
label.textContent = `${subtitlesLabel}: ${e.target.textContent}`;
|
|
798
|
+
}
|
|
728
799
|
}
|
|
729
800
|
}
|
|
730
801
|
});
|