@gcorevideo/player 2.20.7 → 2.20.8

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 (49) hide show
  1. package/dist/core.js +37 -13
  2. package/dist/index.css +1343 -1343
  3. package/dist/index.js +241 -217
  4. package/dist/plugins/index.css +475 -475
  5. package/dist/plugins/index.js +152 -154
  6. package/lib/playback/BasePlayback.d.ts +5 -0
  7. package/lib/playback/BasePlayback.d.ts.map +1 -1
  8. package/lib/playback/BasePlayback.js +8 -0
  9. package/lib/playback/HTML5Video.d.ts +4 -0
  10. package/lib/playback/HTML5Video.d.ts.map +1 -0
  11. package/lib/playback/HTML5Video.js +3 -0
  12. package/lib/playback/dash-playback/DashPlayback.d.ts +1 -0
  13. package/lib/playback/dash-playback/DashPlayback.d.ts.map +1 -1
  14. package/lib/playback/dash-playback/DashPlayback.js +6 -2
  15. package/lib/playback/index.d.ts.map +1 -1
  16. package/lib/playback/index.js +2 -0
  17. package/lib/playback/types.d.ts +9 -0
  18. package/lib/playback/types.d.ts.map +1 -0
  19. package/lib/playback/types.js +9 -0
  20. package/lib/plugins/bottom-gear/BottomGear.d.ts +6 -11
  21. package/lib/plugins/bottom-gear/BottomGear.d.ts.map +1 -1
  22. package/lib/plugins/bottom-gear/BottomGear.js +5 -14
  23. package/lib/plugins/clappr-nerd-stats/ClapprNerdStats.js +2 -2
  24. package/lib/plugins/dvr-controls/DvrControls.d.ts +1 -1
  25. package/lib/plugins/dvr-controls/DvrControls.d.ts.map +1 -1
  26. package/lib/plugins/dvr-controls/DvrControls.js +27 -16
  27. package/lib/plugins/level-selector/LevelSelector.d.ts +2 -0
  28. package/lib/plugins/level-selector/LevelSelector.d.ts.map +1 -1
  29. package/lib/plugins/level-selector/LevelSelector.js +14 -3
  30. package/lib/plugins/media-control/MediaControl.d.ts +1 -0
  31. package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
  32. package/lib/plugins/media-control/MediaControl.js +5 -3
  33. package/lib/plugins/playback-rate/PlaybackRate.d.ts +11 -10
  34. package/lib/plugins/playback-rate/PlaybackRate.d.ts.map +1 -1
  35. package/lib/plugins/playback-rate/PlaybackRate.js +83 -91
  36. package/package.json +1 -1
  37. package/src/playback/BasePlayback.ts +12 -4
  38. package/src/playback/HTML5Video.ts +3 -0
  39. package/src/playback/dash-playback/DashPlayback.ts +15 -11
  40. package/src/playback/index.ts +2 -1
  41. package/src/playback/types.ts +9 -0
  42. package/src/plugins/bottom-gear/BottomGear.ts +6 -15
  43. package/src/plugins/clappr-nerd-stats/ClapprNerdStats.ts +3 -3
  44. package/src/plugins/dvr-controls/DvrControls.ts +87 -54
  45. package/src/plugins/level-selector/LevelSelector.ts +17 -5
  46. package/src/plugins/media-control/MediaControl.ts +9 -6
  47. package/src/plugins/playback-rate/PlaybackRate.ts +89 -105
  48. package/tsconfig.tsbuildinfo +1 -1
  49. package/assets/playback-rate/playback-rate-selector.ejs +0 -9
@@ -1,10 +1,13 @@
1
- import { Core, Events, Playback, UICorePlugin, template } from '@clappr/core';
2
- import assert from 'assert';
1
+ import { Core, Events, Playback, UICorePlugin, template } from '@clappr/core'
2
+ import assert from 'assert'
3
3
 
