myetv-player 1.2.0 → 1.3.0

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.
Files changed (47) hide show
  1. package/css/myetv-player.css +131 -0
  2. package/css/myetv-player.min.css +1 -1
  3. package/dist/myetv-player.js +547 -102
  4. package/dist/myetv-player.min.js +486 -93
  5. package/package.json +35 -17
  6. package/plugins/twitch/myetv-player-twitch-plugin.js +125 -11
  7. package/plugins/vimeo/myetv-player-vimeo.js +80 -49
  8. package/plugins/youtube/README.md +5 -2
  9. package/plugins/youtube/myetv-player-youtube-plugin.js +766 -6
  10. package/.github/workflows/codeql.yml +0 -100
  11. package/.github/workflows/npm-publish.yml +0 -30
  12. package/SECURITY.md +0 -50
  13. package/build.js +0 -195
  14. package/scss/README.md +0 -161
  15. package/scss/_audio-player.scss +0 -21
  16. package/scss/_base.scss +0 -116
  17. package/scss/_controls.scss +0 -204
  18. package/scss/_loading.scss +0 -111
  19. package/scss/_menus.scss +0 -432
  20. package/scss/_mixins.scss +0 -112
  21. package/scss/_poster.scss +0 -8
  22. package/scss/_progress-bar.scss +0 -319
  23. package/scss/_resolution.scss +0 -68
  24. package/scss/_responsive.scss +0 -1368
  25. package/scss/_themes.scss +0 -30
  26. package/scss/_title-overlay.scss +0 -60
  27. package/scss/_tooltips.scss +0 -7
  28. package/scss/_variables.scss +0 -49
  29. package/scss/_video.scss +0 -221
  30. package/scss/_volume.scss +0 -122
  31. package/scss/_watermark.scss +0 -128
  32. package/scss/myetv-player.scss +0 -51
  33. package/scss/package.json +0 -16
  34. package/src/README.md +0 -560
  35. package/src/chapters.js +0 -521
  36. package/src/controls.js +0 -1242
  37. package/src/core.js +0 -1922
  38. package/src/events.js +0 -537
  39. package/src/fullscreen.js +0 -82
  40. package/src/i18n.js +0 -374
  41. package/src/playlist.js +0 -177
  42. package/src/plugins.js +0 -384
  43. package/src/quality.js +0 -963
  44. package/src/streaming.js +0 -346
  45. package/src/subtitles.js +0 -524
  46. package/src/utils.js +0 -65
  47. package/src/watermark.js +0 -246
