@gcorevideo/player 2.21.3 → 2.21.6
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/dvr-controls/dvr_controls.scss +7 -25
- package/assets/dvr-controls/index.ejs +2 -2
- package/assets/media-control/container.scss +1 -1
- package/assets/media-control/media-control.ejs +1 -6
- package/assets/media-control/media-control.scss +14 -7
- package/assets/media-control/width270.scss +1 -1
- package/assets/media-control/width370.scss +5 -5
- package/assets/playback-rate/button.ejs +2 -2
- package/assets/playback-rate/list.ejs +4 -4
- package/assets/style/theme.scss +1 -1
- package/assets/subtitles/combobox.ejs +5 -5
- package/assets/subtitles/string.ejs +1 -1
- package/assets/subtitles/style.scss +2 -2
- package/dist/core.js +2 -1
- package/dist/index.css +993 -993
- package/dist/index.js +199 -178
- package/dist/player.d.ts +141 -119
- package/dist/plugins/index.css +1118 -1118
- package/dist/plugins/index.js +191 -173
- 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/dash-playback/DashPlayback.d.ts.map +1 -1
- package/lib/playback/dash-playback/DashPlayback.js +1 -0
- 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 +6 -2
- package/lib/plugins/bottom-gear/BottomGear.d.ts.map +1 -1
- package/lib/plugins/bottom-gear/BottomGear.js +2 -1
- package/lib/plugins/dvr-controls/DvrControls.d.ts +0 -3
- package/lib/plugins/dvr-controls/DvrControls.d.ts.map +1 -1
- package/lib/plugins/dvr-controls/DvrControls.js +13 -38
- package/lib/plugins/media-control/MediaControl.d.ts +14 -18
- package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
- package/lib/plugins/media-control/MediaControl.js +105 -72
- 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 +0 -1
- package/lib/plugins/playback-rate/PlaybackRate.d.ts.map +1 -1
- package/lib/plugins/playback-rate/PlaybackRate.js +23 -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 +12 -9
- package/lib/plugins/subtitles/Subtitles.d.ts.map +1 -1
- package/lib/plugins/subtitles/Subtitles.js +31 -32
- package/lib/testUtils.d.ts +26 -19
- package/lib/testUtils.d.ts.map +1 -1
- package/lib/testUtils.js +30 -45
- package/package.json +1 -1
- package/src/index.plugins.ts +2 -1
- package/src/index.ts +1 -1
- package/src/playback/dash-playback/DashPlayback.ts +1 -0
- package/src/plugins/audio-selector/AudioSelector.ts +9 -8
- package/src/plugins/bottom-gear/BottomGear.ts +11 -4
- 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/dvr-controls/DvrControls.ts +16 -44
- package/src/plugins/dvr-controls/__tests__/DvrControls.test.ts +18 -22
- package/src/plugins/dvr-controls/__tests__/__snapshots__/DvrControls.test.ts.snap +6 -30
- package/src/plugins/media-control/MediaControl.ts +130 -85
- package/src/plugins/media-control/__tests__/MediaControl.test.ts +132 -0
- package/src/plugins/media-control/__tests__/__snapshots__/MediaControl.test.ts.snap +299 -0
- package/src/plugins/picture-in-picture/PictureInPicture.ts +5 -5
- package/src/plugins/playback-rate/PlaybackRate.ts +142 -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/{Subtitles.ts → ClosedCaptions.ts} +42 -34
- 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 +30 -45
- package/temp/player.api.json +269 -89
- package/tsconfig.tsbuildinfo +1 -1
- package/src/plugins/index.ts +0 -39
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlaybackRate.d.ts","sourceRoot":"","sources":["../../../src/plugins/playback-rate/PlaybackRate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,YAAY,EAAsB,IAAI,EAAE,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"PlaybackRate.d.ts","sourceRoot":"","sources":["../../../src/plugins/playback-rate/PlaybackRate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,YAAY,EAAsB,IAAI,EAAE,MAAM,cAAc,CAAA;AAuC7E;;;;;;;;;;;;;GAaG;AACH,qBAAa,YAAa,SAAQ,YAAY;IAC5C,OAAO,CAAC,aAAa,CAA+C;IAGpE,OAAO,CAAC,gBAAgB,CAAoB;IAE5C,OAAO,CAAC,QAAQ,CAAQ;IAExB,OAAO,CAAC,YAAY,CAAgC;IAEpD;;OAEG;IACH,IAAI,IAAI,WAEP;IAED;;OAEG;IACH,IAAI,gBAAgB;;MAEnB;IAED,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAuB;IAE7D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAqB;gBAE7C,IAAI,EAAE,IAAI;IAQtB;;OAEG;IACH,IAAa,UAAU;;MAItB;IAED;;OAEG;IACH,IAAa,MAAM;;;;MAMlB;IAED;;OAEG;IACM,UAAU;IASnB,OAAO,CAAC,WAAW;IAanB,OAAO,CAAC,uBAAuB;IAgB/B,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,iBAAiB;IASzB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,oBAAoB;IAY5B,OAAO,CAAC,YAAY;IAepB;;OAEG;IACM,MAAM;IAgCf,OAAO,CAAC,SAAS;IAUjB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,MAAM;IAWd,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,MAAM;IAEd,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,UAAU;IAalB,OAAO,CAAC,MAAM;IAMd,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,oBAAoB;CAS7B"}
|
|
@@ -9,7 +9,7 @@ import arrowRightIcon from '../../../assets/icons/new/arrow-right.svg';
|
|
|
9
9
|
import arrowLeftIcon from '../../../assets/icons/new/arrow-left.svg';
|
|
10
10
|
import checkIcon from '../../../assets/icons/new/check.svg';
|
|
11
11
|
import { PlaybackEvents } from '../../playback/types.js';
|
|
12
|
-
import { MediaControlEvents } from '../media-control/MediaControl.js';
|
|
12
|
+
import { MediaControlEvents, } from '../media-control/MediaControl.js';
|
|
13
13
|
const DEFAULT_PLAYBACK_RATES = [
|
|
14
14
|
{ value: '0.5', label: '0.5x' },
|
|
15
15
|
{ value: '0.75', label: '0.75x' },
|
|
@@ -17,7 +17,7 @@ const DEFAULT_PLAYBACK_RATES = [
|
|
|
17
17
|
{ value: '1.25', label: '1.25x' },
|
|
18
18
|
{ value: '1.5', label: '1.5x' },
|
|
19
19
|
{ value: '1.75', label: '1.75x' },
|
|
20
|
-
{ value: '2.0', label: '2x' }
|
|
20
|
+
{ value: '2.0', label: '2x' },
|
|
21
21
|
];
|
|
22
22
|
const DEFAULT_PLAYBACK_RATE = '1.0';
|
|
23
23
|
const T = 'plugins.playback_rate';
|
|
@@ -57,16 +57,17 @@ export class PlaybackRate extends UICorePlugin {
|
|
|
57
57
|
static listTemplate = template(listHtml);
|
|
58
58
|
constructor(core) {
|
|
59
59
|
super(core);
|
|
60
|
-
this.playbackRates =
|
|
61
|
-
|
|
60
|
+
this.playbackRates =
|
|
61
|
+
core.options.playbackRate?.options || DEFAULT_PLAYBACK_RATES;
|
|
62
|
+
this.selectedRate =
|
|
63
|
+
core.options.playbackRate?.defaultValue || DEFAULT_PLAYBACK_RATE;
|
|
62
64
|
}
|
|
63
65
|
/**
|
|
64
66
|
* @internal
|
|
65
67
|
*/
|
|
66
68
|
get attributes() {
|
|
67
69
|
return {
|
|
68
|
-
|
|
69
|
-
'data-playback-rate-select': ''
|
|
70
|
+
class: 'media-control-playbackrate',
|
|
70
71
|
};
|
|
71
72
|
}
|
|
72
73
|
/**
|
|
@@ -87,6 +88,7 @@ export class PlaybackRate extends UICorePlugin {
|
|
|
87
88
|
this.listenTo(this.core, Events.CORE_ACTIVE_CONTAINER_CHANGED, this.onActiveContainerChange);
|
|
88
89
|
}
|
|
89
90
|
onCoreReady() {
|
|
91
|
+
trace(`${T} onCoreReady`);
|
|
90
92
|
const mediaControl = this.core.getPlugin('media_control');
|
|
91
93
|
assert(mediaControl, 'media_control plugin is required');
|
|
92
94
|
const gear = this.core.getPlugin('bottom_gear');
|
|
@@ -94,6 +96,7 @@ export class PlaybackRate extends UICorePlugin {
|
|
|
94
96
|
this.listenTo(mediaControl, MediaControlEvents.MEDIACONTROL_GEAR_RENDERED, this.onGearRendered);
|
|
95
97
|
}
|
|
96
98
|
onActiveContainerChange() {
|
|
99
|
+
trace(`${T} onActiveContainerChange`);
|
|
97
100
|
this.listenTo(this.core.activePlayback, Events.PLAYBACK_STOP, this.onStop);
|
|
98
101
|
this.listenTo(this.core.activePlayback, Events.PLAYBACK_PLAY, this.onPlay);
|
|
99
102
|
this.listenTo(this.core.activePlayback, PlaybackEvents.PLAYBACK_RATE_CHANGED, this.onPlaybackRateChange);
|
|
@@ -117,7 +120,7 @@ export class PlaybackRate extends UICorePlugin {
|
|
|
117
120
|
allRateElements() {
|
|
118
121
|
return this.$('ul.gear-sub-menu li');
|
|
119
122
|
}
|
|
120
|
-
rateElement(rate =
|
|
123
|
+
rateElement(rate = '1') {
|
|
121
124
|
return this.$(`ul.gear-sub-menu a[data-rate="${rate}"]`).parent();
|
|
122
125
|
}
|
|
123
126
|
onPlaybackRateChange(playbackRate) {
|
|
@@ -132,10 +135,11 @@ export class PlaybackRate extends UICorePlugin {
|
|
|
132
135
|
}
|
|
133
136
|
}
|
|
134
137
|
shouldRender() {
|
|
135
|
-
if (!this.core.
|
|
138
|
+
if (!this.core.activePlayback) {
|
|
136
139
|
return false;
|
|
137
140
|
}
|
|
138
|
-
if (this.core.getPlaybackType() === Playback.LIVE &&
|
|
141
|
+
if (this.core.activePlayback.getPlaybackType() === Playback.LIVE &&
|
|
142
|
+
!this.core.activePlayback.dvrEnabled) {
|
|
139
143
|
return false;
|
|
140
144
|
}
|
|
141
145
|
return 'setPlaybackRate' in this.core.activePlayback;
|
|
@@ -158,9 +162,12 @@ export class PlaybackRate extends UICorePlugin {
|
|
|
158
162
|
title: this.getTitle(),
|
|
159
163
|
speedIcon,
|
|
160
164
|
arrowRightIcon,
|
|
165
|
+
i18n: this.core.i18n,
|
|
161
166
|
});
|
|
162
167
|
this.$el.html(button);
|
|
163
|
-
this.core.getPlugin('bottom_gear')
|
|
168
|
+
this.core.getPlugin('bottom_gear')
|
|
169
|
+
?.getElement('rate')
|
|
170
|
+
?.html(this.el);
|
|
164
171
|
this.rendered = true;
|
|
165
172
|
return this;
|
|
166
173
|
}
|
|
@@ -175,7 +182,8 @@ export class PlaybackRate extends UICorePlugin {
|
|
|
175
182
|
}
|
|
176
183
|
}
|
|
177
184
|
onPlay() {
|
|
178
|
-
if (this.core.getPlaybackType() === Playback.LIVE &&
|
|
185
|
+
if (this.core.getPlaybackType() === Playback.LIVE &&
|
|
186
|
+
!this.core.activePlayback.dvrEnabled) {
|
|
179
187
|
this.resetPlaybackRate();
|
|
180
188
|
}
|
|
181
189
|
else {
|
|
@@ -185,8 +193,7 @@ export class PlaybackRate extends UICorePlugin {
|
|
|
185
193
|
resetPlaybackRate() {
|
|
186
194
|
this.setSelectedRate(DEFAULT_PLAYBACK_RATE);
|
|
187
195
|
}
|
|
188
|
-
onStop() {
|
|
189
|
-
}
|
|
196
|
+
onStop() { }
|
|
190
197
|
onRateSelect(event) {
|
|
191
198
|
event.stopPropagation();
|
|
192
199
|
const rate = event.currentTarget.dataset.rate;
|
|
@@ -201,6 +208,7 @@ export class PlaybackRate extends UICorePlugin {
|
|
|
201
208
|
playbackRates: this.playbackRates,
|
|
202
209
|
arrowLeftIcon,
|
|
203
210
|
checkIcon,
|
|
211
|
+
i18n: this.core.i18n,
|
|
204
212
|
}));
|
|
205
213
|
this.core.getPlugin('bottom_gear')?.setContent(this.el);
|
|
206
214
|
this.highlightCurrentRate();
|
|
@@ -216,7 +224,8 @@ export class PlaybackRate extends UICorePlugin {
|
|
|
216
224
|
this.selectedRate = rate;
|
|
217
225
|
}
|
|
218
226
|
getTitle() {
|
|
219
|
-
return this.playbackRates.find((r) => r.value === this.selectedRate)?.label ||
|
|
227
|
+
return (this.playbackRates.find((r) => r.value === this.selectedRate)?.label ||
|
|
228
|
+
this.selectedRate);
|
|
220
229
|
}
|
|
221
230
|
highlightCurrentRate() {
|
|
222
231
|
this.allRateElements().removeClass('current');
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { UICorePlugin } from '@clappr/core';
|
|
2
|
+
import '../../../assets/subtitles/style.scss';
|
|
3
|
+
export type ClosedCaptionsPluginSettings = {
|
|
4
|
+
/**
|
|
5
|
+
* Initially selected subtitles language
|
|
6
|
+
*/
|
|
7
|
+
language?: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* @deprecated Use {@link ClosedCaptionsPluginSettings} instead.
|
|
11
|
+
*/
|
|
12
|
+
export type SubtitlesPluginSettings = ClosedCaptionsPluginSettings;
|
|
13
|
+
/**
|
|
14
|
+
* `PLUGIN` that provides a UI to select the subtitles when available.
|
|
15
|
+
* @beta
|
|
16
|
+
*
|
|
17
|
+
* @remarks
|
|
18
|
+
* The plugin is activated when closed captions tracks are provided with the media source.
|
|
19
|
+
* It shows a familiar "CC" button with a dropdown menu to select the subtitles language.
|
|
20
|
+
*
|
|
21
|
+
* Depends on:
|
|
22
|
+
*
|
|
23
|
+
* - {@link MediaControl}
|
|
24
|
+
*
|
|
25
|
+
* Configuration options - {@link ClosedCaptionsPluginSettings}
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* import { ClosedCaptions } from '@gcorevideo/player'
|
|
29
|
+
*
|
|
30
|
+
* Player.registerPlugin(ClosedCaptions)
|
|
31
|
+
*
|
|
32
|
+
* new Player({
|
|
33
|
+
* ...
|
|
34
|
+
* cc: {
|
|
35
|
+
* language: 'en',
|
|
36
|
+
* },
|
|
37
|
+
* })
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare class ClosedCaptions extends UICorePlugin {
|
|
41
|
+
private isPreselectedApplied;
|
|
42
|
+
private isShowing;
|
|
43
|
+
private track;
|
|
44
|
+
private tracks;
|
|
45
|
+
private $line;
|
|
46
|
+
/**
|
|
47
|
+
* @internal
|
|
48
|
+
*/
|
|
49
|
+
get name(): string;
|
|
50
|
+
/**
|
|
51
|
+
* @internal
|
|
52
|
+
*/
|
|
53
|
+
get supportedVersion(): {
|
|
54
|
+
min: string;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* @internal
|
|
58
|
+
*/
|
|
59
|
+
static get version(): string;
|
|
60
|
+
private static readonly template;
|
|
61
|
+
private static readonly templateString;
|
|
62
|
+
/**
|
|
63
|
+
* @internal
|
|
64
|
+
*/
|
|
65
|
+
get attributes(): {
|
|
66
|
+
class: string;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* @internal
|
|
70
|
+
*/
|
|
71
|
+
get events(): {
|
|
72
|
+
'click [data-cc-select]': string;
|
|
73
|
+
'click [data-cc-button]': string;
|
|
74
|
+
};
|
|
75
|
+
private get preselectedLanguage();
|
|
76
|
+
/**
|
|
77
|
+
* @internal
|
|
78
|
+
*/
|
|
79
|
+
bindEvents(): void;
|
|
80
|
+
private onCoreReady;
|
|
81
|
+
private onContainerChanged;
|
|
82
|
+
private onSubtitleAvailable;
|
|
83
|
+
private onSubtitleChanged;
|
|
84
|
+
private applyTracks;
|
|
85
|
+
private onStartAd;
|
|
86
|
+
private onFinishAd;
|
|
87
|
+
private playerResize;
|
|
88
|
+
/**
|
|
89
|
+
* Hides the subtitles menu and the subtitles.
|
|
90
|
+
*/
|
|
91
|
+
hide(): void;
|
|
92
|
+
/**
|
|
93
|
+
* Shows the subtitles menu and the subtitles.
|
|
94
|
+
*/
|
|
95
|
+
show(): void;
|
|
96
|
+
private shouldRender;
|
|
97
|
+
private resizeFont;
|
|
98
|
+
/**
|
|
99
|
+
* @internal
|
|
100
|
+
*/
|
|
101
|
+
render(): this;
|
|
102
|
+
private findById;
|
|
103
|
+
private selectItem;
|
|
104
|
+
private onItemSelect;
|
|
105
|
+
private applyPreselectedSubtitles;
|
|
106
|
+
private hideMenu;
|
|
107
|
+
private toggleMenu;
|
|
108
|
+
private itemElement;
|
|
109
|
+
private allItemElements;
|
|
110
|
+
private selectSubtitles;
|
|
111
|
+
private getSubtitleText;
|
|
112
|
+
private setSubtitleText;
|
|
113
|
+
private clearSubtitleText;
|
|
114
|
+
private updateSelection;
|
|
115
|
+
private highlightCurrentSubtitles;
|
|
116
|
+
private renderIcon;
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=ClosedCaptions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClosedCaptions.d.ts","sourceRoot":"","sources":["../../../src/plugins/subtitles/ClosedCaptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,YAAY,EAAwB,MAAM,cAAc,CAAA;AAOzE,OAAO,sCAAsC,CAAA;AAe7C,MAAM,MAAM,4BAA4B,GAAG;IACzC;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,4BAA4B,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,cAAe,SAAQ,YAAY;IAC9C,OAAO,CAAC,oBAAoB,CAAQ;IAEpC,OAAO,CAAC,SAAS,CAAQ;IAEzB,OAAO,CAAC,KAAK,CAA6B;IAE1C,OAAO,CAAC,MAAM,CAAsB;IAEpC,OAAO,CAAC,KAAK,CAA2B;IAExC;;OAEG;IACH,IAAI,IAAI,WAEP;IAED;;OAEG;IACH,IAAI,gBAAgB;;MAEnB;IAED;;OAEG;IACH,MAAM,KAAK,OAAO,WAEjB;IAED,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAyB;IAEzD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAuB;IAE7D;;OAEG;IACH,IAAa,UAAU;;MAItB;IAED;;OAEG;IACH,IAAa,MAAM;;;MAKlB;IAED,OAAO,KAAK,mBAAmB,GAE9B;IAED;;OAEG;IACM,UAAU;IAUnB,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,kBAAkB;IAwC1B,OAAO,CAAC,mBAAmB;IAK3B,OAAO,CAAC,iBAAiB;IA+BzB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,YAAY;IAqBpB;;OAEG;IACH,IAAI;IAWJ;;OAEG;IACH,IAAI;IAiBJ,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,UAAU;IAUlB;;OAEG;IACM,MAAM;IA0Bf,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,yBAAyB;IAgBjC,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,eAAe;IAgBvB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,yBAAyB;IAgBjC,OAAO,CAAC,UAAU;CAKnB"}
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
import { Events, UICorePlugin, Browser, template, $ } from '@clappr/core';
|
|
2
|
+
import { reportError, trace } from '@gcorevideo/utils';
|
|
3
|
+
import assert from 'assert';
|
|
4
|
+
import { CLAPPR_VERSION } from '../../build.js';
|
|
5
|
+
import '../../../assets/subtitles/style.scss';
|
|
6
|
+
import subtitlesOffIcon from '../../../assets/icons/new/subtitles-off.svg';
|
|
7
|
+
import subtitlesOnIcon from '../../../assets/icons/new/subtitles-on.svg';
|
|
8
|
+
import comboboxHTML from '../../../assets/subtitles/combobox.ejs';
|
|
9
|
+
import stringHTML from '../../../assets/subtitles/string.ejs';
|
|
10
|
+
import { isFullscreen } from '../utils.js';
|
|
11
|
+
const VERSION = '2.19.14';
|
|
12
|
+
const LOCAL_STORAGE_CC_ID = 'gplayer.plugins.cc.selected';
|
|
13
|
+
const T = 'plugins.cc';
|
|
14
|
+
/**
|
|
15
|
+
* `PLUGIN` that provides a UI to select the subtitles when available.
|
|
16
|
+
* @beta
|
|
17
|
+
*
|
|
18
|
+
* @remarks
|
|
19
|
+
* The plugin is activated when closed captions tracks are provided with the media source.
|
|
20
|
+
* It shows a familiar "CC" button with a dropdown menu to select the subtitles language.
|
|
21
|
+
*
|
|
22
|
+
* Depends on:
|
|
23
|
+
*
|
|
24
|
+
* - {@link MediaControl}
|
|
25
|
+
*
|
|
26
|
+
* Configuration options - {@link ClosedCaptionsPluginSettings}
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* import { ClosedCaptions } from '@gcorevideo/player'
|
|
30
|
+
*
|
|
31
|
+
* Player.registerPlugin(ClosedCaptions)
|
|
32
|
+
*
|
|
33
|
+
* new Player({
|
|
34
|
+
* ...
|
|
35
|
+
* cc: {
|
|
36
|
+
* language: 'en',
|
|
37
|
+
* },
|
|
38
|
+
* })
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export class ClosedCaptions extends UICorePlugin {
|
|
42
|
+
isPreselectedApplied = false;
|
|
43
|
+
isShowing = false;
|
|
44
|
+
track = null;
|
|
45
|
+
tracks = [];
|
|
46
|
+
$line = null;
|
|
47
|
+
/**
|
|
48
|
+
* @internal
|
|
49
|
+
*/
|
|
50
|
+
get name() {
|
|
51
|
+
return 'cc';
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* @internal
|
|
55
|
+
*/
|
|
56
|
+
get supportedVersion() {
|
|
57
|
+
return { min: CLAPPR_VERSION };
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* @internal
|
|
61
|
+
*/
|
|
62
|
+
static get version() {
|
|
63
|
+
return VERSION;
|
|
64
|
+
}
|
|
65
|
+
static template = template(comboboxHTML);
|
|
66
|
+
static templateString = template(stringHTML);
|
|
67
|
+
/**
|
|
68
|
+
* @internal
|
|
69
|
+
*/
|
|
70
|
+
get attributes() {
|
|
71
|
+
return {
|
|
72
|
+
class: 'media-control-cc',
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* @internal
|
|
77
|
+
*/
|
|
78
|
+
get events() {
|
|
79
|
+
return {
|
|
80
|
+
'click [data-cc-select]': 'onItemSelect',
|
|
81
|
+
'click [data-cc-button]': 'toggleMenu',
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
get preselectedLanguage() {
|
|
85
|
+
return this.core.options.cc?.language ?? this.core.options.subtitles?.language ?? '';
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* @internal
|
|
89
|
+
*/
|
|
90
|
+
bindEvents() {
|
|
91
|
+
this.listenTo(this.core, Events.CORE_READY, this.onCoreReady);
|
|
92
|
+
this.listenTo(this.core, Events.CORE_RESIZE, this.playerResize);
|
|
93
|
+
this.listenTo(this.core, Events.CORE_ACTIVE_CONTAINER_CHANGED, this.onContainerChanged);
|
|
94
|
+
}
|
|
95
|
+
onCoreReady() {
|
|
96
|
+
trace(`${T} onCoreReady`);
|
|
97
|
+
const mediaControl = this.core.getPlugin('media_control');
|
|
98
|
+
assert(mediaControl, 'media_control plugin is required');
|
|
99
|
+
this.listenTo(mediaControl, Events.MEDIACONTROL_RENDERED, this.render);
|
|
100
|
+
this.listenTo(mediaControl, Events.MEDIACONTROL_HIDE, this.hideMenu);
|
|
101
|
+
}
|
|
102
|
+
onContainerChanged() {
|
|
103
|
+
trace(`${T} onContainerChanged`);
|
|
104
|
+
this.listenTo(this.core.activeContainer, Events.CONTAINER_FULLSCREEN, this.playerResize);
|
|
105
|
+
this.listenTo(this.core.activeContainer, 'container:advertisement:start', this.onStartAd);
|
|
106
|
+
this.listenTo(this.core.activePlayback, Events.PLAYBACK_SUBTITLE_AVAILABLE, this.onSubtitleAvailable);
|
|
107
|
+
this.listenTo(this.core.activePlayback, Events.PLAYBACK_SUBTITLE_CHANGED, this.onSubtitleChanged);
|
|
108
|
+
// fix for iOS
|
|
109
|
+
const video = this.core.activePlayback.el;
|
|
110
|
+
assert(video, 'video element is required');
|
|
111
|
+
video.addEventListener('webkitbeginfullscreen', () => {
|
|
112
|
+
if (Browser.isiOS) {
|
|
113
|
+
video.classList.add('ios-fullscreen');
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
video.addEventListener('webkitendfullscreen', () => {
|
|
117
|
+
if (Browser.isiOS) {
|
|
118
|
+
video.classList.remove('ios-fullscreen');
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
onSubtitleAvailable() {
|
|
123
|
+
trace(`${T} onSubtitleAvailable`);
|
|
124
|
+
this.applyTracks();
|
|
125
|
+
}
|
|
126
|
+
onSubtitleChanged({ id }) {
|
|
127
|
+
trace(`${T} onSubtitleChanged`, { id });
|
|
128
|
+
if (id === -1) {
|
|
129
|
+
this.clearSubtitleText();
|
|
130
|
+
}
|
|
131
|
+
for (const track of this.tracks) {
|
|
132
|
+
if (track.id === id) {
|
|
133
|
+
track.track.mode = 'showing';
|
|
134
|
+
this.setSubtitleText(this.getSubtitleText(track.track));
|
|
135
|
+
track.track.oncuechange = (e) => {
|
|
136
|
+
try {
|
|
137
|
+
if (track.track.activeCues?.length) {
|
|
138
|
+
const html = track.track.activeCues[0].getCueAsHTML();
|
|
139
|
+
this.setSubtitleText(html);
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
this.clearSubtitleText();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
reportError(error);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
track.track.oncuechange = null;
|
|
152
|
+
track.track.mode = 'hidden';
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
applyTracks() {
|
|
157
|
+
try {
|
|
158
|
+
this.tracks = this.core.activePlayback.closedCaptionsTracks;
|
|
159
|
+
this.applyPreselectedSubtitles();
|
|
160
|
+
this.render();
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
reportError(error);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
onStartAd() {
|
|
167
|
+
if (this.isShowing && this.core.activeContainer) {
|
|
168
|
+
this.hide();
|
|
169
|
+
this.listenTo(this.core.activeContainer, 'container:advertisement:finish', this.onFinishAd);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
onFinishAd() {
|
|
173
|
+
this.show();
|
|
174
|
+
this.stopListening(this.core.activeContainer, 'container:advertisement:finish', this.onFinishAd);
|
|
175
|
+
}
|
|
176
|
+
playerResize() {
|
|
177
|
+
trace(`${T} playerResize`);
|
|
178
|
+
const shouldShow = this.core.activeContainer &&
|
|
179
|
+
isFullscreen(this.core.activeContainer.el) &&
|
|
180
|
+
this.track &&
|
|
181
|
+
this.track.track.mode &&
|
|
182
|
+
Browser.isiOS &&
|
|
183
|
+
this.isShowing;
|
|
184
|
+
if (shouldShow) {
|
|
185
|
+
this.show();
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
this.resizeFont();
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
reportError(error);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Hides the subtitles menu and the subtitles.
|
|
196
|
+
*/
|
|
197
|
+
hide() {
|
|
198
|
+
this.isShowing = false;
|
|
199
|
+
this.renderIcon();
|
|
200
|
+
this.$line.hide();
|
|
201
|
+
if (this.tracks) {
|
|
202
|
+
for (const t of this.tracks) {
|
|
203
|
+
t.track.mode = 'hidden';
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Shows the subtitles menu and the subtitles.
|
|
209
|
+
*/
|
|
210
|
+
show() {
|
|
211
|
+
this.isShowing = true;
|
|
212
|
+
this.renderIcon();
|
|
213
|
+
if (this.core.activeContainer &&
|
|
214
|
+
isFullscreen(this.core.activeContainer.el) &&
|
|
215
|
+
this.track &&
|
|
216
|
+
this.track.track.mode &&
|
|
217
|
+
Browser.isiOS) {
|
|
218
|
+
this.$line.hide();
|
|
219
|
+
this.track.track.mode = 'showing';
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
this.$line.show();
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
shouldRender() {
|
|
226
|
+
return this.tracks?.length > 0;
|
|
227
|
+
}
|
|
228
|
+
resizeFont() {
|
|
229
|
+
if (!this.$line) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const skinWidth = this.core.activeContainer.$el.width();
|
|
233
|
+
this.$line.find('p').css('font-size', skinWidth * 0.03);
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* @internal
|
|
237
|
+
*/
|
|
238
|
+
render() {
|
|
239
|
+
if (!this.core.activeContainer) {
|
|
240
|
+
return this;
|
|
241
|
+
}
|
|
242
|
+
if (!this.shouldRender()) {
|
|
243
|
+
return this;
|
|
244
|
+
}
|
|
245
|
+
const mediaControl = this.core.getPlugin('media_control');
|
|
246
|
+
this.$el.html(ClosedCaptions.template({ tracks: this.tracks }));
|
|
247
|
+
this.core.activeContainer.$el.find('#cc-line').remove();
|
|
248
|
+
this.$line = $(ClosedCaptions.templateString());
|
|
249
|
+
this.resizeFont();
|
|
250
|
+
this.core.activeContainer.$el.append(this.$line);
|
|
251
|
+
mediaControl.putElement('cc', this.el);
|
|
252
|
+
this.updateSelection();
|
|
253
|
+
this.renderIcon();
|
|
254
|
+
return this;
|
|
255
|
+
}
|
|
256
|
+
findById(id) {
|
|
257
|
+
return this.tracks.find((track) => track.id === id) ?? null;
|
|
258
|
+
}
|
|
259
|
+
selectItem(item) {
|
|
260
|
+
this.clearSubtitleText();
|
|
261
|
+
this.track = item;
|
|
262
|
+
this.hideMenu();
|
|
263
|
+
this.updateSelection();
|
|
264
|
+
}
|
|
265
|
+
onItemSelect(event) {
|
|
266
|
+
const id = event.target.dataset.ccSelect ?? '-1';
|
|
267
|
+
trace(`${T} onItemSelect`, { id });
|
|
268
|
+
localStorage.setItem(LOCAL_STORAGE_CC_ID, id);
|
|
269
|
+
this.selectItem(this.findById(Number(id)));
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
applyPreselectedSubtitles() {
|
|
273
|
+
if (!this.isPreselectedApplied) {
|
|
274
|
+
this.isPreselectedApplied = true;
|
|
275
|
+
if (!this.preselectedLanguage) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
setTimeout(() => {
|
|
279
|
+
this.selectItem(this.tracks.find((t) => t.track.language === this.preselectedLanguage) ?? null);
|
|
280
|
+
}, 300); // TODO why delay?
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
hideMenu() {
|
|
284
|
+
;
|
|
285
|
+
this.$('[data-cc] ul').hide();
|
|
286
|
+
}
|
|
287
|
+
toggleMenu() {
|
|
288
|
+
trace(`${T} toggleMenu`);
|
|
289
|
+
this.$('[data-cc] ul').toggle();
|
|
290
|
+
}
|
|
291
|
+
itemElement(id) {
|
|
292
|
+
return this.$(`ul li a[data-cc-select="${id}"]`).parent();
|
|
293
|
+
}
|
|
294
|
+
allItemElements() {
|
|
295
|
+
return this.$('[data-cc] li');
|
|
296
|
+
}
|
|
297
|
+
selectSubtitles() {
|
|
298
|
+
const trackId = this.track ? this.track.id : -1;
|
|
299
|
+
this.core.activePlayback.closedCaptionsTrackId = trackId;
|
|
300
|
+
}
|
|
301
|
+
getSubtitleText(track) {
|
|
302
|
+
const currentTime = this.core.activePlayback?.getCurrentTime() ?? 0;
|
|
303
|
+
const cues = track.cues;
|
|
304
|
+
const lines = [];
|
|
305
|
+
if (cues && cues.length) {
|
|
306
|
+
for (const cue of cues) {
|
|
307
|
+
if (currentTime >= cue.startTime && currentTime <= cue.endTime) {
|
|
308
|
+
lines.push(cue.getCueAsHTML().textContent);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return lines.join('\n');
|
|
313
|
+
}
|
|
314
|
+
setSubtitleText(text) {
|
|
315
|
+
this.$line.find('p').html(text);
|
|
316
|
+
}
|
|
317
|
+
clearSubtitleText() {
|
|
318
|
+
this.setSubtitleText('');
|
|
319
|
+
}
|
|
320
|
+
updateSelection() {
|
|
321
|
+
if (!this.track) {
|
|
322
|
+
this.hide();
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
this.show();
|
|
326
|
+
}
|
|
327
|
+
this.selectSubtitles();
|
|
328
|
+
this.highlightCurrentSubtitles();
|
|
329
|
+
}
|
|
330
|
+
highlightCurrentSubtitles() {
|
|
331
|
+
this.allItemElements()
|
|
332
|
+
.removeClass('current')
|
|
333
|
+
.find('a')
|
|
334
|
+
.removeClass('gcore-skin-active');
|
|
335
|
+
trace(`${T} highlightCurrentSubtitles`, {
|
|
336
|
+
track: this.track?.id,
|
|
337
|
+
});
|
|
338
|
+
const currentLevelElement = this.itemElement(this.track ? this.track.id : -1);
|
|
339
|
+
currentLevelElement
|
|
340
|
+
.addClass('current')
|
|
341
|
+
.find('a')
|
|
342
|
+
.addClass('gcore-skin-active');
|
|
343
|
+
}
|
|
344
|
+
renderIcon() {
|
|
345
|
+
const icon = this.isShowing ? subtitlesOnIcon : subtitlesOffIcon;
|
|
346
|
+
this.$el.find('span.cc-text').html(icon);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { UICorePlugin } from '@clappr/core';
|
|
2
2
|
import '../../../assets/subtitles/style.scss';
|
|
3
|
-
export type
|
|
3
|
+
export type ClosedCaptionsPluginSettings = {
|
|
4
4
|
/**
|
|
5
5
|
* Initially selected subtitles language
|
|
6
6
|
*/
|
|
7
7
|
language?: string;
|
|
8
8
|
};
|
|
9
|
+
/**
|
|
10
|
+
* @deprecated Use {@link ClosedCaptionsPluginSettings} instead.
|
|
11
|
+
*/
|
|
12
|
+
export type SubtitlesPluginSettings = ClosedCaptionsPluginSettings;
|
|
9
13
|
/**
|
|
10
14
|
* `PLUGIN` that provides a UI to select the subtitles when available.
|
|
11
15
|
* @beta
|
|
@@ -15,16 +19,16 @@ export type SubtitlesPluginSettings = {
|
|
|
15
19
|
*
|
|
16
20
|
* - {@link MediaControl}
|
|
17
21
|
*
|
|
18
|
-
* Configuration options - {@link
|
|
22
|
+
* Configuration options - {@link ClosedCaptionsPluginSettings}
|
|
19
23
|
* @example
|
|
20
24
|
* ```ts
|
|
21
|
-
* import {
|
|
25
|
+
* import { ClosedCaptions } from '@gcorevideo/player'
|
|
22
26
|
*
|
|
23
|
-
* Player.registerPlugin(
|
|
27
|
+
* Player.registerPlugin(ClosedCaptions)
|
|
24
28
|
*
|
|
25
29
|
* new Player({
|
|
26
30
|
* ...
|
|
27
|
-
*
|
|
31
|
+
* cc: {
|
|
28
32
|
* language: 'en',
|
|
29
33
|
* },
|
|
30
34
|
* })
|
|
@@ -35,7 +39,7 @@ export declare class Subtitles extends UICorePlugin {
|
|
|
35
39
|
private isShowing;
|
|
36
40
|
private track;
|
|
37
41
|
private tracks;
|
|
38
|
-
private $
|
|
42
|
+
private $line;
|
|
39
43
|
/**
|
|
40
44
|
* @internal
|
|
41
45
|
*/
|
|
@@ -57,14 +61,13 @@ export declare class Subtitles extends UICorePlugin {
|
|
|
57
61
|
*/
|
|
58
62
|
get attributes(): {
|
|
59
63
|
class: string;
|
|
60
|
-
'data-subtitles': string;
|
|
61
64
|
};
|
|
62
65
|
/**
|
|
63
66
|
* @internal
|
|
64
67
|
*/
|
|
65
68
|
get events(): {
|
|
66
|
-
'click [data-
|
|
67
|
-
'click [data-
|
|
69
|
+
'click [data-cc-select]': string;
|
|
70
|
+
'click [data-cc-button]': string;
|
|
68
71
|
};
|
|
69
72
|
private get preselectedLanguage();
|
|
70
73
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Subtitles.d.ts","sourceRoot":"","sources":["../../../src/plugins/subtitles/Subtitles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,YAAY,EAAwB,MAAM,cAAc,CAAA;AAOzE,OAAO,sCAAsC,CAAA;AAe7C,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"Subtitles.d.ts","sourceRoot":"","sources":["../../../src/plugins/subtitles/Subtitles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,YAAY,EAAwB,MAAM,cAAc,CAAA;AAOzE,OAAO,sCAAsC,CAAA;AAe7C,MAAM,MAAM,4BAA4B,GAAG;IACzC;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,4BAA4B,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,SAAU,SAAQ,YAAY;IACzC,OAAO,CAAC,oBAAoB,CAAQ;IAEpC,OAAO,CAAC,SAAS,CAAQ;IAEzB,OAAO,CAAC,KAAK,CAA6B;IAE1C,OAAO,CAAC,MAAM,CAAsB;IAEpC,OAAO,CAAC,KAAK,CAA2B;IAExC;;OAEG;IACH,IAAI,IAAI,WAEP;IAED;;OAEG;IACH,IAAI,gBAAgB;;MAEnB;IAED;;OAEG;IACH,MAAM,KAAK,OAAO,WAEjB;IAED,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAyB;IAEzD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAuB;IAE7D;;OAEG;IACH,IAAa,UAAU;;MAItB;IAED;;OAEG;IACH,IAAa,MAAM;;;MAKlB;IAED,OAAO,KAAK,mBAAmB,GAE9B;IAED;;OAEG;IACM,UAAU;IAUnB,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,kBAAkB;IAwC1B,OAAO,CAAC,mBAAmB;IAK3B,OAAO,CAAC,iBAAiB;IA+BzB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,YAAY;IAqBpB;;OAEG;IACH,IAAI;IAWJ;;OAEG;IACH,IAAI;IAiBJ,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,UAAU;IAUlB;;OAEG;IACM,MAAM;IA0Bf,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,yBAAyB;IAgBjC,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,eAAe;IAgBvB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,yBAAyB;IAgBjC,OAAO,CAAC,UAAU;CAKnB"}
|