@gcorevideo/player 2.19.14 → 2.20.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.
Files changed (196) hide show
  1. package/assets/level-selector/list.ejs +2 -2
  2. package/dist/core.js +2 -2
  3. package/dist/index.css +780 -780
  4. package/dist/index.js +1720 -1473
  5. package/dist/player.d.ts +425 -94
  6. package/dist/plugins/index.css +1466 -1466
  7. package/dist/plugins/index.js +1501 -1252
  8. package/docs/api/player.bottomgear.getelement.md +56 -0
  9. package/docs/api/player.bottomgear.md +51 -0
  10. package/docs/api/player.bottomgear.setcontent.md +56 -0
  11. package/docs/api/player.clapprnerdstats.md +12 -259
  12. package/docs/api/player.dvrcontrols.md +5 -1
  13. package/docs/api/player.errorscreen.attributes.md +3 -0
  14. package/docs/api/player.errorscreen.bindevents.md +3 -0
  15. package/docs/api/player.errorscreen.container.md +3 -0
  16. package/docs/api/player.errorscreen.hide.md +3 -0
  17. package/docs/api/player.errorscreen.md +27 -0
  18. package/docs/api/player.errorscreen.name.md +3 -0
  19. package/docs/api/player.errorscreen.render.md +3 -0
  20. package/docs/api/player.errorscreen.show.md +3 -0
  21. package/docs/api/player.errorscreen.supportedversion.md +3 -0
  22. package/docs/api/player.errorscreen.template.md +3 -0
  23. package/docs/api/player.errorscreen.unbindevents.md +3 -0
  24. package/docs/api/player.gearevents.md +49 -0
  25. package/docs/api/{player.sourcecontroller.name.md → player.gearitemelement.md} +5 -3
  26. package/docs/api/{player.playbackrate.template.md → player.initeventdata.event.md} +3 -3
  27. package/docs/api/{player.playbackrate.updateplaybackrate.md → player.initeventdata.md} +15 -11
  28. package/docs/api/player.levelselector.md +9 -1
  29. package/docs/api/player.md +124 -4
  30. package/docs/api/{player.clapprnerdstats.render.md → player.mediacontrol.getrightpanel.md} +8 -4
  31. package/docs/api/player.mediacontrol.md +14 -0
  32. package/docs/api/player.mediacontrolelement.md +1 -1
  33. package/docs/api/player.pictureinpicture.md +9 -197
  34. package/docs/api/player.playbackrate.md +10 -314
  35. package/docs/api/player.sourcecontroller.md +0 -90
  36. package/docs/api/player.spinnerevents.md +49 -0
  37. package/docs/api/player.spinnerthreebounce._constructor_.md +3 -0
  38. package/docs/api/player.spinnerthreebounce.hide.md +5 -0
  39. package/docs/api/player.spinnerthreebounce.md +14 -95
  40. package/docs/api/player.spinnerthreebounce.show.md +6 -37
  41. package/docs/api/{player.playbackrate.onplay.md → player.stalleventdata.count.md} +5 -7
  42. package/docs/api/{player.playbackrate.name.md → player.stalleventdata.event.md} +3 -3
  43. package/docs/api/player.stalleventdata.md +112 -0
  44. package/docs/api/player.stalleventdata.time.md +13 -0
  45. package/docs/api/player.stalleventdata.total_ms.md +13 -0
  46. package/docs/api/{player.pluginsettings.md → player.starteventdata.event.md} +3 -5
  47. package/docs/api/{player.playbackrate.onrateselect.md → player.starteventdata.md} +15 -11
  48. package/docs/api/player.subtitles.hide.md +5 -0
  49. package/docs/api/player.subtitles.md +23 -275
  50. package/docs/api/player.subtitles.show.md +5 -0
  51. package/docs/api/{player.statistics._constructor_.md → player.telemetry._constructor_.md} +6 -3
  52. package/docs/api/player.telemetry.md +146 -0
  53. package/docs/api/{player.volumefade.name.md → player.telemetry.name.md} +4 -2
  54. package/docs/api/{player.sourcecontroller.supportedversion.md → player.telemetry.supportedversion.md} +4 -2
  55. package/docs/api/player.telemetryevent.md +89 -0
  56. package/docs/api/player.telemetryeventdata.md +15 -0
  57. package/docs/api/player.telemetrypluginsettings.md +57 -0
  58. package/docs/api/player.telemetrypluginsettings.send.md +13 -0
  59. package/docs/api/player.telemetryrecord.md +17 -0
  60. package/docs/api/player.volumefade.md +0 -93
  61. package/docs/api/{player.pictureinpicture.name.md → player.watcheventdata.event.md} +3 -3
  62. package/docs/api/{player.playbackrate.setselectedrate.md → player.watcheventdata.md} +15 -11
  63. package/lib/index.plugins.d.ts +2 -2
  64. package/lib/index.plugins.d.ts.map +1 -1
  65. package/lib/index.plugins.js +2 -2
  66. package/lib/playback/hls-playback/HlsPlayback.js +1 -1
  67. package/lib/plugins/bottom-gear/BottomGear.d.ts +20 -1
  68. package/lib/plugins/bottom-gear/BottomGear.d.ts.map +1 -1
  69. package/lib/plugins/bottom-gear/BottomGear.js +28 -7
  70. package/lib/plugins/clappr-nerd-stats/ClapprNerdStats.d.ts +38 -5
  71. package/lib/plugins/clappr-nerd-stats/ClapprNerdStats.d.ts.map +1 -1
  72. package/lib/plugins/clappr-nerd-stats/ClapprNerdStats.js +67 -21
  73. package/lib/plugins/dvr-controls/DvrControls.d.ts +5 -2
  74. package/lib/plugins/dvr-controls/DvrControls.d.ts.map +1 -1
  75. package/lib/plugins/dvr-controls/DvrControls.js +5 -2
  76. package/lib/plugins/error-screen/ErrorScreen.d.ts +5 -0
  77. package/lib/plugins/error-screen/ErrorScreen.d.ts.map +1 -1
  78. package/lib/plugins/error-screen/ErrorScreen.js +5 -0
  79. package/lib/plugins/index.d.ts +2 -3
  80. package/lib/plugins/index.d.ts.map +1 -1
  81. package/lib/plugins/index.js +2 -3
  82. package/lib/plugins/level-selector/LevelSelector.d.ts +10 -3
  83. package/lib/plugins/level-selector/LevelSelector.d.ts.map +1 -1
  84. package/lib/plugins/level-selector/LevelSelector.js +20 -19
  85. package/lib/plugins/media-control/MediaControl.d.ts +6 -2
  86. package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
  87. package/lib/plugins/media-control/MediaControl.js +40 -39
  88. package/lib/plugins/picture-in-picture/PictureInPicture.d.ts +32 -4
  89. package/lib/plugins/picture-in-picture/PictureInPicture.d.ts.map +1 -1
  90. package/lib/plugins/picture-in-picture/PictureInPicture.js +30 -2
  91. package/lib/plugins/playback-rate/PlaybackRate.d.ts +47 -14
  92. package/lib/plugins/playback-rate/PlaybackRate.d.ts.map +1 -1
  93. package/lib/plugins/playback-rate/PlaybackRate.js +38 -9
  94. package/lib/plugins/source-controller/SourceController.d.ts +9 -0
  95. package/lib/plugins/source-controller/SourceController.d.ts.map +1 -1
  96. package/lib/plugins/source-controller/SourceController.js +11 -1
  97. package/lib/plugins/spinner-three-bounce/SpinnerThreeBounce.d.ts +35 -1
  98. package/lib/plugins/spinner-three-bounce/SpinnerThreeBounce.d.ts.map +1 -1
  99. package/lib/plugins/spinner-three-bounce/SpinnerThreeBounce.js +46 -23
  100. package/lib/plugins/statistics/Statistics.d.ts +38 -3
  101. package/lib/plugins/statistics/Statistics.d.ts.map +1 -1
  102. package/lib/plugins/statistics/Statistics.js +51 -9
  103. package/lib/plugins/subtitles/Subtitles.d.ts +65 -16
  104. package/lib/plugins/subtitles/Subtitles.d.ts.map +1 -1
  105. package/lib/plugins/subtitles/Subtitles.js +131 -109
  106. package/lib/plugins/telemetry/Telemetry.d.ts +135 -0
  107. package/lib/plugins/telemetry/Telemetry.d.ts.map +1 -0
  108. package/lib/plugins/telemetry/Telemetry.js +180 -0
  109. package/lib/plugins/volume-fade/VolumeFade.d.ts +7 -1
  110. package/lib/plugins/volume-fade/VolumeFade.d.ts.map +1 -1
  111. package/lib/plugins/volume-fade/VolumeFade.js +8 -1
  112. package/package.json +1 -1
  113. package/src/index.plugins.ts +2 -2
  114. package/src/playback/hls-playback/HlsPlayback.ts +1 -1
  115. package/src/plugins/bottom-gear/BottomGear.ts +26 -4
  116. package/src/plugins/clappr-nerd-stats/ClapprNerdStats.ts +240 -173
  117. package/src/plugins/dvr-controls/DvrControls.ts +5 -2
  118. package/src/plugins/error-screen/ErrorScreen.ts +5 -0
  119. package/src/plugins/index.ts +2 -3
  120. package/src/plugins/level-selector/LevelSelector.ts +22 -19
  121. package/src/plugins/level-selector/__tests__/LevelSelector.test.ts +47 -26
  122. package/src/plugins/level-selector/__tests__/__snapshots__/LevelSelector.test.ts.snap +18 -18
  123. package/src/plugins/media-control/MediaControl.ts +43 -41
  124. package/src/plugins/picture-in-picture/PictureInPicture.ts +35 -7
  125. package/src/plugins/playback-rate/PlaybackRate.ts +53 -24
  126. package/src/plugins/source-controller/SourceController.ts +11 -1
  127. package/src/plugins/source-controller/__tests__/SourceController.test.ts +1 -1
  128. package/src/plugins/spinner-three-bounce/SpinnerThreeBounce.ts +46 -22
  129. package/src/plugins/subtitles/Subtitles.ts +146 -155
  130. package/src/plugins/telemetry/Telemetry.ts +299 -0
  131. package/src/plugins/volume-fade/VolumeFade.ts +9 -2
  132. package/temp/player.api.json +3384 -4872
  133. package/tsconfig.tsbuildinfo +1 -1
  134. package/docs/api/player.clapprnerdstats.attributes.md +0 -17
  135. package/docs/api/player.clapprnerdstats.bindevents.md +0 -18
  136. package/docs/api/player.clapprnerdstats.events.md +0 -18
  137. package/docs/api/player.clapprnerdstats.name.md +0 -14
  138. package/docs/api/player.clapprnerdstats.playerheight.md +0 -14
  139. package/docs/api/player.clapprnerdstats.playerwidth.md +0 -14
  140. package/docs/api/player.clapprnerdstats.statsboxelem.md +0 -14
  141. package/docs/api/player.clapprnerdstats.statsboxwidththreshold.md +0 -14
  142. package/docs/api/player.clapprnerdstats.supportedversion.md +0 -16
  143. package/docs/api/player.clapprnerdstats.template.md +0 -14
  144. package/docs/api/player.pictureinpicture.bindevents.md +0 -15
  145. package/docs/api/player.pictureinpicture.events.md +0 -13
  146. package/docs/api/player.pictureinpicture.exitpictureinpicture.md +0 -15
  147. package/docs/api/player.pictureinpicture.render.md +0 -15
  148. package/docs/api/player.pictureinpicture.requestpictureinpicture.md +0 -15
  149. package/docs/api/player.pictureinpicture.supportedversion.md +0 -13
  150. package/docs/api/player.pictureinpicture.togglepictureinpicture.md +0 -15
  151. package/docs/api/player.pictureinpicture.version.md +0 -11
  152. package/docs/api/player.pictureinpicture.videoelement.md +0 -11
  153. package/docs/api/player.playbackrate.attributes.md +0 -14
  154. package/docs/api/player.playbackrate.bindevents.md +0 -15
  155. package/docs/api/player.playbackrate.events.md +0 -15
  156. package/docs/api/player.playbackrate.gettitle.md +0 -15
  157. package/docs/api/player.playbackrate.goback.md +0 -15
  158. package/docs/api/player.playbackrate.highlightcurrentrate.md +0 -15
  159. package/docs/api/player.playbackrate.onfinishad.md +0 -15
  160. package/docs/api/player.playbackrate.onshowmenu.md +0 -15
  161. package/docs/api/player.playbackrate.onstartad.md +0 -15
  162. package/docs/api/player.playbackrate.onstop.md +0 -15
  163. package/docs/api/player.playbackrate.reload.md +0 -15
  164. package/docs/api/player.playbackrate.render.md +0 -15
  165. package/docs/api/player.playbackrate.supportedversion.md +0 -13
  166. package/docs/api/player.playbackrate.unbindevents.md +0 -15
  167. package/docs/api/player.sourcecontroller.version.md +0 -14
  168. package/docs/api/player.spinnerthreebounce.attributes.md +0 -14
  169. package/docs/api/player.spinnerthreebounce.name.md +0 -11
  170. package/docs/api/player.spinnerthreebounce.render.md +0 -15
  171. package/docs/api/player.spinnerthreebounce.supportedversion.md +0 -13
  172. package/docs/api/player.statistics.bindevents.md +0 -15
  173. package/docs/api/player.statistics.md +0 -141
  174. package/docs/api/player.statistics.name.md +0 -11
  175. package/docs/api/player.statistics.supportedversion.md +0 -13
  176. package/docs/api/player.subtitles.attributes.md +0 -14
  177. package/docs/api/player.subtitles.bindevents.md +0 -15
  178. package/docs/api/player.subtitles.buttonelement.md +0 -15
  179. package/docs/api/player.subtitles.events.md +0 -14
  180. package/docs/api/player.subtitles.levelelement.md +0 -51
  181. package/docs/api/player.subtitles.name.md +0 -11
  182. package/docs/api/player.subtitles.preselectedlanguage.md +0 -11
  183. package/docs/api/player.subtitles.reload.md +0 -15
  184. package/docs/api/player.subtitles.render.md +0 -15
  185. package/docs/api/player.subtitles.selectsubtitles.md +0 -15
  186. package/docs/api/player.subtitles.startlevelswitch.md +0 -15
  187. package/docs/api/player.subtitles.stoplevelswitch.md +0 -15
  188. package/docs/api/player.subtitles.supportedversion.md +0 -13
  189. package/docs/api/player.subtitles.template.md +0 -11
  190. package/docs/api/player.subtitles.templatestring.md +0 -11
  191. package/docs/api/player.subtitles.unbindevents.md +0 -15
  192. package/docs/api/player.subtitles.version.md +0 -11
  193. package/docs/api/player.volumefade.bindevents.md +0 -18
  194. package/docs/api/player.volumefade.unbindevents.md +0 -18
  195. package/src/plugins/statistics/Statistics.ts +0 -207
  196. /package/src/plugins/{statistics → telemetry}/Statistics copy.xts +0 -0
