myetv-player 1.0.6 → 1.0.10
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 +13 -0
- package/css/myetv-player.css +374 -208
- package/css/myetv-player.min.css +1 -1
- package/dist/myetv-player.js +213 -31
- package/dist/myetv-player.min.js +188 -20
- package/package.json +3 -1
- package/plugins/youtube/README.md +13 -5
- package/plugins/youtube/myetv-player-youtube-plugin.js +1150 -141
- package/scss/_base.scss +0 -15
- package/scss/_controls.scss +311 -30
- package/scss/_menus.scss +51 -0
- package/scss/_responsive.scss +187 -321
- package/scss/_video.scss +0 -75
- package/scss/_watermark.scss +120 -0
- package/scss/myetv-player.scss +7 -7
- package/src/controls.js +73 -22
- package/src/core.js +56 -4
- package/src/events.js +33 -5
- package/src/watermark.js +51 -0
package/dist/myetv-player.min.js
CHANGED
|
@@ -435,6 +435,8 @@ constructor(videoElement, options = {}) {
|
|
|
435
435
|
hlsLibUrl: 'https://cdn.jsdelivr.net/npm/hls.js@latest',
|
|
436
436
|
adaptiveQualityControl: true,
|
|
437
437
|
|
|
438
|
+
seekHandleShape: 'circle',
|
|
439
|
+
|
|
438
440
|
audiofile: false,
|
|
439
441
|
audiowave: false,
|
|
440
442
|
|
|
@@ -1508,14 +1510,19 @@ seek(e) {
|
|
|
1508
1510
|
if (!this.video || !this.progressContainer || !this.progressFilled || !this.progressHandle || this.isChangingQuality) return;
|
|
1509
1511
|
|
|
1510
1512
|
const rect = this.progressContainer.getBoundingClientRect();
|
|
1511
|
-
|
|
1513
|
+
|
|
1514
|
+
|
|
1515
|
+
const clientX = e.clientX !== undefined ? e.clientX : (e.touches && e.touches[0] ? e.touches[0].clientX : (e.changedTouches && e.changedTouches[0] ? e.changedTouches[0].clientX : 0));
|
|
1516
|
+
|
|
1517
|
+
const clickX = clientX - rect.left;
|
|
1512
1518
|
const percentage = Math.max(0, Math.min(1, clickX / rect.width));
|
|
1513
1519
|
|
|
1514
1520
|
if (this.video.duration && !isNaN(this.video.duration)) {
|
|
1515
1521
|
this.video.currentTime = percentage * this.video.duration;
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
this.
|
|
1522
|
+
|
|
1523
|
+
const progress = `${percentage * 100}%`;
|
|
1524
|
+
this.progressFilled.style.width = progress;
|
|
1525
|
+
this.progressHandle.style.left = progress;
|
|
1519
1526
|
}
|
|
1520
1527
|
}
|
|
1521
1528
|
|
|
@@ -2038,6 +2045,41 @@ loadScript(src) {
|
|
|
2038
2045
|
});
|
|
2039
2046
|
}
|
|
2040
2047
|
|
|
2048
|
+
|
|
2049
|
+
setSeekHandleShape(shape) {
|
|
2050
|
+
const validShapes = ['none', 'circle', 'square', 'diamond', 'arrow', 'triangle', 'heart', 'star'];
|
|
2051
|
+
|
|
2052
|
+
if (!validShapes.includes(shape)) {
|
|
2053
|
+
if (this.options.debug) console.warn('Invalid seek handle shape:', shape);
|
|
2054
|
+
return this;
|
|
2055
|
+
}
|
|
2056
|
+
|
|
2057
|
+
this.options.seekHandleShape = shape;
|
|
2058
|
+
|
|
2059
|
+
|
|
2060
|
+
if (this.progressHandle) {
|
|
2061
|
+
|
|
2062
|
+
validShapes.forEach(s => {
|
|
2063
|
+
this.progressHandle.classList.remove(`progress-handle-${s}`);
|
|
2064
|
+
});
|
|
2065
|
+
|
|
2066
|
+
this.progressHandle.classList.add(`progress-handle-${shape}`);
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
if (this.options.debug) console.log('Seek handle shape changed to:', shape);
|
|
2070
|
+
return this;
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
|
|
2074
|
+
getSeekHandleShape() {
|
|
2075
|
+
return this.options.seekHandleShape;
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2078
|
+
|
|
2079
|
+
getAvailableSeekHandleShapes() {
|
|
2080
|
+
return ['none', 'circle', 'square', 'diamond', 'arrow', 'triangle', 'heart', 'star'];
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2041
2083
|
dispose() {
|
|
2042
2084
|
if (this.qualityMonitorInterval) {
|
|
2043
2085
|
clearInterval(this.qualityMonitorInterval);
|
|
@@ -2392,12 +2434,28 @@ addEventListener(eventType, callback) {
|
|
|
2392
2434
|
});
|
|
2393
2435
|
}
|
|
2394
2436
|
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2437
|
+
if (this.progressContainer) {
|
|
2438
|
+
|
|
2439
|
+
this.progressContainer.addEventListener('click', (e) => this.seek(e));
|
|
2440
|
+
this.progressContainer.addEventListener('mousedown', (e) => this.startSeeking(e));
|
|
2441
|
+
|
|
2442
|
+
|
|
2443
|
+
this.progressContainer.addEventListener('touchstart', (e) => {
|
|
2444
|
+
e.preventDefault();
|
|
2445
|
+
this.startSeeking(e);
|
|
2446
|
+
}, { passive: false });
|
|
2399
2447
|
|
|
2400
2448
|
this.setupSeekTooltip();
|
|
2449
|
+
}
|
|
2450
|
+
|
|
2451
|
+
|
|
2452
|
+
if (this.progressHandle) {
|
|
2453
|
+
this.progressHandle.addEventListener('touchstart', (e) => {
|
|
2454
|
+
e.preventDefault();
|
|
2455
|
+
e.stopPropagation();
|
|
2456
|
+
this.startSeeking(e);
|
|
2457
|
+
}, { passive: false });
|
|
2458
|
+
}
|
|
2401
2459
|
|
|
2402
2460
|
|
|
2403
2461
|
|
|
@@ -2418,7 +2476,19 @@ addEventListener(eventType, callback) {
|
|
|
2418
2476
|
document.addEventListener('mozfullscreenchange', () => this.updateFullscreenButton());
|
|
2419
2477
|
|
|
2420
2478
|
document.addEventListener('mousemove', (e) => this.continueSeeking(e));
|
|
2421
|
-
|
|
2479
|
+
document.addEventListener('mouseup', () => this.endSeeking());
|
|
2480
|
+
|
|
2481
|
+
|
|
2482
|
+
document.addEventListener('touchmove', (e) => {
|
|
2483
|
+
if (this.isUserSeeking) {
|
|
2484
|
+
e.preventDefault();
|
|
2485
|
+
this.continueSeeking(e);
|
|
2486
|
+
}
|
|
2487
|
+
}, { passive: false });
|
|
2488
|
+
|
|
2489
|
+
document.addEventListener('touchend', () => this.endSeeking());
|
|
2490
|
+
document.addEventListener('touchcancel', () => this.endSeeking());
|
|
2491
|
+
|
|
2422
2492
|
}
|
|
2423
2493
|
|
|
2424
2494
|
|
|
@@ -2566,6 +2636,11 @@ showControlsNow() {
|
|
|
2566
2636
|
|
|
2567
2637
|
if (this.container) {
|
|
2568
2638
|
this.container.classList.add('has-controls');
|
|
2639
|
+
this.updateControlbarHeight();
|
|
2640
|
+
|
|
2641
|
+
if (this.updateWatermarkPosition) {
|
|
2642
|
+
this.updateWatermarkPosition();
|
|
2643
|
+
}
|
|
2569
2644
|
}
|
|
2570
2645
|
|
|
2571
2646
|
|
|
@@ -2579,24 +2654,34 @@ showControlsNow() {
|
|
|
2579
2654
|
hideControlsNow() {
|
|
2580
2655
|
|
|
2581
2656
|
const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
|
|
2657
|
+
|
|
2582
2658
|
if (this.mouseOverControls && !isTouchDevice) {
|
|
2583
|
-
if (this.autoHideDebug && this.options.debug)
|
|
2659
|
+
if (this.autoHideDebug && this.options.debug) {
|
|
2660
|
+
console.log('🚫 Not hiding - mouse still over controls');
|
|
2661
|
+
}
|
|
2584
2662
|
return;
|
|
2585
2663
|
}
|
|
2586
2664
|
|
|
2587
2665
|
|
|
2588
2666
|
if (this.video && this.video.paused) {
|
|
2589
|
-
if (this.autoHideDebug && this.options.debug)
|
|
2667
|
+
if (this.autoHideDebug && this.options.debug) {
|
|
2668
|
+
console.log('🚫 Not hiding - video is paused');
|
|
2669
|
+
}
|
|
2590
2670
|
return;
|
|
2591
2671
|
}
|
|
2592
2672
|
|
|
2593
2673
|
if (this.controls) {
|
|
2594
2674
|
this.controls.classList.remove('show');
|
|
2595
|
-
}
|
|
2596
2675
|
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2676
|
+
|
|
2677
|
+
if (this.container) {
|
|
2678
|
+
this.container.classList.remove('has-controls');
|
|
2679
|
+
this.updateControlbarHeight();
|
|
2680
|
+
|
|
2681
|
+
if (this.updateWatermarkPosition) {
|
|
2682
|
+
this.updateWatermarkPosition();
|
|
2683
|
+
}
|
|
2684
|
+
}
|
|
2600
2685
|
}
|
|
2601
2686
|
|
|
2602
2687
|
|
|
@@ -2604,7 +2689,9 @@ hideControlsNow() {
|
|
|
2604
2689
|
this.hideTitleOverlay();
|
|
2605
2690
|
}
|
|
2606
2691
|
|
|
2607
|
-
if (this.autoHideDebug && this.options.debug)
|
|
2692
|
+
if (this.autoHideDebug && this.options.debug) {
|
|
2693
|
+
console.log('👁️ Controls hidden');
|
|
2694
|
+
}
|
|
2608
2695
|
}
|
|
2609
2696
|
|
|
2610
2697
|
showControls() {
|
|
@@ -2772,7 +2859,7 @@ createControls() {
|
|
|
2772
2859
|
<div class="progress-bar">
|
|
2773
2860
|
<div class="progress-buffer"></div>
|
|
2774
2861
|
<div class="progress-filled"></div>
|
|
2775
|
-
<div class="progress-handle"></div>
|
|
2862
|
+
<div class="progress-handle progress-handle-${this.options.seekHandleShape}"></div>
|
|
2776
2863
|
</div>
|
|
2777
2864
|
${this.options.showSeekTooltip ? '<div class="seek-tooltip">0:00</div>' : ''}
|
|
2778
2865
|
</div>
|
|
@@ -2882,6 +2969,7 @@ createControls() {
|
|
|
2882
2969
|
|
|
2883
2970
|
setTimeout(() => {
|
|
2884
2971
|
this.initializeResponsiveMenu();
|
|
2972
|
+
this.updateControlbarHeight();
|
|
2885
2973
|
}, 100);
|
|
2886
2974
|
}
|
|
2887
2975
|
|
|
@@ -2895,14 +2983,46 @@ initializeResponsiveMenu() {
|
|
|
2895
2983
|
|
|
2896
2984
|
this.checkScreenSize();
|
|
2897
2985
|
|
|
2898
|
-
|
|
2986
|
+
|
|
2987
|
+
const resizeHandler = () => {
|
|
2899
2988
|
this.checkScreenSize();
|
|
2900
|
-
|
|
2989
|
+
this.updateControlbarHeight();
|
|
2990
|
+
};
|
|
2991
|
+
|
|
2992
|
+
|
|
2993
|
+
this.resizeHandler = resizeHandler.bind(this);
|
|
2994
|
+
window.addEventListener('resize', this.resizeHandler);
|
|
2901
2995
|
|
|
2902
2996
|
|
|
2903
2997
|
this.bindSettingsMenuEvents();
|
|
2904
2998
|
}
|
|
2905
2999
|
|
|
3000
|
+
updateControlbarHeight() {
|
|
3001
|
+
if (!this.controls) return;
|
|
3002
|
+
|
|
3003
|
+
const height = this.controls.offsetHeight;
|
|
3004
|
+
if (this.container) {
|
|
3005
|
+
|
|
3006
|
+
this.container.style.setProperty('--player-controls-height', `${height}px`);
|
|
3007
|
+
|
|
3008
|
+
const watermark = this.container.querySelector('.video-watermark.watermark-bottomleft, .video-watermark.watermark-bottomright');
|
|
3009
|
+
if (watermark) {
|
|
3010
|
+
const hasControls = this.container.classList.contains('has-controls');
|
|
3011
|
+
const isHideOnAutoHide = watermark.classList.contains('hide-on-autohide');
|
|
3012
|
+
|
|
3013
|
+
if (hasControls || !isHideOnAutoHide) {
|
|
3014
|
+
watermark.style.bottom = `${height + 15}px`;
|
|
3015
|
+
} else {
|
|
3016
|
+
watermark.style.bottom = '15px';
|
|
3017
|
+
}
|
|
3018
|
+
}
|
|
3019
|
+
}
|
|
3020
|
+
|
|
3021
|
+
if (this.options.debug) {
|
|
3022
|
+
console.log(`Controlbar height updated: ${height}px`);
|
|
3023
|
+
}
|
|
3024
|
+
}
|
|
3025
|
+
|
|
2906
3026
|
|
|
2907
3027
|
getResponsiveThreshold() {
|
|
2908
3028
|
|
|
@@ -2922,7 +3042,7 @@ checkScreenSize() {
|
|
|
2922
3042
|
this.updateSettingsMenuVisibility();
|
|
2923
3043
|
|
|
2924
3044
|
if (this.options.debug) {
|
|
2925
|
-
console.log(`Screen check: ${window.innerWidth}px vs ${threshold}px threshold
|
|
3045
|
+
console.log(`Screen check: ${window.innerWidth}px vs ${threshold}px (threshold), logo: ${this.options.brandLogoEnabled}, small: ${this.isSmallScreen}`);
|
|
2926
3046
|
}
|
|
2927
3047
|
}
|
|
2928
3048
|
}
|
|
@@ -5584,8 +5704,18 @@ initializeWatermark() {
|
|
|
5584
5704
|
}
|
|
5585
5705
|
|
|
5586
5706
|
|
|
5707
|
+
|
|
5587
5708
|
this.watermarkElement = watermark;
|
|
5588
5709
|
|
|
5710
|
+
|
|
5711
|
+
this.updateWatermarkPosition();
|
|
5712
|
+
|
|
5713
|
+
|
|
5714
|
+
this.watermarkResizeHandler = () => {
|
|
5715
|
+
this.updateWatermarkPosition();
|
|
5716
|
+
};
|
|
5717
|
+
window.addEventListener('resize', this.watermarkResizeHandler);
|
|
5718
|
+
|
|
5589
5719
|
if (this.options.debug) {
|
|
5590
5720
|
console.log('🏷️ Watermark created:', {
|
|
5591
5721
|
url: this.options.watermarkUrl,
|
|
@@ -5598,6 +5728,7 @@ initializeWatermark() {
|
|
|
5598
5728
|
}
|
|
5599
5729
|
|
|
5600
5730
|
|
|
5731
|
+
|
|
5601
5732
|
setWatermark(url, link = '', position = 'bottomright', title = '') {
|
|
5602
5733
|
|
|
5603
5734
|
this.options.watermarkUrl = url;
|
|
@@ -5626,6 +5757,12 @@ removeWatermark() {
|
|
|
5626
5757
|
this.watermarkElement = null;
|
|
5627
5758
|
}
|
|
5628
5759
|
|
|
5760
|
+
|
|
5761
|
+
if (this.watermarkResizeHandler) {
|
|
5762
|
+
window.removeEventListener('resize', this.watermarkResizeHandler);
|
|
5763
|
+
this.watermarkResizeHandler = null;
|
|
5764
|
+
}
|
|
5765
|
+
|
|
5629
5766
|
this.options.watermarkUrl = '';
|
|
5630
5767
|
this.options.watermarkLink = '';
|
|
5631
5768
|
this.options.watermarkPosition = 'bottomright';
|
|
@@ -5637,6 +5774,7 @@ removeWatermark() {
|
|
|
5637
5774
|
}
|
|
5638
5775
|
|
|
5639
5776
|
|
|
5777
|
+
|
|
5640
5778
|
setWatermarkPosition(position) {
|
|
5641
5779
|
if (!['topleft', 'topright', 'bottomleft', 'bottomright'].includes(position)) {
|
|
5642
5780
|
if (this.options.debug) console.warn('🏷️ Invalid watermark position:', position);
|
|
@@ -5664,6 +5802,36 @@ setWatermarkPosition(position) {
|
|
|
5664
5802
|
}
|
|
5665
5803
|
|
|
5666
5804
|
|
|
5805
|
+
updateWatermarkPosition() {
|
|
5806
|
+
if (!this.watermarkElement) return;
|
|
5807
|
+
if (!this.controls) return;
|
|
5808
|
+
|
|
5809
|
+
const position = this.options.watermarkPosition || 'bottomright';
|
|
5810
|
+
|
|
5811
|
+
|
|
5812
|
+
if (position === 'bottomleft' || position === 'bottomright') {
|
|
5813
|
+
const controlsHeight = this.controls.offsetHeight;
|
|
5814
|
+
const spacing = 15;
|
|
5815
|
+
const bottomValue = controlsHeight + spacing;
|
|
5816
|
+
|
|
5817
|
+
|
|
5818
|
+
const hasControls = this.container.classList.contains('has-controls');
|
|
5819
|
+
|
|
5820
|
+
if (hasControls || !this.options.hideWatermark) {
|
|
5821
|
+
|
|
5822
|
+
this.watermarkElement.style.bottom = `${bottomValue}px`;
|
|
5823
|
+
} else {
|
|
5824
|
+
|
|
5825
|
+
this.watermarkElement.style.bottom = '15px';
|
|
5826
|
+
}
|
|
5827
|
+
|
|
5828
|
+
if (this.options.debug) {
|
|
5829
|
+
console.log(`🏷️ Watermark position updated: bottom ${this.watermarkElement.style.bottom}`);
|
|
5830
|
+
}
|
|
5831
|
+
}
|
|
5832
|
+
}
|
|
5833
|
+
|
|
5834
|
+
|
|
5667
5835
|
setWatermarkAutoHide(hide) {
|
|
5668
5836
|
this.options.hideWatermark = hide;
|
|
5669
5837
|
|
package/package.json
CHANGED
|
@@ -117,7 +117,13 @@ const player = new MYETVPlayer('myVideo', {
|
|
|
117
117
|
quality: 'default',
|
|
118
118
|
|
|
119
119
|
// Enable quality control in player UI
|
|
120
|
-
enableQualityControl: true
|
|
120
|
+
enableQualityControl: true,
|
|
121
|
+
|
|
122
|
+
// enable channel information retrieval (NEED THE APIKEY TO WORK)
|
|
123
|
+
enableChannelWatermark: false,
|
|
124
|
+
|
|
125
|
+
// Set the default language for auto subtitles
|
|
126
|
+
autoCaptionLanguage: 'en'
|
|
121
127
|
}
|
|
122
128
|
}
|
|
123
129
|
});
|
|
@@ -197,16 +203,18 @@ const player = new MYETVPlayer('myVideo', {
|
|
|
197
203
|
</script>
|
|
198
204
|
```
|
|
199
205
|
|
|
200
|
-
### Method 4: YouTube
|
|
206
|
+
### Method 4: YouTube video id in the initialization option
|
|
201
207
|
|
|
202
208
|
```html
|
|
203
|
-
<video id="myVideo" class="video-player"
|
|
204
|
-
src="https://youtu.be/dQw4w9WgXcQ">
|
|
209
|
+
<video id="myVideo" class="video-player">
|
|
205
210
|
</video>
|
|
206
211
|
|
|
207
212
|
<script>
|
|
208
213
|
const player = new MYETVPlayer('myVideo', {
|
|
209
|
-
plugins: { youtube: {
|
|
214
|
+
plugins: { youtube: {
|
|
215
|
+
videoId: 'dQw4w9WgXcQ', // YouTube video ID
|
|
216
|
+
autoplay: true
|
|
217
|
+
} }
|
|
210
218
|
});
|
|
211
219
|
</script>
|
|
212
220
|
```
|