myetv-player 1.2.0 → 1.4.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.
- package/css/myetv-player.css +242 -168
- package/css/myetv-player.min.css +1 -1
- package/dist/myetv-player.js +638 -203
- package/dist/myetv-player.min.js +548 -170
- package/package.json +35 -16
- package/plugins/twitch/myetv-player-twitch-plugin.js +125 -11
- package/plugins/vimeo/myetv-player-vimeo.js +80 -49
- package/plugins/youtube/README.md +5 -2
- package/plugins/youtube/myetv-player-youtube-plugin.js +766 -6
- package/.github/workflows/codeql.yml +0 -100
- package/.github/workflows/npm-publish.yml +0 -30
- package/SECURITY.md +0 -50
- package/build.js +0 -195
- package/scss/README.md +0 -161
- package/scss/_audio-player.scss +0 -21
- package/scss/_base.scss +0 -116
- package/scss/_controls.scss +0 -204
- package/scss/_loading.scss +0 -111
- package/scss/_menus.scss +0 -432
- package/scss/_mixins.scss +0 -112
- package/scss/_poster.scss +0 -8
- package/scss/_progress-bar.scss +0 -319
- package/scss/_resolution.scss +0 -68
- package/scss/_responsive.scss +0 -1368
- package/scss/_themes.scss +0 -30
- package/scss/_title-overlay.scss +0 -60
- package/scss/_tooltips.scss +0 -7
- package/scss/_variables.scss +0 -49
- package/scss/_video.scss +0 -221
- package/scss/_volume.scss +0 -122
- package/scss/_watermark.scss +0 -128
- package/scss/myetv-player.scss +0 -51
- package/scss/package.json +0 -16
- package/src/README.md +0 -560
- package/src/chapters.js +0 -521
- package/src/controls.js +0 -1242
- package/src/core.js +0 -1922
- package/src/events.js +0 -537
- package/src/fullscreen.js +0 -82
- package/src/i18n.js +0 -374
- package/src/playlist.js +0 -177
- package/src/plugins.js +0 -384
- package/src/quality.js +0 -963
- package/src/streaming.js +0 -346
- package/src/subtitles.js +0 -524
- package/src/utils.js +0 -65
- package/src/watermark.js +0 -246
package/dist/myetv-player.js
CHANGED
|
@@ -9,14 +9,15 @@ class VideoPlayerI18n {
|
|
|
9
9
|
// Italiano
|
|
10
10
|
'it': {
|
|
11
11
|
'subtitles': 'Sottotitoli (C)',
|
|
12
|
-
'
|
|
13
|
-
'
|
|
12
|
+
'subtitlesoff': 'Disattivati',
|
|
13
|
+
'subtitlesdisable': 'Disabilita sottotitoli',
|
|
14
|
+
'subtitlesenable': 'Abilita sottotitoli',
|
|
14
15
|
'play_pause': 'Play/Pausa (Spazio)',
|
|
15
16
|
'mute_unmute': 'Muta/Smuta (M)',
|
|
16
17
|
'volume': 'Volume',
|
|
17
18
|
'playback_speed': 'Velocità riproduzione',
|
|
18
19
|
'video_quality': 'Qualità video',
|
|
19
|
-
'picture_in_picture': '
|
|
20
|
+
'picture_in_picture': 'Finestra sovrapposta (P)',
|
|
20
21
|
'fullscreen': 'Schermo intero (F)',
|
|
21
22
|
'auto': 'Auto',
|
|
22
23
|
'brand_logo': 'Logo',
|
|
@@ -30,6 +31,7 @@ class VideoPlayerI18n {
|
|
|
30
31
|
// English
|
|
31
32
|
'en': {
|
|
32
33
|
'subtitles': 'Subtitles (C)',
|
|
34
|
+
'subtitlesoff': 'Off',
|
|
33
35
|
'subtitlesdisable': 'Disable Subtitles',
|
|
34
36
|
'subtitlesenable': 'Enable Subtitles',
|
|
35
37
|
'play_pause': 'Play/Pause (Space)',
|
|
@@ -45,24 +47,21 @@ class VideoPlayerI18n {
|
|
|
45
47
|
'prev_video': 'Previous video (P)',
|
|
46
48
|
'playlist_next': 'Next',
|
|
47
49
|
'playlist_prev': 'Previous',
|
|
48
|
-
'next_video': 'Next video (N)',
|
|
49
|
-
'prev_video': 'Previous video (P)',
|
|
50
|
-
'playlist_next': 'Next',
|
|
51
|
-
'playlist_prev': 'Previous',
|
|
52
50
|
'settings_menu': 'Settings'
|
|
53
51
|
},
|
|
54
52
|
|
|
55
53
|
// Español
|
|
56
54
|
'es': {
|
|
57
55
|
'subtitles': 'Subtítulos (C)',
|
|
58
|
-
'
|
|
59
|
-
'
|
|
56
|
+
'subtitlesoff': 'Desactivados',
|
|
57
|
+
'subtitlesdisable': 'Desactivar subtítulos',
|
|
58
|
+
'subtitlesenable': 'Activar subtítulos',
|
|
60
59
|
'play_pause': 'Reproducir/Pausar (Espacio)',
|
|
61
60
|
'mute_unmute': 'Silenciar (M)',
|
|
62
61
|
'volume': 'Volumen',
|
|
63
62
|
'playback_speed': 'Velocidad de reproducción',
|
|
64
63
|
'video_quality': 'Calidad de vídeo',
|
|
65
|
-
'picture_in_picture': '
|
|
64
|
+
'picture_in_picture': 'Imagen en imagen (P)',
|
|
66
65
|
'fullscreen': 'Pantalla completa (F)',
|
|
67
66
|
'auto': 'Auto',
|
|
68
67
|
'brand_logo': 'Logo de marca',
|
|
@@ -70,20 +69,21 @@ class VideoPlayerI18n {
|
|
|
70
69
|
'prev_video': 'Vídeo anterior (P)',
|
|
71
70
|
'playlist_next': 'Siguiente',
|
|
72
71
|
'playlist_prev': 'Anterior',
|
|
73
|
-
'settings_menu': '
|
|
72
|
+
'settings_menu': 'Configuración'
|
|
74
73
|
},
|
|
75
74
|
|
|
76
75
|
// Français
|
|
77
76
|
'fr': {
|
|
78
77
|
'subtitles': 'Sous-titres (C)',
|
|
79
|
-
'
|
|
80
|
-
'
|
|
78
|
+
'subtitlesoff': 'Désactivés',
|
|
79
|
+
'subtitlesdisable': 'Désactiver les sous-titres',
|
|
80
|
+
'subtitlesenable': 'Activer les sous-titres',
|
|
81
81
|
'play_pause': 'Lecture/Pause (Espace)',
|
|
82
82
|
'mute_unmute': 'Muet (M)',
|
|
83
83
|
'volume': 'Volume',
|
|
84
84
|
'playback_speed': 'Vitesse de lecture',
|
|
85
85
|
'video_quality': 'Qualité vidéo',
|
|
86
|
-
'picture_in_picture': '
|
|
86
|
+
'picture_in_picture': 'Image dans l’image (P)',
|
|
87
87
|
'fullscreen': 'Plein écran (F)',
|
|
88
88
|
'auto': 'Auto',
|
|
89
89
|
'brand_logo': 'Logo de marque',
|
|
@@ -91,20 +91,21 @@ class VideoPlayerI18n {
|
|
|
91
91
|
'prev_video': 'Vidéo précédente (P)',
|
|
92
92
|
'playlist_next': 'Suivant',
|
|
93
93
|
'playlist_prev': 'Précédent',
|
|
94
|
-
'settings_menu': '
|
|
94
|
+
'settings_menu': 'Paramètres'
|
|
95
95
|
},
|
|
96
96
|
|
|
97
97
|
// Deutsch
|
|
98
98
|
'de': {
|
|
99
99
|
'subtitles': 'Untertitel (C)',
|
|
100
|
-
'
|
|
101
|
-
'
|
|
100
|
+
'subtitlesoff': 'Aus',
|
|
101
|
+
'subtitlesdisable': 'Untertitel deaktivieren',
|
|
102
|
+
'subtitlesenable': 'Untertitel aktivieren',
|
|
102
103
|
'play_pause': 'Abspielen/Pausieren (Leertaste)',
|
|
103
104
|
'mute_unmute': 'Stumm (M)',
|
|
104
105
|
'volume': 'Lautstärke',
|
|
105
106
|
'playback_speed': 'Wiedergabegeschwindigkeit',
|
|
106
107
|
'video_quality': 'Videoqualität',
|
|
107
|
-
'picture_in_picture': '
|
|
108
|
+
'picture_in_picture': 'Bild-in-Bild (P)',
|
|
108
109
|
'fullscreen': 'Vollbild (F)',
|
|
109
110
|
'auto': 'Auto',
|
|
110
111
|
'brand_logo': 'Markenlogo',
|
|
@@ -112,20 +113,21 @@ class VideoPlayerI18n {
|
|
|
112
113
|
'prev_video': 'Vorheriges Video (P)',
|
|
113
114
|
'playlist_next': 'Weiter',
|
|
114
115
|
'playlist_prev': 'Zurück',
|
|
115
|
-
'settings_menu': '
|
|
116
|
+
'settings_menu': 'Einstellungen'
|
|
116
117
|
},
|
|
117
118
|
|
|
118
119
|
// Português
|
|
119
120
|
'pt': {
|
|
120
121
|
'subtitles': 'Legendas (C)',
|
|
121
|
-
'
|
|
122
|
-
'
|
|
122
|
+
'subtitlesoff': 'Desativadas',
|
|
123
|
+
'subtitlesdisable': 'Desativar legendas',
|
|
124
|
+
'subtitlesenable': 'Ativar legendas',
|
|
123
125
|
'play_pause': 'Reproduzir/Pausar (Espaço)',
|
|
124
126
|
'mute_unmute': 'Silenciar (M)',
|
|
125
127
|
'volume': 'Volume',
|
|
126
128
|
'playback_speed': 'Velocidade de reprodução',
|
|
127
129
|
'video_quality': 'Qualidade do vídeo',
|
|
128
|
-
'picture_in_picture': '
|
|
130
|
+
'picture_in_picture': 'Imagem em imagem (P)',
|
|
129
131
|
'fullscreen': 'Tela cheia (F)',
|
|
130
132
|
'auto': 'Auto',
|
|
131
133
|
'brand_logo': 'Logo da marca',
|
|
@@ -133,14 +135,15 @@ class VideoPlayerI18n {
|
|
|
133
135
|
'prev_video': 'Vídeo anterior (P)',
|
|
134
136
|
'playlist_next': 'Próximo',
|
|
135
137
|
'playlist_prev': 'Anterior',
|
|
136
|
-
'settings_menu': '
|
|
138
|
+
'settings_menu': 'Configurações'
|
|
137
139
|
},
|
|
138
140
|
|
|
139
141
|
// 中文
|
|
140
142
|
'zh': {
|
|
141
143
|
'subtitles': '字幕 (C)',
|
|
142
|
-
'
|
|
143
|
-
'
|
|
144
|
+
'subtitlesoff': '关闭',
|
|
145
|
+
'subtitlesdisable': '禁用字幕',
|
|
146
|
+
'subtitlesenable': '启用字幕',
|
|
144
147
|
'play_pause': '播放/暂停 (空格)',
|
|
145
148
|
'mute_unmute': '静音 (M)',
|
|
146
149
|
'volume': '音量',
|
|
@@ -154,14 +157,15 @@ class VideoPlayerI18n {
|
|
|
154
157
|
'prev_video': '上一个视频 (P)',
|
|
155
158
|
'playlist_next': '下一个',
|
|
156
159
|
'playlist_prev': '上一个',
|
|
157
|
-
'settings_menu': '
|
|
160
|
+
'settings_menu': '设置'
|
|
158
161
|
},
|
|
159
162
|
|
|
160
163
|
// 日本語
|
|
161
164
|
'ja': {
|
|
162
165
|
'subtitles': '字幕 (C)',
|
|
163
|
-
'
|
|
164
|
-
'
|
|
166
|
+
'subtitlesoff': 'オフ',
|
|
167
|
+
'subtitlesdisable': '字幕を無効にする',
|
|
168
|
+
'subtitlesenable': '字幕を有効にする',
|
|
165
169
|
'play_pause': '再生/一時停止 (スペース)',
|
|
166
170
|
'mute_unmute': 'ミュート (M)',
|
|
167
171
|
'volume': '音量',
|
|
@@ -175,14 +179,15 @@ class VideoPlayerI18n {
|
|
|
175
179
|
'prev_video': '前の動画 (P)',
|
|
176
180
|
'playlist_next': '次へ',
|
|
177
181
|
'playlist_prev': '前へ',
|
|
178
|
-
'settings_menu': '
|
|
182
|
+
'settings_menu': '設定'
|
|
179
183
|
},
|
|
180
184
|
|
|
181
185
|
// Русский
|
|
182
186
|
'ru': {
|
|
183
187
|
'subtitles': 'Субтитры (C)',
|
|
184
|
-
'
|
|
185
|
-
'
|
|
188
|
+
'subtitlesoff': 'Выкл',
|
|
189
|
+
'subtitlesdisable': 'Отключить субтитры',
|
|
190
|
+
'subtitlesenable': 'Включить субтитры',
|
|
186
191
|
'play_pause': 'Воспроизведение/Пауза (Пробел)',
|
|
187
192
|
'mute_unmute': 'Звук (M)',
|
|
188
193
|
'volume': 'Громкость',
|
|
@@ -196,14 +201,15 @@ class VideoPlayerI18n {
|
|
|
196
201
|
'prev_video': 'Предыдущее видео (P)',
|
|
197
202
|
'playlist_next': 'Далее',
|
|
198
203
|
'playlist_prev': 'Назад',
|
|
199
|
-
'settings_menu': '
|
|
204
|
+
'settings_menu': 'Настройки'
|
|
200
205
|
},
|
|
201
206
|
|
|
202
207
|
// العربية
|
|
203
208
|
'ar': {
|
|
204
209
|
'subtitles': 'الترجمة (C)',
|
|
205
|
-
'
|
|
206
|
-
'
|
|
210
|
+
'subtitlesoff': 'إيقاف',
|
|
211
|
+
'subtitlesdisable': 'تعطيل الترجمة',
|
|
212
|
+
'subtitlesenable': 'تفعيل الترجمة',
|
|
207
213
|
'play_pause': 'تشغيل/إيقاف مؤقت (مسافة)',
|
|
208
214
|
'mute_unmute': 'كتم الصوت (M)',
|
|
209
215
|
'volume': 'مستوى الصوت',
|
|
@@ -217,10 +223,187 @@ class VideoPlayerI18n {
|
|
|
217
223
|
'prev_video': 'الفيديو السابق (P)',
|
|
218
224
|
'playlist_next': 'التالي',
|
|
219
225
|
'playlist_prev': 'السابق',
|
|
220
|
-
'settings_menu': '
|
|
226
|
+
'settings_menu': 'الإعدادات'
|
|
227
|
+
},
|
|
228
|
+
|
|
229
|
+
// 한국어 (Korean)
|
|
230
|
+
'ko': {
|
|
231
|
+
'subtitles': '자막 (C)',
|
|
232
|
+
'subtitlesoff': '끄기',
|
|
233
|
+
'subtitlesdisable': '자막 비활성화',
|
|
234
|
+
'subtitlesenable': '자막 활성화',
|
|
235
|
+
'play_pause': '재생/일시정지 (스페이스)',
|
|
236
|
+
'mute_unmute': '음소거 (M)',
|
|
237
|
+
'volume': '음량',
|
|
238
|
+
'playback_speed': '재생 속도',
|
|
239
|
+
'video_quality': '비디오 품질',
|
|
240
|
+
'picture_in_picture': '화면 속 화면 (P)',
|
|
241
|
+
'fullscreen': '전체 화면 (F)',
|
|
242
|
+
'auto': '자동',
|
|
243
|
+
'brand_logo': '브랜드 로고',
|
|
244
|
+
'next_video': '다음 비디오 (N)',
|
|
245
|
+
'prev_video': '이전 비디오 (P)',
|
|
246
|
+
'playlist_next': '다음',
|
|
247
|
+
'playlist_prev': '이전',
|
|
248
|
+
'settings_menu': '설정'
|
|
249
|
+
},
|
|
250
|
+
|
|
251
|
+
// Polski
|
|
252
|
+
'pl': {
|
|
253
|
+
'subtitles': 'Napisy (C)',
|
|
254
|
+
'subtitlesoff': 'Wyłączone',
|
|
255
|
+
'subtitlesdisable': 'Wyłącz napisy',
|
|
256
|
+
'subtitlesenable': 'Włącz napisy',
|
|
257
|
+
'play_pause': 'Odtwarzaj/Pauza (Spacja)',
|
|
258
|
+
'mute_unmute': 'Wycisz (M)',
|
|
259
|
+
'volume': 'Głośność',
|
|
260
|
+
'playback_speed': 'Prędkość odtwarzania',
|
|
261
|
+
'video_quality': 'Jakość wideo',
|
|
262
|
+
'picture_in_picture': 'Obraz w obrazie (P)',
|
|
263
|
+
'fullscreen': 'Pełny ekran (F)',
|
|
264
|
+
'auto': 'Auto',
|
|
265
|
+
'brand_logo': 'Logo marki',
|
|
266
|
+
'next_video': 'Następne wideo (N)',
|
|
267
|
+
'prev_video': 'Poprzednie wideo (P)',
|
|
268
|
+
'playlist_next': 'Dalej',
|
|
269
|
+
'playlist_prev': 'Wstecz',
|
|
270
|
+
'settings_menu': 'Ustawienia'
|
|
271
|
+
},
|
|
272
|
+
|
|
273
|
+
// Magyar
|
|
274
|
+
'hu': {
|
|
275
|
+
'subtitles': 'Feliratok (C)',
|
|
276
|
+
'subtitlesoff': 'Kikapcsolva',
|
|
277
|
+
'subtitlesdisable': 'Feliratok kikapcsolása',
|
|
278
|
+
'subtitlesenable': 'Feliratok bekapcsolása',
|
|
279
|
+
'play_pause': 'Lejátszás/Szünet (Szóköz)',
|
|
280
|
+
'mute_unmute': 'Némítás (M)',
|
|
281
|
+
'volume': 'Hangerő',
|
|
282
|
+
'playback_speed': 'Lejátszási sebesség',
|
|
283
|
+
'video_quality': 'Videó minősége',
|
|
284
|
+
'picture_in_picture': 'Kép a képben (P)',
|
|
285
|
+
'fullscreen': 'Teljes képernyő (F)',
|
|
286
|
+
'auto': 'Auto',
|
|
287
|
+
'brand_logo': 'Márka logó',
|
|
288
|
+
'next_video': 'Következő videó (N)',
|
|
289
|
+
'prev_video': 'Előző videó (P)',
|
|
290
|
+
'playlist_next': 'Következő',
|
|
291
|
+
'playlist_prev': 'Előző',
|
|
292
|
+
'settings_menu': 'Beállítások'
|
|
293
|
+
},
|
|
294
|
+
|
|
295
|
+
// Türkçe
|
|
296
|
+
'tr': {
|
|
297
|
+
'subtitles': 'Altyazılar (C)',
|
|
298
|
+
'subtitlesoff': 'Kapalı',
|
|
299
|
+
'subtitlesdisable': 'Altyazıları kapat',
|
|
300
|
+
'subtitlesenable': 'Altyazıları aç',
|
|
301
|
+
'play_pause': 'Oynat/Duraklat (Boşluk)',
|
|
302
|
+
'mute_unmute': 'Sessize al (M)',
|
|
303
|
+
'volume': 'Ses düzeyi',
|
|
304
|
+
'playback_speed': 'Oynatma hızı',
|
|
305
|
+
'video_quality': 'Video kalitesi',
|
|
306
|
+
'picture_in_picture': 'Resim içinde resim (P)',
|
|
307
|
+
'fullscreen': 'Tam ekran (F)',
|
|
308
|
+
'auto': 'Otomatik',
|
|
309
|
+
'brand_logo': 'Marka logosu',
|
|
310
|
+
'next_video': 'Sonraki video (N)',
|
|
311
|
+
'prev_video': 'Önceki video (P)',
|
|
312
|
+
'playlist_next': 'Sonraki',
|
|
313
|
+
'playlist_prev': 'Önceki',
|
|
314
|
+
'settings_menu': 'Ayarlar'
|
|
315
|
+
},
|
|
316
|
+
|
|
317
|
+
// Nederlands
|
|
318
|
+
'nl': {
|
|
319
|
+
'subtitles': 'Ondertitels (C)',
|
|
320
|
+
'subtitlesoff': 'Uit',
|
|
321
|
+
'subtitlesdisable': 'Ondertitels uitschakelen',
|
|
322
|
+
'subtitlesenable': 'Ondertitels inschakelen',
|
|
323
|
+
'play_pause': 'Afspelen/Pauzeren (Spatie)',
|
|
324
|
+
'mute_unmute': 'Dempen (M)',
|
|
325
|
+
'volume': 'Volume',
|
|
326
|
+
'playback_speed': 'Afspeelsnelheid',
|
|
327
|
+
'video_quality': 'Videokwaliteit',
|
|
328
|
+
'picture_in_picture': 'Beeld-in-beeld (P)',
|
|
329
|
+
'fullscreen': 'Volledig scherm (F)',
|
|
330
|
+
'auto': 'Auto',
|
|
331
|
+
'brand_logo': 'Merklogo',
|
|
332
|
+
'next_video': 'Volgende video (N)',
|
|
333
|
+
'prev_video': 'Vorige video (P)',
|
|
334
|
+
'playlist_next': 'Volgende',
|
|
335
|
+
'playlist_prev': 'Vorige',
|
|
336
|
+
'settings_menu': 'Instellingen'
|
|
337
|
+
},
|
|
338
|
+
|
|
339
|
+
// हिन्दी (Hindi)
|
|
340
|
+
'hi': {
|
|
341
|
+
'subtitles': 'उपशीर्षक (C)',
|
|
342
|
+
'subtitlesoff': 'बंद',
|
|
343
|
+
'subtitlesdisable': 'उपशीर्षक अक्षम करें',
|
|
344
|
+
'subtitlesenable': 'उपशीर्षक सक्षम करें',
|
|
345
|
+
'play_pause': 'चलाएं/रोकें (स्पेस)',
|
|
346
|
+
'mute_unmute': 'म्यूट (M)',
|
|
347
|
+
'volume': 'वॉल्यूम',
|
|
348
|
+
'playback_speed': 'प्लेबैक गति',
|
|
349
|
+
'video_quality': 'वीडियो गुणवत्ता',
|
|
350
|
+
'picture_in_picture': 'चित्र-में-चित्र (P)',
|
|
351
|
+
'fullscreen': 'पूर्ण स्क्रीन (F)',
|
|
352
|
+
'auto': 'स्वतः',
|
|
353
|
+
'brand_logo': 'ब्रांड लोगो',
|
|
354
|
+
'next_video': 'अगला वीडियो (N)',
|
|
355
|
+
'prev_video': 'पिछला वीडियो (P)',
|
|
356
|
+
'playlist_next': 'अगला',
|
|
357
|
+
'playlist_prev': 'पिछला',
|
|
358
|
+
'settings_menu': 'सेटिंग्स'
|
|
359
|
+
},
|
|
360
|
+
|
|
361
|
+
// Svenska
|
|
362
|
+
'sv': {
|
|
363
|
+
'subtitles': 'Undertexter (C)',
|
|
364
|
+
'subtitlesoff': 'Av',
|
|
365
|
+
'subtitlesdisable': 'Inaktivera undertexter',
|
|
366
|
+
'subtitlesenable': 'Aktivera undertexter',
|
|
367
|
+
'play_pause': 'Spela/Pausa (Blanksteg)',
|
|
368
|
+
'mute_unmute': 'Stäng av ljud (M)',
|
|
369
|
+
'volume': 'Volym',
|
|
370
|
+
'playback_speed': 'Uppspelningshastighet',
|
|
371
|
+
'video_quality': 'Videokvalitet',
|
|
372
|
+
'picture_in_picture': 'Bild i bild (P)',
|
|
373
|
+
'fullscreen': 'Fullskärm (F)',
|
|
374
|
+
'auto': 'Auto',
|
|
375
|
+
'brand_logo': 'Varumärkeslogotyp',
|
|
376
|
+
'next_video': 'Nästa video (N)',
|
|
377
|
+
'prev_video': 'Föregående video (P)',
|
|
378
|
+
'playlist_next': 'Nästa',
|
|
379
|
+
'playlist_prev': 'Föregående',
|
|
380
|
+
'settings_menu': 'Inställningar'
|
|
381
|
+
},
|
|
382
|
+
|
|
383
|
+
// Bahasa Indonesia
|
|
384
|
+
'id': {
|
|
385
|
+
'subtitles': 'Teks (C)',
|
|
386
|
+
'subtitlesoff': 'Mati',
|
|
387
|
+
'subtitlesdisable': 'Nonaktifkan teks',
|
|
388
|
+
'subtitlesenable': 'Aktifkan teks',
|
|
389
|
+
'play_pause': 'Putar/Jeda (Spasi)',
|
|
390
|
+
'mute_unmute': 'Bisu (M)',
|
|
391
|
+
'volume': 'Volume',
|
|
392
|
+
'playback_speed': 'Kecepatan pemutaran',
|
|
393
|
+
'video_quality': 'Kualitas video',
|
|
394
|
+
'picture_in_picture': 'Gambar-dalam-gambar (P)',
|
|
395
|
+
'fullscreen': 'Layar penuh (F)',
|
|
396
|
+
'auto': 'Otomatis',
|
|
397
|
+
'brand_logo': 'Logo merek',
|
|
398
|
+
'next_video': 'Video berikutnya (N)',
|
|
399
|
+
'prev_video': 'Video sebelumnya (P)',
|
|
400
|
+
'playlist_next': 'Berikutnya',
|
|
401
|
+
'playlist_prev': 'Sebelumnya',
|
|
402
|
+
'settings_menu': 'Pengaturan'
|
|
221
403
|
}
|
|
222
404
|
};
|
|
223
405
|
|
|
406
|
+
|
|
224
407
|
// THEN detect language (after defining translations)
|
|
225
408
|
this.currentLanguage = this.detectLanguage();
|
|
226
409
|
}
|
|
@@ -925,6 +1108,11 @@ markPlayerReady() {
|
|
|
925
1108
|
this.video.style.pointerEvents = '';
|
|
926
1109
|
}
|
|
927
1110
|
|
|
1111
|
+
// UPDATE SETTINGS MENU VISIBILITY IF APPLICABLE
|
|
1112
|
+
if (typeof this.updateSettingsMenuVisibility === 'function') {
|
|
1113
|
+
this.updateSettingsMenuVisibility();
|
|
1114
|
+
}
|
|
1115
|
+
|
|
928
1116
|
// INITIALIZE AUTO-HIDE AFTER EVERYTHING IS READY
|
|
929
1117
|
setTimeout(() => {
|
|
930
1118
|
if (this.options.autoHide && !this.autoHideInitialized) {
|
|
@@ -3303,30 +3491,12 @@ createControls() {
|
|
|
3303
3491
|
<span class="icon"><svg viewBox="0 0 16 16" width="16" height="16" fill="currentColor"><path d="M12.5 4v8l-7-4zm-8 0v8l7-4z"/></svg></span>
|
|
3304
3492
|
</button>
|
|
3305
3493
|
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
<span class="icon"><svg viewBox="0 0 16 16" width="16" height="16" fill="currentColor"><path d="M0 4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm2-1a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1z"/><path d="M6.096 4.972c.234 0 .44.05.617.152.177.1.312.235.405.403.093.169.14.36.14.577 0 .216-.047.406-.14.572a1.03 1.03 0 0 1-.405.403 1.2 1.2 0 0 1-.617.152 1.2 1.2 0 0 1-.615-.152 1.03 1.03 0 0 1-.406-.403 1.28 1.28 0 0 1-.14-.572c0-.216.046-.408.14-.577.093-.168.228-.303.406-.403.177-.101.383-.152.615-.152m4.915 0c.234 0 .44.05.617.152.177.1.312.235.405.403.093.169.14.36.14.577 0 .216-.047.406-.14.572a1.03 1.03 0 0 1-.405.403 1.2 1.2 0 0 1-.617.152 1.2 1.2 0 0 1-.615-.152 1.03 1.03 0 0 1-.406-.403 1.28 1.28 0 0 1-.14-.572c0-.216.046-.408.14-.577.093-.168.228-.303.406-.403.177-.101.383-.152.615-.152M6.096 9.972c.234 0 .44.05.617.152.177.1.312.235.405.403.093.169.14.36.14.577 0 .216-.047.406-.14.572a1.03 1.03 0 0 1-.405.403 1.2 1.2 0 0 1-.617.152 1.2 1.2 0 0 1-.615-.152 1.03 1.03 0 0 1-.406-.403 1.28 1.28 0 0 1-.14-.572c0-.216.046-.408.14-.577.093-.168.228-.303.406-.403.177-.101.383-.152.615-.152m4.915 0c.234 0 .44.05.617.152.177.1.312.235.405.403.093.169.14.36.14.577 0 .216-.047.406-.14.572a1.03 1.03 0 0 1-.405.403 1.2 1.2 0 0 1-.617.152 1.2 1.2 0 0 1-.615-.152 1.03 1.03 0 0 1-.406-.403 1.28 1.28 0 0 1-.14-.572c0-.216.046-.408.14-.577.093-.168.228-.303.406-.403.177-.101.383-.152.615-.152"/></svg></span>
|
|
3494
|
+
<div class="settings-control">
|
|
3495
|
+
<button class="control-btn settings-btn" data-tooltip="settings_menu">
|
|
3496
|
+
<span class="icon"><svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor"><path d="M19.43 12.98c.04-.32.07-.64.07-.98s-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.39-.3-.61-.22l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.23-.09-.49 0-.61.22l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98s.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.12.22.39.3.61.22l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.23.09.49 0 .61-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zM12 15.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z"/></svg></span>
|
|
3310
3497
|
</button>
|
|
3311
|
-
<div class="
|
|
3312
|
-
<div class="subtitles-option active" data-track="off">Off</div>
|
|
3313
|
-
</div>
|
|
3314
|
-
</div>
|
|
3315
|
-
` : ''}
|
|
3316
|
-
|
|
3317
|
-
${this.options.showSpeedControl ? `
|
|
3318
|
-
<div class="speed-control">
|
|
3319
|
-
<button class="control-btn speed-btn" data-tooltip="playback_speed">1x</button>
|
|
3320
|
-
<div class="speed-menu">
|
|
3321
|
-
<div class="speed-option" data-speed="0.5">0.5x</div>
|
|
3322
|
-
<div class="speed-option" data-speed="0.75">0.75x</div>
|
|
3323
|
-
<div class="speed-option active" data-speed="1">1x</div>
|
|
3324
|
-
<div class="speed-option" data-speed="1.25">1.25x</div>
|
|
3325
|
-
<div class="speed-option" data-speed="1.5">1.5x</div>
|
|
3326
|
-
<div class="speed-option" data-speed="2">2x</div>
|
|
3327
|
-
</div>
|
|
3498
|
+
<div class="settings-menu"></div>
|
|
3328
3499
|
</div>
|
|
3329
|
-
` : ''}
|
|
3330
3500
|
|
|
3331
3501
|
${this.options.showQualitySelector && this.originalSources && this.originalSources.length > 1 ? `
|
|
3332
3502
|
<div class="quality-control">
|
|
@@ -3339,8 +3509,8 @@ createControls() {
|
|
|
3339
3509
|
<div class="quality-menu">
|
|
3340
3510
|
<div class="quality-option selected" data-quality="auto">${this.t('auto')}</div>
|
|
3341
3511
|
${this.originalSources.map(s =>
|
|
3342
|
-
|
|
3343
|
-
|
|
3512
|
+
`<div class="quality-option" data-quality="${s.quality}">${s.quality}</div>`
|
|
3513
|
+
).join('')}
|
|
3344
3514
|
</div>
|
|
3345
3515
|
</div>
|
|
3346
3516
|
` : ''}
|
|
@@ -3352,13 +3522,6 @@ createControls() {
|
|
|
3352
3522
|
</button>
|
|
3353
3523
|
` : ''}
|
|
3354
3524
|
|
|
3355
|
-
<div class="settings-control">
|
|
3356
|
-
<button class="control-btn settings-btn" data-tooltip="settings_menu">
|
|
3357
|
-
<span class="icon"><svg viewBox="0 0 16 16" width="16" height="16" fill="currentColor"><path d="M8 4.754a3.246 3.246 0 1 0 0 6.492 3.246 3.246 0 0 0 0-6.492M5.754 8a2.246 2.246 0 1 1 4.492 0 2.246 2.246 0 0 1-4.492 0"/><path d="M9.796 1.343c-.527-1.79-3.065-1.79-3.592 0l-.094.319a.873.873 0 0 1-1.255.52l-.292-.16c-1.64-.892-3.433.902-2.54 2.541l.159.292a.873.873 0 0 1-.52 1.255l-.319.094c-1.79.527-1.79 3.065 0 3.592l.319.094a.873.873 0 0 1 .52 1.255l-.16.292c-.892 1.64.901 3.434 2.541 2.54l.292-.159a.873.873 0 0 1 1.255.52l.094.319c.527 1.79 3.065 1.79 3.592 0l.094-.319a.873.873 0 0 1 1.255-.52l.292.16c1.64.893 3.434-.902 2.54-2.541l-.159-.292a.873.873 0 0 1 .52-1.255l.319-.094c1.79-.527 1.79-3.065 0-3.592l-.319-.094a.873.873 0 0 1-.52-1.255l.16-.292c.893-1.64-.902-3.433-2.541-2.54l-.292.159a.873.873 0 0 1-1.255-.52z"/></svg></span>
|
|
3358
|
-
</button>
|
|
3359
|
-
<div class="settings-menu"></div>
|
|
3360
|
-
</div>
|
|
3361
|
-
|
|
3362
3525
|
${this.options.showFullscreen ? `
|
|
3363
3526
|
<button class="control-btn fullscreen-btn" data-tooltip="fullscreen">
|
|
3364
3527
|
<span class="icon fullscreen-icon"><svg viewBox="0 0 16 16" width="16" height="16" fill="currentColor"><path d="M1.5 1a.5.5 0 0 0-.5.5v4a.5.5 0 0 1-1 0v-4A1.5 1.5 0 0 1 1.5 0h4a.5.5 0 0 1 0 1zM10 .5a.5.5 0 0 1 .5-.5h4A1.5 1.5 0 0 1 16 1.5v4a.5.5 0 0 1-1 0v-4a.5.5 0 0 0-.5-.5h-4a.5.5 0 0 1-.5-.5M.5 10a.5.5 0 0 1 .5.5v4a.5.5 0 0 0 .5.5h4a.5.5 0 0 1 0 1h-4A1.5 1.5 0 0 1 0 14.5v-4a.5.5 0 0 1 .5-.5m15 0a.5.5 0 0 1 .5.5v4a1.5 1.5 0 0 1-1.5 1.5h-4a.5.5 0 0 1 0-1h4a.5.5 0 0 0 .5-.5v-4a.5.5 0 0 1 .5-.5"/></svg></span>
|
|
@@ -3455,44 +3618,22 @@ checkScreenSize() {
|
|
|
3455
3618
|
}
|
|
3456
3619
|
}
|
|
3457
3620
|
|
|
3458
|
-
/* Update settings menu visibility
|
|
3621
|
+
/* Update settings menu visibility */
|
|
3459
3622
|
updateSettingsMenuVisibility() {
|
|
3460
3623
|
const settingsControl = this.controls?.querySelector('.settings-control');
|
|
3461
3624
|
if (!settingsControl) return;
|
|
3462
3625
|
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
settingsControl.style.display = 'block';
|
|
3626
|
+
// always show settings
|
|
3627
|
+
settingsControl.style.display = 'block';
|
|
3466
3628
|
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
const speedControl = this.controls.querySelector('.speed-control');
|
|
3470
|
-
const subtitlesControl = this.controls.querySelector('.subtitles-control');
|
|
3629
|
+
// Populate settings menu
|
|
3630
|
+
this.populateSettingsMenu();
|
|
3471
3631
|
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
} else {
|
|
3478
|
-
// Hide settings menu and show individual controls
|
|
3479
|
-
settingsControl.style.display = 'none';
|
|
3480
|
-
|
|
3481
|
-
// Show original controls
|
|
3482
|
-
const pipBtn = this.controls.querySelector('.pip-btn');
|
|
3483
|
-
const speedControl = this.controls.querySelector('.speed-control');
|
|
3484
|
-
const subtitlesControl = this.controls.querySelector('.subtitles-control');
|
|
3485
|
-
|
|
3486
|
-
if (pipBtn && this.options.showPictureInPicture && this.isPiPSupported) {
|
|
3487
|
-
pipBtn.style.display = 'flex';
|
|
3488
|
-
}
|
|
3489
|
-
if (speedControl && this.options.showSpeedControl) {
|
|
3490
|
-
speedControl.style.display = 'block';
|
|
3491
|
-
}
|
|
3492
|
-
if (subtitlesControl && this.options.showSubtitles && this.textTracks.length > 0) {
|
|
3493
|
-
subtitlesControl.style.display = 'block';
|
|
3494
|
-
}
|
|
3495
|
-
}
|
|
3632
|
+
// hide speed and subtitles controls
|
|
3633
|
+
const speedControl = this.controls.querySelector('.speed-control');
|
|
3634
|
+
const subtitlesControl = this.controls.querySelector('.subtitles-control');
|
|
3635
|
+
if (speedControl) speedControl.style.display = 'none';
|
|
3636
|
+
if (subtitlesControl) subtitlesControl.style.display = 'none';
|
|
3496
3637
|
}
|
|
3497
3638
|
|
|
3498
3639
|
/**
|
|
@@ -3504,54 +3645,40 @@ populateSettingsMenu() {
|
|
|
3504
3645
|
|
|
3505
3646
|
let menuHTML = '';
|
|
3506
3647
|
|
|
3507
|
-
//
|
|
3508
|
-
if (this.options.showPictureInPicture && this.isPiPSupported) {
|
|
3509
|
-
const pipLabel = this.t('picture_in_picture') || 'Picture-in-Picture';
|
|
3510
|
-
menuHTML += `<div class="settings-option" data-action="pip">
|
|
3511
|
-
<span class="settings-option-label">${pipLabel}</span>
|
|
3512
|
-
</div>`;
|
|
3513
|
-
}
|
|
3514
|
-
|
|
3515
|
-
// Speed Control - expandable
|
|
3648
|
+
// SPEED - always included
|
|
3516
3649
|
if (this.options.showSpeedControl) {
|
|
3517
3650
|
const speedLabel = this.t('playback_speed') || 'Playback Speed';
|
|
3518
3651
|
const currentSpeed = this.video ? this.video.playbackRate : 1;
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
<
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
</div>
|
|
3526
|
-
<div class="settings-expandable-content" style="display: none;">`;
|
|
3652
|
+
menuHTML += `<div class="settings-expandable-wrapper">
|
|
3653
|
+
<div class="settings-option expandable-trigger" data-action="speed-expand">
|
|
3654
|
+
<span class="settings-option-label">${speedLabel} <strong>${currentSpeed}x</strong></span>
|
|
3655
|
+
<span class="expand-arrow">▶</span>
|
|
3656
|
+
</div>
|
|
3657
|
+
<div class="settings-expandable-content" style="display: none;">`;
|
|
3527
3658
|
|
|
3528
3659
|
const speeds = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
|
|
3529
3660
|
speeds.forEach(speed => {
|
|
3530
3661
|
const isActive = Math.abs(speed - currentSpeed) < 0.01;
|
|
3531
3662
|
menuHTML += `<div class="settings-suboption ${isActive ? 'active' : ''}" data-speed="${speed}">${speed}x</div>`;
|
|
3532
3663
|
});
|
|
3533
|
-
|
|
3534
3664
|
menuHTML += `</div></div>`;
|
|
3535
3665
|
}
|
|
3536
3666
|
|
|
3537
|
-
//
|
|
3667
|
+
// SUBTITLES - always included
|
|
3538
3668
|
if (this.options.showSubtitles && this.textTracks && this.textTracks.length > 0) {
|
|
3539
3669
|
const subtitlesLabel = this.t('subtitles') || 'Subtitles';
|
|
3540
3670
|
const currentTrack = this.currentSubtitleTrack;
|
|
3541
|
-
const currentLabel = this.subtitlesEnabled
|
|
3671
|
+
const currentLabel = this.subtitlesEnabled ? (currentTrack ? currentTrack.label : 'Unknown') : (this.t('subtitlesoff') || 'Off');
|
|
3542
3672
|
|
|
3543
|
-
menuHTML +=
|
|
3544
|
-
<div class="settings-expandable-
|
|
3545
|
-
<
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
<div class="settings-expandable-content" style="display: none;">`;
|
|
3673
|
+
menuHTML += `<div class="settings-expandable-wrapper">
|
|
3674
|
+
<div class="settings-option expandable-trigger" data-action="subtitles-expand">
|
|
3675
|
+
<span class="settings-option-label">${subtitlesLabel} <strong>${currentLabel}</strong></span>
|
|
3676
|
+
<span class="expand-arrow">▶</span>
|
|
3677
|
+
</div>
|
|
3678
|
+
<div class="settings-expandable-content" style="display: none;">`;
|
|
3550
3679
|
|
|
3551
|
-
// Off option
|
|
3552
3680
|
menuHTML += `<div class="settings-suboption ${!this.subtitlesEnabled ? 'active' : ''}" data-track="off">${this.t('subtitlesoff') || 'Off'}</div>`;
|
|
3553
3681
|
|
|
3554
|
-
// Subtitle tracks
|
|
3555
3682
|
this.textTracks.forEach((trackData, index) => {
|
|
3556
3683
|
const isActive = this.currentSubtitleTrack === trackData.track;
|
|
3557
3684
|
menuHTML += `<div class="settings-suboption ${isActive ? 'active' : ''}" data-track="${index}">${trackData.label}</div>`;
|
|
@@ -3561,9 +3688,6 @@ populateSettingsMenu() {
|
|
|
3561
3688
|
}
|
|
3562
3689
|
|
|
3563
3690
|
settingsMenu.innerHTML = menuHTML;
|
|
3564
|
-
|
|
3565
|
-
// Add scrollbar if needed
|
|
3566
|
-
this.addSettingsMenuScrollbar();
|
|
3567
3691
|
}
|
|
3568
3692
|
|
|
3569
3693
|
/**
|
|
@@ -3573,12 +3697,27 @@ addSettingsMenuScrollbar() {
|
|
|
3573
3697
|
const settingsMenu = this.controls?.querySelector('.settings-menu');
|
|
3574
3698
|
if (!settingsMenu) return;
|
|
3575
3699
|
|
|
3576
|
-
const
|
|
3577
|
-
|
|
3700
|
+
const settingsBtn = document.querySelector('.settings-btn');
|
|
3701
|
+
if (!settingsBtn) return;
|
|
3578
3702
|
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3703
|
+
// helper to update menu height
|
|
3704
|
+
const updateMenuHeight = () => {
|
|
3705
|
+
if (settingsMenu.classList.contains('active')) {
|
|
3706
|
+
const containerRect = settingsMenu.parentElement.parentElement.getBoundingClientRect();
|
|
3707
|
+
const btnRect = settingsBtn.getBoundingClientRect();
|
|
3708
|
+
const spaceBelow = containerRect.bottom - btnRect.bottom;
|
|
3709
|
+
const maxMenuHeight = Math.max(100, Math.min(250, spaceBelow - 20));
|
|
3710
|
+
settingsMenu.style.maxHeight = `${maxMenuHeight}px`;
|
|
3711
|
+
settingsMenu.style.overflowY = 'auto';
|
|
3712
|
+
settingsMenu.style.overflowX = 'hidden';
|
|
3713
|
+
}
|
|
3714
|
+
};
|
|
3715
|
+
|
|
3716
|
+
// run initially
|
|
3717
|
+
updateMenuHeight();
|
|
3718
|
+
|
|
3719
|
+
// recalculate on window resize
|
|
3720
|
+
window.addEventListener('resize', updateMenuHeight);
|
|
3582
3721
|
|
|
3583
3722
|
// Add scrollbar styling
|
|
3584
3723
|
if (!document.getElementById('player-settings-scrollbar-style')) {
|
|
@@ -3611,9 +3750,43 @@ addSettingsMenuScrollbar() {
|
|
|
3611
3750
|
* Bind settings menu events
|
|
3612
3751
|
*/
|
|
3613
3752
|
bindSettingsMenuEvents() {
|
|
3753
|
+
const settingsBtn = this.controls?.querySelector('.settings-btn');
|
|
3614
3754
|
const settingsMenu = this.controls?.querySelector('.settings-menu');
|
|
3615
|
-
if (!settingsMenu) return;
|
|
3755
|
+
if (!settingsMenu || !settingsBtn) return;
|
|
3616
3756
|
|
|
3757
|
+
// toggle menu on button click
|
|
3758
|
+
settingsBtn.addEventListener('click', (e) => {
|
|
3759
|
+
e.stopPropagation();
|
|
3760
|
+
settingsMenu.classList.toggle('active');
|
|
3761
|
+
|
|
3762
|
+
// when menu is opened, set max height and overflow
|
|
3763
|
+
if (settingsMenu.classList.contains('active')) {
|
|
3764
|
+
const settingsBtn = document.querySelector('.settings-btn');
|
|
3765
|
+
const containerRect = settingsMenu.parentElement.parentElement.getBoundingClientRect();
|
|
3766
|
+
const btnRect = settingsBtn.getBoundingClientRect();
|
|
3767
|
+
const spaceBelow = containerRect.bottom - btnRect.bottom;
|
|
3768
|
+
const maxMenuHeight = Math.max(100, Math.min(250, spaceBelow - 20));
|
|
3769
|
+
|
|
3770
|
+
settingsMenu.style.maxHeight = `${maxMenuHeight}px`;
|
|
3771
|
+
settingsMenu.style.overflowY = 'auto';
|
|
3772
|
+
settingsMenu.style.overflowX = 'hidden';
|
|
3773
|
+
} else {
|
|
3774
|
+
settingsMenu.style.maxHeight = 'none';
|
|
3775
|
+
settingsMenu.style.overflowY = 'visible';
|
|
3776
|
+
}
|
|
3777
|
+
|
|
3778
|
+
});
|
|
3779
|
+
|
|
3780
|
+
// close menu when clicking outside
|
|
3781
|
+
document.addEventListener('click', (e) => {
|
|
3782
|
+
if (!settingsBtn?.contains(e.target) && !settingsMenu?.contains(e.target)) {
|
|
3783
|
+
settingsMenu?.classList.remove('active');
|
|
3784
|
+
settingsMenu.style.maxHeight = 'none';
|
|
3785
|
+
settingsMenu.style.overflowY = 'visible';
|
|
3786
|
+
}
|
|
3787
|
+
});
|
|
3788
|
+
|
|
3789
|
+
// manage clicks inside the menu
|
|
3617
3790
|
settingsMenu.addEventListener('click', (e) => {
|
|
3618
3791
|
e.stopPropagation();
|
|
3619
3792
|
|
|
@@ -5719,46 +5892,99 @@ parseTimeToSeconds(timeStr) {
|
|
|
5719
5892
|
* Create visual chapter markers on the progress bar
|
|
5720
5893
|
*/
|
|
5721
5894
|
createChapterMarkers() {
|
|
5722
|
-
if (!this.progressContainer || !this.video || !this.chapters)
|
|
5895
|
+
if (!this.progressContainer || !this.video || !this.chapters) return;
|
|
5896
|
+
|
|
5897
|
+
const duration = this.video.duration;
|
|
5898
|
+
if (!duration || isNaN(duration)) {
|
|
5899
|
+
// Wait for metadata
|
|
5900
|
+
const loadedMetadataHandler = () => {
|
|
5901
|
+
this.createChapterMarkers();
|
|
5902
|
+
this.video.removeEventListener('loadedmetadata', loadedMetadataHandler);
|
|
5903
|
+
};
|
|
5904
|
+
this.video.addEventListener('loadedmetadata', loadedMetadataHandler);
|
|
5723
5905
|
return;
|
|
5724
5906
|
}
|
|
5725
5907
|
|
|
5726
|
-
//
|
|
5908
|
+
// Remove existing markers
|
|
5909
|
+
const existingMarkers = this.progressContainer.querySelector('.chapter-markers-container');
|
|
5910
|
+
if (existingMarkers) {
|
|
5911
|
+
existingMarkers.remove();
|
|
5912
|
+
}
|
|
5913
|
+
|
|
5914
|
+
// Create container for chapter segments
|
|
5727
5915
|
const markersContainer = document.createElement('div');
|
|
5728
5916
|
markersContainer.className = 'chapter-markers-container';
|
|
5729
5917
|
|
|
5918
|
+
// Create segments for each chapter
|
|
5730
5919
|
this.chapters.forEach((chapter, index) => {
|
|
5731
|
-
const
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5920
|
+
const nextChapter = this.chapters[index + 1];
|
|
5921
|
+
const startPercent = (chapter.time / duration) * 100;
|
|
5922
|
+
const endPercent = nextChapter ? (nextChapter.time / duration) * 100 : 100;
|
|
5923
|
+
|
|
5924
|
+
// Calculate segment width minus the gap
|
|
5925
|
+
const gapSize = nextChapter ? 6 : 0; // 6px gap between segments
|
|
5926
|
+
const widthPercent = endPercent - startPercent;
|
|
5927
|
+
|
|
5928
|
+
// Create segment container
|
|
5929
|
+
const segment = document.createElement('div');
|
|
5930
|
+
segment.className = 'chapter-segment';
|
|
5931
|
+
segment.style.cssText = `
|
|
5932
|
+
position: absolute;
|
|
5933
|
+
left: ${startPercent}%;
|
|
5934
|
+
top: 0;
|
|
5935
|
+
width: calc(${widthPercent}% - ${gapSize}px);
|
|
5936
|
+
height: 100%;
|
|
5937
|
+
background: rgba(255, 255, 255, 0.3);
|
|
5938
|
+
cursor: pointer;
|
|
5939
|
+
z-index: 3;
|
|
5940
|
+
transition: background 0.2s;
|
|
5941
|
+
pointer-events: none;
|
|
5942
|
+
`;
|
|
5943
|
+
|
|
5944
|
+
segment.setAttribute('data-chapter-index', index);
|
|
5945
|
+
segment.setAttribute('data-chapter-time', chapter.time);
|
|
5946
|
+
segment.setAttribute('data-chapter-title', chapter.title);
|
|
5947
|
+
|
|
5948
|
+
markersContainer.appendChild(segment);
|
|
5949
|
+
|
|
5950
|
+
// Add marker at the START of next segment (transparent divider)
|
|
5951
|
+
if (nextChapter) {
|
|
5952
|
+
const marker = document.createElement('div');
|
|
5953
|
+
marker.className = 'chapter-marker';
|
|
5954
|
+
marker.style.cssText = `
|
|
5955
|
+
position: absolute !important;
|
|
5956
|
+
left: ${endPercent}% !important;
|
|
5957
|
+
top: 0 !important;
|
|
5958
|
+
width: 6px !important;
|
|
5959
|
+
height: 100% !important;
|
|
5960
|
+
background: transparent !important;
|
|
5961
|
+
border: none !important;
|
|
5962
|
+
box-shadow: none !important;
|
|
5963
|
+
margin-left: -3px !important;
|
|
5964
|
+
cursor: pointer !important;
|
|
5965
|
+
z-index: 10 !important;
|
|
5966
|
+
`;
|
|
5967
|
+
|
|
5968
|
+
marker.setAttribute('data-chapter-time', nextChapter.time);
|
|
5969
|
+
marker.setAttribute('data-chapter-title', nextChapter.title);
|
|
5970
|
+
|
|
5971
|
+
// Click on marker to jump to chapter start
|
|
5972
|
+
marker.addEventListener('click', (e) => {
|
|
5973
|
+
e.stopPropagation();
|
|
5974
|
+
this.jumpToChapter(index + 1);
|
|
5975
|
+
});
|
|
5976
|
+
|
|
5977
|
+
markersContainer.appendChild(marker);
|
|
5740
5978
|
}
|
|
5741
|
-
|
|
5742
|
-
markersContainer.appendChild(marker);
|
|
5743
5979
|
});
|
|
5744
5980
|
|
|
5745
5981
|
// Insert markers container into progress container
|
|
5746
5982
|
this.progressContainer.appendChild(markersContainer);
|
|
5747
5983
|
this.chapterMarkersContainer = markersContainer;
|
|
5748
5984
|
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
this.updateChapterMarkerPositions();
|
|
5752
|
-
} else {
|
|
5753
|
-
// Wait for metadata to be loaded
|
|
5754
|
-
const loadedMetadataHandler = () => {
|
|
5755
|
-
this.updateChapterMarkerPositions();
|
|
5756
|
-
this.video.removeEventListener('loadedmetadata', loadedMetadataHandler);
|
|
5757
|
-
};
|
|
5758
|
-
this.video.addEventListener('loadedmetadata', loadedMetadataHandler);
|
|
5985
|
+
if (this.options.debug) {
|
|
5986
|
+
console.log(`Chapter markers created: ${this.chapters.length} segments`);
|
|
5759
5987
|
}
|
|
5760
|
-
|
|
5761
|
-
if (this.options.debug) console.log('📚 Chapter markers created on timeline');
|
|
5762
5988
|
}
|
|
5763
5989
|
|
|
5764
5990
|
/**
|
|
@@ -5783,70 +6009,278 @@ updateChapterMarkerPositions() {
|
|
|
5783
6009
|
}
|
|
5784
6010
|
|
|
5785
6011
|
/**
|
|
5786
|
-
* Create chapter tooltip
|
|
6012
|
+
* Create chapter tooltip with title and image
|
|
5787
6013
|
*/
|
|
5788
6014
|
createChapterTooltip() {
|
|
5789
|
-
if (!this.progressContainer)
|
|
5790
|
-
|
|
6015
|
+
if (!this.progressContainer) return;
|
|
6016
|
+
|
|
6017
|
+
// Remove existing chapter tooltip
|
|
6018
|
+
let chapterTooltip = this.progressContainer.querySelector('.chapter-tooltip');
|
|
6019
|
+
if (chapterTooltip) {
|
|
6020
|
+
chapterTooltip.remove();
|
|
5791
6021
|
}
|
|
5792
6022
|
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
6023
|
+
// Create chapter tooltip container (positioned ABOVE the time tooltip)
|
|
6024
|
+
chapterTooltip = document.createElement('div');
|
|
6025
|
+
chapterTooltip.className = 'chapter-tooltip';
|
|
6026
|
+
chapterTooltip.style.cssText = `
|
|
6027
|
+
position: absolute;
|
|
6028
|
+
bottom: calc(100% + 35px);
|
|
6029
|
+
left: 0;
|
|
6030
|
+
background: rgba(28, 28, 28, 0.95);
|
|
6031
|
+
color: #fff;
|
|
6032
|
+
border-radius: 4px;
|
|
6033
|
+
pointer-events: none;
|
|
6034
|
+
visibility: hidden;
|
|
6035
|
+
opacity: 0;
|
|
6036
|
+
z-index: 100001;
|
|
6037
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
|
6038
|
+
max-width: 300px;
|
|
6039
|
+
overflow: hidden;
|
|
6040
|
+
transform: translateX(-50%);
|
|
6041
|
+
transition: opacity 0.15s, visibility 0.15s;
|
|
6042
|
+
display: flex;
|
|
6043
|
+
flex-direction: column;
|
|
6044
|
+
`;
|
|
5797
6045
|
|
|
5798
|
-
//
|
|
5799
|
-
|
|
5800
|
-
<div class="chapter-tooltip-
|
|
5801
|
-
|
|
5802
|
-
|
|
6046
|
+
// Create inner content structure
|
|
6047
|
+
chapterTooltip.innerHTML = `
|
|
6048
|
+
<div class="chapter-tooltip-content" style="display: flex; flex-direction: column; gap: 8px; padding: 8px;">
|
|
6049
|
+
<div class="chapter-tooltip-image" style="
|
|
6050
|
+
width: 100%;
|
|
6051
|
+
height: 120px;
|
|
6052
|
+
background-size: cover;
|
|
6053
|
+
background-position: center;
|
|
6054
|
+
border-radius: 3px;
|
|
6055
|
+
display: none;
|
|
6056
|
+
"></div>
|
|
6057
|
+
<div class="chapter-tooltip-info" style="display: flex; flex-direction: column; gap: 4px;">
|
|
6058
|
+
<div class="chapter-tooltip-title" style="
|
|
6059
|
+
font-size: 13px;
|
|
6060
|
+
font-weight: 600;
|
|
6061
|
+
color: #fff;
|
|
6062
|
+
max-width: 280px;
|
|
6063
|
+
overflow: hidden;
|
|
6064
|
+
text-overflow: ellipsis;
|
|
6065
|
+
white-space: nowrap;
|
|
6066
|
+
"></div>
|
|
6067
|
+
<div class="chapter-tooltip-time" style="
|
|
6068
|
+
font-size: 12px;
|
|
6069
|
+
font-weight: 400;
|
|
6070
|
+
color: rgba(255, 255, 255, 0.8);
|
|
6071
|
+
"></div>
|
|
6072
|
+
</div>
|
|
6073
|
+
</div>
|
|
5803
6074
|
`;
|
|
5804
6075
|
|
|
5805
|
-
this.progressContainer.appendChild(
|
|
5806
|
-
this.chapterTooltip =
|
|
6076
|
+
this.progressContainer.appendChild(chapterTooltip);
|
|
6077
|
+
this.chapterTooltip = chapterTooltip;
|
|
5807
6078
|
|
|
5808
|
-
if (this.options.debug)
|
|
6079
|
+
if (this.options.debug) {
|
|
6080
|
+
console.log('Chapter tooltip created');
|
|
6081
|
+
}
|
|
5809
6082
|
}
|
|
5810
6083
|
|
|
5811
6084
|
/**
|
|
5812
|
-
* Bind chapter-related events
|
|
6085
|
+
* Bind chapter-related events - tooltip on progressbar mousemove
|
|
5813
6086
|
*/
|
|
5814
6087
|
bindChapterEvents() {
|
|
5815
|
-
if (!this.
|
|
5816
|
-
|
|
6088
|
+
if (!this.progressContainer) return;
|
|
6089
|
+
|
|
6090
|
+
// Remove existing chapter tooltip if present
|
|
6091
|
+
let chapterTooltip = this.progressContainer.querySelector('.chapter-tooltip-hover');
|
|
6092
|
+
if (chapterTooltip) {
|
|
6093
|
+
chapterTooltip.remove();
|
|
5817
6094
|
}
|
|
5818
6095
|
|
|
5819
|
-
//
|
|
5820
|
-
|
|
6096
|
+
// Create chapter tooltip
|
|
6097
|
+
chapterTooltip = document.createElement('div');
|
|
6098
|
+
chapterTooltip.className = 'chapter-tooltip-hover';
|
|
6099
|
+
chapterTooltip.style.cssText = `
|
|
6100
|
+
position: absolute;
|
|
6101
|
+
bottom: calc(100% + 35px);
|
|
6102
|
+
left: 0;
|
|
6103
|
+
background: rgba(28, 28, 28, 0.95);
|
|
6104
|
+
color: #fff;
|
|
6105
|
+
border-radius: 4px;
|
|
6106
|
+
padding: 8px;
|
|
6107
|
+
pointer-events: none;
|
|
6108
|
+
visibility: hidden;
|
|
6109
|
+
opacity: 0;
|
|
6110
|
+
z-index: 100001;
|
|
6111
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
|
6112
|
+
max-width: 300px;
|
|
6113
|
+
transform: translateX(-50%);
|
|
6114
|
+
transition: opacity 0.15s, visibility 0.15s;
|
|
6115
|
+
`;
|
|
5821
6116
|
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
this.showChapterTooltip(index, e);
|
|
5825
|
-
});
|
|
6117
|
+
this.progressContainer.appendChild(chapterTooltip);
|
|
6118
|
+
this.chapterTooltip = chapterTooltip;
|
|
5826
6119
|
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
|
|
6120
|
+
// Get player container for edge detection
|
|
6121
|
+
const getPlayerBounds = () => {
|
|
6122
|
+
return this.container ? this.container.getBoundingClientRect() : null;
|
|
6123
|
+
};
|
|
5830
6124
|
|
|
5831
|
-
|
|
5832
|
-
|
|
5833
|
-
|
|
6125
|
+
// Mousemove handler to show tooltip with title and image
|
|
6126
|
+
this.progressContainer.addEventListener('mousemove', (e) => {
|
|
6127
|
+
if (!this.video || !this.video.duration || !this.chapters || this.chapters.length === 0) {
|
|
6128
|
+
return;
|
|
6129
|
+
}
|
|
5834
6130
|
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
6131
|
+
const rect = this.progressContainer.getBoundingClientRect();
|
|
6132
|
+
const playerRect = getPlayerBounds();
|
|
6133
|
+
const mouseX = e.clientX - rect.left;
|
|
6134
|
+
const percentage = Math.max(0, Math.min(1, mouseX / rect.width));
|
|
6135
|
+
const time = percentage * this.video.duration;
|
|
6136
|
+
|
|
6137
|
+
// Find chapter at current time
|
|
6138
|
+
let currentChapter = null;
|
|
6139
|
+
for (let i = this.chapters.length - 1; i >= 0; i--) {
|
|
6140
|
+
if (time >= this.chapters[i].time) {
|
|
6141
|
+
currentChapter = this.chapters[i];
|
|
6142
|
+
break;
|
|
6143
|
+
}
|
|
6144
|
+
}
|
|
6145
|
+
|
|
6146
|
+
if (currentChapter) {
|
|
6147
|
+
// Build tooltip HTML
|
|
6148
|
+
let tooltipHTML = '<div style="display: flex; flex-direction: column; gap: 6px;">';
|
|
6149
|
+
|
|
6150
|
+
// Add image if available
|
|
6151
|
+
if (currentChapter.image) {
|
|
6152
|
+
tooltipHTML += `
|
|
6153
|
+
<div style="
|
|
6154
|
+
width: 100%;
|
|
6155
|
+
height: 120px;
|
|
6156
|
+
background-image: url('${currentChapter.image}');
|
|
6157
|
+
background-size: cover;
|
|
6158
|
+
background-position: center;
|
|
6159
|
+
border-radius: 3px;
|
|
6160
|
+
"></div>
|
|
6161
|
+
`;
|
|
6162
|
+
}
|
|
6163
|
+
|
|
6164
|
+
// Add title
|
|
6165
|
+
tooltipHTML += `
|
|
6166
|
+
<div style="
|
|
6167
|
+
font-size: 13px;
|
|
6168
|
+
font-weight: 600;
|
|
6169
|
+
max-width: 280px;
|
|
6170
|
+
overflow: hidden;
|
|
6171
|
+
text-overflow: ellipsis;
|
|
6172
|
+
white-space: nowrap;
|
|
6173
|
+
">
|
|
6174
|
+
${currentChapter.title}
|
|
6175
|
+
</div>
|
|
6176
|
+
`;
|
|
6177
|
+
|
|
6178
|
+
// Add time
|
|
6179
|
+
tooltipHTML += `
|
|
6180
|
+
<div style="
|
|
6181
|
+
font-size: 12px;
|
|
6182
|
+
font-weight: 400;
|
|
6183
|
+
color: rgba(255, 255, 255, 0.8);
|
|
6184
|
+
">
|
|
6185
|
+
${this.formatTime(currentChapter.time)}
|
|
6186
|
+
</div>
|
|
6187
|
+
`;
|
|
6188
|
+
|
|
6189
|
+
tooltipHTML += '</div>';
|
|
6190
|
+
|
|
6191
|
+
chapterTooltip.innerHTML = tooltipHTML;
|
|
6192
|
+
chapterTooltip.style.visibility = 'visible';
|
|
6193
|
+
chapterTooltip.style.opacity = '1';
|
|
6194
|
+
|
|
6195
|
+
// Position tooltip with edge detection
|
|
6196
|
+
setTimeout(() => {
|
|
6197
|
+
const tooltipWidth = chapterTooltip.offsetWidth;
|
|
6198
|
+
const tooltipHalfWidth = tooltipWidth / 2;
|
|
6199
|
+
const absoluteX = e.clientX;
|
|
6200
|
+
|
|
6201
|
+
if (playerRect) {
|
|
6202
|
+
// Left edge
|
|
6203
|
+
if (absoluteX - tooltipHalfWidth < playerRect.left) {
|
|
6204
|
+
chapterTooltip.style.left = `${playerRect.left - rect.left + tooltipHalfWidth}px`;
|
|
6205
|
+
}
|
|
6206
|
+
// Right edge
|
|
6207
|
+
else if (absoluteX + tooltipHalfWidth > playerRect.right) {
|
|
6208
|
+
chapterTooltip.style.left = `${playerRect.right - rect.left - tooltipHalfWidth}px`;
|
|
6209
|
+
}
|
|
6210
|
+
// Normal center
|
|
6211
|
+
else {
|
|
6212
|
+
chapterTooltip.style.left = `${mouseX}px`;
|
|
6213
|
+
}
|
|
6214
|
+
} else {
|
|
6215
|
+
chapterTooltip.style.left = `${mouseX}px`;
|
|
6216
|
+
}
|
|
6217
|
+
}, 0);
|
|
6218
|
+
} else {
|
|
6219
|
+
chapterTooltip.style.visibility = 'hidden';
|
|
6220
|
+
chapterTooltip.style.opacity = '0';
|
|
6221
|
+
}
|
|
6222
|
+
});
|
|
6223
|
+
|
|
6224
|
+
// Mouseleave handler
|
|
6225
|
+
this.progressContainer.addEventListener('mouseleave', () => {
|
|
6226
|
+
chapterTooltip.style.visibility = 'hidden';
|
|
6227
|
+
chapterTooltip.style.opacity = '0';
|
|
5840
6228
|
});
|
|
5841
6229
|
|
|
5842
6230
|
// Update active chapter during playback
|
|
5843
6231
|
if (this.video) {
|
|
5844
|
-
this.video.addEventListener('timeupdate', () =>
|
|
5845
|
-
this.updateActiveChapter();
|
|
5846
|
-
});
|
|
6232
|
+
this.video.addEventListener('timeupdate', () => this.updateActiveChapter());
|
|
5847
6233
|
}
|
|
5848
6234
|
|
|
5849
|
-
if (this.options.debug)
|
|
6235
|
+
if (this.options.debug) {
|
|
6236
|
+
console.log('Chapter events bound with tooltip');
|
|
6237
|
+
}
|
|
6238
|
+
}
|
|
6239
|
+
|
|
6240
|
+
/**
|
|
6241
|
+
* Update chapter name in title overlay dynamically
|
|
6242
|
+
*/
|
|
6243
|
+
updateChapterInTitleOverlay() {
|
|
6244
|
+
if (!this.video || !this.chapters || this.chapters.length === 0) return;
|
|
6245
|
+
|
|
6246
|
+
const titleOverlay = this.container ? this.container.querySelector('.title-overlay') : null;
|
|
6247
|
+
if (!titleOverlay) return;
|
|
6248
|
+
|
|
6249
|
+
// Find or create chapter name element
|
|
6250
|
+
let chapterElement = titleOverlay.querySelector('.chapter-name');
|
|
6251
|
+
if (!chapterElement) {
|
|
6252
|
+
chapterElement = document.createElement('div');
|
|
6253
|
+
chapterElement.className = 'chapter-name';
|
|
6254
|
+
chapterElement.style.cssText = `
|
|
6255
|
+
font-size: 13px;
|
|
6256
|
+
font-weight: 500;
|
|
6257
|
+
color: rgba(255, 255, 255, 0.9);
|
|
6258
|
+
margin-top: 6px;
|
|
6259
|
+
max-width: 400px;
|
|
6260
|
+
overflow: hidden;
|
|
6261
|
+
text-overflow: ellipsis;
|
|
6262
|
+
white-space: nowrap;
|
|
6263
|
+
`;
|
|
6264
|
+
titleOverlay.appendChild(chapterElement);
|
|
6265
|
+
}
|
|
6266
|
+
|
|
6267
|
+
// Find current chapter
|
|
6268
|
+
const currentTime = this.video.currentTime;
|
|
6269
|
+
let currentChapter = null;
|
|
6270
|
+
for (let i = this.chapters.length - 1; i >= 0; i--) {
|
|
6271
|
+
if (currentTime >= this.chapters[i].time) {
|
|
6272
|
+
currentChapter = this.chapters[i];
|
|
6273
|
+
break;
|
|
6274
|
+
}
|
|
6275
|
+
}
|
|
6276
|
+
|
|
6277
|
+
// Update or hide chapter name
|
|
6278
|
+
if (currentChapter) {
|
|
6279
|
+
chapterElement.textContent = currentChapter.title;
|
|
6280
|
+
chapterElement.style.display = 'block';
|
|
6281
|
+
} else {
|
|
6282
|
+
chapterElement.style.display = 'none';
|
|
6283
|
+
}
|
|
5850
6284
|
}
|
|
5851
6285
|
|
|
5852
6286
|
/**
|
|
@@ -5950,9 +6384,7 @@ jumpToChapter(chapterIndex) {
|
|
|
5950
6384
|
* Update active chapter marker during playback
|
|
5951
6385
|
*/
|
|
5952
6386
|
updateActiveChapter() {
|
|
5953
|
-
if (!this.video || !this.chapterMarkersContainer || !this.chapters)
|
|
5954
|
-
return;
|
|
5955
|
-
}
|
|
6387
|
+
if (!this.video || !this.chapterMarkersContainer || !this.chapters) return;
|
|
5956
6388
|
|
|
5957
6389
|
const currentTime = this.video.currentTime;
|
|
5958
6390
|
const markers = this.chapterMarkersContainer.querySelectorAll('.chapter-marker');
|
|
@@ -5974,6 +6406,9 @@ updateActiveChapter() {
|
|
|
5974
6406
|
marker.classList.remove('active');
|
|
5975
6407
|
}
|
|
5976
6408
|
});
|
|
6409
|
+
|
|
6410
|
+
// Update chapter name in title overlay
|
|
6411
|
+
this.updateChapterInTitleOverlay();
|
|
5977
6412
|
}
|
|
5978
6413
|
|
|
5979
6414
|
/**
|