@gcorevideo/player 2.22.2 → 2.22.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 +4 -2
- package/assets/audio-selector/track-selector.ejs +2 -2
- package/assets/media-control/container.scss +1 -1
- package/assets/spinner-three-bounce/spinner.scss +1 -1
- package/dist/core.js +1 -1
- package/dist/index.css +1374 -1372
- package/dist/index.js +76 -95
- package/dist/player.d.ts +6 -3
- package/dist/plugins/index.css +571 -569
- package/dist/plugins/index.js +47 -59
- package/docs/api/player.md +1 -1
- package/docs/api/player.sourcecontroller.md +1 -1
- package/docs/api/player.spinnerthreebounce.md +1 -1
- package/lib/index.plugins.d.ts +2 -0
- package/lib/index.plugins.d.ts.map +1 -1
- package/lib/index.plugins.js +2 -0
- package/lib/plugins/audio-selector/AudioSelector.d.ts +3 -9
- package/lib/plugins/audio-selector/AudioSelector.d.ts.map +1 -1
- package/lib/plugins/audio-selector/AudioSelector.js +34 -57
- package/lib/plugins/spinner-three-bounce/SpinnerThreeBounce.d.ts +1 -0
- package/lib/plugins/spinner-three-bounce/SpinnerThreeBounce.d.ts.map +1 -1
- package/lib/plugins/spinner-three-bounce/SpinnerThreeBounce.js +1 -0
- package/lib/testUtils.d.ts +2 -0
- package/lib/testUtils.d.ts.map +1 -1
- package/lib/testUtils.js +2 -0
- package/package.json +1 -1
- package/src/index.plugins.ts +2 -0
- package/src/plugins/audio-selector/AudioSelector.ts +36 -72
- package/src/plugins/audio-selector/__tests__/AudioSelector.test.ts +176 -0
- package/src/plugins/audio-selector/__tests__/__snapshots__/AudioSelector.test.ts.snap +67 -0
- package/src/plugins/spinner-three-bounce/SpinnerThreeBounce.ts +1 -0
- package/src/testUtils.ts +2 -0
- package/temp/player.api.json +2 -2
- package/tsconfig.tsbuildinfo +1 -1
- package/assets/bottom-gear/bottomgear copy.ejs +0 -10
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Events, UICorePlugin, template } from '@clappr/core'
|
|
2
2
|
import { AudioTrack } from '@clappr/core/types/base/playback/playback.js'
|
|
3
|
-
import { trace } from '@gcorevideo/utils'
|
|
4
3
|
import assert from 'assert'
|
|
5
4
|
|
|
6
5
|
import { CLAPPR_VERSION } from '../../build.js'
|
|
@@ -11,9 +10,9 @@ import audioArrow from '../../../assets/icons/old/quality-arrow.svg'
|
|
|
11
10
|
import { ZeptoResult } from '../../types.js'
|
|
12
11
|
import { MediaControl } from '../media-control/MediaControl.js'
|
|
13
12
|
|
|
14
|
-
const VERSION: string = '
|
|
13
|
+
const VERSION: string = '2.22.4'
|
|
15
14
|
|
|
16
|
-
const T = 'plugins.
|
|
15
|
+
// const T = 'plugins.audiotracks'
|
|
17
16
|
|
|
18
17
|
/**
|
|
19
18
|
* `PLUGIN` that makes possible to switch audio tracks via the media control UI.
|
|
@@ -25,7 +24,7 @@ const T = 'plugins.audio_selector'
|
|
|
25
24
|
*
|
|
26
25
|
* - {@link MediaControl}
|
|
27
26
|
*/
|
|
28
|
-
export class
|
|
27
|
+
export class AudioTracks extends UICorePlugin {
|
|
29
28
|
private currentTrack: AudioTrack | null = null
|
|
30
29
|
|
|
31
30
|
private tracks: AudioTrack[] = []
|
|
@@ -34,7 +33,7 @@ export class AudioSelector extends UICorePlugin {
|
|
|
34
33
|
* @internal
|
|
35
34
|
*/
|
|
36
35
|
get name() {
|
|
37
|
-
return 'audio_selector'
|
|
36
|
+
return 'audio_selector' // TODO rename to audiotracks
|
|
38
37
|
}
|
|
39
38
|
|
|
40
39
|
/**
|
|
@@ -59,7 +58,6 @@ export class AudioSelector extends UICorePlugin {
|
|
|
59
58
|
override get attributes() {
|
|
60
59
|
return {
|
|
61
60
|
class: 'media-control-audiotracks',
|
|
62
|
-
|
|
63
61
|
}
|
|
64
62
|
}
|
|
65
63
|
|
|
@@ -69,7 +67,7 @@ export class AudioSelector extends UICorePlugin {
|
|
|
69
67
|
override get events() {
|
|
70
68
|
return {
|
|
71
69
|
'click [data-audiotracks-select]': 'onTrackSelect',
|
|
72
|
-
'click
|
|
70
|
+
'click #audiotracks-button': 'toggleContextMenu',
|
|
73
71
|
}
|
|
74
72
|
}
|
|
75
73
|
|
|
@@ -77,7 +75,7 @@ export class AudioSelector extends UICorePlugin {
|
|
|
77
75
|
* @internal
|
|
78
76
|
*/
|
|
79
77
|
override bindEvents() {
|
|
80
|
-
this.
|
|
78
|
+
this.listenToOnce(this.core, Events.CORE_READY, this.onCoreReady)
|
|
81
79
|
this.listenTo(
|
|
82
80
|
this.core,
|
|
83
81
|
Events.CORE_ACTIVE_CONTAINER_CHANGED,
|
|
@@ -86,41 +84,30 @@ export class AudioSelector extends UICorePlugin {
|
|
|
86
84
|
}
|
|
87
85
|
|
|
88
86
|
private onCoreReady() {
|
|
89
|
-
trace(`${T} onCoreReady`)
|
|
90
87
|
const mediaControl = this.core.getPlugin('media_control')
|
|
91
88
|
assert(mediaControl, 'media_control plugin is required')
|
|
92
|
-
this.listenTo(mediaControl, Events.MEDIACONTROL_RENDERED,
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
this.hideSelectTrackMenu,
|
|
97
|
-
)
|
|
89
|
+
this.listenTo(mediaControl, Events.MEDIACONTROL_RENDERED, () => {
|
|
90
|
+
mediaControl.putElement('audiotracks', this.$el)
|
|
91
|
+
})
|
|
92
|
+
this.listenTo(mediaControl, Events.MEDIACONTROL_HIDE, this.hideMenu)
|
|
98
93
|
}
|
|
99
94
|
|
|
100
|
-
private
|
|
101
|
-
trace(`${T} bindPlaybackEvents`)
|
|
95
|
+
private onActiveContainerChanged() {
|
|
102
96
|
this.currentTrack = null
|
|
103
|
-
this.listenTo(this.core.activePlayback, Events.PLAYBACK_STOP, this.onStop)
|
|
104
|
-
this.setupAudioTrackListeners()
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
private setupAudioTrackListeners() {
|
|
108
97
|
this.listenTo(
|
|
109
|
-
this.core.
|
|
110
|
-
Events.
|
|
98
|
+
this.core.activeContainer,
|
|
99
|
+
Events.CONTAINER_AUDIO_AVAILABLE,
|
|
111
100
|
(tracks: AudioTrack[]) => {
|
|
112
|
-
trace(`${T} on PLAYBACK_AUDIO_AVAILABLE`, { audioTracks: tracks })
|
|
113
101
|
this.currentTrack =
|
|
114
|
-
tracks.find((track) => track.kind === 'main') ?? null
|
|
115
|
-
this.
|
|
102
|
+
tracks.find((track) => track.kind === 'main') ?? null // TODO test
|
|
103
|
+
this.tracks = tracks
|
|
104
|
+
this.render()
|
|
116
105
|
},
|
|
117
106
|
)
|
|
118
|
-
|
|
119
107
|
this.listenTo(
|
|
120
|
-
this.core.
|
|
121
|
-
Events.
|
|
108
|
+
this.core.activeContainer,
|
|
109
|
+
Events.CONTAINER_AUDIO_CHANGED,
|
|
122
110
|
(track: AudioTrack) => {
|
|
123
|
-
trace(`${T} PLAYBACK_AUDIO_CHANGED`, { audioTrack: track })
|
|
124
111
|
this.currentTrack = track
|
|
125
112
|
this.highlightCurrentTrack()
|
|
126
113
|
this.buttonElement().removeClass('changing')
|
|
@@ -129,24 +116,10 @@ export class AudioSelector extends UICorePlugin {
|
|
|
129
116
|
)
|
|
130
117
|
}
|
|
131
118
|
|
|
132
|
-
private onStop() {
|
|
133
|
-
trace(`${T} onStop`)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
private onActiveContainerChanged() {
|
|
137
|
-
trace(`${T} onActiveContainerChanged`)
|
|
138
|
-
this.bindPlaybackEvents()
|
|
139
|
-
}
|
|
140
|
-
|
|
141
119
|
private shouldRender() {
|
|
142
|
-
|
|
143
|
-
return false
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
this.tracks = this.core.activePlayback.audioTracks
|
|
147
|
-
|
|
120
|
+
// Render is called from the parent class constructor so tracks aren't available
|
|
148
121
|
// Only care if we have at least 2 to choose from
|
|
149
|
-
return this.tracks
|
|
122
|
+
return this.tracks?.length > 1
|
|
150
123
|
}
|
|
151
124
|
|
|
152
125
|
/**
|
|
@@ -159,52 +132,40 @@ export class AudioSelector extends UICorePlugin {
|
|
|
159
132
|
|
|
160
133
|
const mediaControl = this.core.getPlugin('media_control') as MediaControl
|
|
161
134
|
this.$el.html(
|
|
162
|
-
|
|
135
|
+
AudioTracks.template({
|
|
136
|
+
tracks: this.tracks,
|
|
137
|
+
title: this.getTitle(),
|
|
138
|
+
icon: audioArrow,
|
|
139
|
+
}),
|
|
163
140
|
)
|
|
164
|
-
this.$('.audio-arrow').append(audioArrow)
|
|
165
|
-
mediaControl.putElement('audiotracks', this.el)
|
|
166
|
-
|
|
167
141
|
this.updateText()
|
|
168
142
|
this.highlightCurrentTrack()
|
|
169
143
|
|
|
170
144
|
return this
|
|
171
145
|
}
|
|
172
146
|
|
|
173
|
-
private fillTracks(tracks: AudioTrack[]) {
|
|
174
|
-
this.tracks = tracks
|
|
175
|
-
this.render()
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
private findTrackBy(id: string) {
|
|
179
|
-
return this.tracks.find((track) => track.id === id)
|
|
180
|
-
}
|
|
181
|
-
|
|
182
147
|
private onTrackSelect(event: MouseEvent) {
|
|
183
148
|
const id = (event.target as HTMLElement)?.dataset?.audiotracksSelect
|
|
184
149
|
if (id) {
|
|
185
150
|
this.selectAudioTrack(id)
|
|
186
151
|
}
|
|
187
|
-
this.
|
|
152
|
+
this.hideMenu()
|
|
188
153
|
event.stopPropagation()
|
|
189
154
|
return false
|
|
190
155
|
}
|
|
191
156
|
|
|
192
157
|
private selectAudioTrack(id: string) {
|
|
193
158
|
this.startTrackSwitch()
|
|
194
|
-
this.core.
|
|
159
|
+
this.core.activeContainer.switchAudioTrack(id)
|
|
195
160
|
this.updateText()
|
|
196
161
|
}
|
|
197
162
|
|
|
198
|
-
private
|
|
199
|
-
this.
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
private hideSelectTrackMenu() {
|
|
203
|
-
;(this.$('ul') as ZeptoResult).hide()
|
|
163
|
+
private hideMenu() {
|
|
164
|
+
this.$el.find('#audiotracks-select').addClass('hidden')
|
|
204
165
|
}
|
|
205
166
|
|
|
206
167
|
private toggleContextMenu() {
|
|
207
|
-
|
|
168
|
+
this.$el.find('#audiotracks-select').toggleClass('hidden')
|
|
208
169
|
}
|
|
209
170
|
|
|
210
171
|
private buttonElement(): ZeptoResult {
|
|
@@ -218,14 +179,17 @@ export class AudioSelector extends UICorePlugin {
|
|
|
218
179
|
private trackElement(id?: string): ZeptoResult {
|
|
219
180
|
return (
|
|
220
181
|
this.$(
|
|
221
|
-
'
|
|
222
|
-
(id !== undefined ?
|
|
182
|
+
'#audiotracks-select a' +
|
|
183
|
+
(id !== undefined ? `[data-audiotracks-select="${id}"]` : ''),
|
|
223
184
|
) as ZeptoResult
|
|
224
185
|
).parent()
|
|
225
186
|
}
|
|
226
187
|
|
|
227
188
|
private getTitle(): string {
|
|
228
|
-
|
|
189
|
+
if (!this.currentTrack) {
|
|
190
|
+
return ''
|
|
191
|
+
}
|
|
192
|
+
return this.currentTrack.label || this.currentTrack.language
|
|
229
193
|
}
|
|
230
194
|
|
|
231
195
|
private startTrackSwitch() {
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
import { Events } from '@clappr/core'
|
|
3
|
+
|
|
4
|
+
import { AudioTracks } from '../AudioSelector'
|
|
5
|
+
|
|
6
|
+
import { createMockCore, createMockMediaControl } from '../../../testUtils'
|
|
7
|
+
// import { LogTracer, Logger, setTracer } from '@gcorevideo/utils'
|
|
8
|
+
|
|
9
|
+
// Logger.enable('*')
|
|
10
|
+
// setTracer(new LogTracer('AudioSelector.test'))
|
|
11
|
+
|
|
12
|
+
const TRACKS = [
|
|
13
|
+
{ id: '1', label: 'English', language: 'en', track: {} },
|
|
14
|
+
{ id: '2', label: 'Spanish', language: 'es', track: {} },
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
describe('AudioSelector', () => {
|
|
18
|
+
let core: any
|
|
19
|
+
let mediaControl: any
|
|
20
|
+
let audioSelector: AudioTracks
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
core = createMockCore()
|
|
23
|
+
mediaControl = createMockMediaControl(core)
|
|
24
|
+
core.getPlugin = vi.fn().mockImplementation((name: string) => {
|
|
25
|
+
if (name === 'media_control') return mediaControl
|
|
26
|
+
return null
|
|
27
|
+
})
|
|
28
|
+
audioSelector = new AudioTracks(core)
|
|
29
|
+
core.emit(Events.CORE_READY)
|
|
30
|
+
core.emit(Events.CORE_ACTIVE_CONTAINER_CHANGED, core.activeContainer)
|
|
31
|
+
})
|
|
32
|
+
describe('before media control is rendererd', () => {
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
emitTracksAvailable(core, TRACKS)
|
|
35
|
+
})
|
|
36
|
+
it('should not attach to the media control', () => {
|
|
37
|
+
expect(mediaControl.putElement).not.toHaveBeenCalledWith(
|
|
38
|
+
'audiotracks',
|
|
39
|
+
expect.anything(),
|
|
40
|
+
)
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
describe('when media control is rendered', () => {
|
|
44
|
+
beforeEach(() => {
|
|
45
|
+
mediaControl.trigger(Events.MEDIACONTROL_RENDERED)
|
|
46
|
+
})
|
|
47
|
+
it('should attach to the media control', () => {
|
|
48
|
+
expect(mediaControl.putElement).toHaveBeenCalledWith(
|
|
49
|
+
'audiotracks',
|
|
50
|
+
audioSelector.$el,
|
|
51
|
+
)
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
describe('when audio tracks are available', () => {
|
|
55
|
+
beforeEach(() => {
|
|
56
|
+
emitTracksAvailable(core, TRACKS)
|
|
57
|
+
})
|
|
58
|
+
it('should render the button', () => {
|
|
59
|
+
expect(audioSelector.$el.find('#audiotracks-button').length).toBe(1)
|
|
60
|
+
})
|
|
61
|
+
it('should render the menu hidden', () => {
|
|
62
|
+
expect(audioSelector.el.innerHTML).toMatchSnapshot()
|
|
63
|
+
expect(
|
|
64
|
+
audioSelector.$el.find('#audiotracks-select').hasClass('hidden'),
|
|
65
|
+
).toBe(true)
|
|
66
|
+
const trackItems = audioSelector.$el.find('#audiotracks-select li')
|
|
67
|
+
expect(trackItems.length).toBe(2)
|
|
68
|
+
expect(trackItems.eq(0).text().trim()).toBe('English')
|
|
69
|
+
expect(trackItems.eq(1).text().trim()).toBe('Spanish')
|
|
70
|
+
})
|
|
71
|
+
describe('when the button is clicked', () => {
|
|
72
|
+
beforeEach(() => {
|
|
73
|
+
audioSelector.$el.find('#audiotracks-button').click()
|
|
74
|
+
})
|
|
75
|
+
it('should show the menu', () => {
|
|
76
|
+
expect(audioSelector.$el.html()).toMatchSnapshot()
|
|
77
|
+
expect(
|
|
78
|
+
audioSelector.$el.find('#audiotracks-select').hasClass('hidden'),
|
|
79
|
+
).toBe(false)
|
|
80
|
+
})
|
|
81
|
+
describe('when an audio track is selected', () => {
|
|
82
|
+
beforeEach(() => {
|
|
83
|
+
audioSelector.$el
|
|
84
|
+
.find('#audiotracks-select [data-audiotracks-select="2"]')
|
|
85
|
+
.click()
|
|
86
|
+
})
|
|
87
|
+
it('should switch to the selected audio track', () => {
|
|
88
|
+
expect(core.activeContainer.switchAudioTrack).toHaveBeenCalledWith(
|
|
89
|
+
'2',
|
|
90
|
+
)
|
|
91
|
+
})
|
|
92
|
+
it('should hide the menu', () => {
|
|
93
|
+
expect(audioSelector.$el.html()).toMatchSnapshot()
|
|
94
|
+
expect(
|
|
95
|
+
audioSelector.$el.find('#audiotracks-select').hasClass('hidden'),
|
|
96
|
+
).toBe(true)
|
|
97
|
+
})
|
|
98
|
+
it('should add changing class to the button', () => {
|
|
99
|
+
expect(
|
|
100
|
+
audioSelector.$el.find('#audiotracks-button').hasClass('changing'),
|
|
101
|
+
).toBe(true)
|
|
102
|
+
})
|
|
103
|
+
describe('when current audio track changes', () => {
|
|
104
|
+
beforeEach(() => {
|
|
105
|
+
core.activePlayback.currentAudioTrack =
|
|
106
|
+
core.activePlayback.audioTracks[1]
|
|
107
|
+
core.activePlayback.emit(
|
|
108
|
+
Events.PLAYBACK_AUDIO_CHANGED,
|
|
109
|
+
core.activePlayback.currentAudioTrack,
|
|
110
|
+
)
|
|
111
|
+
core.activeContainer.emit(
|
|
112
|
+
Events.CONTAINER_AUDIO_CHANGED,
|
|
113
|
+
core.activePlayback.currentAudioTrack,
|
|
114
|
+
)
|
|
115
|
+
})
|
|
116
|
+
it('should update button class', () => {
|
|
117
|
+
expect(
|
|
118
|
+
audioSelector.$el
|
|
119
|
+
.find('#audiotracks-button')
|
|
120
|
+
.hasClass('changing'),
|
|
121
|
+
).toBe(false)
|
|
122
|
+
})
|
|
123
|
+
it('should update button label', () => {
|
|
124
|
+
expect(
|
|
125
|
+
audioSelector.$el
|
|
126
|
+
.find('#audiotracks-button')
|
|
127
|
+
.text()
|
|
128
|
+
.replace(/\/assets.*\.svg/g, '')
|
|
129
|
+
.trim(),
|
|
130
|
+
).toBe('Spanish')
|
|
131
|
+
})
|
|
132
|
+
it('should highlight the selected menu item', () => {
|
|
133
|
+
const selectedItem = audioSelector.$el.find(
|
|
134
|
+
'#audiotracks-select .current',
|
|
135
|
+
)
|
|
136
|
+
expect(selectedItem.text().trim()).toBe('Spanish')
|
|
137
|
+
expect(
|
|
138
|
+
selectedItem
|
|
139
|
+
.find('a[data-audiotracks-select]')
|
|
140
|
+
.hasClass('gcore-skin-active'),
|
|
141
|
+
).toBe(true)
|
|
142
|
+
})
|
|
143
|
+
it('should unhighlight any previously highlighted menu item', () => {
|
|
144
|
+
expect(
|
|
145
|
+
audioSelector.$el.find('#audiotracks-select li.current').length,
|
|
146
|
+
).toBe(1)
|
|
147
|
+
expect(
|
|
148
|
+
audioSelector.$el.find(
|
|
149
|
+
'#audiotracks-select a.gcore-skin-active[data-audiotracks-select]',
|
|
150
|
+
).length,
|
|
151
|
+
).toBe(1)
|
|
152
|
+
})
|
|
153
|
+
})
|
|
154
|
+
})
|
|
155
|
+
})
|
|
156
|
+
})
|
|
157
|
+
describe('when audio tracks are not available', () => {
|
|
158
|
+
it('should not render the button', () => {
|
|
159
|
+
expect(audioSelector.$el.find('#audiotracks-button').length).toBe(0)
|
|
160
|
+
expect(audioSelector.$el.find('#audiotracks-select').length).toBe(0)
|
|
161
|
+
})
|
|
162
|
+
})
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
function emitTracksAvailable(core: any, tracks: any[]) {
|
|
166
|
+
core.activePlayback.audioTracks = tracks
|
|
167
|
+
core.activePlayback.currentAudioTrack = tracks[0]
|
|
168
|
+
core.activePlayback.emit(
|
|
169
|
+
Events.PLAYBACK_AUDIO_AVAILABLE,
|
|
170
|
+
core.activePlayback.audioTracks,
|
|
171
|
+
)
|
|
172
|
+
core.activeContainer.emit(
|
|
173
|
+
Events.CONTAINER_AUDIO_AVAILABLE,
|
|
174
|
+
core.activePlayback.audioTracks,
|
|
175
|
+
)
|
|
176
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`AudioSelector > when audio tracks are available > should render the menu hidden 1`] = `
|
|
4
|
+
"<button data-audiotracks-button="" class="gcore-skin-button-color" id="audiotracks-button">
|
|
5
|
+
<span class="audio-text"></span> <span class="audio-arrow">/assets/icons/old/quality-arrow.svg</span>
|
|
6
|
+
</button>
|
|
7
|
+
<ul class="gcore-skin-bg-color menu hidden" id="audiotracks-select">
|
|
8
|
+
|
|
9
|
+
<li class="">
|
|
10
|
+
<a href="#" class="gcore-skin-text-color" data-audiotracks-select="1">
|
|
11
|
+
English
|
|
12
|
+
</a>
|
|
13
|
+
</li>
|
|
14
|
+
|
|
15
|
+
<li class="">
|
|
16
|
+
<a href="#" class="gcore-skin-text-color" data-audiotracks-select="2">
|
|
17
|
+
Spanish
|
|
18
|
+
</a>
|
|
19
|
+
</li>
|
|
20
|
+
|
|
21
|
+
</ul>
|
|
22
|
+
"
|
|
23
|
+
`;
|
|
24
|
+
|
|
25
|
+
exports[`AudioSelector > when audio tracks are available > when the button is clicked > should show the menu 1`] = `
|
|
26
|
+
"<button data-audiotracks-button="" class="gcore-skin-button-color" id="audiotracks-button">
|
|
27
|
+
<span class="audio-text"></span> <span class="audio-arrow">/assets/icons/old/quality-arrow.svg</span>
|
|
28
|
+
</button>
|
|
29
|
+
<ul class="gcore-skin-bg-color menu" id="audiotracks-select">
|
|
30
|
+
|
|
31
|
+
<li class="">
|
|
32
|
+
<a href="#" class="gcore-skin-text-color" data-audiotracks-select="1">
|
|
33
|
+
English
|
|
34
|
+
</a>
|
|
35
|
+
</li>
|
|
36
|
+
|
|
37
|
+
<li class="">
|
|
38
|
+
<a href="#" class="gcore-skin-text-color" data-audiotracks-select="2">
|
|
39
|
+
Spanish
|
|
40
|
+
</a>
|
|
41
|
+
</li>
|
|
42
|
+
|
|
43
|
+
</ul>
|
|
44
|
+
"
|
|
45
|
+
`;
|
|
46
|
+
|
|
47
|
+
exports[`AudioSelector > when audio tracks are available > when the button is clicked > when an audio track is selected > should hide the menu 1`] = `
|
|
48
|
+
"<button data-audiotracks-button="" class="gcore-skin-button-color changing" id="audiotracks-button">
|
|
49
|
+
<span class="audio-text"></span> <span class="audio-arrow">/assets/icons/old/quality-arrow.svg</span>
|
|
50
|
+
</button>
|
|
51
|
+
<ul class="gcore-skin-bg-color menu hidden" id="audiotracks-select">
|
|
52
|
+
|
|
53
|
+
<li class="">
|
|
54
|
+
<a href="#" class="gcore-skin-text-color" data-audiotracks-select="1">
|
|
55
|
+
English
|
|
56
|
+
</a>
|
|
57
|
+
</li>
|
|
58
|
+
|
|
59
|
+
<li class="">
|
|
60
|
+
<a href="#" class="gcore-skin-text-color" data-audiotracks-select="2">
|
|
61
|
+
Spanish
|
|
62
|
+
</a>
|
|
63
|
+
</li>
|
|
64
|
+
|
|
65
|
+
</ul>
|
|
66
|
+
"
|
|
67
|
+
`;
|
|
@@ -36,6 +36,7 @@ export enum SpinnerEvents {
|
|
|
36
36
|
* `PLUGIN` that shows a pending operation indicator when playback is buffering or in a similar state.
|
|
37
37
|
* @public
|
|
38
38
|
* @remarks
|
|
39
|
+
* It is aliased as `Spinner` for convenience.
|
|
39
40
|
* Events emitted - {@link SpinnerEvents}
|
|
40
41
|
* Other plugins can use {@link SpinnerThreeBounce.show | show} and {@link SpinnerThreeBounce.hide | hide} methods to
|
|
41
42
|
* implement custom pending/progress indication scenarios.
|
package/src/testUtils.ts
CHANGED
|
@@ -152,6 +152,7 @@ export function createMockPlayback(name = 'mock') {
|
|
|
152
152
|
canAutoPlay: vi.fn().mockImplementation(() => true),
|
|
153
153
|
onResize: vi.fn().mockImplementation(() => true),
|
|
154
154
|
setPlaybackRate: vi.fn(),
|
|
155
|
+
switchAudioTrack: vi.fn(),
|
|
155
156
|
trigger: emitter.emit,
|
|
156
157
|
})
|
|
157
158
|
}
|
|
@@ -171,6 +172,7 @@ export function createMockContainer(playback: any = createMockPlayback()) {
|
|
|
171
172
|
isPlaying: vi.fn().mockReturnValue(false),
|
|
172
173
|
play: vi.fn(),
|
|
173
174
|
seek: vi.fn(),
|
|
175
|
+
switchAudioTrack: vi.fn(),
|
|
174
176
|
trigger: emitter.emit,
|
|
175
177
|
})
|
|
176
178
|
}
|
package/temp/player.api.json
CHANGED
|
@@ -7791,7 +7791,7 @@
|
|
|
7791
7791
|
{
|
|
7792
7792
|
"kind": "Class",
|
|
7793
7793
|
"canonicalReference": "@gcorevideo/player!SourceController:class",
|
|
7794
|
-
"docComment": "/**\n * `PLUGIN` that is
|
|
7794
|
+
"docComment": "/**\n * `PLUGIN` that is managing the automatic failover between media sources.\n *\n * @remarks\n *\n * Have a look at the {@link https://miro.com/app/board/uXjVLiN15tY=/?share_link_id=390327585787 | source failover diagram} for the details on how sources ordering and selection works. Below is a simplified diagram:\n * ```markdown\n * sources_list:\n * - a.mpd | +--------------------+\n * - b.m3u8 |--->| init |\n * - ... | |--------------------|\n * | current_source = 0 |\n * +--------------------+\n * |\n * | source = a.mpd\n * | playback = dash.js\n * v\n * +------------------+\n * +-->| load source |\n * | +---------|--------+\n * | v\n * | +------------------+\n * | | play |\n * | +---------|--------+\n * | |\n * | v\n * | +-----------------------+\n * | | on playback_error |\n * | |-----------------------|\n * | | current_source = |\n * | | (current_source + 1) |\n * | | % len sources_list |\n * | | |\n * | | delay 1..3s |\n * | +---------------|-------+\n * | |\n * | source=b.m3u8 |\n * | playback=hls.js |\n * +-------------------+\n *\n * ```\n *\n * This plugin does not expose any public methods apart from required by the Clappr plugin interface. It is supposed to work autonomously.\n *\n * @example\n * ```ts\n * import { SourceController } from '@gcorevideo/player'\n *\n * Player.registerPlugin(SourceController)\n * ```\n *\n * @public\n */\n",
|
|
7795
7795
|
"excerptTokens": [
|
|
7796
7796
|
{
|
|
7797
7797
|
"kind": "Content",
|
|
@@ -7894,7 +7894,7 @@
|
|
|
7894
7894
|
{
|
|
7895
7895
|
"kind": "Class",
|
|
7896
7896
|
"canonicalReference": "@gcorevideo/player!SpinnerThreeBounce:class",
|
|
7897
|
-
"docComment": "/**\n * `PLUGIN` that shows a pending operation indicator when playback is buffering or in a similar state.\n *\n * @remarks\n *\n * Events emitted- {@link SpinnerEvents} Other plugins can use {@link SpinnerThreeBounce.show | show} and {@link SpinnerThreeBounce.hide | hide} methods to implement custom pending/progress indication scenarios.\n *\n * @public\n */\n",
|
|
7897
|
+
"docComment": "/**\n * `PLUGIN` that shows a pending operation indicator when playback is buffering or in a similar state.\n *\n * @remarks\n *\n * It is aliased as `Spinner` for convenience. Events emitted - {@link SpinnerEvents} Other plugins can use {@link SpinnerThreeBounce.show | show} and {@link SpinnerThreeBounce.hide | hide} methods to implement custom pending/progress indication scenarios.\n *\n * @public\n */\n",
|
|
7898
7898
|
"excerptTokens": [
|
|
7899
7899
|
{
|
|
7900
7900
|
"kind": "Content",
|