myetv-player 1.6.0 → 1.6.2

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.
@@ -25,7 +25,8 @@ class VideoPlayerI18n {
25
25
  'playlist_prev': 'Indietro',
26
26
  'settings_menu': 'Impostazioni',
27
27
  'loading': 'Caricamento...',
28
- 'encoding_in_progress': 'Encoding in corso'
28
+ 'encoding_in_progress': 'Encoding in corso',
29
+ 'restart_video': 'Torna all\'inizio'
29
30
  },
30
31
 
31
32
  'en': {
@@ -48,7 +49,8 @@ class VideoPlayerI18n {
48
49
  'playlist_prev': 'Previous',
49
50
  'settings_menu': 'Settings',
50
51
  'loading': 'Loading...',
51
- 'encoding_in_progress': 'Encoding in progress'
52
+ 'encoding_in_progress': 'Encoding in progress',
53
+ 'restart_video': 'Restart the video'
52
54
  },
53
55
 
54
56
  'es': {
@@ -71,7 +73,8 @@ class VideoPlayerI18n {
71
73
  'playlist_prev': 'Anterior',
72
74
  'settings_menu': 'Configuración',
73
75
  'loading': 'Cargando...',
74
- 'encoding_in_progress': 'Codificación en curso'
76
+ 'encoding_in_progress': 'Codificación en curso',
77
+ 'restart_video': 'Reiniciar el vídeo'
75
78
  },
76
79
 
77
80
  'fr': {
@@ -94,7 +97,8 @@ class VideoPlayerI18n {
94
97
  'playlist_prev': 'Précédent',
95
98
  'settings_menu': 'Paramètres',
96
99
  'loading': 'Chargement...',
97
- 'encoding_in_progress': 'Encodage en cours'
100
+ 'encoding_in_progress': 'Encodage en cours',
101
+ 'restart_video': 'Redémarrer la vidéo'
98
102
  },
99
103
 
100
104
  'de': {
@@ -117,7 +121,8 @@ class VideoPlayerI18n {
117
121
  'playlist_prev': 'Zurück',
118
122
  'settings_menu': 'Einstellungen',
119
123
  'loading': 'Laden...',
120
- 'encoding_in_progress': 'Kodierung läuft'
124
+ 'encoding_in_progress': 'Kodierung läuft',
125
+ 'restart_video': 'Video neu starten'
121
126
  },
122
127
 
123
128
  'pt': {
@@ -140,7 +145,8 @@ class VideoPlayerI18n {
140
145
  'playlist_prev': 'Anterior',
141
146
  'settings_menu': 'Configurações',
142
147
  'loading': 'Carregando...',
143
- 'encoding_in_progress': 'Codificação em andamento'
148
+ 'encoding_in_progress': 'Codificação em andamento',
149
+ 'restart_video': 'Restart video'
144
150
  },
145
151
 
146
152
  'zh': {
@@ -163,7 +169,8 @@ class VideoPlayerI18n {
163
169
  'playlist_prev': '上一个',
164
170
  'settings_menu': '设置',
165
171
  'loading': '加载中...',
166
- 'encoding_in_progress': '编码中'
172
+ 'encoding_in_progress': '编码中',
173
+ 'restart_video': '重新开始视频'
167
174
  },
168
175
 
169
176
  'ja': {
@@ -186,7 +193,8 @@ class VideoPlayerI18n {
186
193
  'playlist_prev': '前へ',
187
194
  'settings_menu': '設定',
188
195
  'loading': '読み込み中...',
189
- 'encoding_in_progress': 'エンコード中'
196
+ 'encoding_in_progress': 'エンコード中',
197
+ 'restart_video': 'ビデオを再開'
190
198
  },
191
199
 
192
200
  'ru': {
@@ -209,7 +217,8 @@ class VideoPlayerI18n {
209
217
  'playlist_prev': 'Назад',
210
218
  'settings_menu': 'Настройки',
211
219
  'loading': 'Загрузка...',
212
- 'encoding_in_progress': 'Кодирование'
220
+ 'encoding_in_progress': 'Кодирование',
221
+ 'restart_video': 'Перезапустить видео'
213
222
  },
214
223
 
215
224
  'ar': {
@@ -232,7 +241,8 @@ class VideoPlayerI18n {
232
241
  'playlist_prev': 'السابق',
233
242
  'settings_menu': 'الإعدادات',
234
243
  'loading': 'جاري التحميل...',
235
- 'encoding_in_progress': 'الترميز جارٍ'
244
+ 'encoding_in_progress': 'الترميز جارٍ',
245
+ 'restart_video': 'إعادة تشغيل الفيديو'
236
246
  },
237
247
 
238
248
  'ko': {
@@ -255,7 +265,8 @@ class VideoPlayerI18n {
255
265
  'playlist_prev': '이전',
256
266
  'settings_menu': '설정',
257
267
  'loading': '로딩 중...',
258
- 'encoding_in_progress': '인코딩 진행 중'
268
+ 'encoding_in_progress': '인코딩 진행 중',
269
+ 'restart_video': 'Restart video'
259
270
  },
260
271
 
261
272
  'pl': {
@@ -278,7 +289,8 @@ class VideoPlayerI18n {
278
289
  'playlist_prev': 'Wstecz',
279
290
  'settings_menu': 'Ustawienia',
280
291
  'loading': 'Ładowanie...',
281
- 'encoding_in_progress': 'Kodowanie w toku'
292
+ 'encoding_in_progress': 'Kodowanie w toku',
293
+ 'restart_video': 'Restart video'
282
294
  },
283
295
 
284
296
  'hu': {
@@ -301,7 +313,8 @@ class VideoPlayerI18n {
301
313
  'playlist_prev': 'Előző',
302
314
  'settings_menu': 'Beállítások',
303
315
  'loading': 'Betöltés...',
304
- 'encoding_in_progress': 'Kódolás folyamatban'
316
+ 'encoding_in_progress': 'Kódolás folyamatban',
317
+ 'restart_video': 'Restart video'
305
318
  },
306
319
 
307
320
  'tr': {
@@ -324,7 +337,8 @@ class VideoPlayerI18n {
324
337
  'playlist_prev': 'Önceki',
325
338
  'settings_menu': 'Ayarlar',
326
339
  'loading': 'Yükleniyor...',
327
- 'encoding_in_progress': 'Kodlama devam ediyor'
340
+ 'encoding_in_progress': 'Kodlama devam ediyor',
341
+ 'restart_video': 'Restart video'
328
342
  },
329
343
 
330
344
  'nl': {
@@ -347,7 +361,8 @@ class VideoPlayerI18n {
347
361
  'playlist_prev': 'Vorige',
348
362
  'settings_menu': 'Instellingen',
349
363
  'loading': 'Laden...',
350
- 'encoding_in_progress': 'Codering bezig'
364
+ 'encoding_in_progress': 'Codering bezig',
365
+ 'restart_video': 'Restart video'
351
366
  },
352
367
 
353
368
  'hi': {
@@ -370,7 +385,8 @@ class VideoPlayerI18n {
370
385
  'playlist_prev': 'पिछला',
371
386
  'settings_menu': 'सेटिंग्स',
372
387
  'loading': 'लोड हो रहा है...',
373
- 'encoding_in_progress': 'एन्कोडिंग प्रगति में'
388
+ 'encoding_in_progress': 'एन्कोडिंग प्रगति में',
389
+ 'restart_video': 'Restart video'
374
390
  },
375
391
 
376
392
  'sv': {
@@ -393,7 +409,8 @@ class VideoPlayerI18n {
393
409
  'playlist_prev': 'Föregående',
394
410
  'settings_menu': 'Inställningar',
395
411
  'loading': 'Laddar...',
396
- 'encoding_in_progress': 'Kodning pågår'
412
+ 'encoding_in_progress': 'Kodning pågår',
413
+ 'restart_video': 'Restart video'
397
414
  },
398
415
 
399
416
  'id': {
@@ -416,7 +433,8 @@ class VideoPlayerI18n {
416
433
  'playlist_prev': 'Sebelumnya',
417
434
  'settings_menu': 'Pengaturan',
418
435
  'loading': 'Memuat...',
419
- 'encoding_in_progress': 'Encoding sedang berlangsung'
436
+ 'encoding_in_progress': 'Encoding sedang berlangsung',
437
+ 'restart_video': 'Restart video'
420
438
  }
421
439
  };
422
440
 
@@ -531,7 +549,8 @@ try {
531
549
  'brand_logo': 'Brand logo',
532
550
  'settings_menu': 'Settings',
533
551
  'loading': 'Loading...',
534
- 'encoding_in_progress': 'Encoding in progress'
552
+ 'encoding_in_progress': 'Encoding in progress',
553
+ 'restart_video': 'Restart video'
535
554
  };
536
555
  return fallback[key] || key;
537
556
  },
@@ -584,6 +603,7 @@ constructor(videoElement, options = {}) {
584
603
  }
585
604
 
586
605
  this.options = {
606
+ playFromStartButton: false, // Enable play from start button (restart video)
587
607
  showQualitySelector: true, // Enable quality selector button
588
608
  showSpeedControl: true, // Enable speed control button
589
609
  showFullscreen: true, // Enable fullscreen button
@@ -683,6 +703,7 @@ constructor(videoElement, options = {}) {
683
703
  'played': [], // Fired when video starts playing
684
704
  'paused': [], // Fired when video is paused
685
705
  'ended': [], // Fired when video playback ends
706
+ 'restarted': [], // Fired when video is restarted from beginning
686
707
 
687
708
  'playing': [], // Fired when video is actually playing (after buffering)
688
709
  'waiting': [], // Fired when video is waiting for data (buffering)
@@ -1188,7 +1209,7 @@ createPlayerStructure() {
1188
1209
  createInitialLoading() {
1189
1210
  const initialLoader = document.createElement('div');
1190
1211
  initialLoader.className = 'initial-loading';
1191
- initialLoader.innerHTML = '<div class="loading-spinner"></div>';
1212
+ initialLoader.innerHTML = '<div class="loading-spinner"></div><div class="loading-text"></div>';
1192
1213
  this.container.appendChild(initialLoader);
1193
1214
  this.initialLoading = initialLoader;
1194
1215
  }
@@ -1201,7 +1222,7 @@ createLoadingOverlay() {
1201
1222
  const overlay = document.createElement('div');
1202
1223
  overlay.className = 'loading-overlay';
1203
1224
  overlay.id = 'loadingOverlay-' + this.getUniqueId();
1204
- overlay.innerHTML = '<div class="loading-spinner"></div>';
1225
+ overlay.innerHTML = '<div class="loading-spinner"></div><div class="loading-text"></div>';
1205
1226
  this.container.appendChild(overlay);
1206
1227
  this.loadingOverlay = overlay;
1207
1228
  }
@@ -1370,6 +1391,7 @@ initializeElements() {
1370
1391
  this.progressHandle = this.controls?.querySelector('.progress-handle');
1371
1392
  this.seekTooltip = this.controls?.querySelector('.seek-tooltip');
1372
1393
 
1394
+ this.playFromStartBtn = this.controls?.querySelector('.play-from-start-btn');
1373
1395
  this.playPauseBtn = this.controls?.querySelector('.play-pause-btn');
1374
1396
  this.muteBtn = this.controls?.querySelector('.mute-btn');
1375
1397
  this.fullscreenBtn = this.controls?.querySelector('.fullscreen-btn');
@@ -1473,6 +1495,42 @@ setupMenuToggles() {
1473
1495
  }
1474
1496
  }
1475
1497
 
1498
+ restartVideo() {
1499
+ if (!this.video) return this;
1500
+
1501
+ const previousTime = this.getCurrentTime();
1502
+ const wasPaused = this.isPaused();
1503
+
1504
+ this.video.currentTime = 0;
1505
+
1506
+ if (typeof this.seek === 'function') {
1507
+ this.seek(0);
1508
+ }
1509
+
1510
+ if (!wasPaused) {
1511
+
1512
+ if (typeof this.play === 'function') {
1513
+ this.play();
1514
+ } else {
1515
+ this.video.play().catch(error => {
1516
+ if (this.options.debug) console.warn('⚠️ Restart play failed:', error);
1517
+ });
1518
+ }
1519
+ }
1520
+
1521
+ if (this.options.debug) {
1522
+ console.log(`🔄 Video restarted from ${this.formatTime(previousTime)} to 0:00`);
1523
+ }
1524
+
1525
+ this.triggerEvent('restarted', {
1526
+ previousTime: previousTime,
1527
+ duration: this.getDuration(),
1528
+ autoPlayed: !wasPaused
1529
+ });
1530
+
1531
+ return this;
1532
+ }
1533
+
1476
1534
  updateVolumeSliderVisual() {
1477
1535
  if (!this.video || !this.container) return;
1478
1536
 
@@ -1743,6 +1801,17 @@ updateProgress() {
1743
1801
  }
1744
1802
  }
1745
1803
 
1804
+ updateLoadingText(text) {
1805
+ if (this.initialLoading) {
1806
+ const textEl = this.initialLoading.querySelector('.loading-text');
1807
+ if (textEl) textEl.textContent = text;
1808
+ }
1809
+ if (this.loadingOverlay) {
1810
+ const textEl = this.loadingOverlay.querySelector('.loading-text');
1811
+ if (textEl) textEl.textContent = text;
1812
+ }
1813
+ }
1814
+
1746
1815
  updateBuffer() {
1747
1816
  if (!this.video || !this.progressBuffer) return;
1748
1817
 
@@ -2521,6 +2590,13 @@ addEventListener(eventType, callback) {
2521
2590
  bindEvents() {
2522
2591
  if (this.video) {
2523
2592
 
2593
+ if (this.playFromStartBtn) {
2594
+ this.playFromStartBtn.addEventListener('click', (e) => {
2595
+ e.stopPropagation();
2596
+ this.restartVideo();
2597
+ });
2598
+ }
2599
+
2524
2600
  this.video.addEventListener('playing', () => {
2525
2601
  this.hideLoading();
2526
2602
  this.closeAllMenus();
@@ -3287,10 +3363,20 @@ createControls() {
3287
3363
 
3288
3364
  <div class="controls-main">
3289
3365
  <div class="controls-left">
3290
- <button class="control-btn play-pause-btn" data-tooltip="play_pause">
3366
+ ${this.options.playFromStartButton ? `
3367
+ <button class="control-btn play-from-start-btn" data-tooltip="restart_video">
3368
+ <span class="icon restart-icon">
3369
+ <svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor">
3370
+ <path d="M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z"/>
3371
+ </svg>
3372
+ </span>
3373
+ </button>
3374
+ ` : ''}
3375
+
3376
+ <button class="control-btn play-pause-btn" data-tooltip="play_pause">
3291
3377
  <span class="icon play-icon"><svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor"><path d="M8 5v14l11-7z"/></svg></span>
3292
3378
  <span class="icon pause-icon hidden"><svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor"><path d="M6 4h4v16H6zm8 0h4v16h-4z"/></svg></span>
3293
- </button>
3379
+ </button>
3294
3380
 
3295
3381
  <button class="control-btn mute-btn" data-tooltip="mute_unmute">
3296
3382
  <span class="icon volume-icon"><svg viewBox="0 0 16 16" width="16" height="16" fill="currentColor"><path d="M11.536 14.01A8.473 8.473 0 0 0 14.026 8a8.473 8.473 0 0 0-2.49-6.01l-.708.707A7.476 7.476 0 0 1 13.025 8c0 2.071-.84 3.946-2.197 5.303z"/><path d="M10.121 12.596A6.48 6.48 0 0 0 12.025 8a6.48 6.48 0 0 0-1.904-4.596l-.707.707A5.483 5.483 0 0 1 11.025 8a5.483 5.483 0 0 1-1.61 3.89z"/><path d="M10.025 8a4.486 4.486 0 0 1-1.318 3.182L8 10.475A3.489 3.489 0 0 0 9.025 8c0-.966-.392-1.841-1.025-2.475l.707-.707A4.486 4.486 0 0 1 10.025 8M7 4a.5.5 0 0 0-.812-.39L3.825 5.5H1.5A.5.5 0 0 0 1 6v4a.5.5 0 0 0 .5.5h2.325l2.363 1.89A.5.5 0 0 0 7 12z"/></svg></span>
@@ -3306,7 +3392,7 @@ createControls() {
3306
3392
  <span>/</span>
3307
3393
  <span class="duration">0:00</span>
3308
3394
  </div>
3309
- </div>
3395
+ </div>
3310
3396
 
3311
3397
  <div class="controls-right">
3312
3398
  <button class="control-btn playlist-prev-btn" data-tooltip="prevvideo" style="display: none;">
@@ -7440,7 +7526,6 @@ skipTime(seconds) {
7440
7526
  }
7441
7527
 
7442
7528
  updateTimeDisplay() {
7443
-
7444
7529
  if (this.currentTimeEl && this.video) {
7445
7530
  this.currentTimeEl.textContent = this.formatTime(this.video.currentTime || 0);
7446
7531
  }
@@ -7451,25 +7536,45 @@ updateTimeDisplay() {
7451
7536
  const currentTime = this.video.currentTime;
7452
7537
  const networkState = this.video.networkState;
7453
7538
 
7454
- const isInitialBuffering = (readyState < 2 && currentTime === 0) ||
7455
- (currentTime === 0 && (!duration || duration === 0) && networkState === 2);
7539
+ const isInitialBuffering = (readyState < 2 && currentTime === 0) || (currentTime === 0 && !duration) || (duration === 0 && networkState === 2);
7456
7540
 
7457
7541
  const isDurationInvalid = !duration || isNaN(duration) || !isFinite(duration);
7458
7542
 
7543
+ const t = (key) => {
7544
+ if (this.isI18nAvailable()) {
7545
+ try {
7546
+ return VideoPlayerTranslations.t(key);
7547
+ } catch (error) {
7548
+ return key;
7549
+ }
7550
+ }
7551
+ const fallback = {
7552
+ 'loading': 'Loading...',
7553
+ 'encodinginprogress': 'Encoding in progress...'
7554
+ };
7555
+ return fallback[key] || key;
7556
+ };
7557
+
7459
7558
  if (isInitialBuffering) {
7460
7559
 
7461
- this.durationEl.textContent = t('loading');
7560
+ this.updateLoadingText(t('loading'));
7561
+ this.durationEl.textContent = this.formatTime(0); // Just show 00:00 or empty
7462
7562
  this.durationEl.classList.remove('encoding-state');
7463
7563
  this.durationEl.classList.add('loading-state');
7464
7564
  } else if (isDurationInvalid) {
7465
7565
 
7466
- this.durationEl.textContent = t('encoding_in_progress');
7566
+ this.updateLoadingText(t('encodinginprogress'));
7567
+
7568
+ this.durationEl.textContent = "--:--";
7569
+
7467
7570
  this.durationEl.classList.remove('loading-state');
7468
7571
  this.durationEl.classList.add('encoding-state');
7469
7572
  } else {
7470
7573
 
7471
7574
  this.durationEl.textContent = this.formatTime(duration);
7472
7575
  this.durationEl.classList.remove('encoding-state', 'loading-state');
7576
+
7577
+ this.updateLoadingText('');
7473
7578
  }
7474
7579
  }
7475
7580
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myetv-player",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "description": "MYETV Video Player - Modular HTML5 video player with plugin support for YouTube, Vimeo, Twitch, Facebook, Cloudflare Stream and streaming protocols (HLS/DASH)",
5
5
  "main": "dist/myetv-player.js",
6
6
  "files": [
@@ -61,3 +61,5 @@
61
61
 
62
62
 
63
63
 
64
+
65
+