4
- import { CLAPPR_VERSION } from '../../build.js';
4
+ import { CLAPPR_VERSION } from '../../build.js'
5
5
 
6
- import dvrHTML from '../../../assets/dvr-controls/index.ejs';
7
- import '../../../assets/dvr-controls/dvr_controls.scss';
6
+ import dvrHTML from '../../../assets/dvr-controls/index.ejs'
7
+ import '../../../assets/dvr-controls/dvr_controls.scss'
8
+ import { trace } from '@gcorevideo/utils'
9
+
10
+ const T = 'plugins.dvr_controls'
8
11
 
9
12
  /**
10
13
  * Adds the DVR controls to the media control UI
@@ -18,20 +21,20 @@ import '../../../assets/dvr-controls/dvr_controls.scss';
18
21
  * The plugin renders the live stream indicator and the DVR seek bar, if DVR is enabled, in the media control UI.
19
22
  */
20
23
  export class DvrControls extends UICorePlugin {
21
- private static readonly template = template(dvrHTML);
24
+ private static readonly template = template(dvrHTML)
22
25
 
23
26
  /**
24
27
  * @internal
25
28
  */
26
29
  get name() {
27
- return 'dvr_controls';
30
+ return 'dvr_controls'
28
31
  }
29
32
 
30
33
  /**
31
34
  * @internal
32
35
  */
33
36
  get supportedVersion() {
34
- return { min: CLAPPR_VERSION };
37
+ return { min: CLAPPR_VERSION }
35
38
  }
36
39
 
37
40
  /**
@@ -39,8 +42,8 @@ export class DvrControls extends UICorePlugin {
39
42
  */
40
43
  override get events() {
41
44
  return {
42
- 'click .live-button': 'click'
43
- };
45
+ 'click .live-button': 'click',
46
+ }
44
47
  }
45
48
 
46
49
  /**
@@ -48,96 +51,126 @@ export class DvrControls extends UICorePlugin {
48
51
  */
49
52
  override get attributes() {
50
53
  return {
51
- 'class': 'dvr-controls',
52
- 'data-dvr-controls': ''
53
- };
54
+ class: 'dvr-controls',
55
+ 'data-dvr-controls': '',
56
+ }
54
57
  }
55
58
 
56
59
  constructor(core: Core) {
57
- super(core);
58
- this.settingsUpdate();
60
+ super(core)
61
+ this.settingsUpdate()
59
62
  }
60
63
 
61
64
  /**
62
65
  * @internal
63
66
  */
64
67
  override bindEvents() {
65
- const mediaControl = this.core.getPlugin('media_control');
66
- assert(mediaControl, 'media_control plugin is required');
67
- this.listenTo(mediaControl, Events.MEDIACONTROL_RENDERED, this.settingsUpdate);
68
- this.listenTo(this.core, Events.CORE_OPTIONS_CHANGE, this.render);
69
- this.listenTo(this.core, Events.CORE_ACTIVE_CONTAINER_CHANGED, this.bindContainerEvents);
68
+ const mediaControl = this.core.getPlugin('media_control')
69
+ assert(mediaControl, 'media_control plugin is required')
70
+ this.listenTo(
71
+ mediaControl,
72
+ Events.MEDIACONTROL_RENDERED,
73
+ this.settingsUpdate,
74
+ )
75
+ this.listenTo(this.core, Events.CORE_OPTIONS_CHANGE, this.render)
76
+ this.listenTo(
77
+ this.core,
78
+ Events.CORE_ACTIVE_CONTAINER_CHANGED,
79
+ this.bindContainerEvents,
80
+ )
70
81
  }
71
82
 
