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.
@@ -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 && this.ytPlayer.mute && this.ytPlayer.unMute) {
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 = 'position:absolute;bottom:calc(100% + 10px);left:0;background:rgba(28,28,28,0.95);color:#fff;padding:6px 10px;border-radius:3px;font-size:13px;font-weight:500;white-space:nowrap;pointer-events:none;visibility:hidden;z-index:99999;box-shadow:0 2px 8px rgba(0,0,0,0.3);';
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
- const clickX = e.clientX - rect.left;
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 + 'px';
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
- this.bindVolumeSlider();
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
- if (liveBadge) {
3432
- // Force 100% for live streams
3433
- progress = 100;
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) currentTimeEl.textContent = this.formatTime(currentTime);
3446
- if (durationEl && duration) durationEl.textContent = this.formatTime(duration);
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
  }
@@ -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
- // Add has-controls class to container for watermark visibility
148
- if (this.container) {
149
- this.container.classList.add('has-controls');
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
- // Show title overlay with controls if not persistent
158
- if (this.options.showTitleOverlay && !this.options.persistentTitle && this.options.videoTitle) {
159
- this.showTitleOverlay();
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
- if (this.autoHideDebug && this.options.debug) console.log('✅ Controls shown');
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
- // Don't hide if mouse is still over controls (allow hiding on touch devices)
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
- // Don't hide if video is paused
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
- // Hide title overlay with controls (if not persistent)
199
- if (this.options.showTitleOverlay && !this.options.persistentTitle) {
200
- this.hideTitleOverlay();
201
- }
193
+ this.updateControlbarHeight();
202
194
 
203
- if (this.autoHideDebug && this.options.debug) {
204
- console.log('👁️ Controls hidden');
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