myetv-player 1.1.4 → 1.1.5
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 +14 -0
- package/css/myetv-player.css +21 -0
- package/css/myetv-player.min.css +1 -1
- package/dist/myetv-player.js +107 -48
- package/dist/myetv-player.min.js +65 -29
- package/package.json +2 -1
- package/plugins/vimeo/myetv-player-vimeo.js +223 -0
- package/plugins/youtube/myetv-player-youtube-plugin.js +106 -114
- package/scss/_controls.scss +21 -0
- package/src/controls.js +90 -32
- package/src/core.js +17 -16
|
@@ -367,10 +367,20 @@
|
|
|
367
367
|
|
|
368
368
|
// Hide original speed menu option from settings (if exists)
|
|
369
369
|
if (settingsMenu) {
|
|
370
|
+
// Hide old non-expandable speed option
|
|
370
371
|
const originalSpeedOption = settingsMenu.querySelector('[data-action="speed"]');
|
|
371
372
|
if (originalSpeedOption) {
|
|
372
373
|
originalSpeedOption.style.display = 'none';
|
|
373
374
|
}
|
|
375
|
+
|
|
376
|
+
// Hide new expandable speed option
|
|
377
|
+
const expandableSpeedWrapper = settingsMenu.querySelector('[data-action="speed-expand"]');
|
|
378
|
+
if (expandableSpeedWrapper) {
|
|
379
|
+
const wrapper = expandableSpeedWrapper.closest('.settings-expandable-wrapper');
|
|
380
|
+
if (wrapper) {
|
|
381
|
+
wrapper.style.display = 'none';
|
|
382
|
+
}
|
|
383
|
+
}
|
|
374
384
|
}
|
|
375
385
|
|
|
376
386
|
// Add subtitles option to settings menu
|
|
@@ -647,6 +657,15 @@
|
|
|
647
657
|
if (originalSpeedOption) {
|
|
648
658
|
originalSpeedOption.style.display = '';
|
|
649
659
|
}
|
|
660
|
+
|
|
661
|
+
// Show expandable speed option again
|
|
662
|
+
const expandableSpeedWrapper = settingsMenu.querySelector('[data-action="speed-expand"]');
|
|
663
|
+
if (expandableSpeedWrapper) {
|
|
664
|
+
const wrapper = expandableSpeedWrapper.closest('.settings-expandable-wrapper');
|
|
665
|
+
if (wrapper) {
|
|
666
|
+
wrapper.style.display = '';
|
|
667
|
+
}
|
|
668
|
+
}
|
|
650
669
|
}
|
|
651
670
|
|
|
652
671
|
// Remove from settings
|
|
@@ -3131,7 +3150,7 @@ startBufferMonitoring() {
|
|
|
3131
3150
|
}
|
|
3132
3151
|
};
|
|
3133
3152
|
|
|
3134
|
-
// Override pause method
|
|
3153
|
+
// Override pause method
|
|
3135
3154
|
const originalPause = this.player.pause;
|
|
3136
3155
|
this.player.pause = () => {
|
|
3137
3156
|
if (this.ytPlayer && this.ytPlayer.pauseVideo) {
|
|
@@ -3203,15 +3222,13 @@ startBufferMonitoring() {
|
|
|
3203
3222
|
// Override mute toggle
|
|
3204
3223
|
const originalToggleMute = this.player.toggleMute;
|
|
3205
3224
|
this.player.toggleMute = () => {
|
|
3206
|
-
if (this.ytPlayer && this.ytPlayer.isMuted
|
|
3225
|
+
if (this.ytPlayer && this.ytPlayer.isMuted) {
|
|
3207
3226
|
const isMuted = this.ytPlayer.isMuted();
|
|
3208
|
-
|
|
3209
3227
|
if (isMuted) {
|
|
3210
3228
|
this.ytPlayer.unMute();
|
|
3211
3229
|
} else {
|
|
3212
3230
|
this.ytPlayer.mute();
|
|
3213
3231
|
}
|
|
3214
|
-
|
|
3215
3232
|
this.updateMuteButtonState(!isMuted);
|
|
3216
3233
|
|
|
3217
3234
|
if (!isMuted) {
|
|
@@ -3225,97 +3242,6 @@ startBufferMonitoring() {
|
|
|
3225
3242
|
}
|
|
3226
3243
|
};
|
|
3227
3244
|
|
|
3228
|
-
// Volume tooltip events for YouTube
|
|
3229
|
-
if (this.api.player.volumeSlider) {
|
|
3230
|
-
const volumeSlider = this.api.player.volumeSlider;
|
|
3231
|
-
const volumeContainer = this.api.container.querySelector('.volume-container');
|
|
3232
|
-
|
|
3233
|
-
// Remove existing listeners to avoid duplicates
|
|
3234
|
-
const newVolumeSlider = volumeSlider.cloneNode(true);
|
|
3235
|
-
volumeSlider.parentNode.replaceChild(newVolumeSlider, volumeSlider);
|
|
3236
|
-
this.api.player.volumeSlider = newVolumeSlider;
|
|
3237
|
-
|
|
3238
|
-
// Update tooltip on input (slider drag)
|
|
3239
|
-
newVolumeSlider.addEventListener('input', (e) => {
|
|
3240
|
-
const value = parseFloat(e.target.value);
|
|
3241
|
-
this.player.updateVolume(value);
|
|
3242
|
-
|
|
3243
|
-
// Update tooltip position and text during drag
|
|
3244
|
-
if (this.api.player.updateVolumeTooltipPosition) {
|
|
3245
|
-
this.api.player.updateVolumeTooltipPosition(value / 100);
|
|
3246
|
-
}
|
|
3247
|
-
if (this.api.player.updateVolumeTooltip) {
|
|
3248
|
-
this.api.player.updateVolumeTooltip();
|
|
3249
|
-
}
|
|
3250
|
-
});
|
|
3251
|
-
|
|
3252
|
-
// Update tooltip position on mousemove over slider
|
|
3253
|
-
newVolumeSlider.addEventListener('mousemove', (e) => {
|
|
3254
|
-
const rect = newVolumeSlider.getBoundingClientRect();
|
|
3255
|
-
const mouseX = e.clientX - rect.left;
|
|
3256
|
-
const percentage = Math.max(0, Math.min(1, mouseX / rect.width));
|
|
3257
|
-
|
|
3258
|
-
// Update tooltip position as mouse moves
|
|
3259
|
-
if (this.api.player.updateVolumeTooltipPosition) {
|
|
3260
|
-
this.api.player.updateVolumeTooltipPosition(percentage);
|
|
3261
|
-
}
|
|
3262
|
-
|
|
3263
|
-
// Update tooltip text to show value under mouse
|
|
3264
|
-
const volumeTooltip = this.api.container.querySelector('.volume-tooltip');
|
|
3265
|
-
if (volumeTooltip) {
|
|
3266
|
-
volumeTooltip.textContent = Math.round(percentage * 100) + '%';
|
|
3267
|
-
}
|
|
3268
|
-
});
|
|
3269
|
-
|
|
3270
|
-
// Show/hide tooltip on hover
|
|
3271
|
-
if (volumeContainer) {
|
|
3272
|
-
volumeContainer.addEventListener('mouseenter', () => {
|
|
3273
|
-
const volumeTooltip = this.api.container.querySelector('.volume-tooltip');
|
|
3274
|
-
if (volumeTooltip) {
|
|
3275
|
-
volumeTooltip.classList.add('visible');
|
|
3276
|
-
}
|
|
3277
|
-
});
|
|
3278
|
-
|
|
3279
|
-
volumeContainer.addEventListener('mouseleave', () => {
|
|
3280
|
-
const volumeTooltip = this.api.container.querySelector('.volume-tooltip');
|
|
3281
|
-
if (volumeTooltip) {
|
|
3282
|
-
volumeTooltip.classList.remove('visible');
|
|
3283
|
-
}
|
|
3284
|
-
});
|
|
3285
|
-
}
|
|
3286
|
-
|
|
3287
|
-
if (this.api.player.options.debug) {
|
|
3288
|
-
console.log('[YT Plugin] Volume tooltip events bound');
|
|
3289
|
-
}
|
|
3290
|
-
}
|
|
3291
|
-
|
|
3292
|
-
// Override playback speed
|
|
3293
|
-
const originalChangeSpeed = this.player.changeSpeed;
|
|
3294
|
-
if (originalChangeSpeed) {
|
|
3295
|
-
this.player.changeSpeed = (e) => {
|
|
3296
|
-
if (!e.target.classList.contains('speed-option')) return;
|
|
3297
|
-
|
|
3298
|
-
const speed = parseFloat(e.target.getAttribute('data-speed'));
|
|
3299
|
-
|
|
3300
|
-
if (this.ytPlayer && this.ytPlayer.setPlaybackRate && speed > 0) {
|
|
3301
|
-
this.ytPlayer.setPlaybackRate(speed);
|
|
3302
|
-
|
|
3303
|
-
const speedBtn = this.api.container.querySelector('.speed-btn');
|
|
3304
|
-
if (speedBtn) speedBtn.textContent = `${speed}x`;
|
|
3305
|
-
|
|
3306
|
-
const speedMenu = this.api.container.querySelector('.speed-menu');
|
|
3307
|
-
if (speedMenu) {
|
|
3308
|
-
speedMenu.querySelectorAll('.speed-option').forEach(option => {
|
|
3309
|
-
option.classList.remove('active');
|
|
3310
|
-
});
|
|
3311
|
-
e.target.classList.add('active');
|
|
3312
|
-
}
|
|
3313
|
-
} else {
|
|
3314
|
-
originalChangeSpeed.call(this.player, e);
|
|
3315
|
-
}
|
|
3316
|
-
};
|
|
3317
|
-
}
|
|
3318
|
-
|
|
3319
3245
|
// Override progress bar seeking
|
|
3320
3246
|
if (this.api.player.progressContainer) {
|
|
3321
3247
|
const progressContainer = this.api.player.progressContainer;
|
|
@@ -3330,7 +3256,22 @@ startBufferMonitoring() {
|
|
|
3330
3256
|
// Create tooltip for seek preview
|
|
3331
3257
|
const seekTooltip = document.createElement('div');
|
|
3332
3258
|
seekTooltip.className = 'yt-seek-tooltip';
|
|
3333
|
-
seekTooltip.style.cssText =
|
|
3259
|
+
seekTooltip.style.cssText = `
|
|
3260
|
+
position: absolute;
|
|
3261
|
+
bottom: calc(100% + 10px);
|
|
3262
|
+
left: 0;
|
|
3263
|
+
background: rgba(28,28,28,0.95);
|
|
3264
|
+
color: #fff;
|
|
3265
|
+
padding: 6px 10px;
|
|
3266
|
+
border-radius: 3px;
|
|
3267
|
+
font-size: 13px;
|
|
3268
|
+
font-weight: 500;
|
|
3269
|
+
white-space: nowrap;
|
|
3270
|
+
pointer-events: none;
|
|
3271
|
+
visibility: hidden;
|
|
3272
|
+
z-index: 99999;
|
|
3273
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
|
|
3274
|
+
`;
|
|
3334
3275
|
newProgressContainer.appendChild(seekTooltip);
|
|
3335
3276
|
|
|
3336
3277
|
// Format time function for tooltip
|
|
@@ -3348,25 +3289,32 @@ startBufferMonitoring() {
|
|
|
3348
3289
|
let isSeeking = false;
|
|
3349
3290
|
|
|
3350
3291
|
const handleSeek = (e) => {
|
|
3351
|
-
if (!this.ytPlayer || !this.ytPlayer.getDuration) return;
|
|
3292
|
+
if (!this.ytPlayer || !this.ytPlayer.getDuration()) return;
|
|
3352
3293
|
|
|
3353
3294
|
const rect = newProgressContainer.getBoundingClientRect();
|
|
3354
|
-
|
|
3295
|
+
|
|
3296
|
+
// Support both mouse and touch events
|
|
3297
|
+
const clientX = e.clientX !== undefined ? e.clientX :
|
|
3298
|
+
(e.touches && e.touches[0] ? e.touches[0].clientX :
|
|
3299
|
+
(e.changedTouches && e.changedTouches[0] ? e.changedTouches[0].clientX : 0));
|
|
3300
|
+
|
|
3301
|
+
const clickX = clientX - rect.left;
|
|
3355
3302
|
const percentage = Math.max(0, Math.min(1, clickX / rect.width));
|
|
3356
3303
|
const duration = this.ytPlayer.getDuration();
|
|
3357
3304
|
const targetTime = percentage * duration;
|
|
3358
3305
|
|
|
3359
3306
|
this.ytPlayer.seekTo(targetTime, true);
|
|
3360
3307
|
|
|
3361
|
-
const progress = percentage * 100
|
|
3308
|
+
const progress = percentage * 100;
|
|
3362
3309
|
if (this.api.player.progressFilled) {
|
|
3363
|
-
this.api.player.progressFilled.style.width = progress
|
|
3310
|
+
this.api.player.progressFilled.style.width = `${progress}%`;
|
|
3364
3311
|
}
|
|
3365
3312
|
if (this.api.player.progressHandle) {
|
|
3366
|
-
this.api.player.progressHandle.style.left = progress
|
|
3313
|
+
this.api.player.progressHandle.style.left = `${progress}%`;
|
|
3367
3314
|
}
|
|
3368
3315
|
};
|
|
3369
3316
|
|
|
3317
|
+
// MOUSE EVENTS
|
|
3370
3318
|
newProgressContainer.addEventListener('mousedown', (e) => {
|
|
3371
3319
|
isSeeking = true;
|
|
3372
3320
|
handleSeek(e);
|
|
@@ -3378,7 +3326,7 @@ startBufferMonitoring() {
|
|
|
3378
3326
|
}
|
|
3379
3327
|
|
|
3380
3328
|
// Show tooltip with timestamp
|
|
3381
|
-
if (!isSeeking && this.ytPlayer && this.ytPlayer.getDuration) {
|
|
3329
|
+
if (!isSeeking && this.ytPlayer && this.ytPlayer.getDuration()) {
|
|
3382
3330
|
const rect = newProgressContainer.getBoundingClientRect();
|
|
3383
3331
|
const mouseX = e.clientX - rect.left;
|
|
3384
3332
|
const percentage = Math.max(0, Math.min(1, mouseX / rect.width));
|
|
@@ -3386,7 +3334,7 @@ startBufferMonitoring() {
|
|
|
3386
3334
|
const time = percentage * duration;
|
|
3387
3335
|
|
|
3388
3336
|
seekTooltip.textContent = formatTimeForTooltip(time);
|
|
3389
|
-
seekTooltip.style.left = mouseX
|
|
3337
|
+
seekTooltip.style.left = `${mouseX}px`;
|
|
3390
3338
|
seekTooltip.style.visibility = 'visible';
|
|
3391
3339
|
}
|
|
3392
3340
|
});
|
|
@@ -3399,10 +3347,50 @@ startBufferMonitoring() {
|
|
|
3399
3347
|
isSeeking = false;
|
|
3400
3348
|
});
|
|
3401
3349
|
|
|
3350
|
+
// TOUCH EVENTS - AGGIUNTI QUI!
|
|
3351
|
+
newProgressContainer.addEventListener('touchstart', (e) => {
|
|
3352
|
+
e.preventDefault(); // scroll prevention during drag
|
|
3353
|
+
isSeeking = true;
|
|
3354
|
+
handleSeek(e);
|
|
3355
|
+
}, { passive: false });
|
|
3356
|
+
|
|
3357
|
+
newProgressContainer.addEventListener('touchmove', (e) => {
|
|
3358
|
+
e.preventDefault(); // scroll prevention during drag
|
|
3359
|
+
|
|
3360
|
+
if (isSeeking) {
|
|
3361
|
+
handleSeek(e);
|
|
3362
|
+
}
|
|
3363
|
+
|
|
3364
|
+
// Show tooltip with timestamp during touch
|
|
3365
|
+
if (!isSeeking && this.ytPlayer && this.ytPlayer.getDuration()) {
|
|
3366
|
+
const rect = newProgressContainer.getBoundingClientRect();
|
|
3367
|
+
const touch = e.touches[0];
|
|
3368
|
+
const touchX = touch.clientX - rect.left;
|
|
3369
|
+
const percentage = Math.max(0, Math.min(1, touchX / rect.width));
|
|
3370
|
+
const duration = this.ytPlayer.getDuration();
|
|
3371
|
+
const time = percentage * duration;
|
|
3372
|
+
|
|
3373
|
+
seekTooltip.textContent = formatTimeForTooltip(time);
|
|
3374
|
+
seekTooltip.style.left = `${touchX}px`;
|
|
3375
|
+
seekTooltip.style.visibility = 'visible';
|
|
3376
|
+
}
|
|
3377
|
+
}, { passive: false });
|
|
3378
|
+
|
|
3379
|
+
newProgressContainer.addEventListener('touchend', () => {
|
|
3380
|
+
isSeeking = false;
|
|
3381
|
+
seekTooltip.style.visibility = 'hidden';
|
|
3382
|
+
});
|
|
3383
|
+
|
|
3384
|
+
newProgressContainer.addEventListener('touchcancel', () => {
|
|
3385
|
+
isSeeking = false;
|
|
3386
|
+
seekTooltip.style.visibility = 'hidden';
|
|
3387
|
+
});
|
|
3388
|
+
|
|
3389
|
+
// CLICK EVENT
|
|
3402
3390
|
newProgressContainer.addEventListener('click', handleSeek);
|
|
3403
|
-
}
|
|
3404
3391
|
|
|
3405
|
-
|
|
3392
|
+
this.bindVolumeSlider();
|
|
3393
|
+
}
|
|
3406
3394
|
|
|
3407
3395
|
// Time update interval
|
|
3408
3396
|
if (this.timeUpdateInterval) {
|
|
@@ -3423,14 +3411,13 @@ startBufferMonitoring() {
|
|
|
3423
3411
|
} else {
|
|
3424
3412
|
// For regular videos, calculate normally
|
|
3425
3413
|
progress = (currentTime / duration) * 100;
|
|
3426
|
-
}
|
|
3427
|
-
|
|
3428
|
-
// Check if live badge exists = it's a live stream
|
|
3429
|
-
const liveBadge = this.api.container.querySelector('.live-badge');
|
|
3430
3414
|
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3415
|
+
// Check if live badge exists = it's a live stream
|
|
3416
|
+
const liveBadge = this.api.container.querySelector('.live-badge');
|
|
3417
|
+
if (liveBadge) {
|
|
3418
|
+
// Force 100% for live streams
|
|
3419
|
+
progress = 100;
|
|
3420
|
+
}
|
|
3434
3421
|
}
|
|
3435
3422
|
|
|
3436
3423
|
this.api.player.progressFilled.style.width = `${progress}%`;
|
|
@@ -3442,8 +3429,13 @@ startBufferMonitoring() {
|
|
|
3442
3429
|
const currentTimeEl = this.api.container.querySelector('.current-time');
|
|
3443
3430
|
const durationEl = this.api.container.querySelector('.duration');
|
|
3444
3431
|
|
|
3445
|
-
if (currentTimeEl)
|
|
3446
|
-
|
|
3432
|
+
if (currentTimeEl) {
|
|
3433
|
+
currentTimeEl.textContent = this.formatTime(currentTime);
|
|
3434
|
+
}
|
|
3435
|
+
|
|
3436
|
+
if (durationEl && duration) {
|
|
3437
|
+
durationEl.textContent = this.formatTime(duration);
|
|
3438
|
+
}
|
|
3447
3439
|
}
|
|
3448
3440
|
}, 250);
|
|
3449
3441
|
}
|
package/scss/_controls.scss
CHANGED
|
@@ -165,3 +165,24 @@
|
|
|
165
165
|
.controls-right .brand-logo-link .brand-logo {
|
|
166
166
|
margin-right: 0;
|
|
167
167
|
}
|
|
168
|
+
|
|
169
|
+
/* Hide cursor when controlbar is hidden */
|
|
170
|
+
.video-wrapper.hide-cursor {
|
|
171
|
+
cursor: none !important;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/* Ensure cursor is visible on controls even when hide-cursor is active */
|
|
175
|
+
.video-wrapper.hide-cursor .controls {
|
|
176
|
+
cursor: default !important;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/* Ensure cursor is visible on buttons */
|
|
180
|
+
.video-wrapper.hide-cursor .control-btn {
|
|
181
|
+
cursor: pointer !important;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* do not hide mouse on iframes */
|
|
185
|
+
.video-wrapper.hide-cursor iframe {
|
|
186
|
+
cursor: auto !important;
|
|
187
|
+
pointer-events: auto !important;
|
|
188
|
+
}
|
package/src/controls.js
CHANGED
|
@@ -85,6 +85,7 @@ initAutoHide() {
|
|
|
85
85
|
|
|
86
86
|
onMouseMoveInPlayer(e) {
|
|
87
87
|
this.showControlsNow();
|
|
88
|
+
this.showCursor();
|
|
88
89
|
this.resetAutoHideTimer();
|
|
89
90
|
}
|
|
90
91
|
|
|
@@ -142,66 +143,69 @@ resetAutoHideTimer() {
|
|
|
142
143
|
showControlsNow() {
|
|
143
144
|
if (this.controls) {
|
|
144
145
|
this.controls.classList.add('show');
|
|
145
|
-
}
|
|
146
146
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
147
|
+
// Add has-controls class to container (for watermark visibility)
|
|
148
|
+
if (this.container) {
|
|
149
|
+
this.container.classList.add('has-controls');
|
|
150
|
+
}
|
|
151
|
+
|
|
150
152
|
this.updateControlbarHeight();
|
|
153
|
+
|
|
151
154
|
// Update watermark position
|
|
152
155
|
if (this.updateWatermarkPosition) {
|
|
153
156
|
this.updateWatermarkPosition();
|
|
154
157
|
}
|
|
155
|
-
}
|
|
156
158
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
159
|
+
// Show title overlay with controls (if not persistent)
|
|
160
|
+
if (this.options.showTitleOverlay && !this.options.persistentTitle && this.options.videoTitle) {
|
|
161
|
+
this.showTitleOverlay();
|
|
162
|
+
}
|
|
161
163
|
|
|
162
|
-
|
|
164
|
+
// *show cursor when controls are shown*
|
|
165
|
+
this.showCursor();
|
|
166
|
+
|
|
167
|
+
if (this.autoHideDebug && this.options.debug) console.log('✅ Controls shown');
|
|
168
|
+
}
|
|
163
169
|
}
|
|
164
170
|
|
|
165
171
|
hideControlsNow() {
|
|
166
|
-
//
|
|
172
|
+
// Dont hide if mouse is still over controls (allow hiding on touch devices)
|
|
167
173
|
const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
|
|
168
|
-
|
|
169
174
|
if (this.mouseOverControls && !isTouchDevice) {
|
|
170
|
-
if (this.autoHideDebug && this.options.debug)
|
|
171
|
-
console.log('🚫 Not hiding - mouse still over controls');
|
|
172
|
-
}
|
|
175
|
+
if (this.autoHideDebug && this.options.debug) console.log('❌ Not hiding - mouse still over controls');
|
|
173
176
|
return;
|
|
174
177
|
}
|
|
175
178
|
|
|
176
|
-
//
|
|
179
|
+
// Dont hide if video is paused
|
|
177
180
|
if (this.video && this.video.paused) {
|
|
178
|
-
if (this.autoHideDebug && this.options.debug)
|
|
179
|
-
console.log('🚫 Not hiding - video is paused');
|
|
180
|
-
}
|
|
181
|
+
if (this.autoHideDebug && this.options.debug) console.log('❌ Not hiding - video is paused');
|
|
181
182
|
return;
|
|
182
183
|
}
|
|
183
184
|
|
|
184
185
|
if (this.controls) {
|
|
185
186
|
this.controls.classList.remove('show');
|
|
186
187
|
|
|
187
|
-
// Remove has-controls class from container for watermark visibility
|
|
188
|
+
// Remove has-controls class from container (for watermark visibility)
|
|
188
189
|
if (this.container) {
|
|
189
190
|
this.container.classList.remove('has-controls');
|
|
190
|
-
this.updateControlbarHeight();
|
|
191
|
-
// Update watermark position
|
|
192
|
-
if (this.updateWatermarkPosition) {
|
|
193
|
-
this.updateWatermarkPosition();
|
|
194
|
-
}
|
|
195
191
|
}
|
|
196
|
-
}
|
|
197
192
|
|
|
198
|
-
|
|
199
|
-
if (this.options.showTitleOverlay && !this.options.persistentTitle) {
|
|
200
|
-
this.hideTitleOverlay();
|
|
201
|
-
}
|
|
193
|
+
this.updateControlbarHeight();
|
|
202
194
|
|
|
203
|
-
|
|
204
|
-
|
|
195
|
+
// Update watermark position
|
|
196
|
+
if (this.updateWatermarkPosition) {
|
|
197
|
+
this.updateWatermarkPosition();
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Hide title overlay with controls (if not persistent)
|
|
201
|
+
if (this.options.showTitleOverlay && !this.options.persistentTitle) {
|
|
202
|
+
this.hideTitleOverlay();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// *hide cursor after controls are hidden*
|
|
206
|
+
this.hideCursor();
|
|
207
|
+
|
|
208
|
+
if (this.autoHideDebug && this.options.debug) console.log('✅ Controls hidden');
|
|
205
209
|
}
|
|
206
210
|
}
|
|
207
211
|
|
|
@@ -1067,6 +1071,60 @@ isAutoHideInitialized() {
|
|
|
1067
1071
|
return this.autoHideInitialized;
|
|
1068
1072
|
}
|
|
1069
1073
|
|
|
1074
|
+
/**
|
|
1075
|
+
* Hide mouse cursor in player container
|
|
1076
|
+
* Only hides cursor in main container, not in plugin iframes
|
|
1077
|
+
*/
|
|
1078
|
+
hideCursor() {
|
|
1079
|
+
if (!this.options.hideCursor) {
|
|
1080
|
+
return; // Do not hide cursor if option is disabled
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
if (this.container) {
|
|
1084
|
+
this.container.classList.add('hide-cursor');
|
|
1085
|
+
if (this.options.debug) console.log('🖱️ Cursor hidden');
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
/**
|
|
1090
|
+
* Show mouse cursor in player container
|
|
1091
|
+
*/
|
|
1092
|
+
showCursor() {
|
|
1093
|
+
if (this.container) {
|
|
1094
|
+
this.container.classList.remove('hide-cursor');
|
|
1095
|
+
if (this.options.debug) console.log('🖱️ Cursor shown');
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
/**
|
|
1100
|
+
* Enable cursor hiding when controlbar is hidden
|
|
1101
|
+
* @returns {Object} this
|
|
1102
|
+
*/
|
|
1103
|
+
enableCursorHiding() {
|
|
1104
|
+
this.options.hideCursor = true;
|
|
1105
|
+
if (this.options.debug) console.log('Cursor hiding enabled');
|
|
1106
|
+
return this;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
/**
|
|
1110
|
+
* Disable cursor hiding - cursor will always be visible
|
|
1111
|
+
* @returns {Object} this
|
|
1112
|
+
*/
|
|
1113
|
+
disableCursorHiding() {
|
|
1114
|
+
this.options.hideCursor = false;
|
|
1115
|
+
this.showCursor(); // Ensure cursor is shown immediately
|
|
1116
|
+
if (this.options.debug) console.log('Cursor hiding disabled');
|
|
1117
|
+
return this;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
/**
|
|
1121
|
+
* Check if cursor hiding is enabled
|
|
1122
|
+
* @returns {Boolean} True if cursor hiding is enabled
|
|
1123
|
+
*/
|
|
1124
|
+
isCursorHidingEnabled() {
|
|
1125
|
+
return this.options.hideCursor;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1070
1128
|
/* PLAYLIST CONTROLS */
|
|
1071
1129
|
showPlaylistControls() {
|
|
1072
1130
|
if (!this.playlistPrevBtn || !this.playlistNextBtn) return;
|
package/src/core.js
CHANGED
|
@@ -12,22 +12,23 @@ constructor(videoElement, options = {}) {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
this.options = {
|
|
15
|
-
showQualitySelector: true,
|
|
16
|
-
showSpeedControl: true,
|
|
17
|
-
showFullscreen: true,
|
|
18
|
-
showPictureInPicture: true,
|
|
19
|
-
showSubtitles: true,
|
|
20
|
-
subtitlesEnabled: false,
|
|
21
|
-
autoHide: true,
|
|
22
|
-
autoHideDelay: 3000,
|
|
15
|
+
showQualitySelector: true, // Enable quality selector button
|
|
16
|
+
showSpeedControl: true, // Enable speed control button
|
|
17
|
+
showFullscreen: true, // Enable fullscreen button
|
|
18
|
+
showPictureInPicture: true, // Enable PiP button
|
|
19
|
+
showSubtitles: true, // Enable subtitles button
|
|
20
|
+
subtitlesEnabled: false, // Enable subtitles by default if available
|
|
21
|
+
autoHide: true, // auto-hide controls when idle
|
|
22
|
+
autoHideDelay: 3000, // hide controls after ... seconds of inactivity (specificed in milliseconds)
|
|
23
|
+
hideCursor: true, // hide mouse cursor when idle
|
|
23
24
|
poster: null, // URL of poster image
|
|
24
25
|
showPosterOnEnd: false, // Show poster again when video ends
|
|
25
|
-
keyboardControls: true,
|
|
26
|
-
showSeekTooltip: true,
|
|
27
|
-
showTitleOverlay: false,
|
|
28
|
-
videoTitle: '',
|
|
29
|
-
videoSubtitle: '',
|
|
30
|
-
persistentTitle: false,
|
|
26
|
+
keyboardControls: true, // Enable keyboard controls
|
|
27
|
+
showSeekTooltip: true, // Show tooltip on seek bar at mouse hover
|
|
28
|
+
showTitleOverlay: false, // Show video title overlay
|
|
29
|
+
videoTitle: '', // Title text to show in overlay
|
|
30
|
+
videoSubtitle: '', // Subtitle text to show in overlay
|
|
31
|
+
persistentTitle: false, // If true, title overlay stays visible
|
|
31
32
|
debug: false, // Enable/disable debug logging
|
|
32
33
|
autoplay: false, // if video should autoplay at start
|
|
33
34
|
defaultQuality: 'auto', // 'auto', '1080p', '720p', '480p', etc.
|
|
@@ -57,8 +58,8 @@ constructor(videoElement, options = {}) {
|
|
|
57
58
|
//seek shape
|
|
58
59
|
seekHandleShape: 'circle', // Available shape: none, circle, square, diamond, arrow, triangle, heart, star
|
|
59
60
|
// AUDIO PLAYER
|
|
60
|
-
audiofile: false,
|
|
61
|
-
audiowave: false,
|
|
61
|
+
audiofile: false, // if true, adapt player to audio file (hide video element)
|
|
62
|
+
audiowave: false, // if true, show audio wave visualization (Web Audio API)
|
|
62
63
|
// RESOLUTION CONTROL
|
|
63
64
|
resolution: "normal", // "normal", "4:3", "16:9", "stretched", "fit-to-screen", "scale-to-fit"
|
|
64
65
|
...options
|