@@ -7,14 +7,15 @@ class VideoPlayerI18n {
7
7
 
8
8
  'it': {
9
9
  'subtitles': 'Sottotitoli (C)',
10
- 'subtitlesdisable': 'Disabilita Sottotitoli',
11
- 'subtitlesenable': 'Abilita Sottotitoli',
10
+ 'subtitlesoff': 'Disattivati',
11
+ 'subtitlesdisable': 'Disabilita sottotitoli',
12
+ 'subtitlesenable': 'Abilita sottotitoli',
12
13
  'play_pause': 'Play/Pausa (Spazio)',
13
14
  'mute_unmute': 'Muta/Smuta (M)',
14
15
  'volume': 'Volume',
15
16
  'playback_speed': 'Velocità riproduzione',
16
17
  'video_quality': 'Qualità video',
17
- 'picture_in_picture': 'Picture-in-Picture (P)',
18
+ 'picture_in_picture': 'Finestra sovrapposta (P)',
18
19
  'fullscreen': 'Schermo intero (F)',
19
20
  'auto': 'Auto',
20
21
  'brand_logo': 'Logo',
@@ -27,6 +28,7 @@ class VideoPlayerI18n {
27
28
 
28
29
  'en': {
29
30
  'subtitles': 'Subtitles (C)',
31
+ 'subtitlesoff': 'Off',
30
32
  'subtitlesdisable': 'Disable Subtitles',
31
33
  'subtitlesenable': 'Enable Subtitles',
32
34
  'play_pause': 'Play/Pause (Space)',
@@ -42,23 +44,20 @@ class VideoPlayerI18n {
42
44
  'prev_video': 'Previous video (P)',
43
45
  'playlist_next': 'Next',
44
46
  'playlist_prev': 'Previous',
45
- 'next_video': 'Next video (N)',
46
- 'prev_video': 'Previous video (P)',
47
- 'playlist_next': 'Next',
48
- 'playlist_prev': 'Previous',
49
47
  'settings_menu': 'Settings'
50
48
  },
51
49
 
52
50
  'es': {
53
51
  'subtitles': 'Subtítulos (C)',
54
- 'subtitlesdisable': 'Disable Subtitles',
55
- 'subtitlesenable': 'Enable Subtitles',
52
+ 'subtitlesoff': 'Desactivados',
53
+ 'subtitlesdisable': 'Desactivar subtítulos',
54
+ 'subtitlesenable': 'Activar subtítulos',
56
55
  'play_pause': 'Reproducir/Pausar (Espacio)',
57
56
  'mute_unmute': 'Silenciar (M)',
58
57
  'volume': 'Volumen',
59
58
  'playback_speed': 'Velocidad de reproducción',
60
59
  'video_quality': 'Calidad de vídeo',
61
- 'picture_in_picture': 'Picture-in-Picture (P)',
60
+ 'picture_in_picture': 'Imagen en imagen (P)',
62
61
  'fullscreen': 'Pantalla completa (F)',
63
62
  'auto': 'Auto',
64
63
  'brand_logo': 'Logo de marca',
@@ -66,19 +65,20 @@ class VideoPlayerI18n {
66
65
  'prev_video': 'Vídeo anterior (P)',
67
66
  'playlist_next': 'Siguiente',
68
67
  'playlist_prev': 'Anterior',
69
- 'settings_menu': 'Settings'
68
+ 'settings_menu': 'Configuración'
70
69
  },
71
70
 
72
71
  'fr': {
73
72
  'subtitles': 'Sous-titres (C)',
74
- 'subtitlesdisable': 'Disable Subtitles',
75
- 'subtitlesenable': 'Enable Subtitles',
73
+ 'subtitlesoff': 'Désactivés',
74
+ 'subtitlesdisable': 'Désactiver les sous-titres',
75
+ 'subtitlesenable': 'Activer les sous-titres',
76
76
  'play_pause': 'Lecture/Pause (Espace)',
77
77
  'mute_unmute': 'Muet (M)',
78
78
  'volume': 'Volume',
79
79
  'playback_speed': 'Vitesse de lecture',
80
80
  'video_quality': 'Qualité vidéo',
81
- 'picture_in_picture': 'Picture-in-Picture (P)',
81
+ 'picture_in_picture': 'Image dans l’image (P)',
82
82
  'fullscreen': 'Plein écran (F)',
83
83
  'auto': 'Auto',
84
84
  'brand_logo': 'Logo de marque',
@@ -86,19 +86,20 @@ class VideoPlayerI18n {
86
86
  'prev_video': 'Vidéo précédente (P)',
87
87
  'playlist_next': 'Suivant',
88
88
  'playlist_prev': 'Précédent',
89
- 'settings_menu': 'Settings'
89
+ 'settings_menu': 'Paramètres'
90
90
  },
91
91
 
92
92
  'de': {
93
93
  'subtitles': 'Untertitel (C)',
94
- 'subtitlesdisable': 'Disable Subtitles',
95
- 'subtitlesenable': 'Enable Subtitles',
94
+ 'subtitlesoff': 'Aus',
95
+ 'subtitlesdisable': 'Untertitel deaktivieren',
96
+ 'subtitlesenable': 'Untertitel aktivieren',
96
97
  'play_pause': 'Abspielen/Pausieren (Leertaste)',
97
98
  'mute_unmute': 'Stumm (M)',
98
99
  'volume': 'Lautstärke',
99
100
  'playback_speed': 'Wiedergabegeschwindigkeit',
100
101
  'video_quality': 'Videoqualität',
101
- 'picture_in_picture': 'Picture-in-Picture (P)',
102
+ 'picture_in_picture': 'Bild-in-Bild (P)',
102
103
  'fullscreen': 'Vollbild (F)',
103
104
  'auto': 'Auto',
104
105
  'brand_logo': 'Markenlogo',
@@ -106,19 +107,20 @@ class VideoPlayerI18n {
106
107
  'prev_video': 'Vorheriges Video (P)',
107
108
  'playlist_next': 'Weiter',
108
109
  'playlist_prev': 'Zurück',
109
- 'settings_menu': 'Settings'
110
+ 'settings_menu': 'Einstellungen'
110
111
  },
111
112
 
112
113
  'pt': {
113
114
  'subtitles': 'Legendas (C)',
114
- 'subtitlesdisable': 'Disable Subtitles',
115
- 'subtitlesenable': 'Enable Subtitles',
115
+ 'subtitlesoff': 'Desativadas',
116
+ 'subtitlesdisable': 'Desativar legendas',
117
+ 'subtitlesenable': 'Ativar legendas',
116
118
  'play_pause': 'Reproduzir/Pausar (Espaço)',
117
119
  'mute_unmute': 'Silenciar (M)',
118
120
  'volume': 'Volume',
119
121
  'playback_speed': 'Velocidade de reprodução',
120
122
  'video_quality': 'Qualidade do vídeo',
121
- 'picture_in_picture': 'Picture-in-Picture (P)',
123
+ 'picture_in_picture': 'Imagem em imagem (P)',
122
124
  'fullscreen': 'Tela cheia (F)',
123
125
  'auto': 'Auto',
124
126
  'brand_logo': 'Logo da marca',
@@ -126,13 +128,14 @@ class VideoPlayerI18n {
126
128
  'prev_video': 'Vídeo anterior (P)',
127
129
  'playlist_next': 'Próximo',
128
130
  'playlist_prev': 'Anterior',
129
- 'settings_menu': 'Settings'
131
+ 'settings_menu': 'Configurações'
130
132
  },
131
133
 
132
134
  'zh': {
133
135
  'subtitles': '字幕 (C)',
134
- 'subtitlesdisable': 'Disable Subtitles',
135
- 'subtitlesenable': 'Enable Subtitles',
136
+ 'subtitlesoff': '关闭',
137
+ 'subtitlesdisable': '禁用字幕',
138
+ 'subtitlesenable': '启用字幕',
136
139
  'play_pause': '播放/暂停 (空格)',
137
140
  'mute_unmute': '静音 (M)',
138
141
  'volume': '音量',
@@ -146,13 +149,14 @@ class VideoPlayerI18n {
146
149
  'prev_video': '上一个视频 (P)',
147
150
  'playlist_next': '下一个',
148
151
  'playlist_prev': '上一个',
149
- 'settings_menu': 'Settings'
152
+ 'settings_menu': '设置'
150
153
  },
151
154
 
152
155
  'ja': {
153
156
  'subtitles': '字幕 (C)',
154
- 'subtitlesdisable': 'Disable Subtitles',
155
- 'subtitlesenable': 'Enable Subtitles',
157
+ 'subtitlesoff': 'オフ',
158
+ 'subtitlesdisable': '字幕を無効にする',
159
+ 'subtitlesenable': '字幕を有効にする',
156
160
  'play_pause': '再生/一時停止 (スペース)',
157
161
  'mute_unmute': 'ミュート (M)',
158
162
  'volume': '音量',
@@ -166,13 +170,14 @@ class VideoPlayerI18n {
166
170
  'prev_video': '前の動画 (P)',
167
171
  'playlist_next': '次へ',
168
172
  'playlist_prev': '前へ',
169
- 'settings_menu': 'Settings'
173
+ 'settings_menu': '設定'
170
174
  },
171
175
 
172
176
  'ru': {
173
177
  'subtitles': 'Субтитры (C)',
174
- 'subtitlesdisable': 'Disable Subtitles',
175
- 'subtitlesenable': 'Enable Subtitles',
178
+ 'subtitlesoff': 'Выкл',
179
+ 'subtitlesdisable': 'Отключить субтитры',
180
+ 'subtitlesenable': 'Включить субтитры',
176
181
  'play_pause': 'Воспроизведение/Пауза (Пробел)',
177
182
  'mute_unmute': 'Звук (M)',
178
183
  'volume': 'Громкость',
@@ -186,13 +191,14 @@ class VideoPlayerI18n {
186
191
  'prev_video': 'Предыдущее видео (P)',
187
192
  'playlist_next': 'Далее',
188
193
  'playlist_prev': 'Назад',
189
- 'settings_menu': 'Settings'
194
+ 'settings_menu': 'Настройки'
190
195
  },
191
196
 
192
197
  'ar': {
193
198
  'subtitles': 'الترجمة (C)',
194
- 'subtitlesdisable': 'Disable Subtitles',
195
- 'subtitlesenable': 'Enable Subtitles',
199
+ 'subtitlesoff': 'إيقاف',
200
+ 'subtitlesdisable': 'تعطيل الترجمة',
201
+ 'subtitlesenable': 'تفعيل الترجمة',
196
202
  'play_pause': 'تشغيل/إيقاف مؤقت (مسافة)',
197
203
  'mute_unmute': 'كتم الصوت (M)',
198
204
  'volume': 'مستوى الصوت',
@@ -206,7 +212,175 @@ class VideoPlayerI18n {
206
212
  'prev_video': 'الفيديو السابق (P)',
207
213
  'playlist_next': 'التالي',
208
214
  'playlist_prev': 'السابق',
209
- 'settings_menu': 'Settings'
215
+ 'settings_menu': 'الإعدادات'
216
+ },
217
+
218
+ 'ko': {
219
+ 'subtitles': '자막 (C)',
220
+ 'subtitlesoff': '끄기',
221
+ 'subtitlesdisable': '자막 비활성화',
222
+ 'subtitlesenable': '자막 활성화',
223
+ 'play_pause': '재생/일시정지 (스페이스)',
224
+ 'mute_unmute': '음소거 (M)',
225
+ 'volume': '음량',
226
+ 'playback_speed': '재생 속도',
227
+ 'video_quality': '비디오 품질',
228
+ 'picture_in_picture': '화면 속 화면 (P)',
229
+ 'fullscreen': '전체 화면 (F)',
230
+ 'auto': '자동',
231
+ 'brand_logo': '브랜드 로고',
232
+ 'next_video': '다음 비디오 (N)',
233
+ 'prev_video': '이전 비디오 (P)',
234
+ 'playlist_next': '다음',
235
+ 'playlist_prev': '이전',
236
+ 'settings_menu': '설정'
237
+ },
238
+
239
+ 'pl': {
240
+ 'subtitles': 'Napisy (C)',
241
+ 'subtitlesoff': 'Wyłączone',
242
+ 'subtitlesdisable': 'Wyłącz napisy',
243
+ 'subtitlesenable': 'Włącz napisy',
244
+ 'play_pause': 'Odtwarzaj/Pauza (Spacja)',
245
+ 'mute_unmute': 'Wycisz (M)',
246
+ 'volume': 'Głośność',
247
+ 'playback_speed': 'Prędkość odtwarzania',
248
+ 'video_quality': 'Jakość wideo',
249
+ 'picture_in_picture': 'Obraz w obrazie (P)',
250
+ 'fullscreen': 'Pełny ekran (F)',
251
+ 'auto': 'Auto',
252
+ 'brand_logo': 'Logo marki',
253
+ 'next_video': 'Następne wideo (N)',
254
+ 'prev_video': 'Poprzednie wideo (P)',
255
+ 'playlist_next': 'Dalej',
256
+ 'playlist_prev': 'Wstecz',
257
+ 'settings_menu': 'Ustawienia'
258
+ },
259
+
260
+ 'hu': {
261
+ 'subtitles': 'Feliratok (C)',
262
+ 'subtitlesoff': 'Kikapcsolva',
263
+ 'subtitlesdisable': 'Feliratok kikapcsolása',
264
+ 'subtitlesenable': 'Feliratok bekapcsolása',
265
+ 'play_pause': 'Lejátszás/Szünet (Szóköz)',
266
+ 'mute_unmute': 'Némítás (M)',
267
+ 'volume': 'Hangerő',
268
+ 'playback_speed': 'Lejátszási sebesség',
269
+ 'video_quality': 'Videó minősége',
270
+ 'picture_in_picture': 'Kép a képben (P)',
271
+ 'fullscreen': 'Teljes képernyő (F)',
272
+ 'auto': 'Auto',
273
+ 'brand_logo': 'Márka logó',
274
+ 'next_video': 'Következő videó (N)',
275
+ 'prev_video': 'Előző videó (P)',
276
+ 'playlist_next': 'Következő',
277
+ 'playlist_prev': 'Előző',
278
+ 'settings_menu': 'Beállítások'
279
+ },
280
+
281
+ 'tr': {
282
+ 'subtitles': 'Altyazılar (C)',
283
+ 'subtitlesoff': 'Kapalı',
284
+ 'subtitlesdisable': 'Altyazıları kapat',
285
+ 'subtitlesenable': 'Altyazıları aç',
286
+ 'play_pause': 'Oynat/Duraklat (Boşluk)',
287
+ 'mute_unmute': 'Sessize al (M)',
288
+ 'volume': 'Ses düzeyi',
289
+ 'playback_speed': 'Oynatma hızı',
290
+ 'video_quality': 'Video kalitesi',
291
+ 'picture_in_picture': 'Resim içinde resim (P)',
292
+ 'fullscreen': 'Tam ekran (F)',
293
+ 'auto': 'Otomatik',
294
+ 'brand_logo': 'Marka logosu',
295
+ 'next_video': 'Sonraki video (N)',
296
+ 'prev_video': 'Önceki video (P)',
297
+ 'playlist_next': 'Sonraki',
298
+ 'playlist_prev': 'Önceki',
299
+ 'settings_menu': 'Ayarlar'
300
+ },
301
+
302
+ 'nl': {
303
+ 'subtitles': 'Ondertitels (C)',
304
+ 'subtitlesoff': 'Uit',
305
+ 'subtitlesdisable': 'Ondertitels uitschakelen',
306
+ 'subtitlesenable': 'Ondertitels inschakelen',
307
+ 'play_pause': 'Afspelen/Pauzeren (Spatie)',
308
+ 'mute_unmute': 'Dempen (M)',
309
+ 'volume': 'Volume',
310
+ 'playback_speed': 'Afspeelsnelheid',
311
+ 'video_quality': 'Videokwaliteit',
312
+ 'picture_in_picture': 'Beeld-in-beeld (P)',
313
+ 'fullscreen': 'Volledig scherm (F)',
314
+ 'auto': 'Auto',
315
+ 'brand_logo': 'Merklogo',
316
+ 'next_video': 'Volgende video (N)',
317
+ 'prev_video': 'Vorige video (P)',
318
+ 'playlist_next': 'Volgende',
319
+ 'playlist_prev': 'Vorige',
320
+ 'settings_menu': 'Instellingen'
321
+ },
322
+
323
+ 'hi': {
324
+ 'subtitles': 'उपशीर्षक (C)',
325
+ 'subtitlesoff': 'बंद',
326
+ 'subtitlesdisable': 'उपशीर्षक अक्षम करें',
327
+ 'subtitlesenable': 'उपशीर्षक सक्षम करें',
328
+ 'play_pause': 'चलाएं/रोकें (स्पेस)',
329
+ 'mute_unmute': 'म्यूट (M)',
330
+ 'volume': 'वॉल्यूम',
331
+ 'playback_speed': 'प्लेबैक गति',
332
+ 'video_quality': 'वीडियो गुणवत्ता',
333
+ 'picture_in_picture': 'चित्र-में-चित्र (P)',
334
+ 'fullscreen': 'पूर्ण स्क्रीन (F)',
335
+ 'auto': 'स्वतः',
336
+ 'brand_logo': 'ब्रांड लोगो',
337
+ 'next_video': 'अगला वीडियो (N)',
338
+ 'prev_video': 'पिछला वीडियो (P)',
339
+ 'playlist_next': 'अगला',
340
+ 'playlist_prev': 'पिछला',
341
+ 'settings_menu': 'सेटिंग्स'
342
+ },
343
+
344
+ 'sv': {
345
+ 'subtitles': 'Undertexter (C)',
346
+ 'subtitlesoff': 'Av',
347
+ 'subtitlesdisable': 'Inaktivera undertexter',
348
+ 'subtitlesenable': 'Aktivera undertexter',
349
+ 'play_pause': 'Spela/Pausa (Blanksteg)',
350
+ 'mute_unmute': 'Stäng av ljud (M)',
351
+ 'volume': 'Volym',
352
+ 'playback_speed': 'Uppspelningshastighet',
353
+ 'video_quality': 'Videokvalitet',
354
+ 'picture_in_picture': 'Bild i bild (P)',
355
+ 'fullscreen': 'Fullskärm (F)',
356
+ 'auto': 'Auto',
357
+ 'brand_logo': 'Varumärkeslogotyp',
358
+ 'next_video': 'Nästa video (N)',
359
+ 'prev_video': 'Föregående video (P)',
360
+ 'playlist_next': 'Nästa',
361
+ 'playlist_prev': 'Föregående',
362
+ 'settings_menu': 'Inställningar'
363
+ },
364
+
365
+ 'id': {
366
+ 'subtitles': 'Teks (C)',
367
+ 'subtitlesoff': 'Mati',
368
+ 'subtitlesdisable': 'Nonaktifkan teks',
369
+ 'subtitlesenable': 'Aktifkan teks',
370
+ 'play_pause': 'Putar/Jeda (Spasi)',
371
+ 'mute_unmute': 'Bisu (M)',
372
+ 'volume': 'Volume',
373
+ 'playback_speed': 'Kecepatan pemutaran',
374
+ 'video_quality': 'Kualitas video',
375
+ 'picture_in_picture': 'Gambar-dalam-gambar (P)',
376
+ 'fullscreen': 'Layar penuh (F)',
377
+ 'auto': 'Otomatis',
378
+ 'brand_logo': 'Logo merek',
379
+ 'next_video': 'Video berikutnya (N)',
380
+ 'prev_video': 'Video sebelumnya (P)',
381
+ 'playlist_next': 'Berikutnya',
382
+ 'playlist_prev': 'Sebelumnya',
383
+ 'settings_menu': 'Pengaturan'
210
384
  }
211
385
  };
212
386
 
@@ -5256,37 +5430,82 @@ parseTimeToSeconds(timeStr) {
5256
5430
  }
5257
5431
 
5258
5432
  createChapterMarkers() {
5259
- if (!this.progressContainer || !this.video || !this.chapters) {
5433
+ if (!this.progressContainer || !this.video || !this.chapters) return;
5434
+
5435
+ const duration = this.video.duration;
5436
+ if (!duration || isNaN(duration)) {
5437
+ const loadedMetadataHandler = () => {
5438
+ this.createChapterMarkers();
5439
+ this.video.removeEventListener('loadedmetadata', loadedMetadataHandler);
5440
+ };
5441
+ this.video.addEventListener('loadedmetadata', loadedMetadataHandler);
5260
5442
  return;
5261
5443
  }
5444
+ const existingMarkers = this.progressContainer.querySelector('.chapter-markers-container');
5445
+ if (existingMarkers) {
5446
+ existingMarkers.remove();
5447
+ }
5262
5448
  const markersContainer = document.createElement('div');
5263
- markersContainer.className = 'chapter-markers-container';
5264
-
5449
+ markersContainer.className = 'chapter-markers-container';
5265
5450
  this.chapters.forEach((chapter, index) => {
5451
+ const nextChapter = this.chapters[index + 1];
5452
+ const startPercent = (chapter.time / duration) * 100;
5453
+ const endPercent = nextChapter ? (nextChapter.time / duration) * 100 : 100;
5454
+ const gapSize = nextChapter ? 6 : 0; // 6px gap between segments
5455
+ const widthPercent = endPercent - startPercent;
5456
+ const segment = document.createElement('div');
5457
+ segment.className = 'chapter-segment';
5458
+ segment.style.cssText = `
5459
+ position: absolute;
5460
+ left: ${startPercent}%;
5461
+ top: 0;
5462
+ width: calc(${widthPercent}% - ${gapSize}px);
5463
+ height: 100%;
5464
+ background: rgba(255, 255, 255, 0.3);
5465
+ cursor: pointer;
5466
+ z-index: 3;
5467
+ transition: background 0.2s;
5468
+ pointer-events: none;
5469
+ `;
5470
+
5471
+ segment.setAttribute('data-chapter-index', index);
5472
+ segment.setAttribute('data-chapter-time', chapter.time);
5473
+ segment.setAttribute('data-chapter-title', chapter.title);
5474
+
5475
+ markersContainer.appendChild(segment);
5476
+ if (nextChapter) {
5266
5477
  const marker = document.createElement('div');
5267
5478
  marker.className = 'chapter-marker';
5268
- marker.setAttribute('data-chapter-index', index);
5269
- marker.setAttribute('data-chapter-time', chapter.time);
5270
- marker.setAttribute('data-chapter-title', chapter.title);
5271
- if (chapter.color) {
5272
- marker.style.backgroundColor = chapter.color;
5273
- }
5479
+ marker.style.cssText = `
5480
+ position: absolute !important;
5481
+ left: ${endPercent}% !important;
5482
+ top: 0 !important;
5483
+ width: 6px !important;
5484
+ height: 100% !important;
5485
+ background: transparent !important;
5486
+ border: none !important;
5487
+ box-shadow: none !important;
5488
+ margin-left: -3px !important;
5489
+ cursor: pointer !important;
5490
+ z-index: 10 !important;
5491
+ `;
5492
+
5493
+ marker.setAttribute('data-chapter-time', nextChapter.time);
5494
+ marker.setAttribute('data-chapter-title', nextChapter.title);
5495
+ marker.addEventListener('click', (e) => {
5496
+ e.stopPropagation();
5497
+ this.jumpToChapter(index + 1);
5498
+ });
5274
5499
 
5275
5500
  markersContainer.appendChild(marker);
5501
+ }
5276
5502
  });
5277
5503
  this.progressContainer.appendChild(markersContainer);
5278
- this.chapterMarkersContainer = markersContainer;
5279
- if (this.video.duration && !isNaN(this.video.duration)) {
5280
- this.updateChapterMarkerPositions();
5281
- } else {
5282
- const loadedMetadataHandler = () => {
5283
- this.updateChapterMarkerPositions();
5284
- this.video.removeEventListener('loadedmetadata', loadedMetadataHandler);
5285
- };
5286
- this.video.addEventListener('loadedmetadata', loadedMetadataHandler);
5287
- }
5504
+ this.chapterMarkersContainer = markersContainer;
5288
5505
 
5289
- if (this.options.debug) console.log('📚 Chapter markers created on timeline');
5506
+ if (this.options.debug) {
5507
+ console.log(`Chapter markers created: ${this.chapters.length} segments`);
5508
+ }
5290
5509
  }
5291
5510
 
5292
5511
  updateChapterMarkerPositions() {
@@ -5308,56 +5527,231 @@ updateChapterMarkerPositions() {
5308
5527
  }
5309
5528
 
5310
5529
  createChapterTooltip() {
5311
- if (!this.progressContainer) {
5312
- return;
5313
- }
5314
-
5315
- const tooltip = document.createElement('div');
5316
- tooltip.className = 'chapter-tooltip';
5317
- tooltip.style.opacity = '0';
5318
- tooltip.style.visibility = 'hidden';
5319
- tooltip.innerHTML = `
5320
- <div class="chapter-tooltip-image"></div>
5321
- <div class="chapter-tooltip-title"></div>
5322
- <div class="chapter-tooltip-time"></div>
5530
+ if (!this.progressContainer) return;
5531
+ let chapterTooltip = this.progressContainer.querySelector('.chapter-tooltip');
5532
+ if (chapterTooltip) {
5533
+ chapterTooltip.remove();
5534
+ }
5535
+ chapterTooltip = document.createElement('div');
5536
+ chapterTooltip.className = 'chapter-tooltip';
5537
+ chapterTooltip.style.cssText = `
5538
+ position: absolute;
5539
+ bottom: calc(100% + 35px);
5540
+ left: 0;
5541
+ background: rgba(28, 28, 28, 0.95);
5542
+ color: #fff;
5543
+ border-radius: 4px;
5544
+ pointer-events: none;
5545
+ visibility: hidden;
5546
+ opacity: 0;
5547
+ z-index: 100001;
5548
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
5549
+ max-width: 300px;
5550
+ overflow: hidden;
5551
+ transform: translateX(-50%);
5552
+ transition: opacity 0.15s, visibility 0.15s;
5553
+ display: flex;
5554
+ flex-direction: column;
5555
+ `;
5556
+ chapterTooltip.innerHTML = `
5557
+ <div class="chapter-tooltip-content" style="display: flex; flex-direction: column; gap: 8px; padding: 8px;">
5558
+ <div class="chapter-tooltip-image" style="
5559
+ width: 100%;
5560
+ height: 120px;
5561
+ background-size: cover;
5562
+ background-position: center;
5563
+ border-radius: 3px;
5564
+ display: none;
5565
+ "></div>
5566
+ <div class="chapter-tooltip-info" style="display: flex; flex-direction: column; gap: 4px;">
5567
+ <div class="chapter-tooltip-title" style="
5568
+ font-size: 13px;
5569
+ font-weight: 600;
5570
+ color: #fff;
5571
+ max-width: 280px;
5572
+ overflow: hidden;
5573
+ text-overflow: ellipsis;
5574
+ white-space: nowrap;
5575
+ "></div>
5576
+ <div class="chapter-tooltip-time" style="
5577
+ font-size: 12px;
5578
+ font-weight: 400;
5579
+ color: rgba(255, 255, 255, 0.8);
5580
+ "></div>
5581
+ </div>
5582
+ </div>
5323
5583
  `;
5324
5584
 
5325
- this.progressContainer.appendChild(tooltip);
5326
- this.chapterTooltip = tooltip;
5585
+ this.progressContainer.appendChild(chapterTooltip);
5586
+ this.chapterTooltip = chapterTooltip;
5327
5587
 
5328
- if (this.options.debug) console.log('📚 Chapter tooltip created');
5588
+ if (this.options.debug) {
5589
+ console.log('Chapter tooltip created');
5590
+ }
5329
5591
  }
5330
5592
 
5331
5593
  bindChapterEvents() {
5332
- if (!this.chapterMarkersContainer || !this.chapterTooltip) {
5594
+ if (!this.progressContainer) return;
5595
+ let chapterTooltip = this.progressContainer.querySelector('.chapter-tooltip-hover');
5596
+ if (chapterTooltip) {
5597
+ chapterTooltip.remove();
5598
+ }
5599
+ chapterTooltip = document.createElement('div');
5600
+ chapterTooltip.className = 'chapter-tooltip-hover';
5601
+ chapterTooltip.style.cssText = `
5602
+ position: absolute;
5603
+ bottom: calc(100% + 35px);
5604
+ left: 0;
5605
+ background: rgba(28, 28, 28, 0.95);
5606
+ color: #fff;
5607
+ border-radius: 4px;
5608
+ padding: 8px;
5609
+ pointer-events: none;
5610
+ visibility: hidden;
5611
+ opacity: 0;
5612
+ z-index: 100001;
5613
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
5614
+ max-width: 300px;
5615
+ transform: translateX(-50%);
5616
+ transition: opacity 0.15s, visibility 0.15s;
5617
+ `;
5618
+
5619
+ this.progressContainer.appendChild(chapterTooltip);
5620
+ this.chapterTooltip = chapterTooltip;
5621
+ const getPlayerBounds = () => {
5622
+ return this.container ? this.container.getBoundingClientRect() : null;
5623
+ };
5624
+ this.progressContainer.addEventListener('mousemove', (e) => {
5625
+ if (!this.video || !this.video.duration || !this.chapters || this.chapters.length === 0) {
5333
5626
  return;
5627
+ }
5628
+
5629
+ const rect = this.progressContainer.getBoundingClientRect();
5630
+ const playerRect = getPlayerBounds();
5631
+ const mouseX = e.clientX - rect.left;
5632
+ const percentage = Math.max(0, Math.min(1, mouseX / rect.width));
5633
+ const time = percentage * this.video.duration;
5634
+ let currentChapter = null;
5635
+ for (let i = this.chapters.length - 1; i >= 0; i--) {
5636
+ if (time >= this.chapters[i].time) {
5637
+ currentChapter = this.chapters[i];
5638
+ break;
5639
+ }
5640
+ }
5641
+
5642
+ if (currentChapter) {
5643
+ let tooltipHTML = '<div style="display: flex; flex-direction: column; gap: 6px;">';
5644
+ if (currentChapter.image) {
5645
+ tooltipHTML += `
5646
+ <div style="
5647
+ width: 100%;
5648
+ height: 120px;
5649
+ background-image: url('${currentChapter.image}');
5650
+ background-size: cover;
5651
+ background-position: center;
5652
+ border-radius: 3px;
5653
+ "></div>
5654
+ `;
5334
5655
  }
5335
- const markers = this.chapterMarkersContainer.querySelectorAll('.chapter-marker');
5656
+ tooltipHTML += `
5657
+ <div style="
5658
+ font-size: 13px;
5659
+ font-weight: 600;
5660
+ max-width: 280px;
5661
+ overflow: hidden;
5662
+ text-overflow: ellipsis;
5663
+ white-space: nowrap;
5664
+ ">
5665
+ ${currentChapter.title}
5666
+ </div>
5667
+ `;
5668
+ tooltipHTML += `
5669
+ <div style="
5670
+ font-size: 12px;
5671
+ font-weight: 400;
5672
+ color: rgba(255, 255, 255, 0.8);
5673
+ ">
5674
+ ${this.formatTime(currentChapter.time)}
5675
+ </div>
5676
+ `;
5336
5677
 
5337
- markers.forEach((marker, index) => {
5338
- marker.addEventListener('mouseenter', (e) => {
5339
- this.showChapterTooltip(index, e);
5340
- });
5678
+ tooltipHTML += '</div>';
5341
5679
 
5342
- marker.addEventListener('mousemove', (e) => {
5343
- this.updateChapterTooltipPosition(e);
5344
- });
5680
+ chapterTooltip.innerHTML = tooltipHTML;
5681
+ chapterTooltip.style.visibility = 'visible';
5682
+ chapterTooltip.style.opacity = '1';
5683
+ setTimeout(() => {
5684
+ const tooltipWidth = chapterTooltip.offsetWidth;
5685
+ const tooltipHalfWidth = tooltipWidth / 2;
5686
+ const absoluteX = e.clientX;
5345
5687
 
5346
- marker.addEventListener('mouseleave', () => {
5347
- this.hideChapterTooltip();
5688
+ if (playerRect) {
5689
+ if (absoluteX - tooltipHalfWidth < playerRect.left) {
5690
+ chapterTooltip.style.left = `${playerRect.left - rect.left + tooltipHalfWidth}px`;
5691
+ }
5692
+ else if (absoluteX + tooltipHalfWidth > playerRect.right) {
5693
+ chapterTooltip.style.left = `${playerRect.right - rect.left - tooltipHalfWidth}px`;
5694
+ }
5695
+ else {
5696
+ chapterTooltip.style.left = `${mouseX}px`;
5697
+ }
5698
+ } else {
5699
+ chapterTooltip.style.left = `${mouseX}px`;
5700
+ }
5701
+ }, 0);
5702
+ } else {
5703
+ chapterTooltip.style.visibility = 'hidden';
5704
+ chapterTooltip.style.opacity = '0';
5705
+ }
5348
5706
  });
5349
- marker.addEventListener('click', (e) => {
5350
- e.stopPropagation();
5351
- this.jumpToChapter(index);
5352
- });
5707
+ this.progressContainer.addEventListener('mouseleave', () => {
5708
+ chapterTooltip.style.visibility = 'hidden';
5709
+ chapterTooltip.style.opacity = '0';
5353
5710
  });
5354
5711
  if (this.video) {
5355
- this.video.addEventListener('timeupdate', () => {
5356
- this.updateActiveChapter();
5357
- });
5712
+ this.video.addEventListener('timeupdate', () => this.updateActiveChapter());
5713
+ }
5714
+
5715
+ if (this.options.debug) {
5716
+ console.log('Chapter events bound with tooltip');
5358
5717
  }
5718
+ }
5719
+
5720
+ updateChapterInTitleOverlay() {
5721
+ if (!this.video || !this.chapters || this.chapters.length === 0) return;
5359
5722
 
5360
- if (this.options.debug) console.log('📚 Chapter events bound');
5723
+ const titleOverlay = this.container ? this.container.querySelector('.title-overlay') : null;
5724
+ if (!titleOverlay) return;
5725
+ let chapterElement = titleOverlay.querySelector('.chapter-name');
5726
+ if (!chapterElement) {
5727
+ chapterElement = document.createElement('div');
5728
+ chapterElement.className = 'chapter-name';
5729
+ chapterElement.style.cssText = `
5730
+ font-size: 13px;
5731
+ font-weight: 500;
5732
+ color: rgba(255, 255, 255, 0.9);
5733
+ margin-top: 6px;
5734
+ max-width: 400px;
5735
+ overflow: hidden;
5736
+ text-overflow: ellipsis;
5737
+ white-space: nowrap;
5738
+ `;
5739
+ titleOverlay.appendChild(chapterElement);
5740
+ }
5741
+ const currentTime = this.video.currentTime;
5742
+ let currentChapter = null;
5743
+ for (let i = this.chapters.length - 1; i >= 0; i--) {
5744
+ if (currentTime >= this.chapters[i].time) {
5745
+ currentChapter = this.chapters[i];
5746
+ break;
5747
+ }
5748
+ }
5749
+ if (currentChapter) {
5750
+ chapterElement.textContent = currentChapter.title;
5751
+ chapterElement.style.display = 'block';
5752
+ } else {
5753
+ chapterElement.style.display = 'none';
5754
+ }
5361
5755
  }
5362
5756
 
5363
5757
  showChapterTooltip(chapterIndex, e) {
@@ -5424,9 +5818,7 @@ jumpToChapter(chapterIndex) {
5424
5818
  }
5425
5819
 
5426
5820
  updateActiveChapter() {
5427
- if (!this.video || !this.chapterMarkersContainer || !this.chapters) {
5428
- return;
5429
- }
5821
+ if (!this.video || !this.chapterMarkersContainer || !this.chapters) return;
5430
5822
 
5431
5823
  const currentTime = this.video.currentTime;
5432
5824
  const markers = this.chapterMarkersContainer.querySelectorAll('.chapter-marker');
@@ -5443,7 +5835,8 @@ updateActiveChapter() {
5443
5835
  } else {
5444
5836
  marker.classList.remove('active');
5445
5837
  }
5446
- });
5838
+ });
5839
+ this.updateChapterInTitleOverlay();
5447
5840
  }
5448
5841
 
5449
5842
  getCurrentChapter() {