@@ -5,6 +5,7 @@ import { type QualityLevel } from '../../playback.types.js'
5
5
  import { CLAPPR_VERSION } from '../../build.js'
6
6
  import { ZeptoResult } from '../../utils/types.js'
7
7
  import { TemplateFunction } from '../types.js'
8
+ import { BottomGear } from '../bottom-gear/BottomGear.js'
8
9
 
9
10
  import buttonHtml from '../../../assets/level-selector/button.ejs'
10
11
  import listHtml from '../../../assets/level-selector/list.ejs'
@@ -13,9 +14,10 @@ import arrowRightIcon from '../../../assets/icons/new/arrow-right.svg'
13
14
  import arrowLeftIcon from '../../../assets/icons/new/arrow-left.svg'
14
15
  import checkIcon from '../../../assets/icons/new/check.svg'
15
16
  import '../../../assets/level-selector/style.scss'
17
+ import assert from 'assert'
16
18
 
17
19
 
18
- const T = 'plugins.media_control_level_selector'
20
+ const T = 'plugins.level_selector'
19
21
  const VERSION = '2.19.4'
20
22
 
21
23
  /**
@@ -23,7 +25,14 @@ const VERSION = '2.19.4'
23
25
  * @beta
24
26
  *
25
27
  * @remarks
26
- * The plugin is rendered as a button in the {@link BottomGear | gear menu}.
28
+ * Depends on:
29
+ *
30
+ * - {@link MediaControl}
31
+ *
32
+ * - {@link BottomGear}
33
+ *
34
+ * The plugin is rendered as an item in the gear menu.
35
+ *
27
36
  * When clicked, it shows a list of quality levels to choose from.
28
37
  *
29
38
  * Configuration options:
@@ -53,15 +62,15 @@ export class LevelSelector extends UICorePlugin {
53
62
 
54
63
  private isOpen = false
55
64
 
56
- private buttonTemplate: TemplateFunction | null = null
65
+ private static readonly buttonTemplate: TemplateFunction = template(buttonHtml)
57
66
 
58
- private listTemplate: TemplateFunction | null = null
67
+ private static readonly listTemplate: TemplateFunction = template(listHtml)
59
68
 
60
69
  /**
61
70
  * @internal
62
71
  */
