@gcorevideo/player 2.22.0 → 2.22.1
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/bottom-gear/bottomgear copy.ejs +10 -0
- package/assets/bottom-gear/bottomgear.ejs +4 -8
- package/assets/bottom-gear/gear-sub-menu.scss +0 -1
- package/assets/bottom-gear/gear.scss +0 -1
- package/assets/clappr-nerd-stats/button.ejs +3 -3
- package/assets/level-selector/button.ejs +2 -4
- package/assets/level-selector/list.ejs +14 -10
- package/assets/level-selector/style.scss +9 -4
- package/assets/playback-rate/list.ejs +5 -5
- package/dist/core.js +1 -2
- package/dist/index.css +1104 -1103
- package/dist/index.js +3849 -3767
- package/dist/player.d.ts +10 -17
- package/dist/plugins/index.css +1541 -1540
- package/dist/plugins/index.js +3949 -3868
- package/docs/api/player.mediacontrol.md +8 -36
- package/docs/api/player.mediacontrol.toggleelement.md +72 -0
- package/docs/api/player.mediacontrolelement.md +1 -1
- package/lib/playback/dash-playback/DashPlayback.d.ts.map +1 -1
- package/lib/playback/dash-playback/DashPlayback.js +0 -1
- package/lib/plugins/bottom-gear/BottomGear.d.ts +65 -14
- package/lib/plugins/bottom-gear/BottomGear.d.ts.map +1 -1
- package/lib/plugins/bottom-gear/BottomGear.js +113 -37
- package/lib/plugins/clappr-nerd-stats/ClapprNerdStats.d.ts +2 -3
- package/lib/plugins/clappr-nerd-stats/ClapprNerdStats.d.ts.map +1 -1
- package/lib/plugins/clappr-nerd-stats/ClapprNerdStats.js +18 -15
- package/lib/plugins/dvr-controls/DvrControls.js +1 -1
- package/lib/plugins/level-selector/LevelSelector.d.ts +8 -11
- package/lib/plugins/level-selector/LevelSelector.d.ts.map +1 -1
- package/lib/plugins/level-selector/LevelSelector.js +66 -102
- package/lib/plugins/media-control/MediaControl.d.ts +7 -5
- package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
- package/lib/plugins/media-control/MediaControl.js +37 -19
- package/lib/plugins/picture-in-picture/PictureInPicture.d.ts.map +1 -1
- package/lib/plugins/picture-in-picture/PictureInPicture.js +7 -2
- package/lib/plugins/playback-rate/PlaybackRate.d.ts +42 -14
- package/lib/plugins/playback-rate/PlaybackRate.d.ts.map +1 -1
- package/lib/plugins/playback-rate/PlaybackRate.js +101 -83
- package/lib/plugins/subtitles/ClosedCaptions.js +1 -1
- package/lib/testUtils.d.ts +1 -0
- package/lib/testUtils.d.ts.map +1 -1
- package/lib/testUtils.js +13 -0
- package/package.json +1 -1
- package/src/playback/dash-playback/DashPlayback.ts +0 -1
- package/src/plugins/bottom-gear/BottomGear.ts +162 -72
- package/src/plugins/bottom-gear/__tests__/BottomGear.test.ts +21 -5
- package/src/plugins/bottom-gear/__tests__/__snapshots__/BottomGear.test.ts.snap +5 -12
- package/src/plugins/clappr-nerd-stats/ClapprNerdStats.ts +27 -25
- package/src/plugins/dvr-controls/DvrControls.ts +1 -1
- package/src/plugins/dvr-controls/__tests__/DvrControls.test.ts +1 -1
- package/src/plugins/level-selector/LevelSelector.ts +80 -120
- package/src/plugins/level-selector/__tests__/LevelSelector.test.ts +69 -79
- package/src/plugins/level-selector/__tests__/__snapshots__/LevelSelector.test.ts.snap +38 -71
- package/src/plugins/media-control/MediaControl.ts +51 -25
- package/src/plugins/media-control/__tests__/MediaControl.test.ts +4 -4
- package/src/plugins/picture-in-picture/PictureInPicture.ts +7 -2
- package/src/plugins/playback-rate/PlaybackRate.ts +136 -108
- package/src/plugins/playback-rate/__tests__/PlaybackRate.test.ts +84 -37
- package/src/plugins/playback-rate/__tests__/__snapshots__/PlaybackRate.test.ts.snap +55 -6
- package/src/plugins/subtitles/ClosedCaptions.ts +1 -1
- package/src/plugins/subtitles/__tests__/ClosedCaptions.test.ts +1 -1
- package/src/testUtils.ts +14 -0
- package/src/typings/vitest.d.ts +1 -0
- package/temp/player.api.json +66 -94
- package/tsconfig.tsbuildinfo +1 -1
- package/docs/api/player.mediacontrol.getcenterpanel.md +0 -18
- package/docs/api/player.mediacontrol.getleftpanel.md +0 -22
- package/docs/api/player.mediacontrol.getrightpanel.md +0 -22
|
@@ -6,7 +6,7 @@ import { type QualityLevel } from '../../playback.types.js'
|
|
|
6
6
|
import { CLAPPR_VERSION } from '../../build.js'
|
|
7
7
|
import { ZeptoResult } from '../../types.js'
|
|
8
8
|
import { TemplateFunction } from '../types.js'
|
|
9
|
-
import { BottomGear } from '../bottom-gear/BottomGear.js'
|
|
9
|
+
import { BottomGear, GearEvents } from '../bottom-gear/BottomGear.js'
|
|
10
10
|
|
|
11
11
|
import buttonHtml from '../../../assets/level-selector/button.ejs'
|
|
12
12
|
import listHtml from '../../../assets/level-selector/list.ejs'
|
|
@@ -15,7 +15,7 @@ import arrowRightIcon from '../../../assets/icons/new/arrow-right.svg'
|
|
|
15
15
|
import arrowLeftIcon from '../../../assets/icons/new/arrow-left.svg'
|
|
16
16
|
import checkIcon from '../../../assets/icons/new/check.svg'
|
|
17
17
|
import '../../../assets/level-selector/style.scss'
|
|
18
|
-
import { MediaControl
|
|
18
|
+
import { MediaControl } from '../media-control/MediaControl.js'
|
|
19
19
|
|
|
20
20
|
const T = 'plugins.level_selector'
|
|
21
21
|
const VERSION = '2.19.4'
|
|
@@ -73,7 +73,9 @@ export class LevelSelector extends UICorePlugin {
|
|
|
73
73
|
|
|
74
74
|
private isHd = false
|
|
75
75
|
|
|
76
|
-
private
|
|
76
|
+
private currentText = ''
|
|
77
|
+
|
|
78
|
+
private selectedLevelId = -1
|
|
77
79
|
|
|
78
80
|
private static readonly buttonTemplate: TemplateFunction =
|
|
79
81
|
template(buttonHtml)
|
|
@@ -111,14 +113,9 @@ export class LevelSelector extends UICorePlugin {
|
|
|
111
113
|
}
|
|
112
114
|
}
|
|
113
115
|
|
|
114
|
-
private currentText = 'Auto'
|
|
115
|
-
|
|
116
|
-
private selectedLevelId = -1
|
|
117
|
-
|
|
118
116
|
override get events() {
|
|
119
117
|
return {
|
|
120
|
-
'click .gear-sub-menu_btn': '
|
|
121
|
-
'click .gear-option': 'onShowLevelSelectMenu',
|
|
118
|
+
'click .gear-sub-menu_btn': 'onSelect',
|
|
122
119
|
'click .go-back': 'goBack',
|
|
123
120
|
}
|
|
124
121
|
}
|
|
@@ -127,27 +124,29 @@ export class LevelSelector extends UICorePlugin {
|
|
|
127
124
|
* @internal
|
|
128
125
|
*/
|
|
129
126
|
override bindEvents() {
|
|
130
|
-
this.
|
|
127
|
+
this.listenToOnce(this.core, Events.CORE_READY, this.onCoreReady)
|
|
131
128
|
this.listenTo(
|
|
132
129
|
this.core,
|
|
133
130
|
Events.CORE_ACTIVE_CONTAINER_CHANGED,
|
|
134
|
-
this.
|
|
131
|
+
this.onActiveContainerChange,
|
|
135
132
|
)
|
|
136
133
|
}
|
|
137
134
|
|
|
138
135
|
private onCoreReady() {
|
|
139
|
-
trace(`${T} onCoreReady`)
|
|
140
|
-
const
|
|
141
|
-
assert(
|
|
142
|
-
|
|
136
|
+
trace(`${T} onCoreReady`)
|
|
137
|
+
const gear = this.core.getPlugin('bottom_gear') as BottomGear
|
|
138
|
+
assert(gear, 'bottom_gear plugin is required')
|
|
139
|
+
|
|
140
|
+
this.currentText = this.core.i18n.t('auto')
|
|
141
|
+
this.listenTo(gear, GearEvents.RENDERED, this.onGearRendered)
|
|
143
142
|
}
|
|
144
143
|
|
|
145
144
|
private onGearRendered() {
|
|
146
|
-
trace(`${T} onGearRendered`)
|
|
147
|
-
this.
|
|
145
|
+
trace(`${T} onGearRendered`)
|
|
146
|
+
this.render()
|
|
148
147
|
}
|
|
149
148
|
|
|
150
|
-
private
|
|
149
|
+
private onActiveContainerChange() {
|
|
151
150
|
this.removeAuto = false
|
|
152
151
|
this.isHd = false
|
|
153
152
|
|
|
@@ -156,7 +155,7 @@ export class LevelSelector extends UICorePlugin {
|
|
|
156
155
|
this.listenTo(
|
|
157
156
|
activePlayback,
|
|
158
157
|
Events.PLAYBACK_LEVELS_AVAILABLE,
|
|
159
|
-
this.
|
|
158
|
+
this.onLevelsAvailable,
|
|
160
159
|
)
|
|
161
160
|
this.listenTo(
|
|
162
161
|
activePlayback,
|
|
@@ -168,31 +167,32 @@ export class LevelSelector extends UICorePlugin {
|
|
|
168
167
|
Events.PLAYBACK_LEVEL_SWITCH_END,
|
|
169
168
|
this.onLevelSwitchEnd,
|
|
170
169
|
)
|
|
171
|
-
this.listenTo(
|
|
172
|
-
activePlayback,
|
|
173
|
-
Events.PLAYBACK_BITRATE,
|
|
174
|
-
this.updateCurrentLevel,
|
|
175
|
-
)
|
|
170
|
+
this.listenTo(activePlayback, Events.PLAYBACK_BITRATE, this.onBitrate)
|
|
176
171
|
this.listenTo(activePlayback, Events.PLAYBACK_STOP, this.onStop)
|
|
177
172
|
this.listenTo(
|
|
178
173
|
activePlayback,
|
|
179
174
|
Events.PLAYBACK_HIGHDEFINITIONUPDATE,
|
|
180
175
|
(isHd: boolean) => {
|
|
181
176
|
this.isHd = isHd
|
|
182
|
-
this.
|
|
177
|
+
this.updateHd()
|
|
183
178
|
},
|
|
184
179
|
)
|
|
185
180
|
if (activePlayback.levels?.length > 0) {
|
|
186
|
-
this.
|
|
181
|
+
this.onLevelsAvailable(activePlayback.levels)
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
private updateHd() {
|
|
186
|
+
if (this.isHd) {
|
|
187
|
+
this.$el.find('.gear-option_hd-icon').removeClass('hidden')
|
|
188
|
+
} else {
|
|
189
|
+
this.$el.find('.gear-option_hd-icon').addClass('hidden')
|
|
187
190
|
}
|
|
188
191
|
}
|
|
189
192
|
|
|
190
193
|
private onStop() {
|
|
191
194
|
trace(`${T} onStop`)
|
|
192
195
|
this.listenToOnce(this.core.activePlayback, Events.PLAYBACK_PLAY, () => {
|
|
193
|
-
trace(`${T} on PLAYBACK_PLAY after stop`, {
|
|
194
|
-
selectedLevelId: this.selectedLevelId,
|
|
195
|
-
})
|
|
196
196
|
if (this.core.activePlayback.getPlaybackType() === 'live') {
|
|
197
197
|
if (this.selectedLevelId !== -1) {
|
|
198
198
|
this.core.activePlayback.currentLevel = this.selectedLevelId
|
|
@@ -222,56 +222,53 @@ export class LevelSelector extends UICorePlugin {
|
|
|
222
222
|
if (!this.shouldRender()) {
|
|
223
223
|
return this
|
|
224
224
|
}
|
|
225
|
-
|
|
226
|
-
this.
|
|
225
|
+
this.renderDropdown()
|
|
226
|
+
this.updateButton()
|
|
227
227
|
|
|
228
228
|
return this
|
|
229
229
|
}
|
|
230
230
|
|
|
231
|
-
private
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
gear?.getElement('quality')?.html(this.el)
|
|
245
|
-
}
|
|
231
|
+
private renderDropdown() {
|
|
232
|
+
this.$el.html(
|
|
233
|
+
LevelSelector.listTemplate({
|
|
234
|
+
arrowLeftIcon,
|
|
235
|
+
checkIcon,
|
|
236
|
+
current: this.selectedLevelId,
|
|
237
|
+
labels: this.levelLabels,
|
|
238
|
+
levels: this.levels,
|
|
239
|
+
maxLevel: this.maxLevel,
|
|
240
|
+
removeAuto: this.removeAuto,
|
|
241
|
+
i18n: this.core.i18n,
|
|
242
|
+
}),
|
|
243
|
+
)
|
|
246
244
|
}
|
|
247
245
|
|
|
248
|
-
private
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
gear?.setContent(this.el)
|
|
246
|
+
private updateButton() {
|
|
247
|
+
;(this.core.getPlugin('bottom_gear') as BottomGear)
|
|
248
|
+
?.addItem('quality', this.$el)
|
|
249
|
+
.html(
|
|
250
|
+
LevelSelector.buttonTemplate({
|
|
251
|
+
arrowRightIcon,
|
|
252
|
+
currentText: this.currentText,
|
|
253
|
+
isHd: this.isHd,
|
|
254
|
+
hdIcon,
|
|
255
|
+
i18n: this.core.i18n,
|
|
256
|
+
}),
|
|
257
|
+
)
|
|
261
258
|
}
|
|
262
259
|
|
|
263
260
|
private get maxLevel() {
|
|
264
261
|
const maxRes = this.core.options.levelSelector?.restrictResolution
|
|
265
262
|
return maxRes
|
|
266
|
-
? this.levels.
|
|
263
|
+
? this.levels.find(
|
|
267
264
|
(level) =>
|
|
268
265
|
(level.height > level.width ? level.width : level.height) ===
|
|
269
266
|
maxRes,
|
|
270
|
-
)
|
|
267
|
+
)?.level ?? -1
|
|
271
268
|
: -1
|
|
272
269
|
}
|
|
273
270
|
|
|
274
|
-
private
|
|
271
|
+
private onLevelsAvailable(levels: QualityLevel[]) {
|
|
275
272
|
const maxResolution = this.core.options.levelSelector?.restrictResolution
|
|
276
273
|
this.levels = levels
|
|
277
274
|
this.makeLevelsLabels()
|
|
@@ -286,77 +283,54 @@ export class LevelSelector extends UICorePlugin {
|
|
|
286
283
|
.pop()
|
|
287
284
|
this.setLevel(initialLevel?.level ?? 0)
|
|
288
285
|
}
|
|
289
|
-
this.
|
|
286
|
+
this.render()
|
|
290
287
|
}
|
|
291
288
|
|
|
292
289
|
private makeLevelsLabels() {
|
|
293
290
|
const labels = this.core.options.levelSelector?.labels ?? {}
|
|
294
291
|
this.levelLabels = []
|
|
295
292
|
|
|
296
|
-
for (
|
|
297
|
-
const level = this.levels[i]
|
|
293
|
+
for (const level of this.levels) {
|
|
298
294
|
const ll = level.width > level.height ? level.height : level.width
|
|
299
295
|
const label = labels[ll] || `${ll}p`
|
|
300
296
|
this.levelLabels.push(label)
|
|
301
297
|
}
|
|
302
298
|
}
|
|
303
299
|
|
|
304
|
-
private
|
|
300
|
+
private onSelect(event: MouseEvent) {
|
|
305
301
|
const selectedLevel = parseInt(
|
|
306
302
|
(event.currentTarget as HTMLElement)?.dataset?.id ?? '-1',
|
|
307
303
|
10,
|
|
308
304
|
)
|
|
309
305
|
this.setLevel(selectedLevel)
|
|
306
|
+
|
|
310
307
|
event.stopPropagation()
|
|
308
|
+
event.preventDefault()
|
|
311
309
|
return false
|
|
312
310
|
}
|
|
313
311
|
|
|
314
312
|
private goBack() {
|
|
315
313
|
trace(`${T} goBack`)
|
|
316
|
-
this.
|
|
317
|
-
setTimeout(() => {
|
|
318
|
-
this.core.getPlugin('bottom_gear').refresh()
|
|
319
|
-
}, 0);
|
|
314
|
+
this.core.getPlugin('bottom_gear').refresh()
|
|
320
315
|
}
|
|
321
316
|
|
|
322
317
|
private setLevel(index: number) {
|
|
323
|
-
trace(`${T} setIndexLevel`, { index })
|
|
324
318
|
this.selectedLevelId = index
|
|
325
|
-
if (!this.core.activePlayback) {
|
|
326
|
-
return
|
|
327
|
-
}
|
|
328
|
-
if (this.core.activePlayback.currentLevel === this.selectedLevelId) {
|
|
329
|
-
return
|
|
330
|
-
}
|
|
331
319
|
this.core.activePlayback.currentLevel = this.selectedLevelId
|
|
332
|
-
|
|
333
|
-
try {
|
|
334
|
-
this.highlightCurrentLevel()
|
|
335
|
-
} catch (error) {
|
|
336
|
-
reportError(error)
|
|
337
|
-
}
|
|
338
|
-
this.deferRender()
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
private onShowLevelSelectMenu() {
|
|
342
|
-
trace(`${T} onShowLevelSelectMenu`)
|
|
343
|
-
this.isOpen = true
|
|
344
|
-
this.renderDropdown()
|
|
345
320
|
this.highlightCurrentLevel()
|
|
346
321
|
}
|
|
347
322
|
|
|
348
323
|
private allLevelElements() {
|
|
349
|
-
return this.$('
|
|
324
|
+
return this.$('#level-selector-menu li') as ZeptoResult
|
|
350
325
|
}
|
|
351
326
|
|
|
352
327
|
private levelElement(id = -1) {
|
|
353
328
|
return (
|
|
354
|
-
this.$(
|
|
329
|
+
this.$(`#level-selector-menu a[data-id="${id}"]`) as ZeptoResult
|
|
355
330
|
).parent()
|
|
356
331
|
}
|
|
357
332
|
|
|
358
333
|
private onLevelSwitchStart() {
|
|
359
|
-
this.core.activePlayback.trigger('playback:level:select:start')
|
|
360
334
|
this.levelElement(this.selectedLevelId).addClass('changing')
|
|
361
335
|
}
|
|
362
336
|
|
|
@@ -365,25 +339,22 @@ export class LevelSelector extends UICorePlugin {
|
|
|
365
339
|
}
|
|
366
340
|
|
|
367
341
|
private updateText(level: number) {
|
|
368
|
-
if (level === undefined || isNaN(level)) {
|
|
369
|
-
return
|
|
370
|
-
}
|
|
371
342
|
this.currentText = this.getLevelLabel(level)
|
|
372
|
-
this.
|
|
343
|
+
this.updateButton()
|
|
373
344
|
}
|
|
374
345
|
|
|
375
346
|
private getLevelLabel(id: number): string {
|
|
376
|
-
if (id
|
|
377
|
-
return '
|
|
347
|
+
if (id < 0) {
|
|
348
|
+
return this.core.i18n.t('auto')
|
|
378
349
|
}
|
|
379
350
|
const index = this.levels.findIndex((l) => l.level === id)
|
|
380
351
|
if (index < 0) {
|
|
381
|
-
return '
|
|
352
|
+
return this.core.i18n.t('auto')
|
|
382
353
|
}
|
|
383
354
|
return this.levelLabels[index] ?? formatLevelLabel(this.levels[index])
|
|
384
355
|
}
|
|
385
356
|
|
|
386
|
-
private
|
|
357
|
+
private onBitrate(info: QualityLevel) {
|
|
387
358
|
trace(`${T} updateCurrentLevel`, { info })
|
|
388
359
|
this.highlightCurrentLevel()
|
|
389
360
|
}
|
|
@@ -392,34 +363,23 @@ export class LevelSelector extends UICorePlugin {
|
|
|
392
363
|
trace(`${T} highlightCurrentLevel`, {
|
|
393
364
|
selectedLevelId: this.selectedLevelId,
|
|
394
365
|
})
|
|
395
|
-
this.allLevelElements()
|
|
396
|
-
|
|
366
|
+
this.allLevelElements()
|
|
367
|
+
.removeClass('current')
|
|
368
|
+
.find('a')
|
|
369
|
+
.removeClass('gcore-skin-active')
|
|
397
370
|
|
|
398
371
|
const currentLevelElement = this.levelElement(this.selectedLevelId)
|
|
399
372
|
|
|
400
|
-
currentLevelElement
|
|
401
|
-
|
|
373
|
+
currentLevelElement
|
|
374
|
+
.addClass('current')
|
|
375
|
+
.find('a')
|
|
376
|
+
.addClass('gcore-skin-active')
|
|
402
377
|
|
|
403
378
|
this.updateText(this.selectedLevelId)
|
|
404
379
|
}
|
|
405
|
-
|
|
406
|
-
private deferRender = debounce(() => this.render(), 0)
|
|
407
380
|
}
|
|
408
381
|
|
|
409
382
|
function formatLevelLabel(level: QualityLevel): string {
|
|
410
383
|
const h = level.width > level.height ? level.height : level.width
|
|
411
384
|
return `${h}p`
|
|
412
385
|
}
|
|
413
|
-
|
|
414
|
-
function debounce(fn: () => void, wait: number) {
|
|
415
|
-
let timerId: ReturnType<typeof setTimeout> | null = null
|
|
416
|
-
return function () {
|
|
417
|
-
if (timerId !== null) {
|
|
418
|
-
clearTimeout(timerId)
|
|
419
|
-
}
|
|
420
|
-
timerId = setTimeout(() => {
|
|
421
|
-
timerId = null
|
|
422
|
-
fn()
|
|
423
|
-
}, wait)
|
|
424
|
-
}
|
|
425
|
-
}
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
|
2
|
-
import {
|
|
3
|
-
import FakeTimers from '@sinonjs/fake-timers'
|
|
4
|
-
import { Logger, LogTracer, setTracer } from '@gcorevideo/utils'
|
|
2
|
+
import { Events } from '@clappr/core'
|
|
5
3
|
import { LevelSelector } from '../LevelSelector.js'
|
|
6
4
|
import {
|
|
5
|
+
createMockBottomGear,
|
|
7
6
|
createMockCore,
|
|
8
7
|
createMockMediaControl,
|
|
9
|
-
createMockPlayback,
|
|
10
8
|
} from '../../../testUtils.js'
|
|
11
|
-
import {
|
|
9
|
+
import { GearEvents } from '../../bottom-gear/BottomGear.js'
|
|
10
|
+
// import { Logger, LogTracer, setTracer } from '@gcorevideo/utils'
|
|
12
11
|
|
|
13
|
-
setTracer(new LogTracer('LevelSelector.test'))
|
|
14
|
-
Logger.enable('*')
|
|
12
|
+
// setTracer(new LogTracer('LevelSelector.test'))
|
|
13
|
+
// Logger.enable('*')
|
|
15
14
|
|
|
16
15
|
const LEVELS = [
|
|
17
16
|
{
|
|
@@ -33,28 +32,20 @@ const LEVELS = [
|
|
|
33
32
|
bitrate: 250000,
|
|
34
33
|
},
|
|
35
34
|
]
|
|
35
|
+
|
|
36
36
|
describe('LevelSelector', () => {
|
|
37
|
-
let clock: FakeTimers.InstalledClock
|
|
38
37
|
let core: any
|
|
39
38
|
let levelSelector: LevelSelector
|
|
40
|
-
let
|
|
41
|
-
let
|
|
42
|
-
let bottomGear: UICorePlugin | null
|
|
43
|
-
beforeEach(() => {
|
|
44
|
-
clock = FakeTimers.install()
|
|
45
|
-
})
|
|
46
|
-
afterEach(() => {
|
|
47
|
-
clock.uninstall()
|
|
48
|
-
})
|
|
39
|
+
let mediaControl: any
|
|
40
|
+
let bottomGear: any
|
|
49
41
|
describe('basically', () => {
|
|
50
42
|
beforeEach(() => {
|
|
51
43
|
core = createMockCore({
|
|
52
44
|
levelSelector: {
|
|
53
45
|
// restrictResolution: 360,
|
|
54
|
-
labels: {
|
|
46
|
+
labels: { 720: 'HD', 1080: 'Full HD' },
|
|
55
47
|
},
|
|
56
48
|
})
|
|
57
|
-
activePlayback = core.activePlayback
|
|
58
49
|
core.getPlugin.mockImplementation((name: string) => {
|
|
59
50
|
if (name === 'media_control') {
|
|
60
51
|
return mediaControl
|
|
@@ -65,43 +56,45 @@ describe('LevelSelector', () => {
|
|
|
65
56
|
return null
|
|
66
57
|
})
|
|
67
58
|
mediaControl = createMockMediaControl(core)
|
|
68
|
-
bottomGear =
|
|
59
|
+
bottomGear = createMockBottomGear(core)
|
|
69
60
|
levelSelector = new LevelSelector(core)
|
|
70
61
|
})
|
|
71
62
|
describe('initially', () => {
|
|
72
|
-
beforeEach(
|
|
73
|
-
core.emit(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
63
|
+
beforeEach(() => {
|
|
64
|
+
core.emit(Events.CORE_READY)
|
|
65
|
+
core.emit(Events.CORE_ACTIVE_CONTAINER_CHANGED)
|
|
66
|
+
bottomGear.trigger(GearEvents.RENDERED)
|
|
67
|
+
core.activePlayback.emit(Events.PLAYBACK_LEVELS_AVAILABLE, LEVELS)
|
|
77
68
|
})
|
|
78
69
|
it('should render proper level label', () => {
|
|
79
|
-
|
|
80
|
-
|
|
70
|
+
expect(
|
|
71
|
+
bottomGear.$el.find('[data-quality]').text(),
|
|
72
|
+
// @ts-ignore
|
|
73
|
+
).toMatchQualityLevelLabel('auto')
|
|
81
74
|
})
|
|
82
75
|
})
|
|
83
76
|
describe.each([
|
|
84
|
-
['auto', LEVELS, -1, '
|
|
77
|
+
['auto', LEVELS, -1, 'auto'],
|
|
85
78
|
['standard label', LEVELS, 0, '360p'],
|
|
86
79
|
['custom label', LEVELS, 1, 'HD'],
|
|
87
80
|
])('%s', (_, levels, current, label) => {
|
|
88
|
-
beforeEach(
|
|
89
|
-
core.emit(
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
activePlayback.emit(
|
|
93
|
-
await clock.tickAsync(1)
|
|
94
|
-
levelSelector.$el.find('.gear-option').click()
|
|
95
|
-
await clock.tickAsync(1)
|
|
81
|
+
beforeEach(() => {
|
|
82
|
+
core.emit(Events.CORE_READY)
|
|
83
|
+
core.emit(Events.CORE_ACTIVE_CONTAINER_CHANGED)
|
|
84
|
+
bottomGear.trigger(GearEvents.RENDERED)
|
|
85
|
+
core.activePlayback.emit(Events.PLAYBACK_LEVELS_AVAILABLE, levels)
|
|
96
86
|
levelSelector.$el
|
|
97
|
-
.find(
|
|
87
|
+
.find(`#level-selector-menu [data-id="${current}"]`)
|
|
98
88
|
.click()
|
|
99
|
-
await clock.tickAsync(1)
|
|
100
89
|
})
|
|
101
|
-
it('should render the proper level
|
|
102
|
-
expect(
|
|
90
|
+
it('should render the proper level label', () => {
|
|
91
|
+
expect(
|
|
92
|
+
bottomGear.$el.find('[data-quality]').text(),
|
|
93
|
+
// @ts-ignore
|
|
94
|
+
).toMatchQualityLevelLabel(label)
|
|
103
95
|
})
|
|
104
96
|
it('should render the selected level', () => {
|
|
97
|
+
expect(levelSelector.el.innerHTML).toMatchSnapshot()
|
|
105
98
|
expect(
|
|
106
99
|
levelSelector.$el.find('ul.gear-sub-menu .current')[0].textContent,
|
|
107
100
|
// @ts-ignore
|
|
@@ -111,15 +104,14 @@ describe('LevelSelector', () => {
|
|
|
111
104
|
})
|
|
112
105
|
describe('options.restrictResolution', () => {
|
|
113
106
|
beforeEach(() => {
|
|
114
|
-
let mediaControl: UICorePlugin | null = null
|
|
115
|
-
let bottomGear: UICorePlugin | null = null
|
|
116
107
|
core = createMockCore({
|
|
117
108
|
levelSelector: {
|
|
118
109
|
restrictResolution: 360,
|
|
119
|
-
labels: { 360: '360p', 720: '720p' },
|
|
110
|
+
labels: { 360: '360p', 720: '720p', 1080: '1080p' },
|
|
120
111
|
},
|
|
121
112
|
})
|
|
122
|
-
|
|
113
|
+
mediaControl = createMockMediaControl(core)
|
|
114
|
+
bottomGear = createMockBottomGear(core)
|
|
123
115
|
core.getPlugin.mockImplementation((name: string) => {
|
|
124
116
|
if (name === 'media_control') {
|
|
125
117
|
return mediaControl
|
|
@@ -130,30 +122,31 @@ describe('LevelSelector', () => {
|
|
|
130
122
|
return null
|
|
131
123
|
})
|
|
132
124
|
mediaControl = createMockMediaControl(core)
|
|
133
|
-
bottomGear =
|
|
125
|
+
bottomGear = createMockBottomGear(core)
|
|
134
126
|
levelSelector = new LevelSelector(core)
|
|
127
|
+
core.emit(Events.CORE_READY)
|
|
128
|
+
core.emit(Events.CORE_ACTIVE_CONTAINER_CHANGED, core.activeContainer)
|
|
129
|
+
bottomGear.trigger(GearEvents.RENDERED)
|
|
135
130
|
})
|
|
136
|
-
describe('
|
|
131
|
+
describe('initially', () => {
|
|
137
132
|
beforeEach(async () => {
|
|
138
|
-
core.emit(
|
|
139
|
-
await clock.tickAsync(1)
|
|
140
|
-
activePlayback.emit('playback:levels:available', LEVELS)
|
|
141
|
-
await clock.tickAsync(1)
|
|
133
|
+
core.activePlayback.emit(Events.PLAYBACK_LEVELS_AVAILABLE, LEVELS)
|
|
142
134
|
})
|
|
143
135
|
it('should render the restricted quality level label', () => {
|
|
136
|
+
expect(bottomGear.$el.find('[data-quality]').html()).toMatchSnapshot()
|
|
144
137
|
expect(
|
|
145
|
-
|
|
138
|
+
bottomGear.$el.find('[data-quality]').text(),
|
|
146
139
|
// @ts-ignore
|
|
147
140
|
).toMatchQualityLevelLabel('360p')
|
|
148
|
-
|
|
149
|
-
|
|
141
|
+
expect(
|
|
142
|
+
levelSelector.$el.find('#level-selector-menu .current').text(),
|
|
143
|
+
// @ts-ignore
|
|
144
|
+
).toMatchQualityLevelOption('360p')
|
|
150
145
|
})
|
|
151
146
|
})
|
|
152
147
|
describe('given vertical video format levels', () => {
|
|
153
|
-
beforeEach(
|
|
154
|
-
core.emit(
|
|
155
|
-
await clock.tickAsync(1)
|
|
156
|
-
activePlayback.emit('playback:levels:available', [
|
|
148
|
+
beforeEach(() => {
|
|
149
|
+
core.activePlayback.emit(Events.PLAYBACK_LEVELS_AVAILABLE, [
|
|
157
150
|
{
|
|
158
151
|
level: 0,
|
|
159
152
|
width: 360,
|
|
@@ -168,22 +161,31 @@ describe('LevelSelector', () => {
|
|
|
168
161
|
},
|
|
169
162
|
{
|
|
170
163
|
level: 2,
|
|
171
|
-
width:
|
|
172
|
-
height:
|
|
164
|
+
width: 1080,
|
|
165
|
+
height: 1920,
|
|
173
166
|
bitrate: 250000,
|
|
174
167
|
},
|
|
175
168
|
])
|
|
176
|
-
await clock.tickAsync(1)
|
|
177
|
-
levelSelector.$el.find('.gear-option').click()
|
|
178
|
-
await clock.tickAsync(1)
|
|
179
169
|
})
|
|
180
170
|
it('should recognize vertical orientation', () => {
|
|
181
171
|
expect(levelSelector.el.innerHTML).toMatchSnapshot()
|
|
182
|
-
expect(
|
|
172
|
+
expect(
|
|
173
|
+
levelSelector.$el.find('#level-selector-menu [data-id]:eq(0)').text(),
|
|
174
|
+
// @ts-ignore
|
|
175
|
+
).toMatchQualityLevelOption('1080p')
|
|
176
|
+
expect(
|
|
177
|
+
levelSelector.$el.find('#level-selector-menu [data-id]:eq(1)').text(),
|
|
178
|
+
// @ts-ignore
|
|
179
|
+
).toMatchQualityLevelOption('720p')
|
|
180
|
+
expect(
|
|
181
|
+
levelSelector.$el.find('#level-selector-menu [data-id]:eq(2)').text(),
|
|
182
|
+
// @ts-ignore
|
|
183
|
+
).toMatchQualityLevelOption('360p')
|
|
183
184
|
})
|
|
184
185
|
it('should properly apply the restriction', () => {
|
|
185
186
|
expect(
|
|
186
|
-
levelSelector.$el.find('li:not(.
|
|
187
|
+
levelSelector.$el.find('#level-selector-menu li:not(.disabled)')[0]
|
|
188
|
+
.textContent,
|
|
187
189
|
// @ts-ignore
|
|
188
190
|
).toMatchQualityLevelOption('360p')
|
|
189
191
|
})
|
|
@@ -195,11 +197,11 @@ expect.extend({
|
|
|
195
197
|
toMatchQualityLevelLabel(received, expected) {
|
|
196
198
|
const { isNot } = this
|
|
197
199
|
const rendered = received
|
|
198
|
-
.replace(
|
|
200
|
+
.replace(/\/assets\/.*\.svg/g, '')
|
|
199
201
|
.replace(/\s+/g, ' ')
|
|
200
202
|
.trim()
|
|
201
203
|
return {
|
|
202
|
-
pass: rendered.includes(`
|
|
204
|
+
pass: rendered.includes(`quality ${expected}`),
|
|
203
205
|
message: () =>
|
|
204
206
|
`Quality label must${
|
|
205
207
|
isNot ? ' not' : ''
|
|
@@ -209,7 +211,7 @@ expect.extend({
|
|
|
209
211
|
toMatchQualityLevelOption(received, expected) {
|
|
210
212
|
const { isNot } = this
|
|
211
213
|
const rendered = received
|
|
212
|
-
.replace(
|
|
214
|
+
.replace(/\/assets\/.*\.svg/g, '')
|
|
213
215
|
.replace(/\s+/g, ' ')
|
|
214
216
|
.trim()
|
|
215
217
|
return {
|
|
@@ -221,15 +223,3 @@ expect.extend({
|
|
|
221
223
|
}
|
|
222
224
|
},
|
|
223
225
|
})
|
|
224
|
-
|
|
225
|
-
function createBottomGear(core: any) {
|
|
226
|
-
const bottomGear = new UICorePlugin(core)
|
|
227
|
-
const elemets = {
|
|
228
|
-
quality: $(document.createElement('div')),
|
|
229
|
-
}
|
|
230
|
-
// @ts-ignore
|
|
231
|
-
bottomGear.getElement = vi.fn().mockImplementation((name) => elemets[name])
|
|
232
|
-
// @ts-ignore
|
|
233
|
-
bottomGear.setContent = vi.fn()
|
|
234
|
-
return bottomGear
|
|
235
|
-
}
|