72
83
  private bindContainerEvents() {
73
- this.listenToOnce(this.core.activeContainer, Events.CONTAINER_TIMEUPDATE, this.render);
74
- this.listenTo(this.core.activeContainer, Events.CONTAINER_PLAYBACKDVRSTATECHANGED, this.dvrChanged);
84
+ this.listenToOnce(
85
+ this.core.activeContainer,
86
+ Events.CONTAINER_TIMEUPDATE,
87
+ this.render,
88
+ )
89
+ this.listenTo(
90
+ this.core.activeContainer,
91
+ Events.CONTAINER_PLAYBACKDVRSTATECHANGED,
92
+ this.onDvrChanged,
93
+ )
75
94
  }
76
95
 
77
- private dvrChanged(dvrEnabled: boolean) {
96
+ private onDvrChanged(dvrEnabled: boolean) {
97
+ trace(`${T} onDvrChanged`, {
98
+ dvrEnabled,
99
+ })
78
100
  if (this.core.getPlaybackType() !== Playback.LIVE) {
79
- return;
101
+ return
80
102
  }
81
- this.settingsUpdate();
82
- this.core.mediaControl.$el.addClass('live');
103
+ this.settingsUpdate()
104
+ this.core.mediaControl.$el.addClass('live')
83
105
  if (dvrEnabled) {
84
- this.core.mediaControl.$playbackRate.removeClass('playbackrate-enable');
106
+ // TODO
85
107
  this.core.mediaControl.$el
86
108
  .addClass('dvr')
87
- .find('.media-control-indicator[data-position], .media-control-indicator[data-duration]')
88
- .hide();
109
+ .find(
110
+ '.media-control-indicator[data-position], .media-control-indicator[data-duration]',
111
+ )
112
+ .hide()
89
113
  } else {
90
- this.core.mediaControl.$playbackRate.addClass('playbackrate-enable');
91
- this.core.mediaControl.$el.removeClass('dvr');
114
+ this.core.mediaControl.$el.removeClass('dvr')
92
115
  }
93
116
  }
94
117
 
95
118
  private click() {
96
- const mediaControl = this.core.getPlugin('media_control');
97
- const container = this.core.activeContainer;
119
+ const mediaControl = this.core.getPlugin('media_control')
120
+ const container = this.core.activeContainer
98
121
 
99
122
  if (!container.isPlaying()) {
100
- container.play();
123
+ container.play()
101
124
  }
102
125
 
103
126
  if (mediaControl.$el.hasClass('dvr')) {
104
- container.seek(container.getDuration());
127
+ container.seek(container.getDuration())
105
128
  }
106
129
  }
107
130
 
108
131
  private settingsUpdate() {
109
132
  // @ts-ignore
110
- this.stopListening(); // TODO sort out
111
- this.core.getPlugin('media_control').$el.removeClass('live'); // TODO don't access directly
133
+ this.stopListening() // TODO sort out
134
+ this.core.getPlugin('media_control').$el.removeClass('live') // TODO don't access directly
112
135
  if (this.shouldRender()) {
113
- this.render();
114
- this.$el.click(() => this.click());
136
+ this.render()
137
+ this.$el.click(() => this.click())
115
138
  }
116
- this.bindEvents();
139
+ this.bindEvents()
117
140
  }
118
141
 
119
142
  private shouldRender() {
120
- const useDvrControls = this.core.options.useDvrControls === undefined || !!this.core.options.useDvrControls;
143
+ const useDvrControls =
144
+ this.core.options.useDvrControls === undefined ||
145
+ !!this.core.options.useDvrControls
121
146
 
122
- return useDvrControls && this.core.getPlaybackType() === Playback.LIVE;
147
+ return useDvrControls && this.core.getPlaybackType() === Playback.LIVE
123
148
  }
124
149
 
125
150
  /**
126
151
  * @internal
127
152
  */
128
153
  override render() {
129
- this.$el.html(DvrControls.template({
130
- live: this.core.i18n.t('live'),
131
- backToLive: this.core.i18n.t('back_to_live')
132
- }));
133
- if (this.shouldRender()) {
134
- const mediaControl = this.core.getPlugin('media_control');
135
- assert(mediaControl, 'media_control plugin is required');
136
- // TODO don't tap into the $el directly
137
- mediaControl.$el.addClass('live');
138
- mediaControl.$('.media-control-left-panel[data-media-control]').append(this.$el);
154
+ trace(`${T} render`, {
155
+ dvrEnabled: this.core.activePlayback?.dvrEnabled,
156
+ })
157
+ if (!this.shouldRender()) {
158
+ return this
139
159
  }
140
-
141
- return this;
160
+ this.$el.html(
161
+ DvrControls.template({
162
+ live: this.core.i18n.t('live'),
163
+ backToLive: this.core.i18n.t('back_to_live'),
164
+ }),
165
+ )
166
+ const mediaControl = this.core.getPlugin('media_control')
167
+ assert(mediaControl, 'media_control plugin is required')
168
+ // TODO don't tap into the $el directly
169
+ mediaControl.$el.addClass('live')
170
+ mediaControl
171
+ .$('.media-control-left-panel[data-media-control]')
172
+ .append(this.$el)
173
+
174
+ return this
142
175
  }
143
176
  }
@@ -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 } from '../media-control/MediaControl.js'
18
+ import { MediaControl, MediaControlEvents } from '../media-control/MediaControl.js'
19
19
 
