myetv-player 1.0.8 → 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/css/myetv-player.css +252 -208
- package/css/myetv-player.min.css +1 -1
- package/dist/myetv-player.js +165 -30
- package/dist/myetv-player.min.js +150 -19
- package/package.json +2 -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 +129 -2
- 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 +72 -21
- package/src/core.js +9 -4
- package/src/events.js +33 -5
- package/src/watermark.js +51 -0
package/dist/myetv-player.js
CHANGED
|
@@ -1533,14 +1533,19 @@ seek(e) {
|
|
|
1533
1533
|
if (!this.video || !this.progressContainer || !this.progressFilled || !this.progressHandle || this.isChangingQuality) return;
|
|
1534
1534
|
|
|
1535
1535
|
const rect = this.progressContainer.getBoundingClientRect();
|
|
1536
|
-
|
|
1536
|
+
|
|
1537
|
+
// Support both mouse and touch events
|
|
1538
|
+
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));
|
|
1539
|
+
|
|
1540
|
+
const clickX = clientX - rect.left;
|
|
1537
1541
|
const percentage = Math.max(0, Math.min(1, clickX / rect.width));
|
|
1538
1542
|
|
|
1539
1543
|
if (this.video.duration && !isNaN(this.video.duration)) {
|
|
1540
1544
|
this.video.currentTime = percentage * this.video.duration;
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
this.
|
|
1545
|
+
|
|
1546
|
+
const progress = `${percentage * 100}%`;
|
|
1547
|
+
this.progressFilled.style.width = progress;
|
|
1548
|
+
this.progressHandle.style.left = progress;
|
|
1544
1549
|
}
|
|
1545
1550
|
}
|
|
1546
1551
|
|
|
@@ -2514,12 +2519,28 @@ addEventListener(eventType, callback) {
|
|
|
2514
2519
|
});
|
|
2515
2520
|
}
|
|
2516
2521
|
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2522
|
+
if (this.progressContainer) {
|
|
2523
|
+
// Mouse events (desktop)
|
|
2524
|
+
this.progressContainer.addEventListener('click', (e) => this.seek(e));
|
|
2525
|
+
this.progressContainer.addEventListener('mousedown', (e) => this.startSeeking(e));
|
|
2526
|
+
|
|
2527
|
+
// Touch events (mobile)
|
|
2528
|
+
this.progressContainer.addEventListener('touchstart', (e) => {
|
|
2529
|
+
e.preventDefault(); // Prevent scrolling when touching the seek bar
|
|
2530
|
+
this.startSeeking(e);
|
|
2531
|
+
}, { passive: false });
|
|
2521
2532
|
|
|
2522
2533
|
this.setupSeekTooltip();
|
|
2534
|
+
}
|
|
2535
|
+
|
|
2536
|
+
// Add touch events directly on the handle for better mobile dragging
|
|
2537
|
+
if (this.progressHandle) {
|
|
2538
|
+
this.progressHandle.addEventListener('touchstart', (e) => {
|
|
2539
|
+
e.preventDefault(); // Prevent default touch behavior
|
|
2540
|
+
e.stopPropagation(); // Stop event from bubbling to progressContainer
|
|
2541
|
+
this.startSeeking(e);
|
|
2542
|
+
}, { passive: false });
|
|
2543
|
+
}
|
|
2523
2544
|
|
|
2524
2545
|
// NOTE: Auto-hide events are handled in initAutoHide() after everything is ready
|
|
2525
2546
|
|
|
@@ -2540,7 +2561,19 @@ addEventListener(eventType, callback) {
|
|
|
2540
2561
|
document.addEventListener('mozfullscreenchange', () => this.updateFullscreenButton());
|
|
2541
2562
|
|
|
2542
2563
|
document.addEventListener('mousemove', (e) => this.continueSeeking(e));
|
|
2543
|
-
|
|
2564
|
+
document.addEventListener('mouseup', () => this.endSeeking());
|
|
2565
|
+
|
|
2566
|
+
// Touch events for seeking (mobile)
|
|
2567
|
+
document.addEventListener('touchmove', (e) => {
|
|
2568
|
+
if (this.isUserSeeking) {
|
|
2569
|
+
e.preventDefault(); // Prevent scrolling while seeking
|
|
2570
|
+
this.continueSeeking(e);
|
|
2571
|
+
}
|
|
2572
|
+
}, { passive: false });
|
|
2573
|
+
|
|
2574
|
+
document.addEventListener('touchend', () => this.endSeeking());
|
|
2575
|
+
document.addEventListener('touchcancel', () => this.endSeeking());
|
|
2576
|
+
|
|
2544
2577
|
}
|
|
2545
2578
|
|
|
2546
2579
|
/* Controls Module for MYETV Video Player
|
|
@@ -2548,7 +2581,7 @@ addEventListener(eventType, callback) {
|
|
|
2548
2581
|
* Created by https://www.myetv.tv https://oskarcosimo.com
|
|
2549
2582
|
*/
|
|
2550
2583
|
|
|
2551
|
-
/* AUTO-HIDE SYSTEM
|
|
2584
|
+
/* AUTO-HIDE SYSTEM */
|
|
2552
2585
|
initAutoHide() {
|
|
2553
2586
|
if (!this.options.autoHide) {
|
|
2554
2587
|
if (this.options.debug) console.log('Auto-hide disabled in options');
|
|
@@ -2688,12 +2721,17 @@ showControlsNow() {
|
|
|
2688
2721
|
this.controls.classList.add('show');
|
|
2689
2722
|
}
|
|
2690
2723
|
|
|
2691
|
-
//
|
|
2724
|
+
// Add has-controls class to container for watermark visibility
|
|
2692
2725
|
if (this.container) {
|
|
2693
2726
|
this.container.classList.add('has-controls');
|
|
2727
|
+
this.updateControlbarHeight();
|
|
2728
|
+
// Update watermark position
|
|
2729
|
+
if (this.updateWatermarkPosition) {
|
|
2730
|
+
this.updateWatermarkPosition();
|
|
2731
|
+
}
|
|
2694
2732
|
}
|
|
2695
2733
|
|
|
2696
|
-
//
|
|
2734
|
+
// Show title overlay with controls if not persistent
|
|
2697
2735
|
if (this.options.showTitleOverlay && !this.options.persistentTitle && this.options.videoTitle) {
|
|
2698
2736
|
this.showTitleOverlay();
|
|
2699
2737
|
}
|
|
@@ -2704,32 +2742,44 @@ showControlsNow() {
|
|
|
2704
2742
|
hideControlsNow() {
|
|
2705
2743
|
// Don't hide if mouse is still over controls (allow hiding on touch devices)
|
|
2706
2744
|
const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
|
|
2745
|
+
|
|
2707
2746
|
if (this.mouseOverControls && !isTouchDevice) {
|
|
2708
|
-
if (this.autoHideDebug && this.options.debug)
|
|
2747
|
+
if (this.autoHideDebug && this.options.debug) {
|
|
2748
|
+
console.log('🚫 Not hiding - mouse still over controls');
|
|
2749
|
+
}
|
|
2709
2750
|
return;
|
|
2710
2751
|
}
|
|
2711
2752
|
|
|
2712
2753
|
// Don't hide if video is paused
|
|
2713
2754
|
if (this.video && this.video.paused) {
|
|
2714
|
-
if (this.autoHideDebug && this.options.debug)
|
|
2755
|
+
if (this.autoHideDebug && this.options.debug) {
|
|
2756
|
+
console.log('🚫 Not hiding - video is paused');
|
|
2757
|
+
}
|
|
2715
2758
|
return;
|
|
2716
2759
|
}
|
|
2717
2760
|
|
|
2718
2761
|
if (this.controls) {
|
|
2719
2762
|
this.controls.classList.remove('show');
|
|
2720
|
-
}
|
|
2721
2763
|
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2764
|
+
// Remove has-controls class from container for watermark visibility
|
|
2765
|
+
if (this.container) {
|
|
2766
|
+
this.container.classList.remove('has-controls');
|
|
2767
|
+
this.updateControlbarHeight();
|
|
2768
|
+
// Update watermark position
|
|
2769
|
+
if (this.updateWatermarkPosition) {
|
|
2770
|
+
this.updateWatermarkPosition();
|
|
2771
|
+
}
|
|
2772
|
+
}
|
|
2725
2773
|
}
|
|
2726
2774
|
|
|
2727
|
-
//
|
|
2775
|
+
// Hide title overlay with controls (if not persistent)
|
|
2728
2776
|
if (this.options.showTitleOverlay && !this.options.persistentTitle) {
|
|
2729
2777
|
this.hideTitleOverlay();
|
|
2730
2778
|
}
|
|
2731
2779
|
|
|
2732
|
-
if (this.autoHideDebug && this.options.debug)
|
|
2780
|
+
if (this.autoHideDebug && this.options.debug) {
|
|
2781
|
+
console.log('👁️ Controls hidden');
|
|
2782
|
+
}
|
|
2733
2783
|
}
|
|
2734
2784
|
|
|
2735
2785
|
showControls() {
|
|
@@ -3008,28 +3058,62 @@ createControls() {
|
|
|
3008
3058
|
// NEW: Initialize responsive settings menu
|
|
3009
3059
|
setTimeout(() => {
|
|
3010
3060
|
this.initializeResponsiveMenu();
|
|
3061
|
+
this.updateControlbarHeight();
|
|
3011
3062
|
}, 100);
|
|
3012
3063
|
}
|
|
3013
3064
|
|
|
3014
|
-
/*
|
|
3065
|
+
/* Initialize responsive menu with dynamic width calculation */
|
|
3015
3066
|
initializeResponsiveMenu() {
|
|
3016
3067
|
if (!this.controls) return;
|
|
3017
3068
|
|
|
3018
3069
|
// Track screen size
|
|
3019
3070
|
this.isSmallScreen = false;
|
|
3020
3071
|
|
|
3021
|
-
// Check initial size
|
|
3072
|
+
// Check initial size
|
|
3022
3073
|
this.checkScreenSize();
|
|
3023
3074
|
|
|
3024
|
-
|
|
3075
|
+
// Bind resize handler with updateControlbarHeight
|
|
3076
|
+
const resizeHandler = () => {
|
|
3025
3077
|
this.checkScreenSize();
|
|
3026
|
-
|
|
3078
|
+
this.updateControlbarHeight();
|
|
3079
|
+
};
|
|
3080
|
+
|
|
3081
|
+
// Bind del context
|
|
3082
|
+
this.resizeHandler = resizeHandler.bind(this);
|
|
3083
|
+
window.addEventListener('resize', this.resizeHandler);
|
|
3027
3084
|
|
|
3028
3085
|
// Bind events for settings menu
|
|
3029
3086
|
this.bindSettingsMenuEvents();
|
|
3030
3087
|
}
|
|
3031
3088
|
|
|
3032
|
-
|
|
3089
|
+
// Dynamic controlbar height tracking for watermark positioning
|
|
3090
|
+
updateControlbarHeight() {
|
|
3091
|
+
if (!this.controls) return;
|
|
3092
|
+
|
|
3093
|
+
const height = this.controls.offsetHeight;
|
|
3094
|
+
if (this.container) {
|
|
3095
|
+
|
|
3096
|
+
this.container.style.setProperty('--player-controls-height', `${height}px`);
|
|
3097
|
+
|
|
3098
|
+
const watermark = this.container.querySelector('.video-watermark.watermark-bottomleft, .video-watermark.watermark-bottomright');
|
|
3099
|
+
if (watermark) {
|
|
3100
|
+
const hasControls = this.container.classList.contains('has-controls');
|
|
3101
|
+
const isHideOnAutoHide = watermark.classList.contains('hide-on-autohide');
|
|
3102
|
+
|
|
3103
|
+
if (hasControls || !isHideOnAutoHide) {
|
|
3104
|
+
watermark.style.bottom = `${height + 15}px`;
|
|
3105
|
+
} else {
|
|
3106
|
+
watermark.style.bottom = '15px';
|
|
3107
|
+
}
|
|
3108
|
+
}
|
|
3109
|
+
}
|
|
3110
|
+
|
|
3111
|
+
if (this.options.debug) {
|
|
3112
|
+
console.log(`Controlbar height updated: ${height}px`);
|
|
3113
|
+
}
|
|
3114
|
+
}
|
|
3115
|
+
|
|
3116
|
+
/* Dynamic width calculation based on logo presence */
|
|
3033
3117
|
getResponsiveThreshold() {
|
|
3034
3118
|
// Check if brand logo is enabled and present
|
|
3035
3119
|
const hasLogo = this.options.brandLogoEnabled && this.options.brandLogoUrl;
|
|
@@ -3038,7 +3122,7 @@ getResponsiveThreshold() {
|
|
|
3038
3122
|
return hasLogo ? 650 : 550;
|
|
3039
3123
|
}
|
|
3040
3124
|
|
|
3041
|
-
/*
|
|
3125
|
+
/* Check if screen is under dynamic threshold */
|
|
3042
3126
|
checkScreenSize() {
|
|
3043
3127
|
const threshold = this.getResponsiveThreshold();
|
|
3044
3128
|
const newIsSmallScreen = window.innerWidth <= threshold;
|
|
@@ -3048,12 +3132,12 @@ checkScreenSize() {
|
|
|
3048
3132
|
this.updateSettingsMenuVisibility();
|
|
3049
3133
|
|
|
3050
3134
|
if (this.options.debug) {
|
|
3051
|
-
console.log(`Screen check: ${window.innerWidth}px vs ${threshold}px threshold
|
|
3135
|
+
console.log(`Screen check: ${window.innerWidth}px vs ${threshold}px (threshold), logo: ${this.options.brandLogoEnabled}, small: ${this.isSmallScreen}`);
|
|
3052
3136
|
}
|
|
3053
3137
|
}
|
|
3054
3138
|
}
|
|
3055
3139
|
|
|
3056
|
-
/*
|
|
3140
|
+
/* Update settings menu visibility based on screen size */
|
|
3057
3141
|
updateSettingsMenuVisibility() {
|
|
3058
3142
|
const settingsControl = this.controls?.querySelector('.settings-control');
|
|
3059
3143
|
if (!settingsControl) return;
|
|
@@ -3093,7 +3177,7 @@ updateSettingsMenuVisibility() {
|
|
|
3093
3177
|
}
|
|
3094
3178
|
}
|
|
3095
3179
|
|
|
3096
|
-
/*
|
|
3180
|
+
/* Populate settings menu with controls */
|
|
3097
3181
|
populateSettingsMenu() {
|
|
3098
3182
|
const settingsMenu = this.controls?.querySelector('.settings-menu');
|
|
3099
3183
|
if (!settingsMenu) return;
|
|
@@ -3155,7 +3239,7 @@ populateSettingsMenu() {
|
|
|
3155
3239
|
settingsMenu.innerHTML = menuHTML;
|
|
3156
3240
|
}
|
|
3157
3241
|
|
|
3158
|
-
/*
|
|
3242
|
+
/* Bind settings menu events */
|
|
3159
3243
|
bindSettingsMenuEvents() {
|
|
3160
3244
|
const settingsMenu = this.controls?.querySelector('.settings-menu');
|
|
3161
3245
|
if (!settingsMenu) return;
|
|
@@ -5784,9 +5868,19 @@ initializeWatermark() {
|
|
|
5784
5868
|
this.container.appendChild(watermark);
|
|
5785
5869
|
}
|
|
5786
5870
|
|
|
5871
|
+
// Store reference to watermark element
|
|
5787
5872
|
// Store reference to watermark element
|
|
5788
5873
|
this.watermarkElement = watermark;
|
|
5789
5874
|
|
|
5875
|
+
// Set initial position
|
|
5876
|
+
this.updateWatermarkPosition();
|
|
5877
|
+
|
|
5878
|
+
// Update position on window resize
|
|
5879
|
+
this.watermarkResizeHandler = () => {
|
|
5880
|
+
this.updateWatermarkPosition();
|
|
5881
|
+
};
|
|
5882
|
+
window.addEventListener('resize', this.watermarkResizeHandler);
|
|
5883
|
+
|
|
5790
5884
|
if (this.options.debug) {
|
|
5791
5885
|
console.log('🏷️ Watermark created:', {
|
|
5792
5886
|
url: this.options.watermarkUrl,
|
|
@@ -5805,6 +5899,7 @@ initializeWatermark() {
|
|
|
5805
5899
|
* @param {string} position - Position of watermark (topleft, topright, bottomleft, bottomright)
|
|
5806
5900
|
* @param {string} title - Optional tooltip title for the watermark
|
|
5807
5901
|
*/
|
|
5902
|
+
|
|
5808
5903
|
setWatermark(url, link = '', position = 'bottomright', title = '') {
|
|
5809
5904
|
// Update options
|
|
5810
5905
|
this.options.watermarkUrl = url;
|
|
@@ -5835,6 +5930,12 @@ removeWatermark() {
|
|
|
5835
5930
|
this.watermarkElement = null;
|
|
5836
5931
|
}
|
|
5837
5932
|
|
|
5933
|
+
// Remove resize listener
|
|
5934
|
+
if (this.watermarkResizeHandler) {
|
|
5935
|
+
window.removeEventListener('resize', this.watermarkResizeHandler);
|
|
5936
|
+
this.watermarkResizeHandler = null;
|
|
5937
|
+
}
|
|
5938
|
+
|
|
5838
5939
|
this.options.watermarkUrl = '';
|
|
5839
5940
|
this.options.watermarkLink = '';
|
|
5840
5941
|
this.options.watermarkPosition = 'bottomright';
|
|
@@ -5849,6 +5950,7 @@ removeWatermark() {
|
|
|
5849
5950
|
* Update watermark position
|
|
5850
5951
|
* @param {string} position - New position (topleft, topright, bottomleft, bottomright)
|
|
5851
5952
|
*/
|
|
5953
|
+
|
|
5852
5954
|
setWatermarkPosition(position) {
|
|
5853
5955
|
if (!['topleft', 'topright', 'bottomleft', 'bottomright'].includes(position)) {
|
|
5854
5956
|
if (this.options.debug) console.warn('🏷️ Invalid watermark position:', position);
|
|
@@ -5875,6 +5977,39 @@ setWatermarkPosition(position) {
|
|
|
5875
5977
|
return this;
|
|
5876
5978
|
}
|
|
5877
5979
|
|
|
5980
|
+
/**
|
|
5981
|
+
* Update watermark position based on current controlbar height
|
|
5982
|
+
* Called during window resize to keep watermark above controlbar
|
|
5983
|
+
*/
|
|
5984
|
+
updateWatermarkPosition() {
|
|
5985
|
+
if (!this.watermarkElement) return;
|
|
5986
|
+
if (!this.controls) return;
|
|
5987
|
+
|
|
5988
|
+
const position = this.options.watermarkPosition || 'bottomright';
|
|
5989
|
+
|
|
5990
|
+
// Only update bottom positions (top positions don't need adjustment)
|
|
5991
|
+
if (position === 'bottomleft' || position === 'bottomright') {
|
|
5992
|
+
const controlsHeight = this.controls.offsetHeight;
|
|
5993
|
+
const spacing = 15; // Same spacing used in CSS
|
|
5994
|
+
const bottomValue = controlsHeight + spacing;
|
|
5995
|
+
|
|
5996
|
+
// Check if controls are visible
|
|
5997
|
+
const hasControls = this.container.classList.contains('has-controls');
|
|
5998
|
+
|
|
5999
|
+
if (hasControls || !this.options.hideWatermark) {
|
|
6000
|
+
// Position above controlbar
|
|
6001
|
+
this.watermarkElement.style.bottom = `${bottomValue}px`;
|
|
6002
|
+
} else {
|
|
6003
|
+
// Position at bottom corner when controls hidden
|
|
6004
|
+
this.watermarkElement.style.bottom = '15px';
|
|
6005
|
+
}
|
|
6006
|
+
|
|
6007
|
+
if (this.options.debug) {
|
|
6008
|
+
console.log(`🏷️ Watermark position updated: bottom ${this.watermarkElement.style.bottom}`);
|
|
6009
|
+
}
|
|
6010
|
+
}
|
|
6011
|
+
}
|
|
6012
|
+
|
|
5878
6013
|
/**
|
|
5879
6014
|
* Set whether watermark should hide with controls
|
|
5880
6015
|
* @param {boolean} hide - True to hide watermark with controls, false to keep always visible
|
package/dist/myetv-player.min.js
CHANGED
|
@@ -1510,14 +1510,19 @@ seek(e) {
|
|
|
1510
1510
|
if (!this.video || !this.progressContainer || !this.progressFilled || !this.progressHandle || this.isChangingQuality) return;
|
|
1511
1511
|
|
|
1512
1512
|
const rect = this.progressContainer.getBoundingClientRect();
|
|
1513
|
-
|
|
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;
|
|
1514
1518
|
const percentage = Math.max(0, Math.min(1, clickX / rect.width));
|
|
1515
1519
|
|
|
1516
1520
|
if (this.video.duration && !isNaN(this.video.duration)) {
|
|
1517
1521
|
this.video.currentTime = percentage * this.video.duration;
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
this.
|
|
1522
|
+
|
|
1523
|
+
const progress = `${percentage * 100}%`;
|
|
1524
|
+
this.progressFilled.style.width = progress;
|
|
1525
|
+
this.progressHandle.style.left = progress;
|
|
1521
1526
|
}
|
|
1522
1527
|
}
|
|
1523
1528
|
|
|
@@ -2429,12 +2434,28 @@ addEventListener(eventType, callback) {
|
|
|
2429
2434
|
});
|
|
2430
2435
|
}
|
|
2431
2436
|
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
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 });
|
|
2436
2447
|
|
|
2437
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
|
+
}
|
|
2438
2459
|
|
|
2439
2460
|
|
|
2440
2461
|
|
|
@@ -2455,7 +2476,19 @@ addEventListener(eventType, callback) {
|
|
|
2455
2476
|
document.addEventListener('mozfullscreenchange', () => this.updateFullscreenButton());
|
|
2456
2477
|
|
|
2457
2478
|
document.addEventListener('mousemove', (e) => this.continueSeeking(e));
|
|
2458
|
-
|
|
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
|
+
|
|
2459
2492
|
}
|
|
2460
2493
|
|
|
2461
2494
|
|
|
@@ -2603,6 +2636,11 @@ showControlsNow() {
|
|
|
2603
2636
|
|
|
2604
2637
|
if (this.container) {
|
|
2605
2638
|
this.container.classList.add('has-controls');
|
|
2639
|
+
this.updateControlbarHeight();
|
|
2640
|
+
|
|
2641
|
+
if (this.updateWatermarkPosition) {
|
|
2642
|
+
this.updateWatermarkPosition();
|
|
2643
|
+
}
|
|
2606
2644
|
}
|
|
2607
2645
|
|
|
2608
2646
|
|
|
@@ -2616,24 +2654,34 @@ showControlsNow() {
|
|
|
2616
2654
|
hideControlsNow() {
|
|
2617
2655
|
|
|
2618
2656
|
const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
|
|
2657
|
+
|
|
2619
2658
|
if (this.mouseOverControls && !isTouchDevice) {
|
|
2620
|
-
if (this.autoHideDebug && this.options.debug)
|
|
2659
|
+
if (this.autoHideDebug && this.options.debug) {
|
|
2660
|
+
console.log('🚫 Not hiding - mouse still over controls');
|
|
2661
|
+
}
|
|
2621
2662
|
return;
|
|
2622
2663
|
}
|
|
2623
2664
|
|
|
2624
2665
|
|
|
2625
2666
|
if (this.video && this.video.paused) {
|
|
2626
|
-
if (this.autoHideDebug && this.options.debug)
|
|
2667
|
+
if (this.autoHideDebug && this.options.debug) {
|
|
2668
|
+
console.log('🚫 Not hiding - video is paused');
|
|
2669
|
+
}
|
|
2627
2670
|
return;
|
|
2628
2671
|
}
|
|
2629
2672
|
|
|
2630
2673
|
if (this.controls) {
|
|
2631
2674
|
this.controls.classList.remove('show');
|
|
2632
|
-
}
|
|
2633
2675
|
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
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
|
+
}
|
|
2637
2685
|
}
|
|
2638
2686
|
|
|
2639
2687
|
|
|
@@ -2641,7 +2689,9 @@ hideControlsNow() {
|
|
|
2641
2689
|
this.hideTitleOverlay();
|
|
2642
2690
|
}
|
|
2643
2691
|
|
|
2644
|
-
if (this.autoHideDebug && this.options.debug)
|
|
2692
|
+
if (this.autoHideDebug && this.options.debug) {
|
|
2693
|
+
console.log('👁️ Controls hidden');
|
|
2694
|
+
}
|
|
2645
2695
|
}
|
|
2646
2696
|
|
|
2647
2697
|
showControls() {
|
|
@@ -2919,6 +2969,7 @@ createControls() {
|
|
|
2919
2969
|
|
|
2920
2970
|
setTimeout(() => {
|
|
2921
2971
|
this.initializeResponsiveMenu();
|
|
2972
|
+
this.updateControlbarHeight();
|
|
2922
2973
|
}, 100);
|
|
2923
2974
|
}
|
|
2924
2975
|
|
|
@@ -2932,14 +2983,46 @@ initializeResponsiveMenu() {
|
|
|
2932
2983
|
|
|
2933
2984
|
this.checkScreenSize();
|
|
2934
2985
|
|
|
2935
|
-
|
|
2986
|
+
|
|
2987
|
+
const resizeHandler = () => {
|
|
2936
2988
|
this.checkScreenSize();
|
|
2937
|
-
|
|
2989
|
+
this.updateControlbarHeight();
|
|
2990
|
+
};
|
|
2991
|
+
|
|
2992
|
+
|
|
2993
|
+
this.resizeHandler = resizeHandler.bind(this);
|
|
2994
|
+
window.addEventListener('resize', this.resizeHandler);
|
|
2938
2995
|
|
|
2939
2996
|
|
|
2940
2997
|
this.bindSettingsMenuEvents();
|
|
2941
2998
|
}
|
|
2942
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
|
+
|
|
2943
3026
|
|
|
2944
3027
|
getResponsiveThreshold() {
|
|
2945
3028
|
|
|
@@ -2959,7 +3042,7 @@ checkScreenSize() {
|
|
|
2959
3042
|
this.updateSettingsMenuVisibility();
|
|
2960
3043
|
|
|
2961
3044
|
if (this.options.debug) {
|
|
2962
|
-
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}`);
|
|
2963
3046
|
}
|
|
2964
3047
|
}
|
|
2965
3048
|
}
|
|
@@ -5621,8 +5704,18 @@ initializeWatermark() {
|
|
|
5621
5704
|
}
|
|
5622
5705
|
|
|
5623
5706
|
|
|
5707
|
+
|
|
5624
5708
|
this.watermarkElement = watermark;
|
|
5625
5709
|
|
|
5710
|
+
|
|
5711
|
+
this.updateWatermarkPosition();
|
|
5712
|
+
|
|
5713
|
+
|
|
5714
|
+
this.watermarkResizeHandler = () => {
|
|
5715
|
+
this.updateWatermarkPosition();
|
|
5716
|
+
};
|
|
5717
|
+
window.addEventListener('resize', this.watermarkResizeHandler);
|
|
5718
|
+
|
|
5626
5719
|
if (this.options.debug) {
|
|
5627
5720
|
console.log('🏷️ Watermark created:', {
|
|
5628
5721
|
url: this.options.watermarkUrl,
|
|
@@ -5635,6 +5728,7 @@ initializeWatermark() {
|
|
|
5635
5728
|
}
|
|
5636
5729
|
|
|
5637
5730
|
|
|
5731
|
+
|
|
5638
5732
|
setWatermark(url, link = '', position = 'bottomright', title = '') {
|
|
5639
5733
|
|
|
5640
5734
|
this.options.watermarkUrl = url;
|
|
@@ -5663,6 +5757,12 @@ removeWatermark() {
|
|
|
5663
5757
|
this.watermarkElement = null;
|
|
5664
5758
|
}
|
|
5665
5759
|
|
|
5760
|
+
|
|
5761
|
+
if (this.watermarkResizeHandler) {
|
|
5762
|
+
window.removeEventListener('resize', this.watermarkResizeHandler);
|
|
5763
|
+
this.watermarkResizeHandler = null;
|
|
5764
|
+
}
|
|
5765
|
+
|
|
5666
5766
|
this.options.watermarkUrl = '';
|
|
5667
5767
|
this.options.watermarkLink = '';
|
|
5668
5768
|
this.options.watermarkPosition = 'bottomright';
|
|
@@ -5674,6 +5774,7 @@ removeWatermark() {
|
|
|
5674
5774
|
}
|
|
5675
5775
|
|
|
5676
5776
|
|
|
5777
|
+
|
|
5677
5778
|
setWatermarkPosition(position) {
|
|
5678
5779
|
if (!['topleft', 'topright', 'bottomleft', 'bottomright'].includes(position)) {
|
|
5679
5780
|
if (this.options.debug) console.warn('🏷️ Invalid watermark position:', position);
|
|
@@ -5701,6 +5802,36 @@ setWatermarkPosition(position) {
|
|
|
5701
5802
|
}
|
|
5702
5803
|
|
|
5703
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
|
+
|
|
5704
5835
|
setWatermarkAutoHide(hide) {
|
|
5705
5836
|
this.options.hideWatermark = hide;
|
|
5706
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
|
```
|