@gcorevideo/player 2.21.1 → 2.21.4
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 +1 -1
- package/assets/audio-selector/track-selector.ejs +3 -3
- package/assets/bottom-gear/bottomgear.ejs +2 -2
- package/assets/media-control/container.scss +1 -1
- package/assets/media-control/media-control.ejs +1 -11
- package/assets/media-control/media-control.scss +49 -57
- package/assets/media-control/width270.scss +1 -1
- package/assets/media-control/width370.scss +7 -9
- package/assets/playback-rate/button.ejs +2 -2
- package/assets/playback-rate/list.ejs +4 -4
- package/assets/subtitles/combobox.ejs +10 -12
- package/assets/subtitles/string.ejs +1 -1
- package/assets/subtitles/style.scss +9 -16
- package/dist/core.js +5 -1
- package/dist/index.css +782 -794
- package/dist/index.js +240 -244
- package/dist/player.d.ts +141 -119
- package/dist/plugins/index.css +862 -874
- package/dist/plugins/index.js +222 -238
- package/docs/api/player.bottomgear.getelement.md +2 -2
- package/docs/api/player.bottomgear.md +1 -1
- package/docs/api/{player.subtitles.hide.md → player.closedcaptions.hide.md} +2 -2
- package/docs/api/{player.subtitles.md → player.closedcaptions.md} +11 -11
- package/docs/api/{player.subtitles.show.md → player.closedcaptions.show.md} +2 -2
- package/docs/api/player.closedcaptionspluginsettings.md +13 -0
- package/docs/api/player.gearitemelement.md +6 -4
- package/docs/api/player.gearoptionsitem.md +16 -0
- package/docs/api/player.md +48 -12
- package/docs/api/player.mediacontrol.putelement.md +2 -2
- package/docs/api/player.mediacontrolelement.md +1 -1
- package/docs/api/player.playbackrate.md +1 -1
- package/docs/api/player.subtitlespluginsettings.md +18 -0
- package/docs/api/player.texttrackitem.id.md +11 -0
- package/docs/api/player.texttrackitem.md +87 -0
- package/docs/api/player.texttrackitem.name.md +11 -0
- package/docs/api/player.texttrackitem.track.md +11 -0
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/index.plugins.d.ts +2 -1
- package/lib/index.plugins.d.ts.map +1 -1
- package/lib/index.plugins.js +2 -1
- package/lib/playback/BasePlayback.d.ts +1 -0
- package/lib/playback/BasePlayback.d.ts.map +1 -1
- package/lib/playback/BasePlayback.js +3 -0
- package/lib/playback/dash-playback/DashPlayback.d.ts.map +1 -1
- package/lib/playback/dash-playback/DashPlayback.js +1 -0
- 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 +2 -3
- package/lib/plugins/audio-selector/AudioSelector.d.ts.map +1 -1
- package/lib/plugins/audio-selector/AudioSelector.js +6 -7
- package/lib/plugins/bottom-gear/BottomGear.d.ts +7 -3
- package/lib/plugins/bottom-gear/BottomGear.d.ts.map +1 -1
- package/lib/plugins/bottom-gear/BottomGear.js +4 -2
- package/lib/plugins/media-control/MediaControl.d.ts +5 -6
- package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
- package/lib/plugins/media-control/MediaControl.js +48 -39
- package/lib/plugins/picture-in-picture/PictureInPicture.d.ts +1 -0
- package/lib/plugins/picture-in-picture/PictureInPicture.d.ts.map +1 -1
- package/lib/plugins/picture-in-picture/PictureInPicture.js +4 -4
- package/lib/plugins/playback-rate/PlaybackRate.d.ts +1 -1
- package/lib/plugins/playback-rate/PlaybackRate.d.ts.map +1 -1
- package/lib/plugins/playback-rate/PlaybackRate.js +24 -14
- package/lib/plugins/subtitles/ClosedCaptions.d.ts +118 -0
- package/lib/plugins/subtitles/ClosedCaptions.d.ts.map +1 -0
- package/lib/plugins/subtitles/ClosedCaptions.js +348 -0
- package/lib/plugins/subtitles/Subtitles.d.ts +31 -26
- package/lib/plugins/subtitles/Subtitles.d.ts.map +1 -1
- package/lib/plugins/subtitles/Subtitles.js +138 -169
- package/lib/testUtils.d.ts +22 -18
- package/lib/testUtils.d.ts.map +1 -1
- package/lib/testUtils.js +22 -36
- package/package.json +1 -1
- package/src/index.plugins.ts +2 -1
- package/src/index.ts +1 -1
- package/src/playback/BasePlayback.ts +4 -0
- package/src/playback/dash-playback/DashPlayback.ts +1 -0
- package/src/playback.types.ts +6 -0
- package/src/plugins/audio-selector/AudioSelector.ts +9 -8
- package/src/plugins/bottom-gear/BottomGear.ts +14 -5
- package/src/plugins/bottom-gear/__tests__/BottomGear.test.ts +1 -1
- package/src/plugins/bottom-gear/__tests__/__snapshots__/BottomGear.test.ts.snap +2 -2
- package/src/plugins/media-control/MediaControl.ts +84 -60
- package/src/plugins/media-control/__tests__/MediaControl.test.ts +43 -0
- package/src/plugins/media-control/__tests__/__snapshots__/MediaControl.test.ts.snap +175 -0
- package/src/plugins/picture-in-picture/PictureInPicture.ts +5 -5
- package/src/plugins/playback-rate/PlaybackRate.ts +143 -100
- package/src/plugins/playback-rate/__tests__/PlaybackRate.test.ts +65 -0
- package/src/plugins/playback-rate/__tests__/__snapshots__/PlaybackRate.test.ts.snap +11 -0
- package/src/plugins/subtitles/ClosedCaptions.ts +469 -0
- package/src/plugins/subtitles/__tests__/ClosedCaptions.test.ts +58 -0
- package/src/plugins/subtitles/__tests__/__snapshots__/ClosedCaptions.test.ts.snap +25 -0
- package/src/testUtils.ts +22 -36
- package/temp/player.api.json +269 -89
- package/tsconfig.tsbuildinfo +1 -1
- package/src/plugins/index.ts +0 -39
- package/src/plugins/subtitles/Subtitles.ts +0 -496
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Events, UICorePlugin, Browser, template,
|
|
1
|
+
import { Events, UICorePlugin, Browser, template, $ } from '@clappr/core';
|
|
2
2
|
import { reportError, trace } from '@gcorevideo/utils';
|
|
3
3
|
import assert from 'assert';
|
|
4
4
|
import { CLAPPR_VERSION } from '../../build.js';
|
|
@@ -9,9 +9,8 @@ import comboboxHTML from '../../../assets/subtitles/combobox.ejs';
|
|
|
9
9
|
import stringHTML from '../../../assets/subtitles/string.ejs';
|
|
10
10
|
import { isFullscreen } from '../utils.js';
|
|
11
11
|
const VERSION = '2.19.14';
|
|
12
|
-
const
|
|
13
|
-
const T = 'plugins.
|
|
14
|
-
const NO_TRACK = { language: 'off' };
|
|
12
|
+
const LOCAL_STORAGE_CC_ID = 'gplayer.plugins.cc.selected';
|
|
13
|
+
const T = 'plugins.cc';
|
|
15
14
|
/**
|
|
16
15
|
* `PLUGIN` that provides a UI to select the subtitles when available.
|
|
17
16
|
* @beta
|
|
@@ -21,36 +20,32 @@ const NO_TRACK = { language: 'off' };
|
|
|
21
20
|
*
|
|
22
21
|
* - {@link MediaControl}
|
|
23
22
|
*
|
|
24
|
-
* Configuration options
|
|
25
|
-
*
|
|
26
|
-
* - subtitles.language - The language of the subtitles to select by default.
|
|
27
|
-
*
|
|
23
|
+
* Configuration options - {@link ClosedCaptionsPluginSettings}
|
|
28
24
|
* @example
|
|
29
25
|
* ```ts
|
|
30
|
-
* import {
|
|
26
|
+
* import { ClosedCaptions } from '@gcorevideo/player'
|
|
31
27
|
*
|
|
32
|
-
* Player.registerPlugin(
|
|
28
|
+
* Player.registerPlugin(ClosedCaptions)
|
|
33
29
|
*
|
|
34
30
|
* new Player({
|
|
35
31
|
* ...
|
|
36
|
-
*
|
|
32
|
+
* cc: {
|
|
37
33
|
* language: 'en',
|
|
38
34
|
* },
|
|
39
35
|
* })
|
|
40
36
|
* ```
|
|
41
37
|
*/
|
|
42
38
|
export class Subtitles extends UICorePlugin {
|
|
43
|
-
currentLevel = null;
|
|
44
39
|
isPreselectedApplied = false;
|
|
45
40
|
isShowing = false;
|
|
46
|
-
track =
|
|
47
|
-
tracks =
|
|
48
|
-
$
|
|
41
|
+
track = null;
|
|
42
|
+
tracks = [];
|
|
43
|
+
$line = null;
|
|
49
44
|
/**
|
|
50
45
|
* @internal
|
|
51
46
|
*/
|
|
52
47
|
get name() {
|
|
53
|
-
return 'subtitles';
|
|
48
|
+
return 'subtitles'; // TODO rename to 'cc'
|
|
54
49
|
}
|
|
55
50
|
/**
|
|
56
51
|
* @internal
|
|
@@ -71,8 +66,7 @@ export class Subtitles extends UICorePlugin {
|
|
|
71
66
|
*/
|
|
72
67
|
get attributes() {
|
|
73
68
|
return {
|
|
74
|
-
class:
|
|
75
|
-
'data-subtitles': '',
|
|
69
|
+
class: 'media-control-cc',
|
|
76
70
|
};
|
|
77
71
|
}
|
|
78
72
|
/**
|
|
@@ -80,28 +74,34 @@ export class Subtitles extends UICorePlugin {
|
|
|
80
74
|
*/
|
|
81
75
|
get events() {
|
|
82
76
|
return {
|
|
83
|
-
'click [data-
|
|
84
|
-
'click [data-
|
|
77
|
+
'click [data-cc-select]': 'onItemSelect',
|
|
78
|
+
'click [data-cc-button]': 'toggleMenu',
|
|
85
79
|
};
|
|
86
80
|
}
|
|
87
81
|
get preselectedLanguage() {
|
|
88
|
-
return this.core.options.subtitles?.language ?? '
|
|
82
|
+
return this.core.options.cc?.language ?? this.core.options.subtitles?.language ?? '';
|
|
89
83
|
}
|
|
90
84
|
/**
|
|
91
85
|
* @internal
|
|
92
86
|
*/
|
|
93
87
|
bindEvents() {
|
|
88
|
+
this.listenTo(this.core, Events.CORE_READY, this.onCoreReady);
|
|
89
|
+
this.listenTo(this.core, Events.CORE_RESIZE, this.playerResize);
|
|
90
|
+
this.listenTo(this.core, Events.CORE_ACTIVE_CONTAINER_CHANGED, this.onContainerChanged);
|
|
91
|
+
}
|
|
92
|
+
onCoreReady() {
|
|
93
|
+
trace(`${T} onCoreReady`);
|
|
94
94
|
const mediaControl = this.core.getPlugin('media_control');
|
|
95
95
|
assert(mediaControl, 'media_control plugin is required');
|
|
96
|
-
this.listenTo(this.core, Events.CORE_RESIZE, this.playerResize);
|
|
97
|
-
this.listenTo(this.core, Events.CORE_ACTIVE_CONTAINER_CHANGED, this.bindPlaybackEvents);
|
|
98
96
|
this.listenTo(mediaControl, Events.MEDIACONTROL_RENDERED, this.render);
|
|
99
|
-
this.listenTo(mediaControl, Events.MEDIACONTROL_HIDE, this.
|
|
97
|
+
this.listenTo(mediaControl, Events.MEDIACONTROL_HIDE, this.hideMenu);
|
|
100
98
|
}
|
|
101
|
-
|
|
99
|
+
onContainerChanged() {
|
|
100
|
+
trace(`${T} onContainerChanged`);
|
|
102
101
|
this.listenTo(this.core.activeContainer, Events.CONTAINER_FULLSCREEN, this.playerResize);
|
|
103
|
-
this.listenToOnce(this.core.activePlayback, Events.PLAYBACK_PLAY, this.getTracks);
|
|
104
102
|
this.listenTo(this.core.activeContainer, 'container:advertisement:start', this.onStartAd);
|
|
103
|
+
this.listenTo(this.core.activePlayback, Events.PLAYBACK_SUBTITLE_AVAILABLE, this.onSubtitleAvailable);
|
|
104
|
+
this.listenTo(this.core.activePlayback, Events.PLAYBACK_SUBTITLE_CHANGED, this.onSubtitleChanged);
|
|
105
105
|
// fix for iOS
|
|
106
106
|
const video = this.core.activePlayback.el;
|
|
107
107
|
assert(video, 'video element is required');
|
|
@@ -116,20 +116,50 @@ export class Subtitles extends UICorePlugin {
|
|
|
116
116
|
}
|
|
117
117
|
});
|
|
118
118
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
119
|
+
onSubtitleAvailable() {
|
|
120
|
+
trace(`${T} onSubtitleAvailable`);
|
|
121
|
+
this.applyTracks();
|
|
122
|
+
}
|
|
123
|
+
onSubtitleChanged({ id }) {
|
|
124
|
+
trace(`${T} onSubtitleChanged`, { id });
|
|
125
|
+
if (id === -1) {
|
|
126
|
+
this.clearSubtitleText();
|
|
127
|
+
}
|
|
128
|
+
for (const track of this.tracks) {
|
|
129
|
+
if (track.id === id) {
|
|
130
|
+
track.track.mode = 'showing';
|
|
131
|
+
this.setSubtitleText(this.getSubtitleText(track.track));
|
|
132
|
+
track.track.oncuechange = (e) => {
|
|
133
|
+
try {
|
|
134
|
+
if (track.track.activeCues?.length) {
|
|
135
|
+
const html = track.track.activeCues[0].getCueAsHTML();
|
|
136
|
+
this.setSubtitleText(html);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
this.clearSubtitleText();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
reportError(error);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
127
146
|
}
|
|
128
|
-
|
|
129
|
-
|
|
147
|
+
else {
|
|
148
|
+
track.track.oncuechange = null;
|
|
149
|
+
track.track.mode = 'hidden';
|
|
130
150
|
}
|
|
131
151
|
}
|
|
132
152
|
}
|
|
153
|
+
applyTracks() {
|
|
154
|
+
try {
|
|
155
|
+
this.tracks = this.core.activePlayback.closedCaptionsTracks;
|
|
156
|
+
this.applyPreselectedSubtitles();
|
|
157
|
+
this.render();
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
reportError(error);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
133
163
|
onStartAd() {
|
|
134
164
|
if (this.isShowing && this.core.activeContainer) {
|
|
135
165
|
this.hide();
|
|
@@ -141,10 +171,11 @@ export class Subtitles extends UICorePlugin {
|
|
|
141
171
|
this.stopListening(this.core.activeContainer, 'container:advertisement:finish', this.onFinishAd);
|
|
142
172
|
}
|
|
143
173
|
playerResize() {
|
|
174
|
+
trace(`${T} playerResize`);
|
|
144
175
|
const shouldShow = this.core.activeContainer &&
|
|
145
176
|
isFullscreen(this.core.activeContainer.el) &&
|
|
146
|
-
this.
|
|
147
|
-
this.
|
|
177
|
+
this.track &&
|
|
178
|
+
this.track.track.mode &&
|
|
148
179
|
Browser.isiOS &&
|
|
149
180
|
this.isShowing;
|
|
150
181
|
if (shouldShow) {
|
|
@@ -163,10 +194,10 @@ export class Subtitles extends UICorePlugin {
|
|
|
163
194
|
hide() {
|
|
164
195
|
this.isShowing = false;
|
|
165
196
|
this.renderIcon();
|
|
166
|
-
this.$
|
|
197
|
+
this.$line.hide();
|
|
167
198
|
if (this.tracks) {
|
|
168
199
|
for (const t of this.tracks) {
|
|
169
|
-
t.mode = 'hidden';
|
|
200
|
+
t.track.mode = 'hidden';
|
|
170
201
|
}
|
|
171
202
|
}
|
|
172
203
|
}
|
|
@@ -178,28 +209,25 @@ export class Subtitles extends UICorePlugin {
|
|
|
178
209
|
this.renderIcon();
|
|
179
210
|
if (this.core.activeContainer &&
|
|
180
211
|
isFullscreen(this.core.activeContainer.el) &&
|
|
181
|
-
this.
|
|
182
|
-
this.
|
|
212
|
+
this.track &&
|
|
213
|
+
this.track.track.mode &&
|
|
183
214
|
Browser.isiOS) {
|
|
184
|
-
this.$
|
|
185
|
-
this.
|
|
215
|
+
this.$line.hide();
|
|
216
|
+
this.track.track.mode = 'showing';
|
|
186
217
|
}
|
|
187
218
|
else {
|
|
188
|
-
this.$
|
|
219
|
+
this.$line.show();
|
|
189
220
|
}
|
|
190
221
|
}
|
|
191
222
|
shouldRender() {
|
|
192
|
-
return
|
|
223
|
+
return this.tracks?.length > 0;
|
|
193
224
|
}
|
|
194
225
|
resizeFont() {
|
|
195
|
-
if (!this
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
if (!this.$string) {
|
|
226
|
+
if (!this.$line) {
|
|
199
227
|
return;
|
|
200
228
|
}
|
|
201
229
|
const skinWidth = this.core.activeContainer.$el.width();
|
|
202
|
-
this.$
|
|
230
|
+
this.$line.find('p').css('font-size', skinWidth * 0.03);
|
|
203
231
|
}
|
|
204
232
|
/**
|
|
205
233
|
* @internal
|
|
@@ -211,143 +239,83 @@ export class Subtitles extends UICorePlugin {
|
|
|
211
239
|
if (!this.shouldRender()) {
|
|
212
240
|
return this;
|
|
213
241
|
}
|
|
214
|
-
trace(`${T} render`, {
|
|
215
|
-
tracks: this.tracks?.length,
|
|
216
|
-
track: this.track?.language,
|
|
217
|
-
});
|
|
218
242
|
const mediaControl = this.core.getPlugin('media_control');
|
|
219
|
-
assert(mediaControl, 'media_control plugin is required');
|
|
220
243
|
this.$el.html(Subtitles.template({ tracks: this.tracks }));
|
|
221
|
-
this.core.activeContainer.$el.find('
|
|
222
|
-
this.$
|
|
244
|
+
this.core.activeContainer.$el.find('#cc-line').remove();
|
|
245
|
+
this.$line = $(Subtitles.templateString());
|
|
223
246
|
this.resizeFont();
|
|
224
|
-
this.core.activeContainer.$el.append(this.$
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
ss.append(this.el);
|
|
228
|
-
}
|
|
229
|
-
else {
|
|
230
|
-
mediaControl.getRightPanel().append(this.el);
|
|
231
|
-
}
|
|
232
|
-
this.updateCurrentLevel(this.track);
|
|
233
|
-
this.highlightCurrentSubtitles();
|
|
234
|
-
this.applyPreselectedSubtitles();
|
|
247
|
+
this.core.activeContainer.$el.append(this.$line);
|
|
248
|
+
mediaControl.putElement('cc', this.el);
|
|
249
|
+
this.updateSelection();
|
|
235
250
|
this.renderIcon();
|
|
236
251
|
return this;
|
|
237
252
|
}
|
|
238
|
-
|
|
239
|
-
this.tracks
|
|
240
|
-
this.render();
|
|
241
|
-
}
|
|
242
|
-
findLevelBy(id) {
|
|
243
|
-
if (this.tracks) {
|
|
244
|
-
for (const track of this.tracks) {
|
|
245
|
-
if (track.language === id) {
|
|
246
|
-
return track; // TODO TrackInfo?
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
253
|
+
findById(id) {
|
|
254
|
+
return this.tracks.find((track) => track.id === id) ?? null;
|
|
250
255
|
}
|
|
251
|
-
|
|
256
|
+
selectItem(item) {
|
|
252
257
|
this.clearSubtitleText();
|
|
253
|
-
this.track =
|
|
254
|
-
this.
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
if (id) {
|
|
263
|
-
localStorage.setItem(LOCAL_STORAGE_SUBTITLES_ID, id);
|
|
264
|
-
this.selectLevel(id);
|
|
265
|
-
}
|
|
258
|
+
this.track = item;
|
|
259
|
+
this.hideMenu();
|
|
260
|
+
this.updateSelection();
|
|
261
|
+
}
|
|
262
|
+
onItemSelect(event) {
|
|
263
|
+
const id = event.target.dataset.ccSelect ?? '-1';
|
|
264
|
+
trace(`${T} onItemSelect`, { id });
|
|
265
|
+
localStorage.setItem(LOCAL_STORAGE_CC_ID, id);
|
|
266
|
+
this.selectItem(this.findById(Number(id)));
|
|
266
267
|
return false;
|
|
267
268
|
}
|
|
268
269
|
applyPreselectedSubtitles() {
|
|
269
270
|
if (!this.isPreselectedApplied) {
|
|
270
271
|
this.isPreselectedApplied = true;
|
|
272
|
+
if (!this.preselectedLanguage) {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
271
275
|
setTimeout(() => {
|
|
272
|
-
this.
|
|
273
|
-
}, 300);
|
|
276
|
+
this.selectItem(this.tracks.find((t) => t.track.language === this.preselectedLanguage) ?? null);
|
|
277
|
+
}, 300); // TODO why delay?
|
|
274
278
|
}
|
|
275
279
|
}
|
|
276
|
-
|
|
277
|
-
trace(`${T} onShowLevelSelectMenu`);
|
|
278
|
-
this.toggleContextMenu();
|
|
279
|
-
}
|
|
280
|
-
hideSelectLevelMenu() {
|
|
280
|
+
hideMenu() {
|
|
281
281
|
;
|
|
282
|
-
this.$('[data-
|
|
282
|
+
this.$('[data-cc] ul').hide();
|
|
283
283
|
}
|
|
284
|
-
|
|
285
|
-
|
|
284
|
+
toggleMenu() {
|
|
285
|
+
trace(`${T} toggleMenu`);
|
|
286
|
+
this.$('[data-cc] ul').toggle();
|
|
286
287
|
}
|
|
287
|
-
|
|
288
|
-
return this.$(
|
|
288
|
+
itemElement(id) {
|
|
289
|
+
return this.$(`ul li a[data-cc-select="${id}"]`).parent();
|
|
289
290
|
}
|
|
290
|
-
|
|
291
|
-
return this.$('[data-
|
|
292
|
-
}
|
|
293
|
-
startLevelSwitch() {
|
|
294
|
-
this.buttonElement().addClass('changing');
|
|
295
|
-
}
|
|
296
|
-
stopLevelSwitch() {
|
|
297
|
-
this.buttonElement().removeClass('changing');
|
|
291
|
+
allItemElements() {
|
|
292
|
+
return this.$('[data-cc] li');
|
|
298
293
|
}
|
|
299
294
|
selectSubtitles() {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
if (cues && cues.length) {
|
|
312
|
-
for (const cue of cues) {
|
|
313
|
-
if (currentTime >= cue.startTime && currentTime <= cue.endTime) {
|
|
314
|
-
subtitleText +=
|
|
315
|
-
cue.getCueAsHTML().textContent + '\n';
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
this.setSubtitleText(subtitleText);
|
|
320
|
-
track.oncuechange = (e) => {
|
|
321
|
-
try {
|
|
322
|
-
if (track.activeCues?.length) {
|
|
323
|
-
const html = track.activeCues[0].getCueAsHTML();
|
|
324
|
-
this.setSubtitleText(html);
|
|
325
|
-
}
|
|
326
|
-
else {
|
|
327
|
-
this.clearSubtitleText();
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
catch (error) {
|
|
331
|
-
// console.error(error);
|
|
332
|
-
reportError(error);
|
|
333
|
-
}
|
|
334
|
-
};
|
|
335
|
-
continue;
|
|
295
|
+
const trackId = this.track ? this.track.id : -1;
|
|
296
|
+
this.core.activePlayback.closedCaptionsTrackId = trackId;
|
|
297
|
+
}
|
|
298
|
+
getSubtitleText(track) {
|
|
299
|
+
const currentTime = this.core.activePlayback?.getCurrentTime() ?? 0;
|
|
300
|
+
const cues = track.cues;
|
|
301
|
+
const lines = [];
|
|
302
|
+
if (cues && cues.length) {
|
|
303
|
+
for (const cue of cues) {
|
|
304
|
+
if (currentTime >= cue.startTime && currentTime <= cue.endTime) {
|
|
305
|
+
lines.push(cue.getCueAsHTML().textContent);
|
|
336
306
|
}
|
|
337
|
-
this.tracks[i].oncuechange = null;
|
|
338
|
-
this.tracks[i].mode = 'hidden';
|
|
339
307
|
}
|
|
340
308
|
}
|
|
309
|
+
return lines.join('\n');
|
|
341
310
|
}
|
|
342
311
|
setSubtitleText(text) {
|
|
343
|
-
this.$
|
|
312
|
+
this.$line.find('p').html(text);
|
|
344
313
|
}
|
|
345
314
|
clearSubtitleText() {
|
|
346
315
|
this.setSubtitleText('');
|
|
347
316
|
}
|
|
348
|
-
|
|
349
|
-
this.
|
|
350
|
-
if (track.language === 'off') {
|
|
317
|
+
updateSelection() {
|
|
318
|
+
if (!this.track) {
|
|
351
319
|
this.hide();
|
|
352
320
|
}
|
|
353
321
|
else {
|
|
@@ -357,20 +325,21 @@ export class Subtitles extends UICorePlugin {
|
|
|
357
325
|
this.highlightCurrentSubtitles();
|
|
358
326
|
}
|
|
359
327
|
highlightCurrentSubtitles() {
|
|
360
|
-
this.
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
}
|
|
328
|
+
this.allItemElements()
|
|
329
|
+
.removeClass('current')
|
|
330
|
+
.find('a')
|
|
331
|
+
.removeClass('gcore-skin-active');
|
|
332
|
+
trace(`${T} highlightCurrentSubtitles`, {
|
|
333
|
+
track: this.track?.id,
|
|
334
|
+
});
|
|
335
|
+
const currentLevelElement = this.itemElement(this.track ? this.track.id : -1);
|
|
336
|
+
currentLevelElement
|
|
337
|
+
.addClass('current')
|
|
338
|
+
.find('a')
|
|
339
|
+
.addClass('gcore-skin-active');
|
|
367
340
|
}
|
|
368
341
|
renderIcon() {
|
|
369
342
|
const icon = this.isShowing ? subtitlesOnIcon : subtitlesOffIcon;
|
|
370
|
-
this.
|
|
371
|
-
.getPlugin('media_control')
|
|
372
|
-
.getElement('subtitlesSelector')
|
|
373
|
-
?.find('span.subtitle-text')
|
|
374
|
-
.html(icon);
|
|
343
|
+
this.$el.find('span.cc-text').html(icon);
|
|
375
344
|
}
|
|
376
345
|
}
|
package/lib/testUtils.d.ts
CHANGED
|
@@ -65,29 +65,31 @@ export declare function createSpinnerPlugin(): Events<string | symbol, any> & {
|
|
|
65
65
|
export declare function createMockPlayback(name?: string): Events<string | symbol, any> & {
|
|
66
66
|
name: string;
|
|
67
67
|
currentLevel: number;
|
|
68
|
+
dvrEnabled: boolean;
|
|
68
69
|
levels: never[];
|
|
69
70
|
consent(): void;
|
|
70
71
|
play(): void;
|
|
71
72
|
pause(): void;
|
|
72
73
|
stop(): void;
|
|
73
|
-
destroy():
|
|
74
|
-
seek():
|
|
75
|
-
seekPercentage():
|
|
76
|
-
getDuration():
|
|
77
|
-
enterPiP():
|
|
78
|
-
exitPiP():
|
|
79
|
-
getPlaybackType():
|
|
80
|
-
getStartTimeOffset():
|
|
81
|
-
getCurrentTime():
|
|
82
|
-
isHighDefinitionInUse():
|
|
83
|
-
mute():
|
|
84
|
-
unmute():
|
|
85
|
-
volume():
|
|
86
|
-
configure():
|
|
87
|
-
attemptAutoPlay():
|
|
88
|
-
canAutoPlay():
|
|
89
|
-
onResize():
|
|
90
|
-
|
|
74
|
+
destroy: import("vitest").Mock<(...args: any[]) => any>;
|
|
75
|
+
seek: import("vitest").Mock<(...args: any[]) => any>;
|
|
76
|
+
seekPercentage: import("vitest").Mock<(...args: any[]) => any>;
|
|
77
|
+
getDuration: import("vitest").Mock<(...args: any[]) => any>;
|
|
78
|
+
enterPiP: import("vitest").Mock<(...args: any[]) => any>;
|
|
79
|
+
exitPiP: import("vitest").Mock<(...args: any[]) => any>;
|
|
80
|
+
getPlaybackType: import("vitest").Mock<(...args: any[]) => any>;
|
|
81
|
+
getStartTimeOffset: import("vitest").Mock<(...args: any[]) => any>;
|
|
82
|
+
getCurrentTime: import("vitest").Mock<(...args: any[]) => any>;
|
|
83
|
+
isHighDefinitionInUse: import("vitest").Mock<(...args: any[]) => any>;
|
|
84
|
+
mute: import("vitest").Mock<(...args: any[]) => any>;
|
|
85
|
+
unmute: import("vitest").Mock<(...args: any[]) => any>;
|
|
86
|
+
volume: import("vitest").Mock<(...args: any[]) => any>;
|
|
87
|
+
configure: import("vitest").Mock<(...args: any[]) => any>;
|
|
88
|
+
attemptAutoPlay: import("vitest").Mock<(...args: any[]) => any>;
|
|
89
|
+
canAutoPlay: import("vitest").Mock<(...args: any[]) => any>;
|
|
90
|
+
onResize: import("vitest").Mock<(...args: any[]) => any>;
|
|
91
|
+
setPlaybackRate: import("vitest").Mock<(...args: any[]) => any>;
|
|
92
|
+
trigger: <T extends string | symbol>(event: T, ...args: any[]) => boolean;
|
|
91
93
|
};
|
|
92
94
|
export declare function createMockContainer(playback?: any): Events<string | symbol, any> & {
|
|
93
95
|
el: HTMLDivElement;
|
|
@@ -95,6 +97,8 @@ export declare function createMockContainer(playback?: any): Events<string | sym
|
|
|
95
97
|
$el: any;
|
|
96
98
|
getDuration: import("vitest").Mock<(...args: any[]) => any>;
|
|
97
99
|
getPlugin: import("vitest").Mock<(...args: any[]) => any>;
|
|
100
|
+
getPlaybackType: import("vitest").Mock<(...args: any[]) => any>;
|
|
101
|
+
isDvrInUse: import("vitest").Mock<(...args: any[]) => any>;
|
|
98
102
|
isPlaying: import("vitest").Mock<(...args: any[]) => any>;
|
|
99
103
|
play: import("vitest").Mock<(...args: any[]) => any>;
|
|
100
104
|
seek: import("vitest").Mock<(...args: any[]) => any>;
|
package/lib/testUtils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../src/testUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAK,YAAY,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,MAAM,MAAM,eAAe,CAAA;AAElC;;;;GAIG;AACH,qBAAa,aAAc,SAAQ,MAAM;IAErC,SAAS,CAAC,OAAO,EAAE,GAAG;IACtB,QAAQ,CAAC,IAAI,EAAE,GAAG;IAClB,SAAS,CAAC,WAAW,CAAC,EAAE,GAAG;gBAFjB,OAAO,EAAE,GAAG,EACb,IAAI,EAAE,GAAG,EACR,WAAW,CAAC,EAAE,GAAG,YAAA;IAK7B,IAAI,IAAI,WAEP;IAED,OAAO;IAEP,IAAI;IAEJ,KAAK;IAEL,IAAI;IAEJ,OAAO;IAEP,IAAI;IAEJ,cAAc;IAEd,WAAW;IAIX,QAAQ;IAER,OAAO;IAEP,eAAe;IAIf,kBAAkB;IAIlB,cAAc;IAId,qBAAqB;IAIrB,IAAI;IAEJ,MAAM;IAEN,MAAM;IAEN,SAAS;IAET,eAAe;IAIf,WAAW;IAIX,QAAQ;IAIR,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE;CAGtC;AAED,wBAAgB,cAAc,CAC5B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,SAAS,GAAE,GAA2B;;;;;;;;;;;;;;;;EAqBvC;AAED,wBAAgB,gBAAgB;;;EAK/B;AAED,wBAAgB,mBAAmB;;;;;;EAKlC;AAED,wBAAgB,kBAAkB,CAAC,IAAI,SAAS
|
|
1
|
+
{"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../src/testUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAK,YAAY,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,MAAM,MAAM,eAAe,CAAA;AAElC;;;;GAIG;AACH,qBAAa,aAAc,SAAQ,MAAM;IAErC,SAAS,CAAC,OAAO,EAAE,GAAG;IACtB,QAAQ,CAAC,IAAI,EAAE,GAAG;IAClB,SAAS,CAAC,WAAW,CAAC,EAAE,GAAG;gBAFjB,OAAO,EAAE,GAAG,EACb,IAAI,EAAE,GAAG,EACR,WAAW,CAAC,EAAE,GAAG,YAAA;IAK7B,IAAI,IAAI,WAEP;IAED,OAAO;IAEP,IAAI;IAEJ,KAAK;IAEL,IAAI;IAEJ,OAAO;IAEP,IAAI;IAEJ,cAAc;IAEd,WAAW;IAIX,QAAQ;IAER,OAAO;IAEP,eAAe;IAIf,kBAAkB;IAIlB,cAAc;IAId,qBAAqB;IAIrB,IAAI;IAEJ,MAAM;IAEN,MAAM;IAEN,SAAS;IAET,eAAe;IAIf,WAAW;IAIX,QAAQ;IAIR,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE;CAGtC;AAED,wBAAgB,cAAc,CAC5B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,SAAS,GAAE,GAA2B;;;;;;;;;;;;;;;;EAqBvC;AAED,wBAAgB,gBAAgB;;;EAK/B;AAED,wBAAgB,mBAAmB;;;;;;EAKlC;AAED,wBAAgB,kBAAkB,CAAC,IAAI,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+B/C;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,GAAE,GAA0B;;;;;;;;;;;;EAgBvE;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,GAAG,gBAqB/C"}
|
package/lib/testUtils.js
CHANGED
|
@@ -98,47 +98,31 @@ export function createMockPlayback(name = 'mock') {
|
|
|
98
98
|
return Object.assign(emitter, {
|
|
99
99
|
name,
|
|
100
100
|
currentLevel: -1,
|
|
101
|
+
dvrEnabled: false,
|
|
101
102
|
levels: [],
|
|
102
103
|
consent() { },
|
|
103
104
|
play() { },
|
|
104
105
|
pause() { },
|
|
105
106
|
stop() { },
|
|
106
|
-
destroy()
|
|
107
|
-
seek()
|
|
108
|
-
seekPercentage()
|
|
109
|
-
getDuration()
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
},
|
|
126
|
-
mute() { },
|
|
127
|
-
unmute() { },
|
|
128
|
-
volume() { },
|
|
129
|
-
configure() { },
|
|
130
|
-
attemptAutoPlay() {
|
|
131
|
-
return true;
|
|
132
|
-
},
|
|
133
|
-
canAutoPlay() {
|
|
134
|
-
return true;
|
|
135
|
-
},
|
|
136
|
-
onResize() {
|
|
137
|
-
return true;
|
|
138
|
-
},
|
|
139
|
-
trigger(event, ...args) {
|
|
140
|
-
emitter.emit(event, ...args);
|
|
141
|
-
},
|
|
107
|
+
destroy: vi.fn(),
|
|
108
|
+
seek: vi.fn(),
|
|
109
|
+
seekPercentage: vi.fn(),
|
|
110
|
+
getDuration: vi.fn().mockImplementation(() => 100),
|
|
111
|
+
enterPiP: vi.fn(),
|
|
112
|
+
exitPiP: vi.fn(),
|
|
113
|
+
getPlaybackType: vi.fn().mockImplementation(() => 'live'),
|
|
114
|
+
getStartTimeOffset: vi.fn().mockImplementation(() => 0),
|
|
115
|
+
getCurrentTime: vi.fn().mockImplementation(() => 0),
|
|
116
|
+
isHighDefinitionInUse: vi.fn().mockImplementation(() => false),
|
|
117
|
+
mute: vi.fn(),
|
|
118
|
+
unmute: vi.fn(),
|
|
119
|
+
volume: vi.fn(),
|
|
120
|
+
configure: vi.fn(),
|
|
121
|
+
attemptAutoPlay: vi.fn().mockImplementation(() => true),
|
|
122
|
+
canAutoPlay: vi.fn().mockImplementation(() => true),
|
|
123
|
+
onResize: vi.fn().mockImplementation(() => true),
|
|
124
|
+
setPlaybackRate: vi.fn(),
|
|
125
|
+
trigger: emitter.emit,
|
|
142
126
|
});
|
|
143
127
|
}
|
|
144
128
|
export function createMockContainer(playback = createMockPlayback()) {
|
|
@@ -150,6 +134,8 @@ export function createMockContainer(playback = createMockPlayback()) {
|
|
|
150
134
|
$el: $(el),
|
|
151
135
|
getDuration: vi.fn().mockReturnValue(0),
|
|
152
136
|
getPlugin: vi.fn(),
|
|
137
|
+
getPlaybackType: vi.fn().mockReturnValue('live'),
|
|
138
|
+
isDvrInUse: vi.fn().mockReturnValue(false),
|
|
153
139
|
isPlaying: vi.fn().mockReturnValue(false),
|
|
154
140
|
play: vi.fn(),
|
|
155
141
|
seek: vi.fn(),
|
package/package.json
CHANGED
package/src/index.plugins.ts
CHANGED
|
@@ -25,7 +25,8 @@ export * from "./plugins/share/Share.js";
|
|
|
25
25
|
export * from "./plugins/skip-time/SkipTime.js";
|
|
26
26
|
export * from "./plugins/spinner-three-bounce/SpinnerThreeBounce.js";
|
|
27
27
|
export * from "./plugins/source-controller/SourceController.js";
|
|
28
|
-
export * from "./plugins/subtitles/
|
|
28
|
+
export * from "./plugins/subtitles/ClosedCaptions.js";
|
|
29
|
+
export { ClosedCaptions as Subtitles } from "./plugins/subtitles/ClosedCaptions.js"; // TODO remove in future versions
|
|
29
30
|
export * from "./plugins/telemetry/Telemetry.js";
|
|
30
31
|
export * from "./plugins/thumbnails/Thumbnails.js";
|
|
31
32
|
// _ vast-ads
|
package/src/index.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* It is built on top of the {@link https://github.com/clappr/clappr | Clappr} library and provides a framework for building custom integrations.
|
|
7
7
|
* Start with {@link Player} for more information.
|
|
8
8
|
*
|
|
9
|
-
* Various plugins (marked with `PLUGIN` keyword) are available to extend the
|
|
9
|
+
* Various plugins (marked with `PLUGIN` keyword) are available to extend the core functionality with additional features.
|
|
10
10
|
* @example
|
|
11
11
|
* ```ts
|
|
12
12
|
* import { Player, MediaControl, ErrorScreen } from '@gcorevideo/player'
|
|
@@ -7,6 +7,10 @@ import { PlaybackErrorCode } from '../playback.types.js'
|
|
|
7
7
|
* @internal
|
|
8
8
|
*/
|
|
9
9
|
export class BasePlayback extends HTML5Video {
|
|
10
|
+
get isHTML5Video() {
|
|
11
|
+
return true
|
|
12
|
+
}
|
|
13
|
+
|
|
10
14
|
createError(errorData: any, options?: ErrorOptions) {
|
|
11
15
|
const i18n =
|
|
12
16
|
this.i18n ||
|
|
@@ -416,6 +416,7 @@ export default class DashPlayback extends BasePlayback {
|
|
|
416
416
|
this.trigger(Events.PLAYBACK_STATS_ADD, { dvr: status })
|
|
417
417
|
}
|
|
418
418
|
|
|
419
|
+
// TODO move to the base class
|
|
419
420
|
override _updateSettings() {
|
|
420
421
|
if (this._playbackType === Playback.VOD) {
|
|
421
422
|
// @ts-expect-error
|