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/scss/_video.scss CHANGED
@@ -2320,81 +2320,6 @@ video::-webkit-media-text-track-display {
2320
2320
  right: 15px;
2321
2321
  }
2322
2322
 
2323
- /* Bottom positions - Increased spacing from controlbar (was 70px, now 90px) */
2324
- .video-watermark.watermark-bottomleft {
2325
- bottom: 90px; /* Increased spacing */
2326
- left: 15px;
2327
- }
2328
-
2329
- .video-watermark.watermark-bottomright {
2330
- bottom: 90px; /* Increased spacing */
2331
- right: 15px;
2332
- }
2333
-
2334
- /* DYNAMIC POSITIONING: Always visible watermark moves down when controls are hidden */
2335
- /* This applies ONLY to watermarks without hide-on-autohide class (always visible) */
2336
- .video-wrapper:not(.has-controls) .video-watermark.watermark-bottomleft:not(.hide-on-autohide) {
2337
- bottom: 15px; /* Move to bottom corner when controls hidden */
2338
- }
2339
-
2340
- .video-wrapper:not(.has-controls) .video-watermark.watermark-bottomright:not(.hide-on-autohide) {
2341
- bottom: 15px; /* Move to bottom corner when controls hidden */
2342
- }
2343
-
2344
- /* When controls are shown, bottom watermark stays above controlbar */
2345
- .video-wrapper.has-controls .video-watermark.watermark-bottomleft,
2346
- .video-wrapper.has-controls .video-watermark.watermark-bottomright {
2347
- bottom: 90px; /* Stay above controlbar */
2348
- }
2349
-
2350
- /* Responsive adjustments for mobile */
2351
- @media (max-width: 768px) {
2352
- .video-watermark img {
2353
- max-width: 100px;
2354
- max-height: 50px;
2355
- }
2356
-
2357
- .video-watermark.watermark-topleft,
2358
- .video-watermark.watermark-topright {
2359
- top: 10px;
2360
- }
2361
-
2362
- .video-watermark.watermark-topleft,
2363
- .video-watermark.watermark-bottomleft {
2364
- left: 10px;
2365
- }
2366
-
2367
- .video-watermark.watermark-topright,
2368
- .video-watermark.watermark-bottomright {
2369
- right: 10px;
2370
- }
2371
-
2372
- /* Bottom spacing adjusted for mobile */
2373
- .video-watermark.watermark-bottomleft,
2374
- .video-watermark.watermark-bottomright {
2375
- bottom: 75px; /* Above controlbar on mobile */
2376
- }
2377
-
2378
- /* Always visible watermark on mobile - moves down when controls hidden */
2379
- .video-wrapper:not(.has-controls) .video-watermark.watermark-bottomleft:not(.hide-on-autohide),
2380
- .video-wrapper:not(.has-controls) .video-watermark.watermark-bottomright:not(.hide-on-autohide) {
2381
- bottom: 10px; /* Move to corner on mobile */
2382
- }
2383
- }
2384
-
2385
- /* Extra small screens */
2386
- @media (max-width: 480px) {
2387
- .video-watermark.watermark-bottomleft,
2388
- .video-watermark.watermark-bottomright {
2389
- bottom: 65px;
2390
- }
2391
-
2392
- .video-wrapper:not(.has-controls) .video-watermark.watermark-bottomleft:not(.hide-on-autohide),
2393
- .video-wrapper:not(.has-controls) .video-watermark.watermark-bottomright:not(.hide-on-autohide) {
2394
- bottom: 8px;
2395
- }
2396
- }
2397
-
2398
2323
  /* Clickable watermark cursor */
