myetv-player 1.5.0 → 1.6.0

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.
@@ -3323,7 +3323,7 @@ createControls() {
3323
3323
  <div class="settings-menu"></div>
3324
3324
  </div>
3325
3325
 
3326
- ${this.options.showQualitySelector && this.originalSources && this.originalSources.length > 1 ? `
3326
+ ${(this.options.showQualitySelector && this.originalSources && this.originalSources.length > 1) || this.options.adaptiveQualityControl ? `
3327
3327
  <div class="quality-control">
3328
3328
  <button class="control-btn quality-btn" data-tooltip="video_quality">
3329
3329
  <div class="quality-btn-text">
@@ -4115,6 +4115,11 @@ updateQualityDisplay() {
4115
4115
  }
4116
4116
 
4117
4117
  updateQualityButton() {
4118
+ if (this.isAdaptiveStream) {
4119
+ if (this.options.debug) console.log('🔒 Adaptive streaming active - quality button managed by streaming.js');
4120
+ return;
4121
+ }
4122
+
4118
4123
  const qualityBtn = this.controls?.querySelector('.quality-btn');
4119
4124
  if (!qualityBtn) return;
4120
4125
 
@@ -4161,6 +4166,11 @@ updateQualityMenu() {
4161
4166
  const qualityMenu = this.controls?.querySelector('.quality-menu');
4162
4167
  if (!qualityMenu) return;
4163
4168
 
4169
+ if (this.isAdaptiveStream) {
4170
+ if (this.options.debug) console.log('🔒 Adaptive streaming active - quality menu managed by streaming.js');
4171
+ return;
4172
+ }
4173
+
4164
4174
  let menuHTML = '';
4165
4175
 
4166
4176
  if (this.isAdaptiveStream && this.adaptiveQualities && this.adaptiveQualities.length > 0) {
@@ -6495,6 +6505,13 @@ async loadAdaptiveLibraries() {
6495
6505
 
6496
6506
  try {
6497
6507
 
6508
+ this.selectedQuality = 'auto';
6509
+ this.qualityEventsInitialized = false;
6510
+
6511
+ if (this.options.debug) {
6512
+ console.log('🔍 initializeDash - FORCED selectedQuality to:', this.selectedQuality);
6513
+ }
6514
+
6498
6515
  if (this.dashPlayer) {
6499
6516
  this.dashPlayer.destroy();
6500
6517
  }
@@ -6646,17 +6663,67 @@ disableDashTextTracks() {
6646
6663
  }
6647
6664
  }
6648
6665
 
6649
- updateAdaptiveQualities() {
6666
+ updateAdaptiveQualities() {
6650
6667
  this.adaptiveQualities = [];
6651
6668
 
6652
6669
  if (this.adaptiveStreamingType === 'dash' && this.dashPlayer) {
6653
- const bitrates = this.dashPlayer.getBitrateInfoListFor('video');
6654
- this.adaptiveQualities = bitrates.map((bitrate, index) => ({
6655
- index: index,
6656
- label: this.getQualityLabel(bitrate.height, bitrate.width),
6670
+ try {
6671
+
6672
+ const videoTracks = this.dashPlayer.getTracksFor('video');
6673
+
6674
+ if (this.options.debug) {
6675
+ console.log('✅ DASH getTracksFor result:', videoTracks);
6676
+ }
6677
+
6678
+ if (videoTracks && videoTracks.length > 0) {
6679
+
6680
+ const allQualities = [];
6681
+
6682
+ videoTracks.forEach((track, trackIndex) => {
6683
+ const bitrateList = track.bitrateList || [];
6684
+
6685
+ if (this.options.debug) {
6686
+ console.log(`✅ Track ${trackIndex} (${track.codec}):`, bitrateList);
6687
+ }
6688
+
6689
+ bitrateList.forEach((bitrate, index) => {
6690
+ allQualities.push({
6691
+ trackIndex: trackIndex,
6692
+ bitrateIndex: index,
6693
+ label: `${bitrate.height}p`,
6657
6694
  height: bitrate.height,
6658
- bandwidth: bitrate.bandwidth
6659
- }));
6695
+ width: bitrate.width,
6696
+ bandwidth: bitrate.bandwidth,
6697
+ codec: track.codec
6698
+ });
6699
+ });
6700
+ });
6701
+
6702
+ const uniqueHeights = [...new Set(allQualities.map(q => q.height))];
6703
+ uniqueHeights.sort((a, b) => b - a);
6704
+
6705
+ this.adaptiveQualities = uniqueHeights.map((height, index) => {
6706
+ const quality = allQualities.find(q => q.height === height);
6707
+ return {
6708
+ index: index,
6709
+ label: `${height}p`,
6710
+ height: height,
6711
+ trackIndex: quality.trackIndex,
6712
+ bitrateIndex: quality.bitrateIndex,
6713
+ bandwidth: quality.bandwidth,
6714
+ codec: quality.codec
6715
+ };
6716
+ });
6717
+
6718
+ if (this.options.debug) {
6719
+ console.log('✅ All DASH qualities merged:', this.adaptiveQualities);
6720
+ }
6721
+ }
6722
+ } catch (error) {
6723
+ if (this.options.debug) {
6724
+ console.error('❌ Error getting DASH qualities:', error);
6725
+ }
6726
+ }
6660
6727
  } else if (this.adaptiveStreamingType === 'hls' && this.hlsPlayer) {
6661
6728
  const levels = this.hlsPlayer.levels;
6662
6729
  this.adaptiveQualities = levels.map((level, index) => ({
@@ -6673,9 +6740,361 @@ disableDashTextTracks() {
6673
6740
 
6674
6741
  if (this.options.debug) {
6675
6742
  console.log('📡 Adaptive qualities available:', this.adaptiveQualities);
6743
+ console.log('📡 Selected quality mode:', this.selectedQuality);
6744
+ }
6745
+ }
6746
+
6747
+ updateAdaptiveQualityMenu() {
6748
+ const qualityMenu = this.controls?.querySelector('.quality-menu');
6749
+ if (!qualityMenu) {
6750
+ if (this.options.debug) console.log('❌ Quality menu not found in DOM');
6751
+ return;
6752
+ }
6753
+
6754
+ if (this.adaptiveQualities.length === 0) {
6755
+ if (this.options.debug) console.log('❌ No adaptive qualities to display');
6756
+ return;
6757
+ }
6758
+
6759
+ const isAutoActive = this.selectedQuality === 'auto';
6760
+ let menuHTML = `<div class="quality-option ${isAutoActive ? 'active' : ''}" data-quality="auto">Auto</div>`;
6761
+
6762
+ this.adaptiveQualities.forEach((quality) => {
6763
+ const isActive = this.selectedQuality === quality.height;
6764
+
6765
+ if (this.options.debug) {
6766
+ console.log('🔍 Quality item:', quality.label, 'height:', quality.height, 'active:', isActive);
6767
+ }
6768
+
6769
+ menuHTML += `<div class="quality-option ${isActive ? 'active' : ''}" data-quality="${quality.height}">
6770
+ ${quality.label}
6771
+ <span class="quality-playing" style="display: none; color: #4CAF50; margin-left: 8px; font-size: 0.85em;">● Playing</span>
6772
+ </div>`;
6773
+ });
6774
+
6775
+ qualityMenu.innerHTML = menuHTML;
6776
+
6777
+ if (this.options.debug) {
6778
+ console.log('✅ Quality menu populated with', this.adaptiveQualities.length, 'options');
6779
+ }
6780
+
6781
+ if (!this.qualityEventsInitialized) {
6782
+ this.bindAdaptiveQualityEvents();
6783
+ this.qualityEventsInitialized = true;
6784
+ }
6785
+
6786
+ this.updateAdaptiveQualityDisplay();
6787
+ }
6788
+
6789
+ updateAdaptiveQualityDisplay() {
6790
+ if (!this.dashPlayer && !this.hlsPlayer) return;
6791
+
6792
+ let currentHeight = null;
6793
+
6794
+ try {
6795
+ if (this.adaptiveStreamingType === 'dash' && this.dashPlayer) {
6796
+
6797
+ if (this.video && this.video.videoHeight) {
6798
+ currentHeight = this.video.videoHeight;
6799
+ }
6800
+
6801
+ if (this.options.debug) {
6802
+ console.log('📊 Current video height:', currentHeight, 'Selected mode:', this.selectedQuality);
6803
+ }
6804
+ } else if (this.adaptiveStreamingType === 'hls' && this.hlsPlayer) {
6805
+ const currentLevel = this.hlsPlayer.currentLevel;
6806
+ if (currentLevel >= 0 && this.hlsPlayer.levels[currentLevel]) {
6807
+ currentHeight = this.hlsPlayer.levels[currentLevel].height;
6808
+ }
6809
+ }
6810
+
6811
+ const qualityBtnText = this.controls?.querySelector('.quality-btn .selected-quality');
6812
+ if (qualityBtnText) {
6813
+ if (this.selectedQuality === 'auto') {
6814
+ qualityBtnText.textContent = 'Auto';
6815
+ } else {
6816
+ qualityBtnText.textContent = `${this.selectedQuality}p`;
6817
+ }
6818
+ }
6819
+
6820
+ const currentQualityText = this.controls?.querySelector('.quality-btn .current-quality');
6821
+ if (currentQualityText) {
6822
+ if (this.selectedQuality === 'auto' && currentHeight) {
6823
+ currentQualityText.textContent = `${currentHeight}p`;
6824
+ currentQualityText.style.display = 'block';
6825
+ } else {
6826
+ currentQualityText.textContent = '';
6827
+ currentQualityText.style.display = 'none';
6828
+ }
6829
+ }
6830
+
6831
+ const qualityMenu = this.controls?.querySelector('.quality-menu');
6832
+ if (qualityMenu) {
6833
+
6834
+ qualityMenu.querySelectorAll('.quality-option').forEach(opt => {
6835
+ opt.classList.remove('active');
6836
+ });
6837
+
6838
+ if (this.selectedQuality === 'auto') {
6839
+ const autoOption = qualityMenu.querySelector('[data-quality="auto"]');
6840
+ if (autoOption) autoOption.classList.add('active');
6841
+ } else {
6842
+ const selectedOption = qualityMenu.querySelector(`[data-quality="${this.selectedQuality}"]`);
6843
+ if (selectedOption) selectedOption.classList.add('active');
6844
+ }
6845
+
6846
+ qualityMenu.querySelectorAll('.quality-playing').forEach(el => {
6847
+ el.style.display = 'none';
6848
+ });
6849
+
6850
+ if (this.selectedQuality === 'auto' && currentHeight) {
6851
+ const playingOption = qualityMenu.querySelector(`[data-quality="${currentHeight}"] .quality-playing`);
6852
+ if (playingOption) {
6853
+ playingOption.style.display = 'inline';
6854
+ }
6855
+ }
6856
+ }
6857
+
6858
+ } catch (error) {
6859
+ if (this.options.debug) console.error('❌ Error updating quality display:', error);
6860
+ }
6861
+ }
6862
+
6863
+ updateQualityButtonText() {
6864
+ const qualityBtn = this.controls?.querySelector('.quality-btn .selected-quality');
6865
+ if (!qualityBtn) return;
6866
+
6867
+ if (this.selectedQuality === 'auto' || !this.selectedQuality) {
6868
+ qualityBtn.textContent = this.t('auto');
6869
+ } else {
6870
+ const quality = this.adaptiveQualities.find(q => q.index === parseInt(this.selectedQuality));
6871
+ qualityBtn.textContent = quality ? quality.label : 'Auto';
6872
+ }
6873
+ }
6874
+
6875
+ bindAdaptiveQualityEvents() {
6876
+ const qualityMenu = this.controls?.querySelector('.quality-menu');
6877
+ const qualityBtn = this.controls?.querySelector('.quality-btn');
6878
+
6879
+ if (!qualityMenu || !qualityBtn) return;
6880
+
6881
+ qualityBtn.addEventListener('click', (e) => {
6882
+ e.stopPropagation();
6883
+ qualityMenu.classList.toggle('active');
6884
+
6885
+ if (qualityMenu.classList.contains('active')) {
6886
+ this.updateAdaptiveQualityDisplay();
6887
+ }
6888
+ });
6889
+
6890
+ const closeMenuHandler = (e) => {
6891
+ if (!qualityBtn.contains(e.target) && !qualityMenu.contains(e.target)) {
6892
+ qualityMenu.classList.remove('active');
6893
+ }
6894
+ };
6895
+ document.addEventListener('click', closeMenuHandler);
6896
+
6897
+ qualityMenu.addEventListener('click', (e) => {
6898
+ const option = e.target.closest('.quality-option');
6899
+ if (!option) return;
6900
+
6901
+ e.stopPropagation();
6902
+
6903
+ const qualityData = option.getAttribute('data-quality');
6904
+
6905
+ if (this.options.debug) {
6906
+ console.log('🎬 Quality clicked - raw data:', qualityData, 'type:', typeof qualityData);
6907
+ }
6908
+
6909
+ if (qualityData === 'auto') {
6910
+
6911
+ this.selectedQuality = 'auto';
6912
+
6913
+ if (this.adaptiveStreamingType === 'dash' && this.dashPlayer) {
6914
+ this.dashPlayer.updateSettings({
6915
+ streaming: {
6916
+ abr: {
6917
+ autoSwitchBitrate: { video: true }
6918
+ }
6919
+ }
6920
+ });
6921
+ if (this.options.debug) console.log('✅ Auto quality enabled');
6922
+ } else if (this.adaptiveStreamingType === 'hls' && this.hlsPlayer) {
6923
+ this.hlsPlayer.currentLevel = -1;
6924
+ }
6925
+
6926
+ } else {
6927
+
6928
+ const selectedHeight = parseInt(qualityData, 10);
6929
+
6930
+ if (isNaN(selectedHeight)) {
6931
+ if (this.options.debug) console.error('❌ Invalid quality data:', qualityData);
6932
+ return;
6933
+ }
6934
+
6935
+ if (this.options.debug) {
6936
+ console.log('🎬 Setting manual quality to height:', selectedHeight);
6937
+ }
6938
+
6939
+ this.selectedQuality = selectedHeight;
6940
+
6941
+ if (this.adaptiveStreamingType === 'dash') {
6942
+ this.setDashQualityByHeight(selectedHeight);
6943
+ } else if (this.adaptiveStreamingType === 'hls') {
6944
+ const levelIndex = this.hlsPlayer.levels.findIndex(l => l.height === selectedHeight);
6945
+ if (levelIndex >= 0) {
6946
+ this.hlsPlayer.currentLevel = levelIndex;
6947
+ }
6676
6948
  }
6677
6949
  }
6678
6950
 
6951
+ this.updateAdaptiveQualityDisplay();
6952
+
6953
+ qualityMenu.classList.remove('active');
6954
+ });
6955
+
6956
+ if (this.options.debug) {
6957
+ console.log('✅ Quality events bound');
6958
+ }
6959
+ }
6960
+
6961
+ setDashQualityByHeight(targetHeight) {
6962
+ if (!this.dashPlayer) return;
6963
+
6964
+ try {
6965
+ const targetQuality = this.adaptiveQualities.find(q => q.height === targetHeight);
6966
+ if (!targetQuality) {
6967
+ if (this.options.debug) console.error('❌ Quality not found for height:', targetHeight);
6968
+ return;
6969
+ }
6970
+
6971
+ if (this.options.debug) {
6972
+ console.log('🎬 Setting quality:', targetQuality);
6973
+ }
6974
+
6975
+ this.dashPlayer.updateSettings({
6976
+ streaming: {
6977
+ abr: {
6978
+ autoSwitchBitrate: { video: false }
6979
+ }
6980
+ }
6981
+ });
6982
+
6983
+ const currentTrack = this.dashPlayer.getCurrentTrackFor('video');
6984
+
6985
+ if (!currentTrack) {
6986
+ if (this.options.debug) console.error('❌ No current video track');
6987
+ return;
6988
+ }
6989
+
6990
+ const allTracks = this.dashPlayer.getTracksFor('video');
6991
+ let targetTrack = null;
6992
+
6993
+ for (const track of allTracks) {
6994
+ if (track.bitrateList && track.bitrateList[targetQuality.bitrateIndex]) {
6995
+ const bitrate = track.bitrateList[targetQuality.bitrateIndex];
6996
+ if (bitrate.height === targetHeight) {
6997
+ targetTrack = track;
6998
+ break;
6999
+ }
7000
+ }
7001
+ }
7002
+
7003
+ if (!targetTrack) {
7004
+ if (this.options.debug) console.error('❌ Target track not found');
7005
+ return;
7006
+ }
7007
+
7008
+ if (currentTrack.index !== targetTrack.index) {
7009
+ this.dashPlayer.setCurrentTrack(targetTrack);
7010
+ if (this.options.debug) {
7011
+ console.log('✅ Switched to track:', targetTrack.index);
7012
+ }
7013
+ }
7014
+
7015
+ setTimeout(() => {
7016
+ try {
7017
+
7018
+ this.dashPlayer.updateSettings({
7019
+ streaming: {
7020
+ abr: {
7021
+ initialBitrate: { video: targetQuality.bandwidth / 1000 },
7022
+ maxBitrate: { video: targetQuality.bandwidth / 1000 },
7023
+ minBitrate: { video: targetQuality.bandwidth / 1000 }
7024
+ }
7025
+ }
7026
+ });
7027
+
7028
+ if (this.options.debug) {
7029
+ console.log('✅ Quality locked to:', targetHeight + 'p', 'bandwidth:', targetQuality.bandwidth);
7030
+ }
7031
+
7032
+ const qualityBtnText = this.controls?.querySelector('.quality-btn .selected-quality');
7033
+ if (qualityBtnText) {
7034
+ qualityBtnText.textContent = `${targetHeight}p`;
7035
+ }
7036
+
7037
+ const currentTime = this.video.currentTime;
7038
+ this.dashPlayer.seek(currentTime + 0.1);
7039
+ setTimeout(() => {
7040
+ this.dashPlayer.seek(currentTime);
7041
+ }, 100);
7042
+
7043
+ } catch (innerError) {
7044
+ if (this.options.debug) console.error('❌ Error setting quality:', innerError);
7045
+ }
7046
+ }, 100);
7047
+
7048
+ } catch (error) {
7049
+ if (this.options.debug) console.error('❌ Error in setDashQualityByHeight:', error);
7050
+ }
7051
+ }
7052
+
7053
+ setDashQuality(qualityIndex) {
7054
+ if (!this.dashPlayer) return;
7055
+
7056
+ try {
7057
+ const selectedQuality = this.adaptiveQualities[qualityIndex];
7058
+ if (!selectedQuality) {
7059
+ if (this.options.debug) console.error('❌ Quality not found at index:', qualityIndex);
7060
+ return;
7061
+ }
7062
+
7063
+ if (this.options.debug) {
7064
+ console.log('🎬 Setting DASH quality:', selectedQuality);
7065
+ }
7066
+
7067
+ this.dashPlayer.updateSettings({
7068
+ streaming: {
7069
+ abr: {
7070
+ autoSwitchBitrate: { video: false }
7071
+ }
7072
+ }
7073
+ });
7074
+
7075
+ setTimeout(() => {
7076
+ try {
7077
+ this.dashPlayer.setQualityFor('video', selectedQuality.bitrateIndex);
7078
+
7079
+ if (this.options.debug) {
7080
+ console.log('✅ DASH quality set to bitrateIndex:', selectedQuality.bitrateIndex, 'height:', selectedQuality.height);
7081
+ }
7082
+
7083
+ const qualityBtnText = this.controls?.querySelector('.quality-btn .selected-quality');
7084
+ if (qualityBtnText) {
7085
+ qualityBtnText.textContent = selectedQuality.label;
7086
+ }
7087
+
7088
+ } catch (innerError) {
7089
+ if (this.options.debug) console.error('❌ Error setting quality:', innerError);
7090
+ }
7091
+ }, 100);
7092
+
7093
+ } catch (error) {
7094
+ if (this.options.debug) console.error('❌ Error in setDashQuality:', error);
7095
+ }
7096
+ }
7097
+
6679
7098
  handleAdaptiveError(data) {
6680
7099
  if (this.options.debug) console.error('📡 Fatal adaptive streaming error:', data);
6681
7100
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "myetv-player",
3
- "version": "1.5.0",
4
- "description": "MYETV Video Player - Modular HTML5 video player with plugin support for YouTube, Vimeo, Twitch, Facebook, and streaming protocols (HLS/DASH)",
3
+ "version": "1.6.0",
4
+ "description": "MYETV Video Player - Modular HTML5 video player with plugin support for YouTube, Vimeo, Twitch, Facebook, Cloudflare Stream and streaming protocols (HLS/DASH)",
5
5
  "main": "dist/myetv-player.js",
6
6
  "files": [
7
7
  "dist/",
@@ -60,3 +60,4 @@
60
60
 
61
61
 
62
62
 
63
+