@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.
Files changed (68) hide show
  1. package/assets/bottom-gear/bottomgear copy.ejs +10 -0
  2. package/assets/bottom-gear/bottomgear.ejs +4 -8
  3. package/assets/bottom-gear/gear-sub-menu.scss +0 -1
  4. package/assets/bottom-gear/gear.scss +0 -1
  5. package/assets/clappr-nerd-stats/button.ejs +3 -3
  6. package/assets/level-selector/button.ejs +2 -4
  7. package/assets/level-selector/list.ejs +14 -10
  8. package/assets/level-selector/style.scss +9 -4
  9. package/assets/playback-rate/list.ejs +5 -5
  10. package/dist/core.js +1 -2
  11. package/dist/index.css +1104 -1103
  12. package/dist/index.js +3849 -3767
  13. package/dist/player.d.ts +10 -17
  14. package/dist/plugins/index.css +1541 -1540
  15. package/dist/plugins/index.js +3949 -3868
  16. package/docs/api/player.mediacontrol.md +8 -36
  17. package/docs/api/player.mediacontrol.toggleelement.md +72 -0
  18. package/docs/api/player.mediacontrolelement.md +1 -1
  19. package/lib/playback/dash-playback/DashPlayback.d.ts.map +1 -1
  20. package/lib/playback/dash-playback/DashPlayback.js +0 -1
  21. package/lib/plugins/bottom-gear/BottomGear.d.ts +65 -14
  22. package/lib/plugins/bottom-gear/BottomGear.d.ts.map +1 -1
  23. package/lib/plugins/bottom-gear/BottomGear.js +113 -37
  24. package/lib/plugins/clappr-nerd-stats/ClapprNerdStats.d.ts +2 -3
  25. package/lib/plugins/clappr-nerd-stats/ClapprNerdStats.d.ts.map +1 -1
  26. package/lib/plugins/clappr-nerd-stats/ClapprNerdStats.js +18 -15
  27. package/lib/plugins/dvr-controls/DvrControls.js +1 -1
  28. package/lib/plugins/level-selector/LevelSelector.d.ts +8 -11
  29. package/lib/plugins/level-selector/LevelSelector.d.ts.map +1 -1
  30. package/lib/plugins/level-selector/LevelSelector.js +66 -102
  31. package/lib/plugins/media-control/MediaControl.d.ts +7 -5
  32. package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
  33. package/lib/plugins/media-control/MediaControl.js +37 -19
  34. package/lib/plugins/picture-in-picture/PictureInPicture.d.ts.map +1 -1
  35. package/lib/plugins/picture-in-picture/PictureInPicture.js +7 -2
  36. package/lib/plugins/playback-rate/PlaybackRate.d.ts +42 -14
  37. package/lib/plugins/playback-rate/PlaybackRate.d.ts.map +1 -1
  38. package/lib/plugins/playback-rate/PlaybackRate.js +101 -83
  39. package/lib/plugins/subtitles/ClosedCaptions.js +1 -1
  40. package/lib/testUtils.d.ts +1 -0
  41. package/lib/testUtils.d.ts.map +1 -1
  42. package/lib/testUtils.js +13 -0
  43. package/package.json +1 -1
  44. package/src/playback/dash-playback/DashPlayback.ts +0 -1
  45. package/src/plugins/bottom-gear/BottomGear.ts +162 -72
  46. package/src/plugins/bottom-gear/__tests__/BottomGear.test.ts +21 -5
  47. package/src/plugins/bottom-gear/__tests__/__snapshots__/BottomGear.test.ts.snap +5 -12
  48. package/src/plugins/clappr-nerd-stats/ClapprNerdStats.ts +27 -25
  49. package/src/plugins/dvr-controls/DvrControls.ts +1 -1
  50. package/src/plugins/dvr-controls/__tests__/DvrControls.test.ts +1 -1
  51. package/src/plugins/level-selector/LevelSelector.ts +80 -120
  52. package/src/plugins/level-selector/__tests__/LevelSelector.test.ts +69 -79
  53. package/src/plugins/level-selector/__tests__/__snapshots__/LevelSelector.test.ts.snap +38 -71
  54. package/src/plugins/media-control/MediaControl.ts +51 -25
  55. package/src/plugins/media-control/__tests__/MediaControl.test.ts +4 -4
  56. package/src/plugins/picture-in-picture/PictureInPicture.ts +7 -2
  57. package/src/plugins/playback-rate/PlaybackRate.ts +136 -108
  58. package/src/plugins/playback-rate/__tests__/PlaybackRate.test.ts +84 -37
  59. package/src/plugins/playback-rate/__tests__/__snapshots__/PlaybackRate.test.ts.snap +55 -6
  60. package/src/plugins/subtitles/ClosedCaptions.ts +1 -1
  61. package/src/plugins/subtitles/__tests__/ClosedCaptions.test.ts +1 -1
  62. package/src/testUtils.ts +14 -0
  63. package/src/typings/vitest.d.ts +1 -0
  64. package/temp/player.api.json +66 -94
  65. package/tsconfig.tsbuildinfo +1 -1
  66. package/docs/api/player.mediacontrol.getcenterpanel.md +0 -18
  67. package/docs/api/player.mediacontrol.getleftpanel.md +0 -22
  68. package/docs/api/player.mediacontrol.getrightpanel.md +0 -22