2399
2324
  .video-watermark[style*="cursor: pointer"] {
2400
2325
  cursor: pointer !important;
@@ -5,4 +5,124 @@
5
5
  @use 'mixins' as *;
6
6
  @use 'variables' as *;
7
7
 
8
+ .video-watermark {
9
+ position: absolute;
10
+ z-index: 15;
11
+ pointer-events: auto;
12
+ opacity: 0.7;
13
+ transition: opacity 0.3s ease, visibility 0.3s ease, bottom 0.3s ease;
14
+ }
8
15
 
16
+ .video-watermark {
17
+ visibility: visible;
18
+ opacity: 0.7;
19
+ }
20
+
21
+ .video-wrapper:not(.has-controls) .video-watermark.hide-on-autohide {
22
+ visibility: hidden;
23
+ opacity: 0;
24
+ }
25
+
26
+ .video-wrapper.has-controls .video-watermark {
27
+ visibility: visible;
28
+ opacity: 0.7;
29
+ }
30
+
31
+ .video-watermark:hover {
32
+ opacity: 1;
33
+ }
34
+
35
+ .video-watermark img {
36
+ display: block;
37
+ max-width: 150px;
38
+ max-height: 80px;
39
+ width: auto;
40
+ height: auto;
41
+ object-fit: contain;
42
+ }
43
+
44
+ /* Top positions */
45
+ .video-watermark.watermark-topleft {
46
+ top: 15px;
47
+ left: 15px;
48
+ }
49
+
50
+ .video-watermark.watermark-topright {
51
+ top: 15px;
52
+ right: 15px;
53
+ }
54
+
55
+ /* Bottom positions - Dynamic with controlbar height + spacing */
56
+ .video-watermark.watermark-bottomleft {
57
+ bottom: calc(var(--player-controls-height, 70px) + 15px);
58
+ left: 15px;
59
+ }
60
+
61
+ .video-watermark.watermark-bottomright {
62
+ bottom: calc(var(--player-controls-height, 70px) + 15px);
63
+ right: 15px;
64
+ }
65
+
66
+ /* When controls hidden, move to corner */
67
+ .video-wrapper:not(.has-controls) .video-watermark.watermark-bottomleft:not(.hide-on-autohide) {
68
+ bottom: 15px;
69
+ }
70
+
71
+ .video-wrapper:not(.has-controls) .video-watermark.watermark-bottomright:not(.hide-on-autohide) {
72
+ bottom: 15px;
73
+ }
74
+
75
+ /* When controls shown, stay above controlbar */
76
+ .video-wrapper.has-controls .video-watermark.watermark-bottomleft,
77
+ .video-wrapper.has-controls .video-watermark.watermark-bottomright {
78
+ bottom: calc(var(--player-controls-height, 70px) + 15px);
79
+ }
80
+
81
+ /* Responsive */
82
+ @media (max-width: 768px) {
83
+ .video-watermark img {
84
+ max-width: 100px;
85
+ max-height: 50px;
86
+ }
87
+
88
+ .video-watermark.watermark-topleft,
89
+ .video-watermark.watermark-topright {
90
+ top: 10px;
91
+ }
92
+
93
+ .video-watermark.watermark-topleft,
94
+ .video-watermark.watermark-bottomleft {
95
+ left: 10px;
96
+ }
97
+
98
+ .video-watermark.watermark-topright,
99
+ .video-watermark.watermark-bottomright {
100
+ right: 10px;
101
+ }
102
+
103
+ .video-watermark.watermark-bottomleft,
104
+ .video-watermark.watermark-bottomright {
105
+ bottom: calc(var(--player-controls-height, 60px) + 10px);
106
+ }
107
+
108
+ .video-wrapper:not(.has-controls) .video-watermark.watermark-bottomleft:not(.hide-on-autohide),
109
+ .video-wrapper:not(.has-controls) .video-watermark.watermark-bottomright:not(.hide-on-autohide) {
110
+ bottom: 10px;
111
+ }
112
+ }
113
+
114
+ @media (max-width: 480px) {
115
+ .video-watermark.watermark-bottomleft,
116
+ .video-watermark.watermark-bottomright {
117
+ bottom: calc(var(--player-controls-height, 55px) + 10px);
118
+ }
119
+
120
+ .video-wrapper:not(.has-controls) .video-watermark.watermark-bottomleft:not(.hide-on-autohide),
121
+ .video-wrapper:not(.has-controls) .video-watermark.watermark-bottomright:not(.hide-on-autohide) {
122
+ bottom: 8px;
123
+ }
124
+ }
125
+
126
+ .video-watermark[style*="cursor: pointer"] {
127
+ cursor: pointer !important;
128
+ }
@@ -35,17 +35,17 @@
35
35
  // 10. Poster Overlay
36
36
  @use 'poster';
37
37
 
38
- // 11. Watermark
39
- @use 'watermark';
40
-
41
- // 12. Tooltips
38
+ // 11. Tooltips
42
39
  @use 'tooltips';
43
40
 
44
- // 12.5 Audio Player (audiofile + audiowave)
41
+ // 12 Audio Player (audiofile + audiowave)
45
42
  @use 'audio-player';
46
43
 
47
44
  // 13. Themes (Blue, Green, Red)
48
45
  @use 'themes';
49
46
 
50
- // 14. Responsive (must be last)
51
- @use 'responsive';
47
+ // 14. Watermark
48
+ @use 'watermark';
49
+
50
+ // 15. Responsive (must be last)
51
+ @use 'responsive';
package/src/controls.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * Created by https://www.myetv.tv https://oskarcosimo.com
5
5
  */
6
6
 
7
- /* AUTO-HIDE SYSTEM - IMPROVED AND COMPREHENSIVE */
7
+ /* AUTO-HIDE SYSTEM */
8
8
  initAutoHide() {
9
9
  if (!this.options.autoHide) {
10
10
  if (this.options.debug) console.log('Auto-hide disabled in options');
@@ -144,12 +144,17 @@ showControlsNow() {
144
144
  this.controls.classList.add('show');
145
145
  }
146
146
 
147
- // ADD THIS: Add has-controls class to container for watermark visibility
147
+ // Add has-controls class to container for watermark visibility
148
148
  if (this.container) {
149
149
  this.container.classList.add('has-controls');
150
+ this.updateControlbarHeight();
151
+ // Update watermark position
152
+ if (this.updateWatermarkPosition) {
153
+ this.updateWatermarkPosition();
154
+ }
150
155
  }
151
156
 
152
- // Fix: Show title overlay with controls if not persistent
157
+ // Show title overlay with controls if not persistent
153
158
  if (this.options.showTitleOverlay && !this.options.persistentTitle && this.options.videoTitle) {
154
159
  this.showTitleOverlay();
155
160
  }
@@ -160,32 +165,44 @@ showControlsNow() {
160
165
  hideControlsNow() {
161
166
  // Don't hide if mouse is still over controls (allow hiding on touch devices)
162
167
  const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
168
+
163
169
  if (this.mouseOverControls && !isTouchDevice) {
164
- if (this.autoHideDebug && this.options.debug) console.log('⏸️ Not hiding - mouse still over controls');
170
+ if (this.autoHideDebug && this.options.debug) {
171
+ console.log('🚫 Not hiding - mouse still over controls');
172
+ }
165
173
  return;
166
174
  }
167
175
 
168
176
  // Don't hide if video is paused
169
177
  if (this.video && this.video.paused) {
170
- if (this.autoHideDebug && this.options.debug) console.log('⏸️ Not hiding - video is paused');
178
+ if (this.autoHideDebug && this.options.debug) {
179
+ console.log('🚫 Not hiding - video is paused');
180
+ }
171
181
  return;
172
182
  }
173
183
 
174
184
  if (this.controls) {
175
185
  this.controls.classList.remove('show');
176
- }
177
186
 
178
- // ADD THIS: Remove has-controls class from container for watermark visibility
179
- if (this.container) {
180
- this.container.classList.remove('has-controls');
187
+ // Remove has-controls class from container for watermark visibility
188
+ if (this.container) {
189
+ this.container.classList.remove('has-controls');
190
+ this.updateControlbarHeight();
191
+ // Update watermark position
192
+ if (this.updateWatermarkPosition) {
193
+ this.updateWatermarkPosition();
194
+ }
195
+ }
181
196
  }
182
197
 
183
- // Fix: Hide title overlay with controls if not persistent
198
+ // Hide title overlay with controls (if not persistent)
184
199
  if (this.options.showTitleOverlay && !this.options.persistentTitle) {
185
200
  this.hideTitleOverlay();
186
201
  }
187
202
 
188
- if (this.autoHideDebug && this.options.debug) console.log('❌ Controls hidden');
203
+ if (this.autoHideDebug && this.options.debug) {
204
+ console.log('👁️ Controls hidden');
205
+ }
189
206
  }
190
207
 
191
208
  showControls() {
@@ -464,28 +481,62 @@ createControls() {
464
481
  // NEW: Initialize responsive settings menu
465
482
  setTimeout(() => {
466
483
  this.initializeResponsiveMenu();
484
+ this.updateControlbarHeight();
467
485
  }, 100);
468
486
  }
469
487
 
470
- /* NEW: Initialize responsive menu with dynamic width calculation */
488
+ /* Initialize responsive menu with dynamic width calculation */
471
489
  initializeResponsiveMenu() {
472
490
  if (!this.controls) return;
473
491
 
474
492
  // Track screen size
475
493
  this.isSmallScreen = false;
476
494
 
477
- // Check initial size and set up listener
495
+ // Check initial size
478
496
  this.checkScreenSize();
479
497
 
480
- window.addEventListener('resize', () => {
498
+ // Bind resize handler with updateControlbarHeight
499
+ const resizeHandler = () => {
481
500
  this.checkScreenSize();
482
- });
501
+ this.updateControlbarHeight();
502
+ };
503
+
504
+ // Bind del context
505
+ this.resizeHandler = resizeHandler.bind(this);
506
+ window.addEventListener('resize', this.resizeHandler);
483
507
 
484
508
  // Bind events for settings menu
485
509
  this.bindSettingsMenuEvents();
486
510
  }
487
511
 
488
- /* NEW: Dynamic width calculation based on logo presence */
512
+ // Dynamic controlbar height tracking for watermark positioning
513
+ updateControlbarHeight() {
514
+ if (!this.controls) return;
515
+
516
+ const height = this.controls.offsetHeight;
517
+ if (this.container) {
518
+
519
+ this.container.style.setProperty('--player-controls-height', `${height}px`);
520
+
521
+ const watermark = this.container.querySelector('.video-watermark.watermark-bottomleft, .video-watermark.watermark-bottomright');
522
+ if (watermark) {
523
+ const hasControls = this.container.classList.contains('has-controls');
524
+ const isHideOnAutoHide = watermark.classList.contains('hide-on-autohide');
525
+
526
+ if (hasControls || !isHideOnAutoHide) {
527
+ watermark.style.bottom = `${height + 15}px`;
528
+ } else {
529
+ watermark.style.bottom = '15px';
530
+ }
531
+ }
532
+ }
533
+
534
+ if (this.options.debug) {
535
+ console.log(`Controlbar height updated: ${height}px`);
536
+ }
537
+ }
538
+
539
+ /* Dynamic width calculation based on logo presence */
489
540
  getResponsiveThreshold() {
490
541
  // Check if brand logo is enabled and present
491
542
  const hasLogo = this.options.brandLogoEnabled && this.options.brandLogoUrl;
@@ -494,7 +545,7 @@ getResponsiveThreshold() {
494
545
  return hasLogo ? 650 : 550;
495
546
  }
496
547
 
497
- /* NEW: Check if screen is under dynamic threshold */
548
+ /* Check if screen is under dynamic threshold */
498
549
  checkScreenSize() {
499
550
  const threshold = this.getResponsiveThreshold();
500
551
  const newIsSmallScreen = window.innerWidth <= threshold;
@@ -504,12 +555,12 @@ checkScreenSize() {
504
555
  this.updateSettingsMenuVisibility();
505
556
 
506
557
  if (this.options.debug) {
507
- console.log(`Screen check: ${window.innerWidth}px vs ${threshold}px threshold (logo: ${this.options.brandLogoEnabled}), small: ${this.isSmallScreen}`);
558
+ console.log(`Screen check: ${window.innerWidth}px vs ${threshold}px (threshold), logo: ${this.options.brandLogoEnabled}, small: ${this.isSmallScreen}`);
508
559
  }
509
560
  }
510
561
  }
511
562
 
512
- /* NEW: Update settings menu visibility based on screen size */
563
+ /* Update settings menu visibility based on screen size */
513
564
  updateSettingsMenuVisibility() {
514
565
  const settingsControl = this.controls?.querySelector('.settings-control');
515
566
  if (!settingsControl) return;
@@ -549,7 +600,7 @@ updateSettingsMenuVisibility() {
549
600
  }
550
601
  }
551
602
 
552
- /* NEW: Populate settings menu with controls */
603
+ /* Populate settings menu with controls */
553
604
  populateSettingsMenu() {
554
605
  const settingsMenu = this.controls?.querySelector('.settings-menu');
555
606
  if (!settingsMenu) return;
@@ -611,7 +662,7 @@ populateSettingsMenu() {
611
662
  settingsMenu.innerHTML = menuHTML;
612
663
  }
613
664
 
614
- /* NEW: Bind settings menu events */
665
+ /* Bind settings menu events */
615
666
  bindSettingsMenuEvents() {
616
667
  const settingsMenu = this.controls?.querySelector('.settings-menu');
617
668
  if (!settingsMenu) return;
package/src/core.js CHANGED
@@ -1137,14 +1137,19 @@ seek(e) {
1137
1137
  if (!this.video || !this.progressContainer || !this.progressFilled || !this.progressHandle || this.isChangingQuality) return;
1138
1138
 
1139
1139
  const rect = this.progressContainer.getBoundingClientRect();
1140
- const clickX = e.clientX - rect.left;
1140
+
1141
+ // Support both mouse and touch events
1142
+ 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));
1143
+
1144
+ const clickX = clientX - rect.left;
1141
1145
  const percentage = Math.max(0, Math.min(1, clickX / rect.width));
1142
1146
 
1143
1147
  if (this.video.duration && !isNaN(this.video.duration)) {
1144
1148
  this.video.currentTime = percentage * this.video.duration;
1145
- const progress = percentage * 100;
1146
- this.progressFilled.style.width = progress + '%';
1147
- this.progressHandle.style.left = progress + '%';
1149
+
1150
+ const progress = `${percentage * 100}%`;
1151
+ this.progressFilled.style.width = progress;
1152
+ this.progressHandle.style.left = progress;
1148
1153
  }
1149
1154
  }
1150
1155
 
package/src/events.js CHANGED
@@ -297,12 +297,28 @@
297
297
  });
298
298
  }
299
299
 
300
- if (this.progressContainer) {
301
- this.progressContainer.addEventListener('click', (e) => this.seek(e));
302
- this.progressContainer.addEventListener('mousedown', (e) => this.startSeeking(e));
303
- }
300
+ if (this.progressContainer) {
301
+ // Mouse events (desktop)
302
+ this.progressContainer.addEventListener('click', (e) => this.seek(e));
303
+ this.progressContainer.addEventListener('mousedown', (e) => this.startSeeking(e));
304
+
305
+ // Touch events (mobile)
306
+ this.progressContainer.addEventListener('touchstart', (e) => {
307
+ e.preventDefault(); // Prevent scrolling when touching the seek bar
308
+ this.startSeeking(e);
309
+ }, { passive: false });
304
310
 
305
311
  this.setupSeekTooltip();
312
+ }
313
+
314
+ // Add touch events directly on the handle for better mobile dragging
315
+ if (this.progressHandle) {
316
+ this.progressHandle.addEventListener('touchstart', (e) => {
317
+ e.preventDefault(); // Prevent default touch behavior
318
+ e.stopPropagation(); // Stop event from bubbling to progressContainer
319
+ this.startSeeking(e);
320
+ }, { passive: false });
321
+ }
306
322
 
307
323
  // NOTE: Auto-hide events are handled in initAutoHide() after everything is ready
308
324
 
@@ -323,7 +339,19 @@
323
339
  document.addEventListener('mozfullscreenchange', () => this.updateFullscreenButton());
324
340
 
325
341
  document.addEventListener('mousemove', (e) => this.continueSeeking(e));
326
- document.addEventListener('mouseup', () => this.endSeeking());
342
+ document.addEventListener('mouseup', () => this.endSeeking());
343
+
344
+ // Touch events for seeking (mobile)
345
+ document.addEventListener('touchmove', (e) => {
346
+ if (this.isUserSeeking) {
347
+ e.preventDefault(); // Prevent scrolling while seeking
348
+ this.continueSeeking(e);
349
+ }
350
+ }, { passive: false });
351
+
352
+ document.addEventListener('touchend', () => this.endSeeking());
353
+ document.addEventListener('touchcancel', () => this.endSeeking());
354
+
327
355
  }
328
356
 
329
357
  // Events methods for main class
package/src/watermark.js CHANGED
@@ -69,9 +69,19 @@ initializeWatermark() {
69
69
  this.container.appendChild(watermark);
70
70
  }
71
71
 
72
+ // Store reference to watermark element
72
73
  // Store reference to watermark element
73
74
  this.watermarkElement = watermark;
74
75
 
76
+ // Set initial position
77
+ this.updateWatermarkPosition();
78
+
79
+ // Update position on window resize
80
+ this.watermarkResizeHandler = () => {
81
+ this.updateWatermarkPosition();
82
+ };
83
+ window.addEventListener('resize', this.watermarkResizeHandler);
84
+
75
85
  if (this.options.debug) {
76
86
  console.log('🏷️ Watermark created:', {
77
87
  url: this.options.watermarkUrl,
@@ -90,6 +100,7 @@ initializeWatermark() {
90
100
  * @param {string} position - Position of watermark (topleft, topright, bottomleft, bottomright)
91
101
  * @param {string} title - Optional tooltip title for the watermark
92
102
  */
103
+
93
104
  setWatermark(url, link = '', position = 'bottomright', title = '') {
94
105
  // Update options
95
106
  this.options.watermarkUrl = url;
@@ -120,6 +131,12 @@ removeWatermark() {
120
131
  this.watermarkElement = null;
121
132
  }
122
133
 
134
+ // Remove resize listener
135
+ if (this.watermarkResizeHandler) {
136
+ window.removeEventListener('resize', this.watermarkResizeHandler);
137
+ this.watermarkResizeHandler = null;
138
+ }
139
+
123
140
  this.options.watermarkUrl = '';
124
141
  this.options.watermarkLink = '';
125
142
  this.options.watermarkPosition = 'bottomright';
@@ -134,6 +151,7 @@ removeWatermark() {
134
151
  * Update watermark position
135
152
  * @param {string} position - New position (topleft, topright, bottomleft, bottomright)
136
153
  */
154
+
137
155
  setWatermarkPosition(position) {
138
156
  if (!['topleft', 'topright', 'bottomleft', 'bottomright'].includes(position)) {
139
157
  if (this.options.debug) console.warn('🏷️ Invalid watermark position:', position);
@@ -160,6 +178,39 @@ setWatermarkPosition(position) {
160
178
  return this;
161
179
  }
162
180
 
181
+ /**
182
+ * Update watermark position based on current controlbar height
183
+ * Called during window resize to keep watermark above controlbar
184
+ */
185
+ updateWatermarkPosition() {
186
+ if (!this.watermarkElement) return;
187
+ if (!this.controls) return;
188
+
189
+ const position = this.options.watermarkPosition || 'bottomright';
190
+
191
+ // Only update bottom positions (top positions don't need adjustment)
192
+ if (position === 'bottomleft' || position === 'bottomright') {
193
+ const controlsHeight = this.controls.offsetHeight;
194
+ const spacing = 15; // Same spacing used in CSS
195
+ const bottomValue = controlsHeight + spacing;
196
+
197
+ // Check if controls are visible
198
+ const hasControls = this.container.classList.contains('has-controls');
199
+
200
+ if (hasControls || !this.options.hideWatermark) {
201
+ // Position above controlbar
202
+ this.watermarkElement.style.bottom = `${bottomValue}px`;
203
+ } else {
204
+ // Position at bottom corner when controls hidden
205
+ this.watermarkElement.style.bottom = '15px';
206
+ }
207
+
208
+ if (this.options.debug) {
209
+ console.log(`🏷️ Watermark position updated: bottom ${this.watermarkElement.style.bottom}`);
210
+ }
211
+ }
212
+ }
213
+
163
214
  /**
164
215
  * Set whether watermark should hide with controls
165
216
  * @param {boolean} hide - True to hide watermark with controls, false to keep always visible