63
72
  get name() {
64
- return 'media_control_level_selector'
73
+ return 'level_selector'
65
74
  }
66
75
 
67
76
  /**
@@ -183,6 +192,8 @@ export class LevelSelector extends UICorePlugin {
183
192
  * @internal
184
193
  */
185
194
  override render() {
195
+ assert(this.core.getPlugin('bottom_gear'), 'bottom_gear plugin is required')
196
+
186
197
  if (!this.shouldRender()) {
187
198
  return this
188
199
  }
@@ -193,29 +204,21 @@ export class LevelSelector extends UICorePlugin {
193
204
  }
194
205
 
195
206
  private renderButton() {
196
- if (!this.buttonTemplate) {
197
- this.buttonTemplate = template(buttonHtml)
198
- }
199
207
  if (!this.isOpen) {
200
- const html = this.buttonTemplate?.({
208
+ const html = LevelSelector.buttonTemplate({
201
209
  arrowRightIcon,
202
210
  currentText: this.currentText,
203
211
  isHd: this.isHd,
204
212
  hdIcon,
205
213
  })
206
214
  this.$el.html(html)
207
- const mediaControl = this.core.getPlugin('media_control')
208
- mediaControl.getElement('bottomGear')
209
- ?.find('.gear-options-list [data-quality]')
210
- ?.html(this.el)
215
+ const gear = this.core.getPlugin('bottom_gear') as BottomGear
216
+ gear.getElement('quality')?.html(this.el)
211
217
  }
212
218
  }
213
219
 
214
220
  private renderDropdown() {
215
- if (!this.listTemplate) {
216
- this.listTemplate = template(listHtml)
217
- }
218
- const html = this.listTemplate!({
221
+ const html = LevelSelector.listTemplate({
219
222
  arrowLeftIcon,
220
223
  checkIcon,
221
224
  labels: this.levelLabels,
@@ -224,8 +227,8 @@ export class LevelSelector extends UICorePlugin {
224
227
  removeAuto: this.removeAuto,
225
228
  })
226
229
  this.$el.html(html)
227
- const mediaControl = this.core.getPlugin('media_control')
228
- mediaControl.getElement('bottomGear')?.find('.gear-wrapper').html(this.el)
230
+ const gear = this.core.getPlugin('bottom_gear') as BottomGear
231
+ gear?.setContent(this.el)
229
232
  }
230
233
 
231
234
  private get maxLevel() {
@@ -44,6 +44,7 @@ describe('LevelSelector', () => {
44
44
  const activeContainer = createContainer()
45
45
  activePlayback = createPlayback()
46
46
  let mediaControl: UICorePlugin | null = null
47
+ let bottomGear: UICorePlugin | null = null
47
48
  core = Object.assign(new EventLite(), {
48
49
  activeContainer,
49
50
  activePlayback,
@@ -57,10 +58,14 @@ describe('LevelSelector', () => {
57
58
  if (name === 'media_control') {
58
59
  return mediaControl
59
60
  }
61
+ if (name === 'bottom_gear') {
62
+ return bottomGear
63
+ }
60
64
  return null
61
65
  }),
62
66
  })
63
67
  mediaControl = createMediaControl(core)
68
+ bottomGear = createBottomGear(core)
64
69
  levelSelector = new LevelSelector(core)
65
70
  })
66
71
  describe('initially', () => {
@@ -71,29 +76,15 @@ describe('LevelSelector', () => {
71
76
  await clock.tickAsync(1)
72
77
  })
73
78
  it('should render the proper level label', () => {
79
+ // @ts-ignore
74
80
  expect(levelSelector.el.textContent).toMatchQualityLevelLabel('Auto')
75
81
  })
76
82
  })
77
83
  describe.each([
78
- [
79
- 'auto',
80
- LEVELS,
81
- -1,
82
- 'Auto',
83
- ],
84
- [
85
- 'standard label',
86
- LEVELS,
87
- 0,
88
- '360p',
89
- ],
90
- [
91
- 'custom label',
92
- LEVELS,
93
- 1,
94
- 'HD',
95
- ],
96
- ])("%s", (_, levels, current, label) => {
84
+ ['auto', LEVELS, -1, 'Auto'],
85
+ ['standard label', LEVELS, 0, '360p'],
86
+ ['custom label', LEVELS, 1, 'HD'],
87
+ ])('%s', (_, levels, current, label) => {
97
88
  beforeEach(async () => {
98
89
  core.emit('core:active:container:changed')
99
90
  await clock.tickAsync(1)
@@ -102,14 +93,19 @@ describe('LevelSelector', () => {
102
93
  await clock.tickAsync(1)
103
94
  levelSelector.$el.find('.gear-option').click()
104
95
  await clock.tickAsync(1)
105
- levelSelector.$el.find(`.gear-sub-menu_btn[data-id="${current}"]`).click()
96
+ levelSelector.$el
97
+ .find(`.gear-sub-menu_btn[data-id="${current}"]`)
98
+ .click()
106
99
  await clock.tickAsync(1)
107
100
  })
108
101
  it('should render the proper level labels', () => {
109
102
  expect(levelSelector.el.innerHTML).toMatchSnapshot()
110
103
  })
111
104
  it('should render the selected level', () => {
112
- expect(levelSelector.$el.find('ul.gear-sub-menu .current')[0].textContent).toMatchQualityLevelOption(label)
105
+ expect(
106
+ levelSelector.$el.find('ul.gear-sub-menu .current')[0].textContent,
107
+ // @ts-ignore
108
+ ).toMatchQualityLevelOption(label)
113
109
  })
114
110
  })
115
111
  })
@@ -118,6 +114,7 @@ describe('LevelSelector', () => {
118
114
  const activeContainer = createContainer()
119
115
  activePlayback = createPlayback()
120
116
  let mediaControl: UICorePlugin | null = null
117
+ let bottomGear: UICorePlugin | null = null
121
118
  core = Object.assign(new EventLite(), {
122
119
  activeContainer,
123
120
  activePlayback,
@@ -131,10 +128,14 @@ describe('LevelSelector', () => {
131
128
  if (name === 'media_control') {
132
129
  return mediaControl
133
130
  }
131
+ if (name === 'bottom_gear') {
132
+ return bottomGear
133
+ }
134
134
  return null
135
135
  }),
136
136
  })
137
137
  mediaControl = createMediaControl(core)
138
+ bottomGear = createBottomGear(core)
138
139
  levelSelector = new LevelSelector(core)
139
140
  })
140
141
  describe('basically', () => {
@@ -146,7 +147,8 @@ describe('LevelSelector', () => {
146
147
  })
147
148
  it('should render the restricted quality level label', () => {
148
149
  expect(
149
- levelSelector.el.textContent
150
+ levelSelector.el.textContent,
151
+ // @ts-ignore
150
152
  ).toMatchQualityLevelLabel('360p')
151
153
 
152
154
  expect(levelSelector.el.innerHTML).toMatchSnapshot()
@@ -185,7 +187,10 @@ describe('LevelSelector', () => {
185
187
  expect(levelSelector.el.innerHTML).toMatchSnapshot()
186
188
  })
187
189
  it('should properly apply the restriction', () => {
188
- expect(levelSelector.$el.find('li:not(.level-disabled)')[0].textContent).toMatchQualityLevelOption('360p')
190
+ expect(
191
+ levelSelector.$el.find('li:not(.level-disabled)')[0].textContent,
192
+ // @ts-ignore
193
+ ).toMatchQualityLevelOption('360p')
189
194
  })
190
195
  })
191
196
  })
@@ -217,7 +222,10 @@ expect.extend({
217
222
  .trim()
218
223
  return {
219
224
  pass: rendered.includes(`Quality ${expected}`),
220
- message: () => `Quality label must${isNot ? ' not' : ''} be ${expected} in "${rendered}"`,
225
+ message: () =>
226
+ `Quality label must${
227
+ isNot ? ' not' : ''
228
+ } be ${expected} in "${rendered}"`,
221
229
  }
222
230
  },
223
231
  toMatchQualityLevelOption(received, expected) {
@@ -228,13 +236,26 @@ expect.extend({
228
236
  .trim()
229
237
  return {
230
238
  pass: rendered === expected,
231
- message: () => `Quality option must${isNot ? ' not' : ''} be ${expected} in "${rendered}"`,
239
+ message: () =>
240
+ `Quality option must${
241
+ isNot ? ' not' : ''
242
+ } be ${expected} in "${rendered}"`,
232
243
  }
233
- }
244
+ },
234
245
  })
235
246
 
236
247
  function createMediaControl(core: any) {
237
248
  const mediaControl = new UICorePlugin(core)
249
+ // @ts-ignore
238
250
  mediaControl.getElement = vi.fn().mockReturnValue(null)
239
251
  return mediaControl
240
252
  }
253
+
254
+ function createBottomGear(core: any) {
255
+ const bottomGear = new UICorePlugin(core)
256
+ // @ts-ignore
257
+ bottomGear.getElement = vi.fn().mockReturnValue(null)
258
+ // @ts-ignore
259
+ bottomGear.setContent = vi.fn()
260
+ return bottomGear
261
+ }
@@ -8,7 +8,7 @@ exports[`LevelSelector > basically > auto > should render the proper level label
8
8
  <ul class="gear-sub-menu">
9
9
 
10
10
  <li class="current">
11
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color gcore-skin-active" data-id="-1">
11
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color gcore-skin-active" data-id="-1" id="level_selector_auto">
12
12
  <span class="check-icon">/assets/icons/new/check.svg</span>
13
13
  Auto
14
14
  </a>
@@ -16,21 +16,21 @@ exports[`LevelSelector > basically > auto > should render the proper level label
16
16
 
17
17
 
18
18
  <li class="">
19
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="2">
19
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="2" id="level_selector_1080">
20
20
  <span class="check-icon">/assets/icons/new/check.svg</span>
21
21
  1080p
22
22
  </a>
23
23
  </li>
24
24
 
25
25
  <li class="">
26
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="1">
26
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="1" id="level_selector_720">
27
27
  <span class="check-icon">/assets/icons/new/check.svg</span>
28
28
  HD
29
29
  </a>
30
30
  </li>
31
31
 
32
32
  <li class="">
33
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="0">
33
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="0" id="level_selector_360">
34
34
  <span class="check-icon">/assets/icons/new/check.svg</span>
35
35
  360p
36
36
  </a>
@@ -48,7 +48,7 @@ exports[`LevelSelector > basically > custom label > should render the proper lev
48
48
  <ul class="gear-sub-menu">
49
49
 
50
50
  <li class="">
51
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="-1">
51
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="-1" id="level_selector_auto">
52
52
  <span class="check-icon">/assets/icons/new/check.svg</span>
53
53
  Auto
54
54
  </a>
@@ -56,21 +56,21 @@ exports[`LevelSelector > basically > custom label > should render the proper lev
56
56
 
57
57
 
58
58
  <li class="">
59
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="2">
59
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="2" id="level_selector_1080">
60
60
  <span class="check-icon">/assets/icons/new/check.svg</span>
61
61
  1080p
62
62
  </a>
63
63
  </li>
64
64
 
65
65
  <li class="current">
66
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color gcore-skin-active" data-id="1">
66
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color gcore-skin-active" data-id="1" id="level_selector_720">
67
67
  <span class="check-icon">/assets/icons/new/check.svg</span>
68
68
  HD
69
69
  </a>
70
70
  </li>
71
71
 
72
72
  <li class="">
73
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="0">
73
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="0" id="level_selector_360">
74
74
  <span class="check-icon">/assets/icons/new/check.svg</span>
75
75
  360p
76
76
  </a>
@@ -88,7 +88,7 @@ exports[`LevelSelector > basically > standard label > should render the proper l
88
88
  <ul class="gear-sub-menu">
89
89
 
90
90
  <li class="">
91
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="-1">
91
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="-1" id="level_selector_auto">
92
92
  <span class="check-icon">/assets/icons/new/check.svg</span>
93
93
  Auto
94
94
  </a>
@@ -96,21 +96,21 @@ exports[`LevelSelector > basically > standard label > should render the proper l
96
96
 
97
97
 
98
98
  <li class="">
99
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="2">
99
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="2" id="level_selector_1080">
100
100
  <span class="check-icon">/assets/icons/new/check.svg</span>
101
101
  1080p
102
102
  </a>
103
103
  </li>
104
104
 
105
105
  <li class="">
106
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="1">
106
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="1" id="level_selector_720">
107
107
  <span class="check-icon">/assets/icons/new/check.svg</span>
108
108
  HD
109
109
  </a>
110
110
  </li>
111
111
 
112
112
  <li class="current">
113
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color gcore-skin-active" data-id="0">
113
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color gcore-skin-active" data-id="0" id="level_selector_360">
114
114
  <span class="check-icon">/assets/icons/new/check.svg</span>
115
115
  360p
116
116
  </a>
@@ -139,21 +139,21 @@ exports[`LevelSelector > options.restrictResolution > given vertical video forma
139
139
 
140
140
 
141
141
  <li class="level-disabled">
142
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="2">
142
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="2" id="level_selector_1080">
143
143
  <span class="check-icon">/assets/icons/new/check.svg</span>
144
144
  1080p
145
145
  </a>
146
146
  </li>
147
147
 
148
148
  <li class="level-disabled">
149
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="1">
149
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="1" id="level_selector_1280">
150
150
  <span class="check-icon">/assets/icons/new/check.svg</span>
151
151
  720p
152
152
  </a>
153
153
  </li>
154
154
 
155
155
  <li class="current">
156
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color gcore-skin-active" data-id="0">
156
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color gcore-skin-active" data-id="0" id="level_selector_640">
157
157
  <span class="check-icon">/assets/icons/new/check.svg</span>
158
158
  360p
159
159
  </a>
@@ -172,21 +172,21 @@ exports[`LevelSelector > options.restrictResolution > given vertical video forma
172
172
 
173
173
 
174
174
  <li class="level-disabled">
175
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="2">
175
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="2" id="level_selector_1080">
176
176
  <span class="check-icon">/assets/icons/new/check.svg</span>
177
177
  1080p
178
178
  </a>
179
179
  </li>
180
180
 
181
181
  <li class="level-disabled">
182
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="1">
182
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="1" id="level_selector_1280">
183
183
  <span class="check-icon">/assets/icons/new/check.svg</span>
184
184
  720p
185
185
  </a>
186
186
  </li>
187
187
 
188
188
  <li class="current">
189
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color gcore-skin-active" data-id="0">
189
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color gcore-skin-active" data-id="0" id="level_selector_640">
190
190
  <span class="check-icon">/assets/icons/new/check.svg</span>
191
191
  360p
192
192
  </a>
@@ -45,6 +45,7 @@ export type MediaControlElement =
45
45
  | 'pip'
46
46
  | 'playbackRate'
47
47
  | 'seekBarContainer'
48
+ | 'subtitlesSelector'
48
49
 
49
50
  const T = 'plugins.media_control'
50
51
 
@@ -207,7 +208,7 @@ export class MediaControl extends UICorePlugin {
207
208
  * @deprecated
208
209
  */
209
210
  get container() {
210
- return this.core && this.core.activeContainer
211
+ return this.core.activeContainer
211
212
  }
212
213
 
213
214
  /**
@@ -215,7 +216,7 @@ export class MediaControl extends UICorePlugin {
215
216
  * @deprecated
216
217
  */
217
218
  get playback() {
218
- return this.core && this.core.activePlayback
219
+ return this.core.activePlayback
219
220
  }
220
221
 
221
222
  /**
@@ -327,7 +328,6 @@ export class MediaControl extends UICorePlugin {
327
328
  this.listenTo(this.core, Events.CORE_FULLSCREEN, this.show)
328
329
  this.listenTo(this.core, Events.CORE_OPTIONS_CHANGE, this.configure)
329
330
  this.listenTo(this.core, Events.CORE_RESIZE, this.playerResize)
330
- this.bindContainerEvents()
331
331
 
332
332
  this.listenTo(this.core, 'core:advertisement:start', this.onStartAd)
333
333
  this.listenTo(this.core, 'core:advertisement:finish', this.onFinishAd)
@@ -355,63 +355,60 @@ export class MediaControl extends UICorePlugin {
355
355
  }
356
356
 
357
357
  private bindContainerEvents() {
358
- if (!this.container) {
359
- return
360
- }
361
- this.listenTo(this.container, Events.CONTAINER_PLAY, this.changeTogglePlay)
362
- this.listenTo(this.container, Events.CONTAINER_PAUSE, this.changeTogglePlay)
363
- this.listenTo(this.container, Events.CONTAINER_STOP, this.changeTogglePlay)
358
+ this.listenTo(this.core.activeContainer, Events.CONTAINER_PLAY, this.changeTogglePlay)
359
+ this.listenTo(this.core.activeContainer, Events.CONTAINER_PAUSE, this.changeTogglePlay)
360
+ this.listenTo(this.core.activeContainer, Events.CONTAINER_STOP, this.changeTogglePlay)
364
361
  this.listenTo(
365
- this.container,
362
+ this.core.activeContainer,
366
363
  Events.CONTAINER_DBLCLICK,
367
364
  this.toggleFullscreen,
368
365
  )
369
366
  this.listenTo(
370
- this.container,
367
+ this.core.activeContainer,
371
368
  Events.CONTAINER_TIMEUPDATE,
372
369
  this.onTimeUpdate,
373
370
  )
374
371
  this.listenTo(
375
- this.container,
372
+ this.core.activeContainer,
376
373
  Events.CONTAINER_PROGRESS,
377
374
  this.updateProgressBar,
378
375
  )
379
376
  this.listenTo(
380
- this.container,
377
+ this.core.activeContainer,
381
378
  Events.CONTAINER_SETTINGSUPDATE,
382
379
  this.settingsUpdate,
383
380
  )
384
381
  this.listenTo(
385
- this.container,
382
+ this.core.activeContainer,
386
383
  Events.CONTAINER_PLAYBACKDVRSTATECHANGED,
387
384
  this.settingsUpdate,
388
385
  )
389
386
  this.listenTo(
390
- this.container,
387
+ this.core.activeContainer,
391
388
  Events.CONTAINER_HIGHDEFINITIONUPDATE,
392
389
  this.highDefinitionUpdate,
393
390
  )
394
391
  this.listenTo(
395
- this.container,
392
+ this.core.activeContainer,
396
393
  Events.CONTAINER_MEDIACONTROL_DISABLE,
397
394
  this.disable,
398
395
  )
399
396
  this.listenTo(
400
- this.container,
397
+ this.core.activeContainer,
401
398
  Events.CONTAINER_MEDIACONTROL_ENABLE,
402
399
  this.enable,
403
400
  )
404
- this.listenTo(this.container, Events.CONTAINER_ENDED, this.ended)
405
- this.listenTo(this.container, Events.CONTAINER_VOLUME, this.onVolumeChanged)
401
+ this.listenTo(this.core.activeContainer, Events.CONTAINER_ENDED, this.ended)
402
+ this.listenTo(this.core.activeContainer, Events.CONTAINER_VOLUME, this.onVolumeChanged)
406
403
  this.listenTo(
407
- this.container,
404
+ this.core.activeContainer,
408
405
  Events.CONTAINER_OPTIONS_CHANGE,
409
406
  this.setInitialVolume,
410
407
  )
411
- if (this.container.playback.el.nodeName.toLowerCase() === 'video') {
408
+ if (this.core.activePlayback.el.nodeName.toLowerCase() === 'video') {
412
409
  // wait until the metadata has loaded and then check if fullscreen on video tag is supported
413
410
  this.listenToOnce(
414
- this.container,
411
+ this.core.activeContainer,
415
412
  Events.CONTAINER_LOADEDMETADATA,
416
413
  this.onLoadedMetadataOnVideoTag,
417
414
  )
@@ -455,7 +452,7 @@ export class MediaControl extends UICorePlugin {
455
452
  }
456
453
 
457
454
  private onLoadedMetadataOnVideoTag(event: any) {
458
- const video = this.playback && this.playback.el
455
+ const video = this.core.activePlayback?.el
459
456
 
460
457
  // video.webkitSupportsFullscreen is deprecated but iOS appears to only use this
461
458
  // see https://github.com/clappr/clappr/issues/1127
@@ -729,32 +726,33 @@ export class MediaControl extends UICorePlugin {
729
726
 
730
727
  private onActiveContainerChanged() {
731
728
  this.fullScreenOnVideoTagSupported = null
732
- this.bindEvents()
733
729
  // set the new container to match the volume of the last one
734
730
  this.setInitialVolume()
735
731
  this.changeTogglePlay()
736
732
  this.bindContainerEvents()
737
733
  this.settingsUpdate()
738
- this.container &&
739
- this.container.trigger(
734
+ this.core.activeContainer &&
735
+ this.core.activeContainer.trigger(
740
736
  Events.CONTAINER_PLAYBACKDVRSTATECHANGED,
741
- this.container.isDvrInUse(),
737
+ this.core.activeContainer.isDvrInUse(),
742
738
  )
743
- this.container && this.container.mediaControlDisabled && this.disable()
739
+ this.core.activeContainer && this.core.activeContainer.mediaControlDisabled && this.disable()
744
740
  this.trigger(Events.MEDIACONTROL_CONTAINERCHANGED)
745
741
 
746
- if (this.container.$el) {
747
- this.container.$el.addClass('container-skin-1')
742
+ if (this.core.activeContainer.$el) {
743
+ this.core.activeContainer.$el.addClass('container-skin-1')
748
744
  }
749
745
 
750
746
  if (this.options.cropVideo) {
751
- this.container.$el.addClass('crop-video')
747
+ this.core.activeContainer.$el.addClass('crop-video')
752
748
  }
753
749
 
754
- const spinnerPlugin = this.container.getPlugin('spinner')
750
+ // TODO handle by the spinner itself
751
+ const spinnerPlugin = this.core.activeContainer.getPlugin('spinner')
755
752
 
756
753
  spinnerPlugin?.$el.find('div').addClass('gcore-skin-main-color')
757
754
 
755
+ // TODO handle by the seek_time itself
758
756
  const seekTimePlugin = this.container.getPlugin('seek_time')
759
757
 
760
758
  seekTimePlugin?.$el.addClass('gcore-skin-bg-color')
@@ -964,12 +962,11 @@ export class MediaControl extends UICorePlugin {
964
962
  }
965
963
 
966
964
  private settingsUpdate() {
967
- const newSettings = this.getSettings()
968
- $.extend(true, newSettings, {
965
+ const newSettings = $.extend(true, {
969
966
  left: [],
970
967
  default: [],
971
968
  right: [],
972
- })
969
+ }, this.core.activeContainer?.settings)
973
970
 
974
971
  newSettings.left = orderByOrderPattern(
975
972
  [...newSettings.left, 'clipsText', 'volume'],
@@ -1014,11 +1011,6 @@ export class MediaControl extends UICorePlugin {
1014
1011
  }
1015
1012
  }
1016
1013
 
1017
- private getSettings() {
1018
- // TODO show live and remove duration/position if live
1019
- return $.extend(true, {}, this.container && this.container.settings)
1020
- }
1021
-
1022
1014
  private highDefinitionUpdate(isHD: boolean) {
1023
1015
  this.isHD = isHD
1024
1016
  }
@@ -1102,9 +1094,19 @@ export class MediaControl extends UICorePlugin {
1102
1094
  return this.$playbackRate
1103
1095
  case 'seekBarContainer':
1104
1096
  return this.$seekBarContainer
1097
+ case 'subtitlesSelector':
1098
+ return this.$subtitlesSelector
1105
1099
  }
1106
1100
  }
1107
1101
 
1102
+ /**
1103
+ * Get the right panel area to append custom elements to
1104
+ * @returns ZeptoSelector of the right panel element
1105
+ */
1106
+ getRightPanel() {
1107
+ return this.$el.find('.media-control-right-panel')
1108
+ }
1109
+
1108
1110
  private resetIndicators() {
1109
1111
  assert.ok(
1110
1112
  this.$duration && this.$position,
@@ -1298,7 +1300,7 @@ export class MediaControl extends UICorePlugin {
1298
1300
 
1299
1301
  this.changeTogglePlay()
1300
1302
 
1301
- if (this.container) {
1303
+ if (this.core.activeContainer) {
1302
1304
  this.hideId = setTimeout(() => this.hide(), timeout)
1303
1305
  this.disabled && this.hide()
1304
1306
  }