@@ -1,24 +1,24 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
- exports[`LevelSelector > basically > auto > should render the proper level labels 1`] = `
4
- "<button class="gplayer-lite-btn go-back gcore-skin-text-color">
3
+ exports[`LevelSelector > basically > auto > should render the selected level 1`] = `
4
+ "<button class="gplayer-lite-btn go-back gcore-skin-text-color" id="level-selector-back-button">
5
5
  <span class="arrow-left-icon">/assets/icons/new/arrow-left.svg</span>
6
- Quality
6
+ quality
7
7
  </button>
8
- <ul class="gear-sub-menu">
8
+ <ul class="gear-sub-menu" id="level-selector-menu">
9
9
 
10
10
  <li class="current">
11
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
- Auto
14
- </a>
15
- </li>
13
+ auto
14
+ </a>
15
+ </li>
16
16
 
17
17
 
18
18
  <li class="">
19
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
- 1080p
21
+ Full HD
22
22
  </a>
23
23
  </li>
24
24
 
@@ -40,25 +40,25 @@ exports[`LevelSelector > basically > auto > should render the proper level label
40
40
  "
41
41
  `;
42
42
 
43
- exports[`LevelSelector > basically > custom label > should render the proper level labels 1`] = `
44
- "<button class="gplayer-lite-btn go-back gcore-skin-text-color">
43
+ exports[`LevelSelector > basically > custom label > should render the selected level 1`] = `
44
+ "<button class="gplayer-lite-btn go-back gcore-skin-text-color" id="level-selector-back-button">
45
45
  <span class="arrow-left-icon">/assets/icons/new/arrow-left.svg</span>
46
- Quality
46
+ quality
47
47
  </button>
48
- <ul class="gear-sub-menu">
48
+ <ul class="gear-sub-menu" id="level-selector-menu">
49
49
 
50
50
  <li class="">
51
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
- Auto
54
- </a>
55
- </li>
53
+ auto
54
+ </a>
55
+ </li>
56
56
 
57
57
 
58
58
  <li class="">
59
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
- 1080p
61
+ Full HD
62
62
  </a>
63
63
  </li>
64
64
 
@@ -80,25 +80,25 @@ exports[`LevelSelector > basically > custom label > should render the proper lev
80
80
  "
81
81
  `;
82
82
 
83
- exports[`LevelSelector > basically > standard label > should render the proper level labels 1`] = `
84
- "<button class="gplayer-lite-btn go-back gcore-skin-text-color">
83
+ exports[`LevelSelector > basically > standard label > should render the selected level 1`] = `
84
+ "<button class="gplayer-lite-btn go-back gcore-skin-text-color" id="level-selector-back-button">
85
85
  <span class="arrow-left-icon">/assets/icons/new/arrow-left.svg</span>
86
- Quality
86
+ quality
87
87
  </button>
88
- <ul class="gear-sub-menu">
88
+ <ul class="gear-sub-menu" id="level-selector-menu">
89
89
 
90
90
  <li class="">
91
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
- Auto
94
- </a>
95
- </li>
93
+ auto
94
+ </a>
95
+ </li>
96
96
 
97
97
 
98
98
  <li class="">
99
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
- 1080p
101
+ Full HD
102
102
  </a>
103
103
  </li>
104
104
 
@@ -120,40 +120,30 @@ exports[`LevelSelector > basically > standard label > should render the proper l
120
120
  "
121
121
  `;
122
122
 
123
- exports[`LevelSelector > options.restrictResolution > basically > should render the restricted quality level label 1`] = `
124
- "<button class="gplayer-lite-btn gcore-skin-text-color gear-option">
125
-
126
- <span>Quality</span>
127
- <span class="gear-option_arrow-right-icon">/assets/icons/new/arrow-right.svg</span>
128
- <span class="gear-option_value">360p</span>
129
- </button>
130
- "
131
- `;
132
-
133
123
  exports[`LevelSelector > options.restrictResolution > given vertical video format levels > should recognize vertical orientation 1`] = `
134
- "<button class="gplayer-lite-btn go-back gcore-skin-text-color">
124
+ "<button class="gplayer-lite-btn go-back gcore-skin-text-color" id="level-selector-back-button">
135
125
  <span class="arrow-left-icon">/assets/icons/new/arrow-left.svg</span>
136
- Quality
126
+ quality
137
127
  </button>
138
- <ul class="gear-sub-menu">
128
+ <ul class="gear-sub-menu" id="level-selector-menu">
139
129
 
140
130
 
141
- <li class="level-disabled">
131
+ <li class="disabled ">
142
132
  <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="2" id="level_selector_1080">
143
133
  <span class="check-icon">/assets/icons/new/check.svg</span>
144
134
  1080p
145
135
  </a>
146
136
  </li>
147
137
 
148
- <li class="level-disabled">
149
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="1" id="level_selector_1280">
138
+ <li class="disabled ">
139
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="1" id="level_selector_720">
150
140
  <span class="check-icon">/assets/icons/new/check.svg</span>
151
141
  720p
152
142
  </a>
153
143
  </li>
154
144
 
155
- <li class="current">
156
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color gcore-skin-active" data-id="0" id="level_selector_640">
145
+ <li class="current ">
146
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color gcore-skin-active" data-id="0" id="level_selector_360">
157
147
  <span class="check-icon">/assets/icons/new/check.svg</span>
158
148
  360p
159
149
  </a>
@@ -163,35 +153,12 @@ exports[`LevelSelector > options.restrictResolution > given vertical video forma
163
153
  "
164
154
  `;
165
155
 
166
- exports[`LevelSelector > options.restrictResolution > given vertical video format levels > should recognize vertical orientation 2`] = `
167
- "<button class="gplayer-lite-btn go-back gcore-skin-text-color">
168
- <span class="arrow-left-icon">/assets/icons/new/arrow-left.svg</span>
169
- Quality
156
+ exports[`LevelSelector > options.restrictResolution > initially > should render the restricted quality level label 1`] = `
157
+ "<button class="gplayer-lite-btn gcore-skin-text-color gear-option">
158
+ <span class="gear-option_hd-icon hidden">/assets/icons/new/hd.svg</span>
159
+ <span>quality</span>
160
+ <span class="gear-option_arrow-right-icon">/assets/icons/new/arrow-right.svg</span>
161
+ <span class="gear-option_value">360p</span>
170
162
  </button>
171
- <ul class="gear-sub-menu">
172
-
173
-
174
- <li class="level-disabled">
175
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="2" id="level_selector_1080">
176
- <span class="check-icon">/assets/icons/new/check.svg</span>
177
- 1080p
178
- </a>
179
- </li>
180
-
181
- <li class="level-disabled">
182
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="1" id="level_selector_1280">
183
- <span class="check-icon">/assets/icons/new/check.svg</span>
184
- 720p
185
- </a>
186
- </li>
187
-
188
- <li class="current">
189
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color gcore-skin-active" data-id="0" id="level_selector_640">
190
- <span class="check-icon">/assets/icons/new/check.svg</span>
191
- 360p
192
- </a>
193
- </li>
194
-
195
- </ul>
196
163
  "
197
164
  `;
@@ -47,11 +47,15 @@ export type MediaControlElement =
47
47
  | 'clipText'
48
48
  | 'dvr'
49
49
  | 'duration'
50
+ | 'fullscreen'
50
51
  | 'gear'
52
+ | 'multicamera'
51
53
  | 'pip'
52
54
  | 'playbackRate'
53
55
  | 'position'
54
56
  | 'seekBarContainer'
57
+ | 'vr'
58
+ | 'volume'
55
59
 
56
60
  type MediaControlSettings = {
57
61
  left: MediaControlElement[]
@@ -62,7 +66,16 @@ type MediaControlSettings = {
62
66
 
63
67
  const DEFAULT_SETTINGS: MediaControlSettings = {
64
68
  left: [],
65
- right: [],
69
+ right: [
70
+ 'fullscreen',
71
+ 'pip',
72
+ 'gear',
73
+ 'cc',
74
+ 'multicamera',
75
+ // 'playbackrate',
76
+ 'vr',
77
+ 'audiotracks',
78
+ ],
66
79
  default: [],
67
80
  seekEnabled: true,
68
81
  }
@@ -70,6 +83,7 @@ const DEFAULT_SETTINGS: MediaControlSettings = {
70
83
  /**
71
84
  * Custom events emitted by the plugins to communicate with one another
72
85
  * @beta
86
+ * @deprecated
73
87
  */
74
88
  export enum MediaControlEvents {
75
89
  /**
@@ -83,7 +97,6 @@ const T = 'plugins.media_control'
83
97
  const LEFT_ORDER = [
84
98
  'playpause',
85
99
  'playstop',
86
- // 'live',
87
100
  'dvr',
88
101
  'volume',
89
102
  'position',
@@ -115,6 +128,9 @@ type DisabledClickable = {
115
128
  export class MediaControl extends UICorePlugin {
116
129
  // private advertisementPlaying = false
117
130
 
131
+ private customAreaElements: Record<string, HTMLElement> = {}
132
+ private customAreaHandler?: (name: string, element: HTMLElement) => void
133
+
118
134
  private buttonsColor: string | null = null
119
135
 
120
136
  private currentDurationValue: number = 0
@@ -155,8 +171,6 @@ export class MediaControl extends UICorePlugin {
155
171
 
156
172
  private verticalVolume = false
157
173
 
158
- private $audioTracksSelector: ZeptoResult | null = null
159
-
160
174
  private $clipText: ZeptoResult | null = null
161
175
 
162
176
  private $clipTextContainer: ZeptoResult | null = null
@@ -167,8 +181,6 @@ export class MediaControl extends UICorePlugin {
167
181
 
168
182
  private $multiCameraSelector: ZeptoResult | null = null
169
183
 
170
- private $pip: ZeptoResult | null = null
171
-
172
184
  private $playPauseToggle: ZeptoResult | null = null
173
185
 
174
186
  private $playStopToggle: ZeptoResult | null = null
@@ -740,9 +752,13 @@ export class MediaControl extends UICorePlugin {
740
752
  if (this.core.activeContainer && this.core.activeContainer.isReady) {
741
753
  this.core.activeContainer.setVolume(value)
742
754
  } else {
743
- this.listenToOnce(this.core.activeContainer, Events.CONTAINER_READY, () => {
744
- this.core.activeContainer.setVolume(value)
745
- })
755
+ this.listenToOnce(
756
+ this.core.activeContainer,
757
+ Events.CONTAINER_READY,
758
+ () => {
759
+ this.core.activeContainer.setVolume(value)
760
+ },
761
+ )
746
762
  }
747
763
  }
748
764
 
@@ -815,10 +831,12 @@ export class MediaControl extends UICorePlugin {
815
831
  if (!this.$volumeBarContainer) {
816
832
  return
817
833
  }
834
+ if (this.hideVolumeId) {
835
+ clearTimeout(this.hideVolumeId)
836
+ }
818
837
  if (this.draggingVolumeBar) {
819
838
  this.hideVolumeId = setTimeout(() => this.hideVolumeBar(), timeout)
820
839
  } else {
821
- this.hideVolumeId && clearTimeout(this.hideVolumeId)
822
840
  this.hideVolumeId = setTimeout(
823
841
  () => this.$volumeBarContainer?.addClass('volume-bar-hide'),
824
842
  timeout,
@@ -1025,16 +1043,7 @@ export class MediaControl extends UICorePlugin {
1025
1043
  }
1026
1044
 
1027
1045
  // actual order of the items appear rendered is controlled by CSS
1028
- newSettings.right = [
1029
- 'fullscreen',
1030
- 'pip',
1031
- 'gear',
1032
- 'cc',
1033
- 'multicamera',
1034
- 'playbackrate',
1035
- 'vr',
1036
- 'audiotracks',
1037
- ]
1046
+ newSettings.right = DEFAULT_SETTINGS.right
1038
1047
 
1039
1048
  if (
1040
1049
  (!this.fullScreenOnVideoTagSupported &&
@@ -1140,31 +1149,40 @@ export class MediaControl extends UICorePlugin {
1140
1149
  }
1141
1150
  }
1142
1151
 
1143
- putElement(name: MediaControlElement, element: HTMLElement) {
1152
+ putElement(name: MediaControlElement, element: ZeptoResult) {
1144
1153
  const panel = this.getElementLocation(name)
1145
1154
  trace(`${T} putElement`, { name, panel: !!panel })
1146
1155
  if (panel) {
1147
1156
  const current = panel.find(`[data-${name}]`)
1148
- element.setAttribute(`data-${name}`, '')
1157
+ element.attr(`data-${name}`, '')
1149
1158
  // TODO test
1150
1159
  if (current.length) {
1151
- if (current[0] === element) {
1160
+ if (current[0] === element[0]) {
1152
1161
  return
1153
1162
  }
1154
1163
  current.replaceWith(element)
1155
1164
  } else {
1156
1165
  panel.append(element)
1157
1166
  }
1167
+ return
1158
1168
  }
1159
1169
  }
1160
1170
 
1171
+ handleCustomArea(handler: (name: string, content: HTMLElement) => void) {
1172
+ this.customAreaHandler = handler
1173
+ Object.entries(this.customAreaElements).forEach(([name, element]) => {
1174
+ handler(name, element)
1175
+ })
1176
+ this.customAreaElements = {}
1177
+ }
1178
+
1161
1179
  /**
1162
1180
  * Toggle the visibility of a media control element
1163
1181
  * @param name - The name of the media control element
1164
1182
  * @param show - Whether to show or hide the element
1165
1183
  */
1166
- toggleElement(name: MediaControlElement, show: boolean) {
1167
- this.$el.find(`[data-${name}]`).toggle(show)
1184
+ toggleElement(area: MediaControlElement, show: boolean) {
1185
+ this.$el.find(`[data-${area}]`).toggle(show)
1168
1186
  }
1169
1187
 
1170
1188
  private getRightPanel() {
@@ -1356,6 +1374,7 @@ export class MediaControl extends UICorePlugin {
1356
1374
  * @internal
1357
1375
  */
1358
1376
  override render() {
1377
+ trace(`${T} render`)
1359
1378
  const timeout = this.options.hideMediaControlDelay || 2000
1360
1379
 
1361
1380
  const html = MediaControl.template({ settings: this.settings ?? {} })
@@ -1417,6 +1436,7 @@ export class MediaControl extends UICorePlugin {
1417
1436
 
1418
1437
  this.rendered = true
1419
1438
  this.updateVolumeUI()
1439
+ // TODO setTimeout
1420
1440
  this.trigger(Events.MEDIACONTROL_RENDERED)
1421
1441
 
1422
1442
  return this
@@ -1505,6 +1525,12 @@ export class MediaControl extends UICorePlugin {
1505
1525
  }
1506
1526
 
1507
1527
  private getElementLocation(name: MediaControlElement) {
1528
+ trace(`${T} getElementLocation`, {
1529
+ name,
1530
+ right: this.settings.right,
1531
+ left: this.settings.left,
1532
+ default: this.settings.default,
1533
+ })
1508
1534
  if (this.settings.right?.includes(name)) {
1509
1535
  return this.getRightPanel()
1510
1536
  }
@@ -2,7 +2,7 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'
2
2
  import { MediaControl, MediaControlElement } from '../MediaControl'
3
3
  import { createMockCore } from '../../../testUtils'
4
4
  import { LogTracer, Logger, setTracer } from '@gcorevideo/utils'
5
- import { Events, Playback } from '@clappr/core'
5
+ import { $, Events, Playback } from '@clappr/core'
6
6
 
7
7
  Logger.enable('*')
8
8
  setTracer(new LogTracer('MediaControl.test'))
@@ -60,7 +60,7 @@ describe('MediaControl', () => {
60
60
  const element = document.createElement('div')
61
61
  element.className = 'my-media-control'
62
62
  element.textContent = 'test'
63
- mediaControl.putElement(mcName, element)
63
+ mediaControl.putElement(mcName, $(element))
64
64
 
65
65
  expect(mediaControl.el.innerHTML).toMatchSnapshot()
66
66
  expect(mediaControl.$el.find('.media-control-right-panel .my-media-control').length).toEqual(1)
@@ -90,7 +90,7 @@ describe('MediaControl', () => {
90
90
  const element = document.createElement('div')
91
91
  element.className = 'my-dvr-controls'
92
92
  element.textContent = 'live'
93
- mediaControl.putElement('dvr', element)
93
+ mediaControl.putElement('dvr', $(element))
94
94
  expect(mediaControl.el.innerHTML).toMatchSnapshot()
95
95
  expect(mediaControl.$el.find('.media-control-left-panel .my-dvr-controls').length).toEqual(1)
96
96
  })
@@ -100,7 +100,7 @@ describe('MediaControl', () => {
100
100
  const element = document.createElement('div')
101
101
  element.className = 'my-dvr-controls'
102
102
  element.textContent = 'live'
103
- mediaControl.putElement('dvr', element)
103
+ mediaControl.putElement('dvr', $(element))
104
104
  expect(mediaControl.el.innerHTML).toMatchSnapshot()
105
105
  expect(mediaControl.$el.find('.media-control-left-panel .my-dvr-controls').length).toEqual(0)
106
106
  })
@@ -6,6 +6,7 @@ import { CLAPPR_VERSION } from '../../build.js';
6
6
  import pipIcon from '../../../assets/icons/new/pip.svg';
7
7
  import buttonHtml from '../../../assets/picture-in-picture/button.ejs';
8
8
  import '../../../assets/picture-in-picture/button.scss';
9
+ import assert from 'assert';
9
10
 
10
11
  const VERSION = '0.0.1';
11
12
 
@@ -68,7 +69,11 @@ export class PictureInPicture extends UICorePlugin {
68
69
  * @internal
69
70
  */
70
71
  override bindEvents() {
71
- this.listenTo(this.core.mediaControl, Events.MEDIACONTROL_RENDERED, this.render);
72
+ this.listenToOnce(this.core, Events.CORE_READY, () => {
73
+ const mediaControl = this.core.getPlugin('media_control');
74
+ assert(mediaControl, 'media_control plugin is required');
75
+ this.listenTo(mediaControl, Events.MEDIACONTROL_RENDERED, this.render);
76
+ });
72
77
  }
73
78
 
74
79
  private isPiPSupported() {
@@ -92,7 +97,7 @@ export class PictureInPicture extends UICorePlugin {
92
97
 
93
98
  const mediaControl = this.core.getPlugin('media_control');
94
99
  if (mediaControl) {
95
- mediaControl.putElement('pip', this.el);
100
+ mediaControl.putElement('pip', this.$el);
96
101
  }
97
102
 
98
103
  return this;