20
20
  const T = 'plugins.level_selector'
21
21
  const VERSION = '2.19.4'
@@ -125,8 +125,7 @@ export class LevelSelector extends UICorePlugin {
125
125
  * @internal
126
126
  */
127
127
  override bindEvents() {
128
- const mediaControl = this.core.getPlugin('media_control') as MediaControl
129
- assert(mediaControl, 'media_control plugin is required')
128
+ this.listenTo(this.core, Events.CORE_READY, this.onCoreReady);
130
129
  this.listenTo(
131
130
  this.core,
132
131
  Events.CORE_ACTIVE_CONTAINER_CHANGED,
@@ -134,6 +133,18 @@ export class LevelSelector extends UICorePlugin {
134
133
  )
135
134
  }
136
135
 
136
+ private onCoreReady() {
137
+ trace(`${T} onCoreReady`);
138
+ const mediaControl = this.core.getPlugin('media_control') as MediaControl
139
+ assert(mediaControl, 'media_control plugin is required')
140
+ this.listenTo(mediaControl, MediaControlEvents.MEDIACONTROL_GEAR_RENDERED, this.onGearRendered);
141
+ }
142
+
143
+ private onGearRendered() {
144
+ trace(`${T} onGearRendered`);
145
+ this.deferRender();
146
+ }
147
+
137
148
  private bindPlaybackEvents() {
138
149
  this.removeAuto = false
139
150
  this.isHd = false
@@ -301,8 +312,9 @@ export class LevelSelector extends UICorePlugin {
301
312
  private goBack() {
302
313
  trace(`${T} goBack`)
303
314
  this.isOpen = false
304
- this.core.trigger('gear:refresh')
305
- this.deferRender()
315
+ setTimeout(() => {
316
+ this.core.getPlugin('bottom_gear').refresh()
317
+ }, 0);
306
318
  }
307
319
 
308
320
  private setLevel(index: number) {
@@ -107,7 +107,7 @@ export class MediaControl extends UICorePlugin {
107
107
 
108
108
  private currentDurationValue: number = 0
109
109
  private currentPositionValue: number = 0
110
- private currentSeekBarPercentage: number | null = null
110
+ private currentSeekBarPercentage = 0
111
111
 
112
112
  private disabledClickableList: DisabledClickable[] = []
113
113
  private displayedDuration: string | null = null
@@ -275,6 +275,10 @@ export class MediaControl extends UICorePlugin {
275
275
  }
276
276
  }
277
277
 
278
+ get currentSeekPos() {
279
+ return this.currentSeekBarPercentage
280
+ }
281
+
278
282
  /**
279
283
  * Current volume [0..100]
280
284
  */
@@ -746,11 +750,10 @@ export class MediaControl extends UICorePlugin {
746
750
  this.changeTogglePlay()
747
751
  this.bindContainerEvents()
748
752
  this.settingsUpdate()
749
- this.core.activeContainer &&
750
- this.core.activeContainer.trigger(
751
- Events.CONTAINER_PLAYBACKDVRSTATECHANGED,
752
- this.core.activeContainer.isDvrInUse(),
753
- )
753
+ this.core.activeContainer.trigger(
754
+ Events.CONTAINER_PLAYBACKDVRSTATECHANGED,
755
+ this.core.activeContainer.isDvrInUse(),
756
+ )
754
757
  // TODO test
755
758
  if (this.core.activeContainer.mediaControlDisabled) {
756
759
  this.disable()
@@ -1,15 +1,19 @@
1
- import { Events, UICorePlugin, Playback, template } from '@clappr/core';
1
+ import { Events, UICorePlugin, Playback, template, Core } from '@clappr/core';
2
+ import { trace } from '@gcorevideo/utils';
3
+ import assert from 'assert';
2
4
 
3
5
  import { CLAPPR_VERSION } from '../../build.js';
4
6
  import type { ZeptoResult } from '../../utils/types.js';
5
7
 
6
- import pluginHtml from '../../../assets/playback-rate/playback-rate-selector.ejs';
7
8
  import buttonHtml from '../../../assets/playback-rate/button.ejs';
8
9
  import listHtml from '../../../assets/playback-rate/list.ejs';
9
10
  import speedIcon from '../../../assets/icons/new/speed.svg';
10
11
  import arrowRightIcon from '../../../assets/icons/new/arrow-right.svg';
11
12
  import arrowLeftIcon from '../../../assets/icons/new/arrow-left.svg';
12
13
  import checkIcon from '../../../assets/icons/new/check.svg';
14
+ import { BottomGear } from '../bottom-gear/BottomGear.js';
15
+ import { PlaybackEvents } from '../../playback/types.js';
16
+ import { MediaControl, MediaControlEvents } from '../media-control/MediaControl.js';
13
17
 
14
18
  type PlaybackRateOption = {
15
19
  value: string;
@@ -28,11 +32,10 @@ const DEFAULT_PLAYBACK_RATES = [
28
32
 
29
33
  const DEFAULT_PLAYBACK_RATE = '1.0';
30
34
 
31
- // TODO
32
- const MEDIACONTROL_PLAYBACKRATE = 'playbackRate';
35
+ const T = 'plugins.playback_rate';
33
36
 
34
37
  /**
35
- * Allows changing the playback speed of the video.
38
+ * PLUGIN that allows changing the playback speed of the video.
36
39
  * @beta
37
40
  *
38
41
  * @remarks
@@ -42,15 +45,16 @@ const MEDIACONTROL_PLAYBACKRATE = 'playbackRate';
42
45
  *
43
46
  * - {@link BottomGear | bottom_gear}
44
47
  *
45
- * It renders a button in the gear menu, which opens a dropdown with the available playback rates.
48
+ * It renders a button in the gear menu, which opens a dropdown with the options to change the playback rate.
46
49
  */
47
50
  export class PlaybackRate extends UICorePlugin {
48
- private currentPlayback: Playback | null = null;
49
-
50
51
  private playbackRates: PlaybackRateOption[] = DEFAULT_PLAYBACK_RATES;
51
52
 
53
+ // Saved when an ad starts to restore after it finishes
52
54
  private prevSelectedRate: string | undefined;
53
55
 
56
+ private rendered = false;
57
+
54
58
  private selectedRate: string = DEFAULT_PLAYBACK_RATE;
55
59
 
56
60
  /**
@@ -67,12 +71,16 @@ export class PlaybackRate extends UICorePlugin {
67
71
  return { min: CLAPPR_VERSION };
68
72
  }
69
73
 
70
- private static readonly template = template(pluginHtml);
71
-
72
74
  private static readonly buttonTemplate = template(buttonHtml);
73
75
 
74
76
  private static readonly listTemplate = template(listHtml);
75
77
 
78
+ constructor(core: Core) {
79
+ super(core);
80
+ this.playbackRates = core.options.playbackRate?.options || DEFAULT_PLAYBACK_RATES;
81
+ this.selectedRate = core.options.playbackRate?.defaultValue || DEFAULT_PLAYBACK_RATE;
82
+ }
83
+
76
84
  /**
77
85
  * @internal
78
86
  */
@@ -98,31 +106,40 @@ export class PlaybackRate extends UICorePlugin {
98
106
  * @internal
99
107
  */
100
108
  override bindEvents() {
101
- this.listenTo(this.core, 'gear:rendered', this.render);
102
- // TODO this.core.getPlugin('media_control'), bottom_gear
103
- this.listenTo(this.core.mediaControl, Events.MEDIACONTROL_CONTAINERCHANGED, this.reload);
104
- this.listenTo(this.core.mediaControl, MEDIACONTROL_PLAYBACKRATE, this.updatePlaybackRate);
105
-
106
- this.listenTo(this.core, 'core:advertisement:start', this.onStartAd);
107
- this.listenTo(this.core, 'core:advertisement:finish', this.onFinishAd);
108
- if (this.core.activeContainer) {
109
- this.listenTo(this.core.activePlayback, Events.PLAYBACK_BUFFERFULL, this.updateLiveStatus);
110
- }
109
+ this.listenTo(this.core, Events.CORE_READY, this.onCoreReady);
110
+ this.listenTo(this.core, Events.CORE_ACTIVE_CONTAINER_CHANGED, this.onActiveContainerChange);
111
+ }
111
112
 
112
- if (this.currentPlayback) {
113
- this.listenTo(this.currentPlayback, Events.PLAYBACK_STOP, this.onStop);
114
- this.listenTo(this.currentPlayback, Events.PLAYBACK_PLAY, this.onPlay);
113
+ private onCoreReady() {
114
+ const mediaControl = this.core.getPlugin('media_control');
115
+ assert(mediaControl, 'media_control plugin is required');
116
+ const gear = this.core.getPlugin('bottom_gear') as BottomGear;
117
+ assert(gear, 'bottom_gear plugin is required');
118
+ this.listenTo(mediaControl, MediaControlEvents.MEDIACONTROL_GEAR_RENDERED, this.onGearRendered);
119
+ }
115
120
 
116
- // TODO import dash playback events
117
- this.listenTo(this.currentPlayback, 'dash:playback-rate-changed', this.onDashRateChange);
118
- }
121
+ private onActiveContainerChange() {
122
+ this.listenTo(this.core.activePlayback, Events.PLAYBACK_STOP, this.onStop);
123
+ this.listenTo(this.core.activePlayback, Events.PLAYBACK_PLAY, this.onPlay);
124
+ this.listenTo(this.core.activePlayback, PlaybackEvents.PLAYBACK_RATE_CHANGED, this.onPlaybackRateChange);
125
+ this.listenTo(this.core.activeContainer, Events.CONTAINER_PLAYBACKDVRSTATECHANGED, this.onDvrStateChanged);
119
126
  }
120
127
 
121
- private unBindEvents() {
122
- this.stopListening(this.core, 'gear:rendered', this.render);
123
- this.stopListening(this.core.mediaControl, Events.MEDIACONTROL_CONTAINERCHANGED, this.reload);
124
- this.stopListening(this.core, 'core:advertisement:start', this.onStartAd);
125
- this.stopListening(this.core, 'core:advertisement:finish', this.onFinishAd);
128
+ private onGearRendered() {
129
+ trace(`${T} onGearRendered`, {
130
+ rendered: this.rendered,
131
+ });
132
+ this.rendered = false;
133
+ this.render();
134
+ }
135
+
136
+ private onDvrStateChanged(dvrEnabled: boolean) {
137
+ trace(`${T} onDvrStateChanged`, {
138
+ dvrEnabled,
139
+ })
140
+ if (dvrEnabled) {
141
+ this.render();
142
+ }
126
143
  }
127
144
 
128
145
  private allRateElements(): ZeptoResult {
@@ -133,86 +150,65 @@ export class PlaybackRate extends UICorePlugin {
133
150
  return (this.$(`ul.gear-sub-menu a[data-rate="${rate}"]`) as ZeptoResult).parent();
134
151
  }
135
152
 
136
- private onDashRateChange() {
137
- // TODO consider removing
138
- ((this.currentPlayback as any)._dash as any)?.setPlaybackRate(this.selectedRate);
139
- }
140
-
141
- private updateLiveStatus() {
142
- if (this.core.getPlaybackType() === Playback.LIVE) {
143
- if (this.core.mediaControl.currentSeekBarPercentage <= 98.9) {
144
- this.core.mediaControl.$playbackRate.removeClass('playbackrate-enable');
145
- this.core.mediaControl.$el.addClass('dvr');
146
-
147
- return;
148
- }
149
- this.updatePlaybackRate(DEFAULT_PLAYBACK_RATE);
150
- this.core.mediaControl.$playbackRate.addClass('playbackrate-enable');
151
- this.core.mediaControl.$el.removeClass('dvr');
153
+ private onPlaybackRateChange(playbackRate: number) {
154
+ const selectedRate = parseInt(this.selectedRate, 10);
155
+ if (playbackRate !== selectedRate) {
156
+ trace(`${T} onPlaybackRateChange setting target rate`, {
157
+ playbackRate,
158
+ selectedRate,
159
+ })
160
+ this.core.activePlayback?.setPlaybackRate(selectedRate);
152
161
  }
153
162
  }
154
163
 
155
- private reload() {
156
- this.unBindEvents();
157
- this.bindEvents();
158
- }
159
-
160
164
  private shouldRender() {
161
165
  if (!this.core.activeContainer) {
162
166
  return false;
163
167
  }
164
168
 
165
- this.currentPlayback = this.core.activePlayback;
169
+ if (this.core.getPlaybackType() === Playback.LIVE && !this.core.activePlayback.dvrEnabled) {
170
+ return false;
171
+ }
166
172
 
167
- return !(this.currentPlayback?.tagName !== 'video' && this.currentPlayback?.tagName !== 'audio');
173
+ return 'setPlaybackRate' in this.core.activePlayback;
168
174
  }
169
175
 
170
176
  /**
171
177
  * @internal
172
178
  */
173
179
  override render() {
174
- const container = this.core.activeContainer;
180
+ trace(`${T} render`, {
181
+ rendered: this.rendered,
182
+ shouldRender: this.shouldRender(),
183
+ })
175
184
 
176
- if (this.core.getPlaybackType() === Playback.LIVE && !container.isDvrEnabled()) {
185
+ if (!this.shouldRender()) {
177
186
  return this;
178
187
  }
179
- const cfg = this.core.options.playbackRateConfig || {};
180
188
 
181
- if (!this.playbackRates) {
182
- this.playbackRates = cfg.options || DEFAULT_PLAYBACK_RATES;
183
- }
184
-
185
- if (!this.selectedRate) {
186
- this.selectedRate = cfg.defaultValue || DEFAULT_PLAYBACK_RATE;
189
+ if (this.rendered) {
190
+ return this;
187
191
  }
188
192
 
189
- if (this.shouldRender()) {
190
- const button = PlaybackRate.buttonTemplate({
191
- title: this.getTitle(),
192
- speedIcon,
193
- arrowRightIcon,
194
- });
195
-
196
- this.$el.html(button);
197
-
198
- // if (this.core.getPlaybackType() === Playback.LIVE) {
199
- // this.core.mediaControl.$playbackRate.addClass('playbackrate-enable');
200
- // }
193
+ const button = PlaybackRate.buttonTemplate({
194
+ title: this.getTitle(),
195
+ speedIcon,
196
+ arrowRightIcon,
197
+ });
201
198
 
202
- // this.core.mediaControl.$playbackRate.append(this.el);
199
+ this.$el.html(button);
203
200
 
204
- this.core.mediaControl.$el?.find('.gear-options-list [data-rate]').html(this.el);
201
+ (this.core.getPlugin('bottom_gear') as BottomGear)?.getElement('rate')?.html(this.el);
205
202
 
206
- // this.updateText();
207
- }
203
+ this.rendered = true;
208
204
 
209
205
  return this;
210
206
  }
211
207
 
212
208
  private onStartAd() {
213
209
  this.prevSelectedRate = this.selectedRate;
214
- this.setSelectedRate('1.0');
215
- this.listenToOnce(this.currentPlayback, Events.PLAYBACK_PLAY, this.onFinishAd);
210
+ this.resetPlaybackRate();
211
+ this.listenToOnce(this.core.activePlayback, Events.PLAYBACK_PLAY, this.onFinishAd);
216
212
  }
217
213
 
218
214
  private onFinishAd() {
@@ -222,16 +218,17 @@ export class PlaybackRate extends UICorePlugin {
222
218
  }
223
219
 
224
220
  private onPlay() {
225
- if (!this.core.mediaControl.$el.hasClass('dvr')) {
226
- if (this.core.getPlaybackType() === Playback.LIVE) {
227
- this.updatePlaybackRate(DEFAULT_PLAYBACK_RATE);
228
- this.core.mediaControl.$playbackRate.addClass('playbackrate-enable');
229
- }
221
+ if (this.core.getPlaybackType() === Playback.LIVE && !this.core.activePlayback.dvrEnabled) {
222
+ this.resetPlaybackRate();
230
223
  } else {
231
224
  this.setSelectedRate(this.selectedRate);
232
225
  }
233
226
  }
234
227
 
228
+ private resetPlaybackRate() {
229
+ this.setSelectedRate(DEFAULT_PLAYBACK_RATE);
230
+ }
231
+
235
232
  private onStop() {
236
233
  }
237
234
 
@@ -252,37 +249,24 @@ export class PlaybackRate extends UICorePlugin {
252
249
  arrowLeftIcon,
253
250
  checkIcon,
254
251
  }));
255
-
256
- this.core.mediaControl.$el?.find('.gear-wrapper').html(this.el);
252
+ (this.core.getPlugin('bottom_gear') as BottomGear)?.setContent(this.el);
257
253
  this.highlightCurrentRate();
258
254
  }
259
255
 
260
256
  private goBack() {
261
- this.core.trigger('gear:refresh');
262
- }
263
-
264
- private updatePlaybackRate(rate: string) {
265
- this.setSelectedRate(rate);
257
+ setTimeout(() => {
258
+ this.core.getPlugin('bottom_gear').refresh()
259
+ }, 0);
266
260
  }
267
261
 
268
262
  private setSelectedRate(rate: string) {
269
263
  // Set <video playbackRate="..."
270
- this.core.$el.find('video,audio').get(0).playbackRate = rate;
264
+ this.core.activePlayback?.setPlaybackRate(rate);
271
265
  this.selectedRate = rate;
272
- // TODO
273
- // Player.player.trigger('playbackRateChanged', rate);
274
266
  }
275
267
 
276
268
  private getTitle() {
277
- let title = this.selectedRate;
278
-
279
- this.playbackRates.forEach((r) => {
280
- if (r.value === this.selectedRate) {
281
- title = r.label;
282
- }
283
- });
284
-
285
- return title;
269
+ return this.playbackRates.find((r) => r.value === this.selectedRate)?.label || this.selectedRate;
286
270
  }
287
271
 
288
272
  private highlightCurrentRate() {