myetv-player 1.5.0 → 1.6.1
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/README.md +66 -1
- package/css/myetv-player.css +15 -1
- package/css/myetv-player.min.css +1 -1
- package/dist/myetv-player.js +590 -56
- package/dist/myetv-player.min.js +524 -30
- package/package.json +4 -2
- package/plugins/google-adsense-ads/README.md +230 -0
- package/plugins/google-adsense-ads/g-adsense-ads-plugin.js +75 -8
- package/plugins/google-ima-ads/README.md +258 -0
- package/plugins/google-ima-ads/g-ima-ads-plugin.js +2 -2
- package/plugins/iframe-ads/myetv-iframe-banner-ads.js +926 -0
- package/plugins/iframe-ads/readme.md +191 -0
- package/plugins/vast-vpaid-ads/README.md +146 -0
- package/plugins/youtube/myetv-player-youtube-plugin.js +72 -39
package/dist/myetv-player.js
CHANGED
|
@@ -27,7 +27,8 @@ class VideoPlayerI18n {
|
|
|
27
27
|
'playlist_prev': 'Indietro',
|
|
28
28
|
'settings_menu': 'Impostazioni',
|
|
29
29
|
'loading': 'Caricamento...',
|
|
30
|
-
'encoding_in_progress': 'Encoding in corso'
|
|
30
|
+
'encoding_in_progress': 'Encoding in corso',
|
|
31
|
+
'restart_video': 'Torna all\'inizio'
|
|
31
32
|
},
|
|
32
33
|
|
|
33
34
|
// English
|
|
@@ -51,7 +52,8 @@ class VideoPlayerI18n {
|
|
|
51
52
|
'playlist_prev': 'Previous',
|
|
52
53
|
'settings_menu': 'Settings',
|
|
53
54
|
'loading': 'Loading...',
|
|
54
|
-
'encoding_in_progress': 'Encoding in progress'
|
|
55
|
+
'encoding_in_progress': 'Encoding in progress',
|
|
56
|
+
'restart_video': 'Restart the video'
|
|
55
57
|
},
|
|
56
58
|
|
|
57
59
|
// Español
|
|
@@ -75,7 +77,8 @@ class VideoPlayerI18n {
|
|
|
75
77
|
'playlist_prev': 'Anterior',
|
|
76
78
|
'settings_menu': 'Configuración',
|
|
77
79
|
'loading': 'Cargando...',
|
|
78
|
-
'encoding_in_progress': 'Codificación en curso'
|
|
80
|
+
'encoding_in_progress': 'Codificación en curso',
|
|
81
|
+
'restart_video': 'Reiniciar el vídeo'
|
|
79
82
|
},
|
|
80
83
|
|
|
81
84
|
// Français
|
|
@@ -99,7 +102,8 @@ class VideoPlayerI18n {
|
|
|
99
102
|
'playlist_prev': 'Précédent',
|
|
100
103
|
'settings_menu': 'Paramètres',
|
|
101
104
|
'loading': 'Chargement...',
|
|
102
|
-
'encoding_in_progress': 'Encodage en cours'
|
|
105
|
+
'encoding_in_progress': 'Encodage en cours',
|
|
106
|
+
'restart_video': 'Redémarrer la vidéo'
|
|
103
107
|
},
|
|
104
108
|
|
|
105
109
|
// Deutsch
|
|
@@ -123,7 +127,8 @@ class VideoPlayerI18n {
|
|
|
123
127
|
'playlist_prev': 'Zurück',
|
|
124
128
|
'settings_menu': 'Einstellungen',
|
|
125
129
|
'loading': 'Laden...',
|
|
126
|
-
'encoding_in_progress': 'Kodierung läuft'
|
|
130
|
+
'encoding_in_progress': 'Kodierung läuft',
|
|
131
|
+
'restart_video': 'Video neu starten'
|
|
127
132
|
},
|
|
128
133
|
|
|
129
134
|
// Português
|
|
@@ -147,7 +152,8 @@ class VideoPlayerI18n {
|
|
|
147
152
|
'playlist_prev': 'Anterior',
|
|
148
153
|
'settings_menu': 'Configurações',
|
|
149
154
|
'loading': 'Carregando...',
|
|
150
|
-
'encoding_in_progress': 'Codificação em andamento'
|
|
155
|
+
'encoding_in_progress': 'Codificação em andamento',
|
|
156
|
+
'restart_video': 'Restart video'
|
|
151
157
|
},
|
|
152
158
|
|
|
153
159
|
// 中文
|
|
@@ -171,7 +177,8 @@ class VideoPlayerI18n {
|
|
|
171
177
|
'playlist_prev': '上一个',
|
|
172
178
|
'settings_menu': '设置',
|
|
173
179
|
'loading': '加载中...',
|
|
174
|
-
'encoding_in_progress': '编码中'
|
|
180
|
+
'encoding_in_progress': '编码中',
|
|
181
|
+
'restart_video': '重新开始视频'
|
|
175
182
|
},
|
|
176
183
|
|
|
177
184
|
// 日本語
|
|
@@ -195,7 +202,8 @@ class VideoPlayerI18n {
|
|
|
195
202
|
'playlist_prev': '前へ',
|
|
196
203
|
'settings_menu': '設定',
|
|
197
204
|
'loading': '読み込み中...',
|
|
198
|
-
'encoding_in_progress': 'エンコード中'
|
|
205
|
+
'encoding_in_progress': 'エンコード中',
|
|
206
|
+
'restart_video': 'ビデオを再開'
|
|
199
207
|
},
|
|
200
208
|
|
|
201
209
|
// Русский
|
|
@@ -219,7 +227,8 @@ class VideoPlayerI18n {
|
|
|
219
227
|
'playlist_prev': 'Назад',
|
|
220
228
|
'settings_menu': 'Настройки',
|
|
221
229
|
'loading': 'Загрузка...',
|
|
222
|
-
'encoding_in_progress': 'Кодирование'
|
|
230
|
+
'encoding_in_progress': 'Кодирование',
|
|
231
|
+
'restart_video': 'Перезапустить видео'
|
|
223
232
|
},
|
|
224
233
|
|
|
225
234
|
// العربية
|
|
@@ -243,7 +252,8 @@ class VideoPlayerI18n {
|
|
|
243
252
|
'playlist_prev': 'السابق',
|
|
244
253
|
'settings_menu': 'الإعدادات',
|
|
245
254
|
'loading': 'جاري التحميل...',
|
|
246
|
-
'encoding_in_progress': 'الترميز جارٍ'
|
|
255
|
+
'encoding_in_progress': 'الترميز جارٍ',
|
|
256
|
+
'restart_video': 'إعادة تشغيل الفيديو'
|
|
247
257
|
},
|
|
248
258
|
|
|
249
259
|
// 한국어 (Korean)
|
|
@@ -267,7 +277,8 @@ class VideoPlayerI18n {
|
|
|
267
277
|
'playlist_prev': '이전',
|
|
268
278
|
'settings_menu': '설정',
|
|
269
279
|
'loading': '로딩 중...',
|
|
270
|
-
'encoding_in_progress': '인코딩 진행 중'
|
|
280
|
+
'encoding_in_progress': '인코딩 진행 중',
|
|
281
|
+
'restart_video': 'Restart video'
|
|
271
282
|
},
|
|
272
283
|
|
|
273
284
|
// Polski
|
|
@@ -291,7 +302,8 @@ class VideoPlayerI18n {
|
|
|
291
302
|
'playlist_prev': 'Wstecz',
|
|
292
303
|
'settings_menu': 'Ustawienia',
|
|
293
304
|
'loading': 'Ładowanie...',
|
|
294
|
-
'encoding_in_progress': 'Kodowanie w toku'
|
|
305
|
+
'encoding_in_progress': 'Kodowanie w toku',
|
|
306
|
+
'restart_video': 'Restart video'
|
|
295
307
|
},
|
|
296
308
|
|
|
297
309
|
// Magyar
|
|
@@ -315,7 +327,8 @@ class VideoPlayerI18n {
|
|
|
315
327
|
'playlist_prev': 'Előző',
|
|
316
328
|
'settings_menu': 'Beállítások',
|
|
317
329
|
'loading': 'Betöltés...',
|
|
318
|
-
'encoding_in_progress': 'Kódolás folyamatban'
|
|
330
|
+
'encoding_in_progress': 'Kódolás folyamatban',
|
|
331
|
+
'restart_video': 'Restart video'
|
|
319
332
|
},
|
|
320
333
|
|
|
321
334
|
// Türkçe
|
|
@@ -339,7 +352,8 @@ class VideoPlayerI18n {
|
|
|
339
352
|
'playlist_prev': 'Önceki',
|
|
340
353
|
'settings_menu': 'Ayarlar',
|
|
341
354
|
'loading': 'Yükleniyor...',
|
|
342
|
-
'encoding_in_progress': 'Kodlama devam ediyor'
|
|
355
|
+
'encoding_in_progress': 'Kodlama devam ediyor',
|
|
356
|
+
'restart_video': 'Restart video'
|
|
343
357
|
},
|
|
344
358
|
|
|
345
359
|
// Nederlands
|
|
@@ -363,7 +377,8 @@ class VideoPlayerI18n {
|
|
|
363
377
|
'playlist_prev': 'Vorige',
|
|
364
378
|
'settings_menu': 'Instellingen',
|
|
365
379
|
'loading': 'Laden...',
|
|
366
|
-
'encoding_in_progress': 'Codering bezig'
|
|
380
|
+
'encoding_in_progress': 'Codering bezig',
|
|
381
|
+
'restart_video': 'Restart video'
|
|
367
382
|
},
|
|
368
383
|
|
|
369
384
|
// हिन्दी (Hindi)
|
|
@@ -387,7 +402,8 @@ class VideoPlayerI18n {
|
|
|
387
402
|
'playlist_prev': 'पिछला',
|
|
388
403
|
'settings_menu': 'सेटिंग्स',
|
|
389
404
|
'loading': 'लोड हो रहा है...',
|
|
390
|
-
'encoding_in_progress': 'एन्कोडिंग प्रगति में'
|
|
405
|
+
'encoding_in_progress': 'एन्कोडिंग प्रगति में',
|
|
406
|
+
'restart_video': 'Restart video'
|
|
391
407
|
},
|
|
392
408
|
|
|
393
409
|
// Svenska
|
|
@@ -411,7 +427,8 @@ class VideoPlayerI18n {
|
|
|
411
427
|
'playlist_prev': 'Föregående',
|
|
412
428
|
'settings_menu': 'Inställningar',
|
|
413
429
|
'loading': 'Laddar...',
|
|
414
|
-
'encoding_in_progress': 'Kodning pågår'
|
|
430
|
+
'encoding_in_progress': 'Kodning pågår',
|
|
431
|
+
'restart_video': 'Restart video'
|
|
415
432
|
},
|
|
416
433
|
|
|
417
434
|
// Bahasa Indonesia
|
|
@@ -435,7 +452,8 @@ class VideoPlayerI18n {
|
|
|
435
452
|
'playlist_prev': 'Sebelumnya',
|
|
436
453
|
'settings_menu': 'Pengaturan',
|
|
437
454
|
'loading': 'Memuat...',
|
|
438
|
-
'encoding_in_progress': 'Encoding sedang berlangsung'
|
|
455
|
+
'encoding_in_progress': 'Encoding sedang berlangsung',
|
|
456
|
+
'restart_video': 'Restart video'
|
|
439
457
|
}
|
|
440
458
|
};
|
|
441
459
|
|
|
@@ -565,7 +583,8 @@ try {
|
|
|
565
583
|
'brand_logo': 'Brand logo',
|
|
566
584
|
'settings_menu': 'Settings',
|
|
567
585
|
'loading': 'Loading...',
|
|
568
|
-
'encoding_in_progress': 'Encoding in progress'
|
|
586
|
+
'encoding_in_progress': 'Encoding in progress',
|
|
587
|
+
'restart_video': 'Restart video'
|
|
569
588
|
};
|
|
570
589
|
return fallback[key] || key;
|
|
571
590
|
},
|
|
@@ -629,6 +648,7 @@ constructor(videoElement, options = {}) {
|
|
|
629
648
|
}
|
|
630
649
|
|
|
631
650
|
this.options = {
|
|
651
|
+
playFromStartButton: false, // Enable play from start button (restart video)
|
|
632
652
|
showQualitySelector: true, // Enable quality selector button
|
|
633
653
|
showSpeedControl: true, // Enable speed control button
|
|
634
654
|
showFullscreen: true, // Enable fullscreen button
|
|
@@ -737,6 +757,7 @@ constructor(videoElement, options = {}) {
|
|
|
737
757
|
'played': [], // Fired when video starts playing
|
|
738
758
|
'paused': [], // Fired when video is paused
|
|
739
759
|
'ended': [], // Fired when video playback ends
|
|
760
|
+
'restarted': [], // Fired when video is restarted from beginning
|
|
740
761
|
|
|
741
762
|
// Playback state events
|
|
742
763
|
'playing': [], // Fired when video is actually playing (after buffering)
|
|
@@ -1454,6 +1475,7 @@ initializeElements() {
|
|
|
1454
1475
|
this.progressHandle = this.controls?.querySelector('.progress-handle');
|
|
1455
1476
|
this.seekTooltip = this.controls?.querySelector('.seek-tooltip');
|
|
1456
1477
|
|
|
1478
|
+
this.playFromStartBtn = this.controls?.querySelector('.play-from-start-btn');
|
|
1457
1479
|
this.playPauseBtn = this.controls?.querySelector('.play-pause-btn');
|
|
1458
1480
|
this.muteBtn = this.controls?.querySelector('.mute-btn');
|
|
1459
1481
|
this.fullscreenBtn = this.controls?.querySelector('.fullscreen-btn');
|
|
@@ -1559,6 +1581,51 @@ setupMenuToggles() {
|
|
|
1559
1581
|
}
|
|
1560
1582
|
}
|
|
1561
1583
|
|
|
1584
|
+
/**
|
|
1585
|
+
* Restart video from beginning - Works with HTML5 video and ALL plugins
|
|
1586
|
+
* @returns {this} Returns this for method chaining
|
|
1587
|
+
*/
|
|
1588
|
+
restartVideo() {
|
|
1589
|
+
if (!this.video) return this;
|
|
1590
|
+
|
|
1591
|
+
const previousTime = this.getCurrentTime();
|
|
1592
|
+
const wasPaused = this.isPaused();
|
|
1593
|
+
|
|
1594
|
+
// Set video to beginning (0 seconds)
|
|
1595
|
+
// This works for both HTML5 video and plugins
|
|
1596
|
+
this.video.currentTime = 0;
|
|
1597
|
+
|
|
1598
|
+
// Alternative: use seek method if available (for plugins)
|
|
1599
|
+
if (typeof this.seek === 'function') {
|
|
1600
|
+
this.seek(0);
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
// Auto-play after restart if video was playing
|
|
1604
|
+
if (!wasPaused) {
|
|
1605
|
+
// Use player's play method (works for HTML5 and plugins)
|
|
1606
|
+
if (typeof this.play === 'function') {
|
|
1607
|
+
this.play();
|
|
1608
|
+
} else {
|
|
1609
|
+
this.video.play().catch(error => {
|
|
1610
|
+
if (this.options.debug) console.warn('⚠️ Restart play failed:', error);
|
|
1611
|
+
});
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
if (this.options.debug) {
|
|
1616
|
+
console.log(`🔄 Video restarted from ${this.formatTime(previousTime)} to 0:00`);
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
// Trigger custom event
|
|
1620
|
+
this.triggerEvent('restarted', {
|
|
1621
|
+
previousTime: previousTime,
|
|
1622
|
+
duration: this.getDuration(),
|
|
1623
|
+
autoPlayed: !wasPaused
|
|
1624
|
+
});
|
|
1625
|
+
|
|
1626
|
+
return this;
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1562
1629
|
updateVolumeSliderVisual() {
|
|
1563
1630
|
if (!this.video || !this.container) return;
|
|
1564
1631
|
|
|
@@ -2762,6 +2829,14 @@ addEventListener(eventType, callback) {
|
|
|
2762
2829
|
bindEvents() {
|
|
2763
2830
|
if (this.video) {
|
|
2764
2831
|
|
|
2832
|
+
// Play from start button
|
|
2833
|
+
if (this.playFromStartBtn) {
|
|
2834
|
+
this.playFromStartBtn.addEventListener('click', (e) => {
|
|
2835
|
+
e.stopPropagation();
|
|
2836
|
+
this.restartVideo();
|
|
2837
|
+
});
|
|
2838
|
+
}
|
|
2839
|
+
|
|
2765
2840
|
// Playback events
|
|
2766
2841
|
this.video.addEventListener('playing', () => {
|
|
2767
2842
|
this.hideLoading();
|
|
@@ -3587,26 +3662,36 @@ createControls() {
|
|
|
3587
3662
|
|
|
3588
3663
|
<div class="controls-main">
|
|
3589
3664
|
<div class="controls-left">
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3665
|
+
${this.options.playFromStartButton ? `
|
|
3666
|
+
<button class="control-btn play-from-start-btn" data-tooltip="restart_video">
|
|
3667
|
+
<span class="icon restart-icon">
|
|
3668
|
+
<svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor">
|
|
3669
|
+
<path d="M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z"/>
|
|
3670
|
+
</svg>
|
|
3671
|
+
</span>
|
|
3672
|
+
</button>
|
|
3673
|
+
` : ''}
|
|
3594
3674
|
|
|
3595
|
-
|
|
3596
|
-
<span class="icon
|
|
3597
|
-
<span class="icon
|
|
3598
|
-
|
|
3675
|
+
<button class="control-btn play-pause-btn" data-tooltip="play_pause">
|
|
3676
|
+
<span class="icon play-icon"><svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor"><path d="M8 5v14l11-7z"/></svg></span>
|
|
3677
|
+
<span class="icon pause-icon hidden"><svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor"><path d="M6 4h4v16H6zm8 0h4v16h-4z"/></svg></span>
|
|
3678
|
+
</button>
|
|
3599
3679
|
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3680
|
+
<button class="control-btn mute-btn" data-tooltip="mute_unmute">
|
|
3681
|
+
<span class="icon volume-icon"><svg viewBox="0 0 16 16" width="16" height="16" fill="currentColor"><path d="M11.536 14.01A8.473 8.473 0 0 0 14.026 8a8.473 8.473 0 0 0-2.49-6.01l-.708.707A7.476 7.476 0 0 1 13.025 8c0 2.071-.84 3.946-2.197 5.303z"/><path d="M10.121 12.596A6.48 6.48 0 0 0 12.025 8a6.48 6.48 0 0 0-1.904-4.596l-.707.707A5.483 5.483 0 0 1 11.025 8a5.483 5.483 0 0 1-1.61 3.89z"/><path d="M10.025 8a4.486 4.486 0 0 1-1.318 3.182L8 10.475A3.489 3.489 0 0 0 9.025 8c0-.966-.392-1.841-1.025-2.475l.707-.707A4.486 4.486 0 0 1 10.025 8M7 4a.5.5 0 0 0-.812-.39L3.825 5.5H1.5A.5.5 0 0 0 1 6v4a.5.5 0 0 0 .5.5h2.325l2.363 1.89A.5.5 0 0 0 7 12z"/></svg></span>
|
|
3682
|
+
<span class="icon mute-icon hidden"><svg viewBox="0 0 16 16" width="16" height="16" fill="currentColor"><path d="M6.717 3.55A.5.5 0 0 1 7 4v8a.5.5 0 0 1-.812.39L3.825 10.5H1.5A.5.5 0 0 1 1 10V6a.5.5 0 0 1 .5-.5h2.325l2.363-1.89a.5.5 0 0 1 .529-.06m7.137 2.096a.5.5 0 0 1 0 .708L12.207 8l1.647 1.646a.5.5 0 0 1-.708.708L11.5 8.707l-1.646 1.647a.5.5 0 0 1-.708-.708L10.793 8 9.146 6.354a.5.5 0 1 1 .708-.708L11.5 7.293l1.646-1.647a.5.5 0 0 1 .708 0"/></svg></span>
|
|
3683
|
+
</button>
|
|
3603
3684
|
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3685
|
+
<div class="volume-container" data-mobile-slider="${this.options.volumeSlider}">
|
|
3686
|
+
<input type="range" class="volume-slider" min="0" max="100" value="100" data-tooltip="volume">
|
|
3687
|
+
</div>
|
|
3688
|
+
|
|
3689
|
+
<div class="time-display">
|
|
3690
|
+
<span class="current-time">0:00</span>
|
|
3691
|
+
<span>/</span>
|
|
3692
|
+
<span class="duration">0:00</span>
|
|
3693
|
+
</div>
|
|
3694
|
+
</div>
|
|
3610
3695
|
|
|
3611
3696
|
<div class="controls-right">
|
|
3612
3697
|
<button class="control-btn playlist-prev-btn" data-tooltip="prevvideo" style="display: none;">
|
|
@@ -3623,7 +3708,7 @@ createControls() {
|
|
|
3623
3708
|
<div class="settings-menu"></div>
|
|
3624
3709
|
</div>
|
|
3625
3710
|
|
|
3626
|
-
|
|
3711
|
+
${(this.options.showQualitySelector && this.originalSources && this.originalSources.length > 1) || this.options.adaptiveQualityControl ? `
|
|
3627
3712
|
<div class="quality-control">
|
|
3628
3713
|
<button class="control-btn quality-btn" data-tooltip="video_quality">
|
|
3629
3714
|
<div class="quality-btn-text">
|
|
@@ -4494,6 +4579,11 @@ updateQualityDisplay() {
|
|
|
4494
4579
|
}
|
|
4495
4580
|
|
|
4496
4581
|
updateQualityButton() {
|
|
4582
|
+
if (this.isAdaptiveStream) {
|
|
4583
|
+
if (this.options.debug) console.log('🔒 Adaptive streaming active - quality button managed by streaming.js');
|
|
4584
|
+
return;
|
|
4585
|
+
}
|
|
4586
|
+
|
|
4497
4587
|
const qualityBtn = this.controls?.querySelector('.quality-btn');
|
|
4498
4588
|
if (!qualityBtn) return;
|
|
4499
4589
|
|
|
@@ -4545,6 +4635,11 @@ updateQualityMenu() {
|
|
|
4545
4635
|
const qualityMenu = this.controls?.querySelector('.quality-menu');
|
|
4546
4636
|
if (!qualityMenu) return;
|
|
4547
4637
|
|
|
4638
|
+
if (this.isAdaptiveStream) {
|
|
4639
|
+
if (this.options.debug) console.log('🔒 Adaptive streaming active - quality menu managed by streaming.js');
|
|
4640
|
+
return;
|
|
4641
|
+
}
|
|
4642
|
+
|
|
4548
4643
|
let menuHTML = '';
|
|
4549
4644
|
|
|
4550
4645
|
// Check if adaptive streaming is active (HLS/DASH)
|
|
@@ -7220,6 +7315,16 @@ async loadAdaptiveLibraries() {
|
|
|
7220
7315
|
}
|
|
7221
7316
|
|
|
7222
7317
|
try {
|
|
7318
|
+
// Initialize quality selection to Auto BEFORE creating player
|
|
7319
|
+
|
|
7320
|
+
// FORCE Auto mode - always reset at initialization
|
|
7321
|
+
this.selectedQuality = 'auto';
|
|
7322
|
+
this.qualityEventsInitialized = false;
|
|
7323
|
+
|
|
7324
|
+
if (this.options.debug) {
|
|
7325
|
+
console.log('🔍 initializeDash - FORCED selectedQuality to:', this.selectedQuality);
|
|
7326
|
+
}
|
|
7327
|
+
|
|
7223
7328
|
// Destroy existing DASH player
|
|
7224
7329
|
if (this.dashPlayer) {
|
|
7225
7330
|
this.dashPlayer.destroy();
|
|
@@ -7384,35 +7489,464 @@ disableDashTextTracks() {
|
|
|
7384
7489
|
}
|
|
7385
7490
|
}
|
|
7386
7491
|
|
|
7387
|
-
|
|
7388
|
-
|
|
7492
|
+
updateAdaptiveQualities() {
|
|
7493
|
+
this.adaptiveQualities = [];
|
|
7494
|
+
|
|
7495
|
+
if (this.adaptiveStreamingType === 'dash' && this.dashPlayer) {
|
|
7496
|
+
try {
|
|
7497
|
+
// dash.js 5.x - Get ALL video tracks
|
|
7498
|
+
const videoTracks = this.dashPlayer.getTracksFor('video');
|
|
7499
|
+
|
|
7500
|
+
if (this.options.debug) {
|
|
7501
|
+
console.log('✅ DASH getTracksFor result:', videoTracks);
|
|
7502
|
+
}
|
|
7503
|
+
|
|
7504
|
+
if (videoTracks && videoTracks.length > 0) {
|
|
7505
|
+
// Collect qualities from ALL video tracks
|
|
7506
|
+
const allQualities = [];
|
|
7389
7507
|
|
|
7508
|
+
videoTracks.forEach((track, trackIndex) => {
|
|
7509
|
+
const bitrateList = track.bitrateList || [];
|
|
7510
|
+
|
|
7511
|
+
if (this.options.debug) {
|
|
7512
|
+
console.log(`✅ Track ${trackIndex} (${track.codec}):`, bitrateList);
|
|
7513
|
+
}
|
|
7514
|
+
|
|
7515
|
+
bitrateList.forEach((bitrate, index) => {
|
|
7516
|
+
allQualities.push({
|
|
7517
|
+
trackIndex: trackIndex,
|
|
7518
|
+
bitrateIndex: index,
|
|
7519
|
+
label: `${bitrate.height}p`,
|
|
7520
|
+
height: bitrate.height,
|
|
7521
|
+
width: bitrate.width,
|
|
7522
|
+
bandwidth: bitrate.bandwidth,
|
|
7523
|
+
codec: track.codec
|
|
7524
|
+
});
|
|
7525
|
+
});
|
|
7526
|
+
});
|
|
7527
|
+
|
|
7528
|
+
// Sort by height (descending) and remove duplicates
|
|
7529
|
+
const uniqueHeights = [...new Set(allQualities.map(q => q.height))];
|
|
7530
|
+
uniqueHeights.sort((a, b) => b - a);
|
|
7531
|
+
|
|
7532
|
+
this.adaptiveQualities = uniqueHeights.map((height, index) => {
|
|
7533
|
+
const quality = allQualities.find(q => q.height === height);
|
|
7534
|
+
return {
|
|
7535
|
+
index: index,
|
|
7536
|
+
label: `${height}p`,
|
|
7537
|
+
height: height,
|
|
7538
|
+
trackIndex: quality.trackIndex,
|
|
7539
|
+
bitrateIndex: quality.bitrateIndex,
|
|
7540
|
+
bandwidth: quality.bandwidth,
|
|
7541
|
+
codec: quality.codec
|
|
7542
|
+
};
|
|
7543
|
+
});
|
|
7544
|
+
|
|
7545
|
+
if (this.options.debug) {
|
|
7546
|
+
console.log('✅ All DASH qualities merged:', this.adaptiveQualities);
|
|
7547
|
+
}
|
|
7548
|
+
}
|
|
7549
|
+
} catch (error) {
|
|
7550
|
+
if (this.options.debug) {
|
|
7551
|
+
console.error('❌ Error getting DASH qualities:', error);
|
|
7552
|
+
}
|
|
7553
|
+
}
|
|
7554
|
+
} else if (this.adaptiveStreamingType === 'hls' && this.hlsPlayer) {
|
|
7555
|
+
const levels = this.hlsPlayer.levels;
|
|
7556
|
+
this.adaptiveQualities = levels.map((level, index) => ({
|
|
7557
|
+
index: index,
|
|
7558
|
+
label: this.getQualityLabel(level.height, level.width),
|
|
7559
|
+
height: level.height,
|
|
7560
|
+
bandwidth: level.bitrate
|
|
7561
|
+
}));
|
|
7562
|
+
}
|
|
7563
|
+
|
|
7564
|
+
if (this.options.adaptiveQualityControl) {
|
|
7565
|
+
this.updateAdaptiveQualityMenu();
|
|
7566
|
+
}
|
|
7567
|
+
|
|
7568
|
+
if (this.options.debug) {
|
|
7569
|
+
console.log('📡 Adaptive qualities available:', this.adaptiveQualities);
|
|
7570
|
+
console.log('📡 Selected quality mode:', this.selectedQuality);
|
|
7571
|
+
}
|
|
7572
|
+
}
|
|
7573
|
+
|
|
7574
|
+
updateAdaptiveQualityMenu() {
|
|
7575
|
+
const qualityMenu = this.controls?.querySelector('.quality-menu');
|
|
7576
|
+
if (!qualityMenu) {
|
|
7577
|
+
if (this.options.debug) console.log('❌ Quality menu not found in DOM');
|
|
7578
|
+
return;
|
|
7579
|
+
}
|
|
7580
|
+
|
|
7581
|
+
if (this.adaptiveQualities.length === 0) {
|
|
7582
|
+
if (this.options.debug) console.log('❌ No adaptive qualities to display');
|
|
7583
|
+
return;
|
|
7584
|
+
}
|
|
7585
|
+
|
|
7586
|
+
// Generate menu HTML with "Auto" option
|
|
7587
|
+
const isAutoActive = this.selectedQuality === 'auto';
|
|
7588
|
+
let menuHTML = `<div class="quality-option ${isAutoActive ? 'active' : ''}" data-quality="auto">Auto</div>`;
|
|
7589
|
+
|
|
7590
|
+
// Add all quality options
|
|
7591
|
+
this.adaptiveQualities.forEach((quality) => {
|
|
7592
|
+
const isActive = this.selectedQuality === quality.height;
|
|
7593
|
+
|
|
7594
|
+
if (this.options.debug) {
|
|
7595
|
+
console.log('🔍 Quality item:', quality.label, 'height:', quality.height, 'active:', isActive);
|
|
7596
|
+
}
|
|
7597
|
+
|
|
7598
|
+
menuHTML += `<div class="quality-option ${isActive ? 'active' : ''}" data-quality="${quality.height}">
|
|
7599
|
+
${quality.label}
|
|
7600
|
+
<span class="quality-playing" style="display: none; color: #4CAF50; margin-left: 8px; font-size: 0.85em;">● Playing</span>
|
|
7601
|
+
</div>`;
|
|
7602
|
+
});
|
|
7603
|
+
|
|
7604
|
+
qualityMenu.innerHTML = menuHTML;
|
|
7605
|
+
|
|
7606
|
+
if (this.options.debug) {
|
|
7607
|
+
console.log('✅ Quality menu populated with', this.adaptiveQualities.length, 'options');
|
|
7608
|
+
}
|
|
7609
|
+
|
|
7610
|
+
// Bind events ONCE
|
|
7611
|
+
if (!this.qualityEventsInitialized) {
|
|
7612
|
+
this.bindAdaptiveQualityEvents();
|
|
7613
|
+
this.qualityEventsInitialized = true;
|
|
7614
|
+
}
|
|
7615
|
+
|
|
7616
|
+
// Update display
|
|
7617
|
+
this.updateAdaptiveQualityDisplay();
|
|
7618
|
+
}
|
|
7619
|
+
|
|
7620
|
+
updateAdaptiveQualityDisplay() {
|
|
7621
|
+
if (!this.dashPlayer && !this.hlsPlayer) return;
|
|
7622
|
+
|
|
7623
|
+
let currentHeight = null;
|
|
7624
|
+
|
|
7625
|
+
try {
|
|
7390
7626
|
if (this.adaptiveStreamingType === 'dash' && this.dashPlayer) {
|
|
7391
|
-
|
|
7392
|
-
this.
|
|
7393
|
-
|
|
7394
|
-
|
|
7395
|
-
|
|
7396
|
-
|
|
7397
|
-
|
|
7627
|
+
// Get video element to check actual resolution
|
|
7628
|
+
if (this.video && this.video.videoHeight) {
|
|
7629
|
+
currentHeight = this.video.videoHeight;
|
|
7630
|
+
}
|
|
7631
|
+
|
|
7632
|
+
if (this.options.debug) {
|
|
7633
|
+
console.log('📊 Current video height:', currentHeight, 'Selected mode:', this.selectedQuality);
|
|
7634
|
+
}
|
|
7398
7635
|
} else if (this.adaptiveStreamingType === 'hls' && this.hlsPlayer) {
|
|
7399
|
-
const
|
|
7400
|
-
this.
|
|
7401
|
-
|
|
7402
|
-
|
|
7403
|
-
|
|
7404
|
-
|
|
7405
|
-
|
|
7636
|
+
const currentLevel = this.hlsPlayer.currentLevel;
|
|
7637
|
+
if (currentLevel >= 0 && this.hlsPlayer.levels[currentLevel]) {
|
|
7638
|
+
currentHeight = this.hlsPlayer.levels[currentLevel].height;
|
|
7639
|
+
}
|
|
7640
|
+
}
|
|
7641
|
+
|
|
7642
|
+
// Update button text (top text)
|
|
7643
|
+
const qualityBtnText = this.controls?.querySelector('.quality-btn .selected-quality');
|
|
7644
|
+
if (qualityBtnText) {
|
|
7645
|
+
if (this.selectedQuality === 'auto') {
|
|
7646
|
+
qualityBtnText.textContent = 'Auto';
|
|
7647
|
+
} else {
|
|
7648
|
+
qualityBtnText.textContent = `${this.selectedQuality}p`;
|
|
7649
|
+
}
|
|
7650
|
+
}
|
|
7651
|
+
|
|
7652
|
+
// Update current quality display (bottom text) - ONLY in Auto mode
|
|
7653
|
+
const currentQualityText = this.controls?.querySelector('.quality-btn .current-quality');
|
|
7654
|
+
if (currentQualityText) {
|
|
7655
|
+
if (this.selectedQuality === 'auto' && currentHeight) {
|
|
7656
|
+
currentQualityText.textContent = `${currentHeight}p`;
|
|
7657
|
+
currentQualityText.style.display = 'block';
|
|
7658
|
+
} else {
|
|
7659
|
+
currentQualityText.textContent = '';
|
|
7660
|
+
currentQualityText.style.display = 'none';
|
|
7661
|
+
}
|
|
7662
|
+
}
|
|
7663
|
+
|
|
7664
|
+
// Update menu active states
|
|
7665
|
+
const qualityMenu = this.controls?.querySelector('.quality-menu');
|
|
7666
|
+
if (qualityMenu) {
|
|
7667
|
+
// Remove all active states
|
|
7668
|
+
qualityMenu.querySelectorAll('.quality-option').forEach(opt => {
|
|
7669
|
+
opt.classList.remove('active');
|
|
7670
|
+
});
|
|
7671
|
+
|
|
7672
|
+
// Set active based on selection
|
|
7673
|
+
if (this.selectedQuality === 'auto') {
|
|
7674
|
+
const autoOption = qualityMenu.querySelector('[data-quality="auto"]');
|
|
7675
|
+
if (autoOption) autoOption.classList.add('active');
|
|
7676
|
+
} else {
|
|
7677
|
+
const selectedOption = qualityMenu.querySelector(`[data-quality="${this.selectedQuality}"]`);
|
|
7678
|
+
if (selectedOption) selectedOption.classList.add('active');
|
|
7679
|
+
}
|
|
7680
|
+
|
|
7681
|
+
// Hide all playing indicators
|
|
7682
|
+
qualityMenu.querySelectorAll('.quality-playing').forEach(el => {
|
|
7683
|
+
el.style.display = 'none';
|
|
7684
|
+
});
|
|
7685
|
+
|
|
7686
|
+
// Show playing indicator only in Auto mode
|
|
7687
|
+
if (this.selectedQuality === 'auto' && currentHeight) {
|
|
7688
|
+
const playingOption = qualityMenu.querySelector(`[data-quality="${currentHeight}"] .quality-playing`);
|
|
7689
|
+
if (playingOption) {
|
|
7690
|
+
playingOption.style.display = 'inline';
|
|
7691
|
+
}
|
|
7692
|
+
}
|
|
7693
|
+
}
|
|
7694
|
+
|
|
7695
|
+
} catch (error) {
|
|
7696
|
+
if (this.options.debug) console.error('❌ Error updating quality display:', error);
|
|
7697
|
+
}
|
|
7698
|
+
}
|
|
7699
|
+
|
|
7700
|
+
updateQualityButtonText() {
|
|
7701
|
+
const qualityBtn = this.controls?.querySelector('.quality-btn .selected-quality');
|
|
7702
|
+
if (!qualityBtn) return;
|
|
7703
|
+
|
|
7704
|
+
if (this.selectedQuality === 'auto' || !this.selectedQuality) {
|
|
7705
|
+
qualityBtn.textContent = this.t('auto');
|
|
7706
|
+
} else {
|
|
7707
|
+
const quality = this.adaptiveQualities.find(q => q.index === parseInt(this.selectedQuality));
|
|
7708
|
+
qualityBtn.textContent = quality ? quality.label : 'Auto';
|
|
7709
|
+
}
|
|
7710
|
+
}
|
|
7711
|
+
|
|
7712
|
+
bindAdaptiveQualityEvents() {
|
|
7713
|
+
const qualityMenu = this.controls?.querySelector('.quality-menu');
|
|
7714
|
+
const qualityBtn = this.controls?.querySelector('.quality-btn');
|
|
7715
|
+
|
|
7716
|
+
if (!qualityMenu || !qualityBtn) return;
|
|
7717
|
+
|
|
7718
|
+
// Toggle menu
|
|
7719
|
+
qualityBtn.addEventListener('click', (e) => {
|
|
7720
|
+
e.stopPropagation();
|
|
7721
|
+
qualityMenu.classList.toggle('active');
|
|
7722
|
+
|
|
7723
|
+
// Update display when opening
|
|
7724
|
+
if (qualityMenu.classList.contains('active')) {
|
|
7725
|
+
this.updateAdaptiveQualityDisplay();
|
|
7406
7726
|
}
|
|
7727
|
+
});
|
|
7407
7728
|
|
|
7408
|
-
|
|
7409
|
-
|
|
7729
|
+
// Close menu on outside click
|
|
7730
|
+
const closeMenuHandler = (e) => {
|
|
7731
|
+
if (!qualityBtn.contains(e.target) && !qualityMenu.contains(e.target)) {
|
|
7732
|
+
qualityMenu.classList.remove('active');
|
|
7410
7733
|
}
|
|
7734
|
+
};
|
|
7735
|
+
document.addEventListener('click', closeMenuHandler);
|
|
7736
|
+
|
|
7737
|
+
// Handle quality selection
|
|
7738
|
+
qualityMenu.addEventListener('click', (e) => {
|
|
7739
|
+
const option = e.target.closest('.quality-option');
|
|
7740
|
+
if (!option) return;
|
|
7741
|
+
|
|
7742
|
+
e.stopPropagation();
|
|
7743
|
+
|
|
7744
|
+
const qualityData = option.getAttribute('data-quality');
|
|
7411
7745
|
|
|
7412
7746
|
if (this.options.debug) {
|
|
7413
|
-
console.log('
|
|
7747
|
+
console.log('🎬 Quality clicked - raw data:', qualityData, 'type:', typeof qualityData);
|
|
7414
7748
|
}
|
|
7749
|
+
|
|
7750
|
+
if (qualityData === 'auto') {
|
|
7751
|
+
// Enable auto mode
|
|
7752
|
+
this.selectedQuality = 'auto';
|
|
7753
|
+
|
|
7754
|
+
if (this.adaptiveStreamingType === 'dash' && this.dashPlayer) {
|
|
7755
|
+
this.dashPlayer.updateSettings({
|
|
7756
|
+
streaming: {
|
|
7757
|
+
abr: {
|
|
7758
|
+
autoSwitchBitrate: { video: true }
|
|
7759
|
+
}
|
|
7760
|
+
}
|
|
7761
|
+
});
|
|
7762
|
+
if (this.options.debug) console.log('✅ Auto quality enabled');
|
|
7763
|
+
} else if (this.adaptiveStreamingType === 'hls' && this.hlsPlayer) {
|
|
7764
|
+
this.hlsPlayer.currentLevel = -1;
|
|
7765
|
+
}
|
|
7766
|
+
|
|
7767
|
+
} else {
|
|
7768
|
+
// Manual quality selection
|
|
7769
|
+
const selectedHeight = parseInt(qualityData, 10);
|
|
7770
|
+
|
|
7771
|
+
if (isNaN(selectedHeight)) {
|
|
7772
|
+
if (this.options.debug) console.error('❌ Invalid quality data:', qualityData);
|
|
7773
|
+
return;
|
|
7774
|
+
}
|
|
7775
|
+
|
|
7776
|
+
if (this.options.debug) {
|
|
7777
|
+
console.log('🎬 Setting manual quality to height:', selectedHeight);
|
|
7778
|
+
}
|
|
7779
|
+
|
|
7780
|
+
this.selectedQuality = selectedHeight;
|
|
7781
|
+
|
|
7782
|
+
if (this.adaptiveStreamingType === 'dash') {
|
|
7783
|
+
this.setDashQualityByHeight(selectedHeight);
|
|
7784
|
+
} else if (this.adaptiveStreamingType === 'hls') {
|
|
7785
|
+
const levelIndex = this.hlsPlayer.levels.findIndex(l => l.height === selectedHeight);
|
|
7786
|
+
if (levelIndex >= 0) {
|
|
7787
|
+
this.hlsPlayer.currentLevel = levelIndex;
|
|
7788
|
+
}
|
|
7789
|
+
}
|
|
7790
|
+
}
|
|
7791
|
+
|
|
7792
|
+
// Update display immediately
|
|
7793
|
+
this.updateAdaptiveQualityDisplay();
|
|
7794
|
+
|
|
7795
|
+
// Close menu
|
|
7796
|
+
qualityMenu.classList.remove('active');
|
|
7797
|
+
});
|
|
7798
|
+
|
|
7799
|
+
if (this.options.debug) {
|
|
7800
|
+
console.log('✅ Quality events bound');
|
|
7415
7801
|
}
|
|
7802
|
+
}
|
|
7803
|
+
|
|
7804
|
+
setDashQualityByHeight(targetHeight) {
|
|
7805
|
+
if (!this.dashPlayer) return;
|
|
7806
|
+
|
|
7807
|
+
try {
|
|
7808
|
+
const targetQuality = this.adaptiveQualities.find(q => q.height === targetHeight);
|
|
7809
|
+
if (!targetQuality) {
|
|
7810
|
+
if (this.options.debug) console.error('❌ Quality not found for height:', targetHeight);
|
|
7811
|
+
return;
|
|
7812
|
+
}
|
|
7813
|
+
|
|
7814
|
+
if (this.options.debug) {
|
|
7815
|
+
console.log('🎬 Setting quality:', targetQuality);
|
|
7816
|
+
}
|
|
7817
|
+
|
|
7818
|
+
// Disable auto quality
|
|
7819
|
+
this.dashPlayer.updateSettings({
|
|
7820
|
+
streaming: {
|
|
7821
|
+
abr: {
|
|
7822
|
+
autoSwitchBitrate: { video: false }
|
|
7823
|
+
}
|
|
7824
|
+
}
|
|
7825
|
+
});
|
|
7826
|
+
|
|
7827
|
+
// Get current video track
|
|
7828
|
+
const currentTrack = this.dashPlayer.getCurrentTrackFor('video');
|
|
7829
|
+
|
|
7830
|
+
if (!currentTrack) {
|
|
7831
|
+
if (this.options.debug) console.error('❌ No current video track');
|
|
7832
|
+
return;
|
|
7833
|
+
}
|
|
7834
|
+
|
|
7835
|
+
// Find the correct track for this quality
|
|
7836
|
+
const allTracks = this.dashPlayer.getTracksFor('video');
|
|
7837
|
+
let targetTrack = null;
|
|
7838
|
+
|
|
7839
|
+
for (const track of allTracks) {
|
|
7840
|
+
if (track.bitrateList && track.bitrateList[targetQuality.bitrateIndex]) {
|
|
7841
|
+
const bitrate = track.bitrateList[targetQuality.bitrateIndex];
|
|
7842
|
+
if (bitrate.height === targetHeight) {
|
|
7843
|
+
targetTrack = track;
|
|
7844
|
+
break;
|
|
7845
|
+
}
|
|
7846
|
+
}
|
|
7847
|
+
}
|
|
7848
|
+
|
|
7849
|
+
if (!targetTrack) {
|
|
7850
|
+
if (this.options.debug) console.error('❌ Target track not found');
|
|
7851
|
+
return;
|
|
7852
|
+
}
|
|
7853
|
+
|
|
7854
|
+
// Switch track if different
|
|
7855
|
+
if (currentTrack.index !== targetTrack.index) {
|
|
7856
|
+
this.dashPlayer.setCurrentTrack(targetTrack);
|
|
7857
|
+
if (this.options.debug) {
|
|
7858
|
+
console.log('✅ Switched to track:', targetTrack.index);
|
|
7859
|
+
}
|
|
7860
|
+
}
|
|
7861
|
+
|
|
7862
|
+
// Force quality on current track
|
|
7863
|
+
setTimeout(() => {
|
|
7864
|
+
try {
|
|
7865
|
+
// Use the MediaPlayer API to set quality
|
|
7866
|
+
this.dashPlayer.updateSettings({
|
|
7867
|
+
streaming: {
|
|
7868
|
+
abr: {
|
|
7869
|
+
initialBitrate: { video: targetQuality.bandwidth / 1000 },
|
|
7870
|
+
maxBitrate: { video: targetQuality.bandwidth / 1000 },
|
|
7871
|
+
minBitrate: { video: targetQuality.bandwidth / 1000 }
|
|
7872
|
+
}
|
|
7873
|
+
}
|
|
7874
|
+
});
|
|
7875
|
+
|
|
7876
|
+
if (this.options.debug) {
|
|
7877
|
+
console.log('✅ Quality locked to:', targetHeight + 'p', 'bandwidth:', targetQuality.bandwidth);
|
|
7878
|
+
}
|
|
7879
|
+
|
|
7880
|
+
// Update button text immediately
|
|
7881
|
+
const qualityBtnText = this.controls?.querySelector('.quality-btn .selected-quality');
|
|
7882
|
+
if (qualityBtnText) {
|
|
7883
|
+
qualityBtnText.textContent = `${targetHeight}p`;
|
|
7884
|
+
}
|
|
7885
|
+
|
|
7886
|
+
// Force reload of segments at new quality
|
|
7887
|
+
const currentTime = this.video.currentTime;
|
|
7888
|
+
this.dashPlayer.seek(currentTime + 0.1);
|
|
7889
|
+
setTimeout(() => {
|
|
7890
|
+
this.dashPlayer.seek(currentTime);
|
|
7891
|
+
}, 100);
|
|
7892
|
+
|
|
7893
|
+
} catch (innerError) {
|
|
7894
|
+
if (this.options.debug) console.error('❌ Error setting quality:', innerError);
|
|
7895
|
+
}
|
|
7896
|
+
}, 100);
|
|
7897
|
+
|
|
7898
|
+
} catch (error) {
|
|
7899
|
+
if (this.options.debug) console.error('❌ Error in setDashQualityByHeight:', error);
|
|
7900
|
+
}
|
|
7901
|
+
}
|
|
7902
|
+
|
|
7903
|
+
setDashQuality(qualityIndex) {
|
|
7904
|
+
if (!this.dashPlayer) return;
|
|
7905
|
+
|
|
7906
|
+
try {
|
|
7907
|
+
const selectedQuality = this.adaptiveQualities[qualityIndex];
|
|
7908
|
+
if (!selectedQuality) {
|
|
7909
|
+
if (this.options.debug) console.error('❌ Quality not found at index:', qualityIndex);
|
|
7910
|
+
return;
|
|
7911
|
+
}
|
|
7912
|
+
|
|
7913
|
+
if (this.options.debug) {
|
|
7914
|
+
console.log('🎬 Setting DASH quality:', selectedQuality);
|
|
7915
|
+
}
|
|
7916
|
+
|
|
7917
|
+
// Disable auto quality
|
|
7918
|
+
this.dashPlayer.updateSettings({
|
|
7919
|
+
streaming: {
|
|
7920
|
+
abr: {
|
|
7921
|
+
autoSwitchBitrate: { video: false }
|
|
7922
|
+
}
|
|
7923
|
+
}
|
|
7924
|
+
});
|
|
7925
|
+
|
|
7926
|
+
// Set the specific quality using bitrateIndex
|
|
7927
|
+
setTimeout(() => {
|
|
7928
|
+
try {
|
|
7929
|
+
this.dashPlayer.setQualityFor('video', selectedQuality.bitrateIndex);
|
|
7930
|
+
|
|
7931
|
+
if (this.options.debug) {
|
|
7932
|
+
console.log('✅ DASH quality set to bitrateIndex:', selectedQuality.bitrateIndex, 'height:', selectedQuality.height);
|
|
7933
|
+
}
|
|
7934
|
+
|
|
7935
|
+
// Update button text immediately
|
|
7936
|
+
const qualityBtnText = this.controls?.querySelector('.quality-btn .selected-quality');
|
|
7937
|
+
if (qualityBtnText) {
|
|
7938
|
+
qualityBtnText.textContent = selectedQuality.label;
|
|
7939
|
+
}
|
|
7940
|
+
|
|
7941
|
+
} catch (innerError) {
|
|
7942
|
+
if (this.options.debug) console.error('❌ Error setting quality:', innerError);
|
|
7943
|
+
}
|
|
7944
|
+
}, 100);
|
|
7945
|
+
|
|
7946
|
+
} catch (error) {
|
|
7947
|
+
if (this.options.debug) console.error('❌ Error in setDashQuality:', error);
|
|
7948
|
+
}
|
|
7949
|
+
}
|
|
7416
7950
|
|
|
7417
7951
|
handleAdaptiveError(data) {
|
|
7418
7952
|
if (this.options.debug) console.error('📡 Fatal adaptive streaming error:', data);
|