@gcorevideo/player 2.20.22 → 2.21.3
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/assets/audio-selector/style.scss +48 -82
- package/assets/audio-selector/track-selector.ejs +3 -3
- package/assets/bottom-gear/bottomgear.ejs +10 -12
- package/assets/bottom-gear/gear-sub-menu.scss +0 -15
- package/assets/bottom-gear/gear.scss +3 -32
- package/assets/media-control/media-control.ejs +5 -25
- package/assets/media-control/media-control.scss +114 -34
- package/assets/media-control/width370.scss +35 -109
- package/assets/picture-in-picture/button.ejs +1 -1
- package/assets/picture-in-picture/button.scss +5 -4
- package/assets/subtitles/combobox.ejs +7 -9
- package/assets/subtitles/style.scss +8 -15
- package/dist/core.js +151 -23
- package/dist/index.css +897 -1000
- package/dist/index.js +416 -438
- package/dist/player.d.ts +19 -16
- package/dist/plugins/index.css +1454 -1557
- package/dist/plugins/index.js +826 -23550
- package/docs/api/player.audioselector.md +4 -59
- package/docs/api/player.md +1 -1
- package/docs/api/player.mediacontrol.getelement.md +5 -0
- package/docs/api/player.mediacontrol.md +14 -0
- package/docs/api/{player.audioselector.updatecurrenttrack.md → player.mediacontrol.putelement.md} +7 -7
- package/docs/api/player.mediacontrolelement.md +1 -1
- package/docs/api/{player.audioselector.starttrackswitch.md → player.pictureinpicture.attributes.md} +5 -7
- package/docs/api/player.pictureinpicture.md +45 -0
- package/lib/playback/BasePlayback.d.ts +1 -1
- package/lib/playback/BasePlayback.d.ts.map +1 -1
- package/lib/playback/BasePlayback.js +3 -1
- package/lib/playback/HTML5Video.d.ts +4 -0
- package/lib/playback/HTML5Video.d.ts.map +1 -1
- package/lib/playback/HTML5Video.js +53 -4
- package/lib/playback/dash-playback/DashPlayback.d.ts +5 -0
- package/lib/playback/dash-playback/DashPlayback.d.ts.map +1 -1
- package/lib/playback/dash-playback/DashPlayback.js +48 -4
- package/lib/playback/hls-playback/HlsPlayback.d.ts +31 -25
- package/lib/playback/hls-playback/HlsPlayback.d.ts.map +1 -1
- package/lib/playback/hls-playback/HlsPlayback.js +47 -14
- package/lib/playback.types.d.ts +5 -0
- package/lib/playback.types.d.ts.map +1 -1
- package/lib/plugins/audio-selector/AudioSelector.d.ts +12 -11
- package/lib/plugins/audio-selector/AudioSelector.d.ts.map +1 -1
- package/lib/plugins/audio-selector/AudioSelector.js +65 -185
- package/lib/plugins/bottom-gear/BottomGear.d.ts +2 -2
- package/lib/plugins/bottom-gear/BottomGear.d.ts.map +1 -1
- package/lib/plugins/bottom-gear/BottomGear.js +12 -10
- package/lib/plugins/level-selector/LevelSelector.js +1 -1
- package/lib/plugins/media-control/MediaControl.d.ts +3 -4
- package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
- package/lib/plugins/media-control/MediaControl.js +23 -13
- package/lib/plugins/picture-in-picture/PictureInPicture.d.ts +3 -0
- package/lib/plugins/picture-in-picture/PictureInPicture.d.ts.map +1 -1
- package/lib/plugins/picture-in-picture/PictureInPicture.js +6 -1
- package/lib/plugins/playback-rate/PlaybackRate.d.ts +1 -0
- package/lib/plugins/playback-rate/PlaybackRate.d.ts.map +1 -1
- package/lib/plugins/playback-rate/PlaybackRate.js +1 -0
- package/lib/plugins/source-controller/SourceController.d.ts.map +1 -1
- package/lib/plugins/source-controller/SourceController.js +0 -1
- package/lib/plugins/spinner-three-bounce/SpinnerThreeBounce.d.ts +0 -2
- package/lib/plugins/spinner-three-bounce/SpinnerThreeBounce.d.ts.map +1 -1
- package/lib/plugins/spinner-three-bounce/SpinnerThreeBounce.js +1 -18
- package/lib/plugins/subtitles/Subtitles.d.ts +21 -19
- package/lib/plugins/subtitles/Subtitles.d.ts.map +1 -1
- package/lib/plugins/subtitles/Subtitles.js +121 -151
- package/lib/testUtils.d.ts.map +1 -1
- package/lib/testUtils.js +2 -0
- package/package.json +1 -1
- package/src/playback/BasePlayback.ts +4 -1
- package/src/playback/HTML5Video.ts +57 -4
- package/src/playback/dash-playback/DashPlayback.ts +64 -6
- package/src/playback/hls-playback/HlsPlayback.ts +82 -40
- package/src/playback.types.ts +6 -0
- package/src/plugins/audio-selector/AudioSelector.ts +84 -278
- package/src/plugins/bottom-gear/BottomGear.ts +14 -11
- package/src/plugins/bottom-gear/__tests__/BottomGear.test.ts +1 -3
- package/src/plugins/bottom-gear/__tests__/__snapshots__/BottomGear.test.ts.snap +14 -37
- package/src/plugins/level-selector/LevelSelector.ts +1 -1
- package/src/plugins/media-control/MediaControl.ts +54 -32
- package/src/plugins/picture-in-picture/PictureInPicture.ts +7 -1
- package/src/plugins/playback-rate/PlaybackRate.ts +1 -0
- package/src/plugins/source-controller/SourceController.ts +0 -1
- package/src/plugins/spinner-three-bounce/SpinnerThreeBounce.ts +1 -20
- package/src/plugins/subtitles/Subtitles.ts +144 -179
- package/src/testUtils.ts +2 -0
- package/src/typings/globals.d.ts +19 -0
- package/temp/player.api.json +102 -143
- package/tsconfig.tsbuildinfo +1 -1
- package/assets/media-control/plugins.scss +0 -94
- package/docs/api/player.audioselector.highlightcurrenttrack.md +0 -18
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Events,
|
|
3
|
-
UICorePlugin,
|
|
4
|
-
Browser,
|
|
5
|
-
template,
|
|
6
|
-
$,
|
|
7
|
-
} from '@clappr/core'
|
|
1
|
+
import { Events, UICorePlugin, Browser, template, $ } from '@clappr/core'
|
|
8
2
|
import { reportError, trace } from '@gcorevideo/utils'
|
|
9
3
|
import assert from 'assert'
|
|
10
4
|
|
|
11
5
|
import { CLAPPR_VERSION } from '../../build.js'
|
|
6
|
+
import type { TextTrackItem } from '../../playback.types.js'
|
|
12
7
|
|
|
13
8
|
import '../../../assets/subtitles/style.scss'
|
|
14
9
|
import subtitlesOffIcon from '../../../assets/icons/new/subtitles-off.svg'
|
|
@@ -21,18 +16,17 @@ import type { ZeptoResult } from '../../types.js'
|
|
|
21
16
|
|
|
22
17
|
const VERSION: string = '2.19.14'
|
|
23
18
|
|
|
24
|
-
const LOCAL_STORAGE_SUBTITLES_ID =
|
|
25
|
-
'gplayer.plugins.subtitles.selected'
|
|
19
|
+
const LOCAL_STORAGE_SUBTITLES_ID = 'gplayer.plugins.subtitles.selected'
|
|
26
20
|
|
|
27
21
|
const T = 'plugins.subtitles'
|
|
28
22
|
|
|
29
|
-
type
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
export type SubtitlesPluginSettings = {
|
|
24
|
+
/**
|
|
25
|
+
* Initially selected subtitles language
|
|
26
|
+
*/
|
|
27
|
+
language?: string
|
|
32
28
|
}
|
|
33
29
|
|
|
34
|
-
const NO_TRACK = { language: 'off' }
|
|
35
|
-
|
|
36
30
|
/**
|
|
37
31
|
* `PLUGIN` that provides a UI to select the subtitles when available.
|
|
38
32
|
* @beta
|
|
@@ -42,10 +36,7 @@ const NO_TRACK = { language: 'off' }
|
|
|
42
36
|
*
|
|
43
37
|
* - {@link MediaControl}
|
|
44
38
|
*
|
|
45
|
-
* Configuration options
|
|
46
|
-
*
|
|
47
|
-
* - subtitles.language - The language of the subtitles to select by default.
|
|
48
|
-
*
|
|
39
|
+
* Configuration options - {@link SubtitlesPluginSettings}
|
|
49
40
|
* @example
|
|
50
41
|
* ```ts
|
|
51
42
|
* import { Subtitles } from '@gcorevideo/player'
|
|
@@ -61,15 +52,13 @@ const NO_TRACK = { language: 'off' }
|
|
|
61
52
|
* ```
|
|
62
53
|
*/
|
|
63
54
|
export class Subtitles extends UICorePlugin {
|
|
64
|
-
private currentLevel: TextTrackInfo | null = null
|
|
65
|
-
|
|
66
55
|
private isPreselectedApplied = false
|
|
67
56
|
|
|
68
57
|
private isShowing = false
|
|
69
58
|
|
|
70
|
-
private track:
|
|
59
|
+
private track: TextTrackItem | null = null
|
|
71
60
|
|
|
72
|
-
private tracks:
|
|
61
|
+
private tracks: TextTrackItem[] = []
|
|
73
62
|
|
|
74
63
|
private $string: ZeptoResult | null = null
|
|
75
64
|
|
|
@@ -103,7 +92,7 @@ export class Subtitles extends UICorePlugin {
|
|
|
103
92
|
*/
|
|
104
93
|
override get attributes() {
|
|
105
94
|
return {
|
|
106
|
-
class:
|
|
95
|
+
class: 'media-control-subtitles',
|
|
107
96
|
'data-subtitles': '',
|
|
108
97
|
}
|
|
109
98
|
}
|
|
@@ -113,51 +102,62 @@ export class Subtitles extends UICorePlugin {
|
|
|
113
102
|
*/
|
|
114
103
|
override get events() {
|
|
115
104
|
return {
|
|
116
|
-
'click [data-subtitles-select]': '
|
|
117
|
-
'click [data-subtitles-button]': '
|
|
105
|
+
'click [data-subtitles-select]': 'onItemSelect',
|
|
106
|
+
'click [data-subtitles-button]': 'toggleMenu',
|
|
118
107
|
}
|
|
119
108
|
}
|
|
120
109
|
|
|
121
110
|
private get preselectedLanguage(): string {
|
|
122
|
-
return this.core.options.subtitles?.language ?? '
|
|
111
|
+
return this.core.options.subtitles?.language ?? ''
|
|
123
112
|
}
|
|
124
113
|
|
|
125
114
|
/**
|
|
126
115
|
* @internal
|
|
127
116
|
*/
|
|
128
117
|
override bindEvents() {
|
|
129
|
-
|
|
130
|
-
assert(mediaControl, 'media_control plugin is required')
|
|
118
|
+
this.listenTo(this.core, Events.CORE_READY, this.onCoreReady)
|
|
131
119
|
this.listenTo(this.core, Events.CORE_RESIZE, this.playerResize)
|
|
132
120
|
this.listenTo(
|
|
133
121
|
this.core,
|
|
134
122
|
Events.CORE_ACTIVE_CONTAINER_CHANGED,
|
|
135
|
-
this.
|
|
123
|
+
this.onContainerChanged,
|
|
136
124
|
)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private onCoreReady() {
|
|
128
|
+
trace(`${T} onCoreReady`)
|
|
129
|
+
const mediaControl = this.core.getPlugin('media_control')
|
|
130
|
+
assert(mediaControl, 'media_control plugin is required')
|
|
137
131
|
this.listenTo(mediaControl, Events.MEDIACONTROL_RENDERED, this.render)
|
|
138
132
|
this.listenTo(
|
|
139
133
|
mediaControl,
|
|
140
134
|
Events.MEDIACONTROL_HIDE,
|
|
141
|
-
this.
|
|
135
|
+
this.hideMenu,
|
|
142
136
|
)
|
|
143
137
|
}
|
|
144
138
|
|
|
145
|
-
private
|
|
139
|
+
private onContainerChanged() {
|
|
140
|
+
trace(`${T} onContainerChanged`)
|
|
146
141
|
this.listenTo(
|
|
147
142
|
this.core.activeContainer,
|
|
148
143
|
Events.CONTAINER_FULLSCREEN,
|
|
149
144
|
this.playerResize,
|
|
150
145
|
)
|
|
151
|
-
this.listenToOnce(
|
|
152
|
-
this.core.activePlayback,
|
|
153
|
-
Events.PLAYBACK_PLAY,
|
|
154
|
-
this.getTracks,
|
|
155
|
-
)
|
|
156
146
|
this.listenTo(
|
|
157
147
|
this.core.activeContainer,
|
|
158
148
|
'container:advertisement:start',
|
|
159
149
|
this.onStartAd,
|
|
160
150
|
)
|
|
151
|
+
this.listenTo(
|
|
152
|
+
this.core.activePlayback,
|
|
153
|
+
Events.PLAYBACK_SUBTITLE_AVAILABLE,
|
|
154
|
+
this.onSubtitleAvailable,
|
|
155
|
+
)
|
|
156
|
+
this.listenTo(
|
|
157
|
+
this.core.activePlayback,
|
|
158
|
+
Events.PLAYBACK_SUBTITLE_CHANGED,
|
|
159
|
+
this.onSubtitleChanged,
|
|
160
|
+
)
|
|
161
161
|
|
|
162
162
|
// fix for iOS
|
|
163
163
|
const video = this.core.activePlayback.el
|
|
@@ -176,20 +176,52 @@ export class Subtitles extends UICorePlugin {
|
|
|
176
176
|
})
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
-
private
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
179
|
+
private onSubtitleAvailable() {
|
|
180
|
+
trace(`${T} onSubtitleAvailable`)
|
|
181
|
+
this.applyTracks()
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
private onSubtitleChanged({ id }: { id: number }) {
|
|
185
|
+
trace(`${T} onSubtitleChanged`, { id })
|
|
186
|
+
if (id === -1) {
|
|
187
|
+
this.clearSubtitleText()
|
|
188
|
+
}
|
|
189
|
+
for (const track of this.tracks) {
|
|
190
|
+
if (track.id === id) {
|
|
191
|
+
track.track.mode = 'showing'
|
|
192
|
+
|
|
193
|
+
this.setSubtitleText(this.getSubtitleText(track.track))
|
|
194
|
+
|
|
195
|
+
track.track.oncuechange = (e) => {
|
|
196
|
+
try {
|
|
197
|
+
if (track.track.activeCues?.length) {
|
|
198
|
+
const html = (track.track.activeCues[0] as VTTCue).getCueAsHTML()
|
|
199
|
+
|
|
200
|
+
this.setSubtitleText(html)
|
|
201
|
+
} else {
|
|
202
|
+
this.clearSubtitleText()
|
|
203
|
+
}
|
|
204
|
+
} catch (error) {
|
|
205
|
+
reportError(error)
|
|
206
|
+
}
|
|
186
207
|
}
|
|
187
|
-
}
|
|
188
|
-
|
|
208
|
+
} else {
|
|
209
|
+
track.track.oncuechange = null
|
|
210
|
+
track.track.mode = 'hidden'
|
|
189
211
|
}
|
|
190
212
|
}
|
|
191
213
|
}
|
|
192
214
|
|
|
215
|
+
private applyTracks() {
|
|
216
|
+
try {
|
|
217
|
+
this.tracks = this.core.activePlayback.closedCaptionsTracks
|
|
218
|
+
this.applyPreselectedSubtitles()
|
|
219
|
+
this.render()
|
|
220
|
+
} catch (error) {
|
|
221
|
+
reportError(error)
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
193
225
|
private onStartAd() {
|
|
194
226
|
if (this.isShowing && this.core.activeContainer) {
|
|
195
227
|
this.hide()
|
|
@@ -211,11 +243,12 @@ export class Subtitles extends UICorePlugin {
|
|
|
211
243
|
}
|
|
212
244
|
|
|
213
245
|
private playerResize() {
|
|
246
|
+
trace(`${T} playerResize`)
|
|
214
247
|
const shouldShow =
|
|
215
248
|
this.core.activeContainer &&
|
|
216
249
|
isFullscreen(this.core.activeContainer.el) &&
|
|
217
|
-
this.
|
|
218
|
-
this.
|
|
250
|
+
this.track &&
|
|
251
|
+
this.track.track.mode &&
|
|
219
252
|
Browser.isiOS &&
|
|
220
253
|
this.isShowing
|
|
221
254
|
|
|
@@ -239,7 +272,7 @@ export class Subtitles extends UICorePlugin {
|
|
|
239
272
|
this.$string.hide()
|
|
240
273
|
if (this.tracks) {
|
|
241
274
|
for (const t of this.tracks) {
|
|
242
|
-
t.mode = 'hidden'
|
|
275
|
+
t.track.mode = 'hidden'
|
|
243
276
|
}
|
|
244
277
|
}
|
|
245
278
|
}
|
|
@@ -253,26 +286,22 @@ export class Subtitles extends UICorePlugin {
|
|
|
253
286
|
if (
|
|
254
287
|
this.core.activeContainer &&
|
|
255
288
|
isFullscreen(this.core.activeContainer.el) &&
|
|
256
|
-
this.
|
|
257
|
-
this.
|
|
289
|
+
this.track &&
|
|
290
|
+
this.track.track.mode &&
|
|
258
291
|
Browser.isiOS
|
|
259
292
|
) {
|
|
260
293
|
this.$string.hide()
|
|
261
|
-
this.
|
|
294
|
+
this.track.track.mode = 'showing'
|
|
262
295
|
} else {
|
|
263
296
|
this.$string.show()
|
|
264
297
|
}
|
|
265
298
|
}
|
|
266
299
|
|
|
267
300
|
private shouldRender() {
|
|
268
|
-
return
|
|
301
|
+
return this.tracks.length > 0
|
|
269
302
|
}
|
|
270
303
|
|
|
271
304
|
private resizeFont() {
|
|
272
|
-
if (!this.core.activeContainer) {
|
|
273
|
-
return
|
|
274
|
-
}
|
|
275
|
-
|
|
276
305
|
if (!this.$string) {
|
|
277
306
|
return
|
|
278
307
|
}
|
|
@@ -294,71 +323,42 @@ export class Subtitles extends UICorePlugin {
|
|
|
294
323
|
return this
|
|
295
324
|
}
|
|
296
325
|
|
|
297
|
-
trace(`${T} render`, {
|
|
298
|
-
tracks: this.tracks?.length,
|
|
299
|
-
track: this.track?.language,
|
|
300
|
-
})
|
|
301
|
-
|
|
302
326
|
const mediaControl = this.core.getPlugin('media_control')
|
|
303
|
-
assert(mediaControl, 'media_control plugin is required')
|
|
304
327
|
|
|
305
328
|
this.$el.html(Subtitles.template({ tracks: this.tracks }))
|
|
306
329
|
this.core.activeContainer.$el.find('.subtitle-string').remove()
|
|
307
330
|
this.$string = $(Subtitles.templateString())
|
|
308
331
|
this.resizeFont()
|
|
309
332
|
|
|
310
|
-
this.core.activeContainer.$el.append(this.$string
|
|
311
|
-
|
|
312
|
-
if (ss && ss.length > 0) {
|
|
313
|
-
ss.append(this.el)
|
|
314
|
-
} else {
|
|
315
|
-
mediaControl.getRightPanel().append(this.el)
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
this.updateCurrentLevel(this.track)
|
|
319
|
-
this.highlightCurrentSubtitles()
|
|
333
|
+
this.core.activeContainer.$el.append(this.$string)
|
|
334
|
+
mediaControl.putElement('subtitlesSelector', this.$el)
|
|
320
335
|
|
|
321
|
-
this.
|
|
336
|
+
this.updateSelection()
|
|
322
337
|
|
|
323
338
|
this.renderIcon()
|
|
324
339
|
|
|
325
340
|
return this
|
|
326
341
|
}
|
|
327
342
|
|
|
328
|
-
private
|
|
329
|
-
this.tracks
|
|
330
|
-
this.render()
|
|
343
|
+
private findById(id: number) {
|
|
344
|
+
return this.tracks.find((track) => track.id === id) ?? null
|
|
331
345
|
}
|
|
332
346
|
|
|
333
|
-
private
|
|
334
|
-
if (this.tracks) {
|
|
335
|
-
for (const track of this.tracks) {
|
|
336
|
-
if (track.language === id) {
|
|
337
|
-
return track // TODO TrackInfo?
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
private selectLevel(id: string) {
|
|
347
|
+
private selectItem(item: TextTrackItem | null) {
|
|
344
348
|
this.clearSubtitleText()
|
|
345
|
-
this.track =
|
|
346
|
-
|
|
347
|
-
this.hideSelectLevelMenu()
|
|
348
|
-
if (!this.track) {
|
|
349
|
-
this.track = { language: 'off' }
|
|
350
|
-
}
|
|
349
|
+
this.track = item
|
|
351
350
|
|
|
352
|
-
this.
|
|
351
|
+
this.hideMenu()
|
|
352
|
+
this.updateSelection()
|
|
353
353
|
}
|
|
354
354
|
|
|
355
|
-
private
|
|
356
|
-
const id = (event.target as HTMLElement).dataset.subtitlesSelect
|
|
355
|
+
private onItemSelect(event: MouseEvent) {
|
|
356
|
+
const id = (event.target as HTMLElement).dataset.subtitlesSelect ?? '-1'
|
|
357
357
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
358
|
+
trace(`${T} onItemSelect`, { id })
|
|
359
|
+
|
|
360
|
+
localStorage.setItem(LOCAL_STORAGE_SUBTITLES_ID, id)
|
|
361
|
+
this.selectItem(this.findById(Number(id)))
|
|
362
362
|
|
|
363
363
|
return false
|
|
364
364
|
}
|
|
@@ -366,91 +366,57 @@ export class Subtitles extends UICorePlugin {
|
|
|
366
366
|
private applyPreselectedSubtitles() {
|
|
367
367
|
if (!this.isPreselectedApplied) {
|
|
368
368
|
this.isPreselectedApplied = true
|
|
369
|
+
if (!this.preselectedLanguage) {
|
|
370
|
+
return
|
|
371
|
+
}
|
|
369
372
|
setTimeout(() => {
|
|
370
|
-
this.
|
|
371
|
-
|
|
373
|
+
this.selectItem(
|
|
374
|
+
this.tracks.find(
|
|
375
|
+
(t) => t.track.language === this.preselectedLanguage,
|
|
376
|
+
) ?? null,
|
|
377
|
+
)
|
|
378
|
+
}, 300) // TODO why delay?
|
|
372
379
|
}
|
|
373
380
|
}
|
|
374
381
|
|
|
375
|
-
private
|
|
376
|
-
trace(`${T} onShowLevelSelectMenu`)
|
|
377
|
-
this.toggleContextMenu()
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
private hideSelectLevelMenu() {
|
|
382
|
+
private hideMenu() {
|
|
381
383
|
;(this.$('[data-subtitles] ul') as ZeptoResult).hide()
|
|
382
384
|
}
|
|
383
385
|
|
|
384
|
-
private
|
|
385
|
-
(this.$('[data-subtitles] ul') as ZeptoResult).toggle()
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
private buttonElement(): ZeptoResult {
|
|
389
|
-
return this.$('[data-subtitles] button')
|
|
386
|
+
private toggleMenu() {
|
|
387
|
+
;(this.$('[data-subtitles] ul') as ZeptoResult).toggle()
|
|
390
388
|
}
|
|
391
389
|
|
|
392
|
-
private
|
|
390
|
+
private itemElement(id: number): ZeptoResult {
|
|
393
391
|
return (
|
|
394
|
-
this.$(
|
|
395
|
-
'[data-subtitles] ul a' + (id ? '[data-subtitles-select="' + id + '"]' : ''),
|
|
396
|
-
) as ZeptoResult
|
|
392
|
+
this.$(`ul li a[data-subtitles-select="${id}"]`) as ZeptoResult
|
|
397
393
|
).parent()
|
|
398
394
|
}
|
|
399
395
|
|
|
400
|
-
private
|
|
401
|
-
this
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
private stopLevelSwitch() {
|
|
405
|
-
this.buttonElement().removeClass('changing')
|
|
396
|
+
private allItemElements(): ZeptoResult {
|
|
397
|
+
return this.$('[data-subtitles] li')
|
|
406
398
|
}
|
|
407
399
|
|
|
408
400
|
private selectSubtitles() {
|
|
409
|
-
|
|
410
|
-
return
|
|
411
|
-
}
|
|
401
|
+
const trackId = this.track ? this.track.id : -1
|
|
412
402
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
const track = this.tracks[i]
|
|
416
|
-
if (track.language === this.currentLevel.language) {
|
|
417
|
-
track.mode = 'showing'
|
|
418
|
-
|
|
419
|
-
const currentTime = this.core.activePlayback?.getCurrentTime() ?? 0
|
|
420
|
-
const cues = track.cues
|
|
421
|
-
let subtitleText = ''
|
|
422
|
-
|
|
423
|
-
if (cues && cues.length) {
|
|
424
|
-
for (const cue of cues) {
|
|
425
|
-
if (currentTime >= cue.startTime && currentTime <= cue.endTime) {
|
|
426
|
-
subtitleText +=
|
|
427
|
-
(cue as VTTCue).getCueAsHTML().textContent + '\n'
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
this.setSubtitleText(subtitleText)
|
|
403
|
+
this.core.activePlayback.closedCaptionsTrackId = trackId
|
|
404
|
+
}
|
|
433
405
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
406
|
+
private getSubtitleText(track: TextTrack) {
|
|
407
|
+
const currentTime = this.core.activePlayback?.getCurrentTime() ?? 0
|
|
408
|
+
const cues = track.cues
|
|
409
|
+
const lines = []
|
|
438
410
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
} catch (error) {
|
|
444
|
-
// console.error(error);
|
|
445
|
-
reportError(error)
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
continue
|
|
411
|
+
if (cues && cues.length) {
|
|
412
|
+
for (const cue of cues) {
|
|
413
|
+
if (currentTime >= cue.startTime && currentTime <= cue.endTime) {
|
|
414
|
+
lines.push((cue as VTTCue).getCueAsHTML().textContent)
|
|
449
415
|
}
|
|
450
|
-
this.tracks[i].oncuechange = null
|
|
451
|
-
this.tracks[i].mode = 'hidden'
|
|
452
416
|
}
|
|
453
417
|
}
|
|
418
|
+
|
|
419
|
+
return lines.join('\n')
|
|
454
420
|
}
|
|
455
421
|
|
|
456
422
|
private setSubtitleText(text: string | DocumentFragment) {
|
|
@@ -461,9 +427,8 @@ export class Subtitles extends UICorePlugin {
|
|
|
461
427
|
this.setSubtitleText('')
|
|
462
428
|
}
|
|
463
429
|
|
|
464
|
-
private
|
|
465
|
-
this.
|
|
466
|
-
if (track.language === 'off') {
|
|
430
|
+
private updateSelection() {
|
|
431
|
+
if (!this.track) {
|
|
467
432
|
this.hide()
|
|
468
433
|
} else {
|
|
469
434
|
this.show()
|
|
@@ -473,24 +438,24 @@ export class Subtitles extends UICorePlugin {
|
|
|
473
438
|
}
|
|
474
439
|
|
|
475
440
|
private highlightCurrentSubtitles() {
|
|
476
|
-
this.
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
const currentLevelElement = this.levelElement(this.currentLevel.language)
|
|
441
|
+
this.allItemElements()
|
|
442
|
+
.removeClass('current')
|
|
443
|
+
.find('a')
|
|
444
|
+
.removeClass('gcore-skin-active')
|
|
481
445
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
}
|
|
446
|
+
trace(`${T} highlightCurrentSubtitles`, {
|
|
447
|
+
track: this.track?.id,
|
|
448
|
+
})
|
|
449
|
+
const currentLevelElement = this.itemElement(this.track ? this.track.id : -1)
|
|
450
|
+
currentLevelElement
|
|
451
|
+
.addClass('current')
|
|
452
|
+
.find('a')
|
|
453
|
+
.addClass('gcore-skin-active')
|
|
485
454
|
}
|
|
486
455
|
|
|
487
456
|
private renderIcon() {
|
|
488
457
|
const icon = this.isShowing ? subtitlesOnIcon : subtitlesOffIcon
|
|
489
458
|
|
|
490
|
-
this.
|
|
491
|
-
.getPlugin('media_control')
|
|
492
|
-
.getElement('subtitlesSelector')
|
|
493
|
-
?.find('span.subtitle-text')
|
|
494
|
-
.html(icon)
|
|
459
|
+
this.$el.find('span.subtitle-text').html(icon)
|
|
495
460
|
}
|
|
496
461
|
}
|
package/src/testUtils.ts
CHANGED
|
@@ -199,6 +199,8 @@ export function createMockMediaControl(core: any) {
|
|
|
199
199
|
// @ts-ignore
|
|
200
200
|
mediaControl.getElement = vi.fn().mockImplementation((name) => elements[name])
|
|
201
201
|
// @ts-ignore
|
|
202
|
+
mediaControl.putElement = vi.fn()
|
|
203
|
+
// @ts-ignore
|
|
202
204
|
mediaControl.getLeftPanel = vi.fn().mockImplementation(() => mediaControl.$el.find('.media-control-left-panel'))
|
|
203
205
|
// @ts-ignore
|
|
204
206
|
mediaControl.getRightPanel = vi.fn().mockImplementation(() => mediaControl.$el.find('.media-control-right-panel'))
|
package/src/typings/globals.d.ts
CHANGED
|
@@ -2,6 +2,25 @@ declare interface HTMLVideoElement {
|
|
|
2
2
|
webkitDisplayingFullscreen?: boolean;
|
|
3
3
|
}
|
|
4
4
|
|
|
5
|
+
declare interface HTMLMediaElement {
|
|
6
|
+
audioTracks?: AudioTrackList;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
declare interface AudioTrackW3C {
|
|
10
|
+
readonly id: string;
|
|
11
|
+
enabled: boolean;
|
|
12
|
+
readonly kind: string;
|
|
13
|
+
readonly label: string;
|
|
14
|
+
readonly language: string;
|
|
15
|
+
readonly sourceBuffer: SourceBuffer | null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
declare interface AudioTrackList {
|
|
19
|
+
getTrackById(id: string): AudioTrackW3C | null;
|
|
20
|
+
length: number;
|
|
21
|
+
[index: number]: AudioTrackW3C;
|
|
22
|
+
}
|
|
23
|
+
|
|
5
24
|
declare module "*.css";
|
|
6
25
|
declare module "*.scss";
|
|
7
26
|
declare module "*.svg";
|