@gcorevideo/player 2.20.6 → 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.
- package/dist/core.js +37 -13
- package/dist/index.css +1163 -1163
- package/dist/index.js +2557 -2513
- package/dist/plugins/index.css +470 -470
- package/dist/plugins/index.js +5230 -5217
- package/lib/playback/BasePlayback.d.ts +5 -0
- package/lib/playback/BasePlayback.d.ts.map +1 -1
- package/lib/playback/BasePlayback.js +8 -0
- package/lib/playback/HTML5Video.d.ts +4 -0
- package/lib/playback/HTML5Video.d.ts.map +1 -0
- package/lib/playback/HTML5Video.js +3 -0
- package/lib/playback/dash-playback/DashPlayback.d.ts +1 -0
- package/lib/playback/dash-playback/DashPlayback.d.ts.map +1 -1
- package/lib/playback/dash-playback/DashPlayback.js +6 -2
- package/lib/playback/index.d.ts.map +1 -1
- package/lib/playback/index.js +2 -0
- package/lib/playback/types.d.ts +9 -0
- package/lib/playback/types.d.ts.map +1 -0
- package/lib/playback/types.js +9 -0
- package/lib/plugins/bottom-gear/BottomGear.d.ts +6 -11
- package/lib/plugins/bottom-gear/BottomGear.d.ts.map +1 -1
- package/lib/plugins/bottom-gear/BottomGear.js +9 -21
- package/lib/plugins/clappr-nerd-stats/ClapprNerdStats.js +2 -2
- package/lib/plugins/dvr-controls/DvrControls.d.ts +1 -1
- package/lib/plugins/dvr-controls/DvrControls.d.ts.map +1 -1
- package/lib/plugins/dvr-controls/DvrControls.js +27 -16
- package/lib/plugins/level-selector/LevelSelector.d.ts +17 -5
- package/lib/plugins/level-selector/LevelSelector.d.ts.map +1 -1
- package/lib/plugins/level-selector/LevelSelector.js +35 -24
- package/lib/plugins/media-control/MediaControl.d.ts +11 -0
- package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
- package/lib/plugins/media-control/MediaControl.js +16 -3
- package/lib/plugins/playback-rate/PlaybackRate.d.ts +11 -10
- package/lib/plugins/playback-rate/PlaybackRate.d.ts.map +1 -1
- package/lib/plugins/playback-rate/PlaybackRate.js +83 -91
- package/lib/plugins/source-controller/SourceController.d.ts +1 -0
- package/lib/plugins/source-controller/SourceController.d.ts.map +1 -1
- package/lib/plugins/source-controller/SourceController.js +8 -4
- package/lib/plugins/spinner-three-bounce/SpinnerThreeBounce.d.ts +7 -3
- package/lib/plugins/spinner-three-bounce/SpinnerThreeBounce.d.ts.map +1 -1
- package/lib/plugins/spinner-three-bounce/SpinnerThreeBounce.js +35 -27
- package/lib/testUtils.d.ts +5 -8
- package/lib/testUtils.d.ts.map +1 -1
- package/lib/testUtils.js +15 -9
- package/package.json +1 -1
- package/src/playback/BasePlayback.ts +12 -4
- package/src/playback/HTML5Video.ts +3 -0
- package/src/playback/dash-playback/DashPlayback.ts +15 -11
- package/src/playback/index.ts +2 -1
- package/src/playback/types.ts +9 -0
- package/src/plugins/bottom-gear/BottomGear.ts +10 -21
- package/src/plugins/bottom-gear/__tests__/BottomGear.test.ts +36 -0
- package/src/plugins/bottom-gear/__tests__/__snapshots__/BottomGear.test.ts.snap +41 -0
- package/src/plugins/clappr-nerd-stats/ClapprNerdStats.ts +3 -3
- package/src/plugins/dvr-controls/DvrControls.ts +87 -54
- package/src/plugins/level-selector/LevelSelector.ts +64 -31
- package/src/plugins/level-selector/__tests__/LevelSelector.test.ts +15 -16
- package/src/plugins/media-control/MediaControl.ts +20 -6
- package/src/plugins/playback-rate/PlaybackRate.ts +89 -105
- package/src/plugins/source-controller/SourceController.ts +9 -4
- package/src/plugins/source-controller/__tests__/SourceController.test.ts +35 -1
- package/src/plugins/spinner-three-bounce/SpinnerThreeBounce.ts +80 -57
- package/src/testUtils.ts +16 -9
- package/tsconfig.tsbuildinfo +1 -1
- package/assets/playback-rate/playback-rate-selector.ejs +0 -9
package/lib/testUtils.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { UICorePlugin } from '@clappr/core';
|
|
1
2
|
import Events from 'eventemitter3';
|
|
2
3
|
/**
|
|
3
4
|
* @internal
|
|
@@ -35,10 +36,7 @@ export declare class _MockPlayback extends Events {
|
|
|
35
36
|
}
|
|
36
37
|
export declare function createMockCore(options?: Record<string, unknown>, container?: any): Events<string | symbol, any> & {
|
|
37
38
|
el: HTMLDivElement;
|
|
38
|
-
$el:
|
|
39
|
-
0: HTMLDivElement;
|
|
40
|
-
append: import("vitest").Mock<(...args: any[]) => any>;
|
|
41
|
-
};
|
|
39
|
+
$el: any;
|
|
42
40
|
activePlayback: any;
|
|
43
41
|
activeContainer: any;
|
|
44
42
|
options: {
|
|
@@ -47,6 +45,7 @@ export declare function createMockCore(options?: Record<string, unknown>, contai
|
|
|
47
45
|
configure: import("vitest").Mock<(...args: any[]) => any>;
|
|
48
46
|
getPlugin: import("vitest").Mock<(...args: any[]) => any>;
|
|
49
47
|
load: import("vitest").Mock<(...args: any[]) => any>;
|
|
48
|
+
trigger: <T extends string | symbol>(event: T, ...args: any[]) => boolean;
|
|
50
49
|
};
|
|
51
50
|
export declare function createMockPlugin(): Events<string | symbol, any> & {
|
|
52
51
|
enable: import("vitest").Mock<(...args: any[]) => any>;
|
|
@@ -87,12 +86,10 @@ export declare function createMockPlayback(name?: string): Events<string | symbo
|
|
|
87
86
|
trigger(event: string, ...args: any[]): void;
|
|
88
87
|
};
|
|
89
88
|
export declare function createMockContainer(playback?: any): Events<string | symbol, any> & {
|
|
90
|
-
$el:
|
|
91
|
-
html: import("vitest").Mock<(...args: any[]) => any>;
|
|
92
|
-
0: HTMLDivElement;
|
|
93
|
-
};
|
|
89
|
+
$el: any;
|
|
94
90
|
el: HTMLDivElement;
|
|
95
91
|
getPlugin: import("vitest").Mock<(...args: any[]) => any>;
|
|
96
92
|
playback: any;
|
|
97
93
|
};
|
|
94
|
+
export declare function createMockMediaControl(core: any): UICorePlugin;
|
|
98
95
|
//# sourceMappingURL=testUtils.d.ts.map
|
package/lib/testUtils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../src/testUtils.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,eAAe,CAAA;AAElC;;;;GAIG;AACH,qBAAa,aAAc,SAAQ,MAAM;IAErC,SAAS,CAAC,OAAO,EAAE,GAAG;IACtB,QAAQ,CAAC,IAAI,EAAE,GAAG;IAClB,SAAS,CAAC,WAAW,CAAC,EAAE,GAAG;gBAFjB,OAAO,EAAE,GAAG,EACb,IAAI,EAAE,GAAG,EACR,WAAW,CAAC,EAAE,GAAG,YAAA;IAK7B,IAAI,IAAI,WAEP;IAED,OAAO;IAEP,IAAI;IAEJ,KAAK;IAEL,IAAI;IAEJ,OAAO;IAEP,IAAI;IAEJ,cAAc;IAEd,WAAW;IAIX,QAAQ;IAER,OAAO;IAEP,eAAe;IAIf,kBAAkB;IAIlB,cAAc;IAId,qBAAqB;IAIrB,IAAI;IAEJ,MAAM;IAEN,MAAM;IAEN,SAAS;IAET,eAAe;IAIf,WAAW;IAIX,QAAQ;IAIR,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE;CAGtC;AAED,wBAAgB,cAAc,CAAC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EAAE,SAAS,GAAE,GAA2B
|
|
1
|
+
{"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../src/testUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAK,YAAY,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,MAAM,MAAM,eAAe,CAAA;AAElC;;;;GAIG;AACH,qBAAa,aAAc,SAAQ,MAAM;IAErC,SAAS,CAAC,OAAO,EAAE,GAAG;IACtB,QAAQ,CAAC,IAAI,EAAE,GAAG;IAClB,SAAS,CAAC,WAAW,CAAC,EAAE,GAAG;gBAFjB,OAAO,EAAE,GAAG,EACb,IAAI,EAAE,GAAG,EACR,WAAW,CAAC,EAAE,GAAG,YAAA;IAK7B,IAAI,IAAI,WAEP;IAED,OAAO;IAEP,IAAI;IAEJ,KAAK;IAEL,IAAI;IAEJ,OAAO;IAEP,IAAI;IAEJ,cAAc;IAEd,WAAW;IAIX,QAAQ;IAER,OAAO;IAEP,eAAe;IAIf,kBAAkB;IAIlB,cAAc;IAId,qBAAqB;IAIrB,IAAI;IAEJ,MAAM;IAEN,MAAM;IAEN,SAAS;IAET,eAAe;IAIf,WAAW;IAIX,QAAQ;IAIR,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE;CAGtC;AAED,wBAAgB,cAAc,CAAC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EAAE,SAAS,GAAE,GAA2B;;;;;;;;;;;;EAgB3G;AAED,wBAAgB,gBAAgB;;;EAK/B;AAED,wBAAgB,mBAAmB;;;;;;EAKlC;AAED,wBAAgB,kBAAkB,CAAC,IAAI,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;mBA2C7B,MAAM,WAAW,GAAG,EAAE;EAIxC;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,GAAE,GAA0B;;;;;EAQvE;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,GAAG,gBAQ/C"}
|
package/lib/testUtils.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { $, UICorePlugin } from '@clappr/core';
|
|
1
2
|
import Events from 'eventemitter3';
|
|
2
3
|
import { vi } from 'vitest';
|
|
3
4
|
/**
|
|
@@ -61,12 +62,10 @@ export class _MockPlayback extends Events {
|
|
|
61
62
|
}
|
|
62
63
|
export function createMockCore(options = {}, container = createMockContainer()) {
|
|
63
64
|
const el = document.createElement('div');
|
|
64
|
-
|
|
65
|
+
const emitter = new Events();
|
|
66
|
+
return Object.assign(emitter, {
|
|
65
67
|
el,
|
|
66
|
-
$el:
|
|
67
|
-
[0]: el,
|
|
68
|
-
append: vi.fn(),
|
|
69
|
-
},
|
|
68
|
+
$el: $(el),
|
|
70
69
|
activePlayback: container.playback,
|
|
71
70
|
activeContainer: container,
|
|
72
71
|
options: {
|
|
@@ -75,6 +74,7 @@ export function createMockCore(options = {}, container = createMockContainer())
|
|
|
75
74
|
configure: vi.fn(),
|
|
76
75
|
getPlugin: vi.fn(),
|
|
77
76
|
load: vi.fn(),
|
|
77
|
+
trigger: emitter.emit,
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
80
|
export function createMockPlugin() {
|
|
@@ -140,12 +140,18 @@ export function createMockPlayback(name = 'mock') {
|
|
|
140
140
|
export function createMockContainer(playback = createMockPlayback()) {
|
|
141
141
|
const el = document.createElement('div');
|
|
142
142
|
return Object.assign(new Events(), {
|
|
143
|
-
$el:
|
|
144
|
-
html: vi.fn(),
|
|
145
|
-
[0]: el,
|
|
146
|
-
},
|
|
143
|
+
$el: $(el),
|
|
147
144
|
el,
|
|
148
145
|
getPlugin: vi.fn(),
|
|
149
146
|
playback,
|
|
150
147
|
});
|
|
151
148
|
}
|
|
149
|
+
export function createMockMediaControl(core) {
|
|
150
|
+
const mediaControl = new UICorePlugin(core);
|
|
151
|
+
const elements = {
|
|
152
|
+
gear: $(document.createElement('div')),
|
|
153
|
+
};
|
|
154
|
+
// @ts-ignore
|
|
155
|
+
mediaControl.getElement = vi.fn().mockImplementation((name) => elements[name]);
|
|
156
|
+
return mediaControl;
|
|
157
|
+
}
|
package/package.json
CHANGED
|
@@ -11,10 +11,10 @@ export class BasePlayback extends HTML5Video {
|
|
|
11
11
|
createError(errorData: any, options?: ErrorOptions) {
|
|
12
12
|
const i18n =
|
|
13
13
|
this.i18n ||
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
// @ts-ignore
|
|
15
|
+
(this.core && this.core.i18n) ||
|
|
16
|
+
// @ts-ignore
|
|
17
|
+
(this.container && this.container.i18n)
|
|
18
18
|
|
|
19
19
|
if (
|
|
20
20
|
i18n &&
|
|
@@ -34,6 +34,14 @@ export class BasePlayback extends HTML5Video {
|
|
|
34
34
|
return super.createError(errorData, options)
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Sets the playback rate.
|
|
39
|
+
* @param rate - The playback rate to set.
|
|
40
|
+
*/
|
|
41
|
+
setPlaybackRate(rate: number) {
|
|
42
|
+
;(this.el as HTMLMediaElement).playbackRate = rate
|
|
43
|
+
}
|
|
44
|
+
|
|
37
45
|
override _onPlaying() {
|
|
38
46
|
super._onPlaying()
|
|
39
47
|
this.trigger(Events.PLAYBACK_MEDIACONTROL_ENABLE)
|
|
@@ -17,7 +17,6 @@ import DASHJS, {
|
|
|
17
17
|
import {
|
|
18
18
|
PlaybackError,
|
|
19
19
|
PlaybackErrorCode,
|
|
20
|
-
PlayerComponentType,
|
|
21
20
|
QualityLevel,
|
|
22
21
|
TimePosition,
|
|
23
22
|
TimeUpdate,
|
|
@@ -25,6 +24,7 @@ import {
|
|
|
25
24
|
} from '../../playback.types.js'
|
|
26
25
|
import { isDashSource } from '../../utils/mediaSources.js'
|
|
27
26
|
import { BasePlayback } from '../BasePlayback.js'
|
|
27
|
+
import { PlaybackEvents } from '../types.js'
|
|
28
28
|
|
|
29
29
|
const AUTO = -1
|
|
30
30
|
|
|
@@ -300,8 +300,8 @@ export default class DashPlayback extends BasePlayback {
|
|
|
300
300
|
},
|
|
301
301
|
)
|
|
302
302
|
|
|
303
|
-
this._dash.on(DASHJS.MediaPlayer.events.PLAYBACK_RATE_CHANGED, () => {
|
|
304
|
-
this.trigger(
|
|
303
|
+
this._dash.on(DASHJS.MediaPlayer.events.PLAYBACK_RATE_CHANGED, (e: DASHJS.PlaybackRateChangedEvent) => {
|
|
304
|
+
this.trigger(PlaybackEvents.PLAYBACK_RATE_CHANGED, e.playbackRate)
|
|
305
305
|
})
|
|
306
306
|
}
|
|
307
307
|
|
|
@@ -361,7 +361,7 @@ export default class DashPlayback extends BasePlayback {
|
|
|
361
361
|
return this._startTime
|
|
362
362
|
}
|
|
363
363
|
|
|
364
|
-
seekPercentage(percentage: number) {
|
|
364
|
+
override seekPercentage(percentage: number) {
|
|
365
365
|
let seekTo = this._duration
|
|
366
366
|
|
|
367
367
|
if (percentage > 0) {
|
|
@@ -376,7 +376,7 @@ export default class DashPlayback extends BasePlayback {
|
|
|
376
376
|
this.seek(seekTo)
|
|
377
377
|
}
|
|
378
378
|
|
|
379
|
-
seek(time: TimeValue) {
|
|
379
|
+
override seek(time: TimeValue) {
|
|
380
380
|
if (time < 0) {
|
|
381
381
|
// eslint-disable-next-line max-len
|
|
382
382
|
Log.warn(
|
|
@@ -478,7 +478,7 @@ export default class DashPlayback extends BasePlayback {
|
|
|
478
478
|
}, 10)
|
|
479
479
|
}
|
|
480
480
|
|
|
481
|
-
_onTimeUpdate() {
|
|
481
|
+
override _onTimeUpdate() {
|
|
482
482
|
if (this.startChangeQuality) {
|
|
483
483
|
return
|
|
484
484
|
}
|
|
@@ -499,7 +499,7 @@ export default class DashPlayback extends BasePlayback {
|
|
|
499
499
|
this.trigger(Events.PLAYBACK_TIMEUPDATE, update, this.name)
|
|
500
500
|
}
|
|
501
501
|
|
|
502
|
-
_onDurationChange() {
|
|
502
|
+
override _onDurationChange() {
|
|
503
503
|
const duration = this.getDuration()
|
|
504
504
|
|
|
505
505
|
if (this._lastDuration === duration) {
|
|
@@ -540,7 +540,7 @@ export default class DashPlayback extends BasePlayback {
|
|
|
540
540
|
this.trigger(Events.PLAYBACK_PROGRESS, progress, {})
|
|
541
541
|
}
|
|
542
542
|
|
|
543
|
-
play() {
|
|
543
|
+
override play() {
|
|
544
544
|
trace(`${T} play`, { dash: !!this._dash })
|
|
545
545
|
if (!this._dash) {
|
|
546
546
|
this._setup()
|
|
@@ -550,7 +550,7 @@ export default class DashPlayback extends BasePlayback {
|
|
|
550
550
|
this._startTimeUpdateTimer()
|
|
551
551
|
}
|
|
552
552
|
|
|
553
|
-
pause() {
|
|
553
|
+
override pause() {
|
|
554
554
|
if (!this._dash) {
|
|
555
555
|
return
|
|
556
556
|
}
|
|
@@ -560,7 +560,7 @@ export default class DashPlayback extends BasePlayback {
|
|
|
560
560
|
}
|
|
561
561
|
}
|
|
562
562
|
|
|
563
|
-
stop() {
|
|
563
|
+
override stop() {
|
|
564
564
|
if (this._dash) {
|
|
565
565
|
this._stopTimeUpdateTimer()
|
|
566
566
|
this._dash.reset()
|
|
@@ -569,7 +569,7 @@ export default class DashPlayback extends BasePlayback {
|
|
|
569
569
|
}
|
|
570
570
|
}
|
|
571
571
|
|
|
572
|
-
destroy() {
|
|
572
|
+
override destroy() {
|
|
573
573
|
this._stopTimeUpdateTimer()
|
|
574
574
|
if (this._dash) {
|
|
575
575
|
this._dash.off(DASHJS.MediaPlayer.events.ERROR, this._onDASHJSSError)
|
|
@@ -638,6 +638,10 @@ export default class DashPlayback extends BasePlayback {
|
|
|
638
638
|
assert.ok(ret, 'Invalid quality level')
|
|
639
639
|
return ret
|
|
640
640
|
}
|
|
641
|
+
|
|
642
|
+
setPlaybackRate(rate: number) {
|
|
643
|
+
this._dash?.setPlaybackRate(rate)
|
|
644
|
+
}
|
|
641
645
|
}
|
|
642
646
|
|
|
643
647
|
DashPlayback.canPlay = function (resource, mimeType) {
|
package/src/playback/index.ts
CHANGED
|
@@ -2,9 +2,10 @@ import { Loader } from '@clappr/core'
|
|
|
2
2
|
|
|
3
3
|
import DashPlayback from './dash-playback/DashPlayback.js'
|
|
4
4
|
import HlsPlayback from './hls-playback/HlsPlayback.js'
|
|
5
|
-
|
|
5
|
+
import HTML5Video from './HTML5Video.js'
|
|
6
6
|
// TODO consider allowing the variation of the order of playback modules
|
|
7
7
|
export function registerPlaybacks() {
|
|
8
|
+
Loader.registerPlayback(HTML5Video) // TODO check it overrides the default HTML5Video
|
|
8
9
|
Loader.registerPlayback(HlsPlayback)
|
|
9
10
|
Loader.registerPlayback(DashPlayback)
|
|
10
11
|
}
|
|
@@ -10,22 +10,12 @@ import '../../../assets/bottom-gear/gear-sub-menu.scss';
|
|
|
10
10
|
import gearIcon from '../../../assets/icons/new/gear.svg';
|
|
11
11
|
import gearHdIcon from '../../../assets/icons/new/gear-hd.svg';
|
|
12
12
|
import { ZeptoResult } from '../../utils/types.js';
|
|
13
|
+
import { MediaControlEvents } from '../media-control/MediaControl';
|
|
13
14
|
|
|
14
15
|
const VERSION = '2.19.12';
|
|
15
16
|
|
|
16
17
|
const T = 'plugins.bottom_gear';
|
|
17
18
|
|
|
18
|
-
/**
|
|
19
|
-
* Custom events emitted by the plugin
|
|
20
|
-
* @beta
|
|
21
|
-
*/
|
|
22
|
-
export enum GearEvents {
|
|
23
|
-
/**
|
|
24
|
-
* Emitted when the gear menu is rendered
|
|
25
|
-
*/
|
|
26
|
-
MEDIACONTROL_GEAR_RENDERED = 'mediacontrol:gear:rendered',
|
|
27
|
-
}
|
|
28
|
-
|
|
29
19
|
/**
|
|
30
20
|
* An element inside the gear menu
|
|
31
21
|
* @beta
|
|
@@ -95,7 +85,6 @@ export class BottomGear extends UICorePlugin {
|
|
|
95
85
|
assert(mediaControl, 'media_control plugin is required');
|
|
96
86
|
|
|
97
87
|
this.listenTo(this.core, ClapprEvents.CORE_ACTIVE_CONTAINER_CHANGED, this.onActiveContainerChanged);
|
|
98
|
-
this.listenTo(this.core, 'gear:refresh', this.refresh); // TODO use direct plugin method call
|
|
99
88
|
this.listenTo(mediaControl, ClapprEvents.MEDIACONTROL_RENDERED, this.render);
|
|
100
89
|
this.listenTo(mediaControl, ClapprEvents.MEDIACONTROL_HIDE, this.hide); // TODO mediacontrol show as well
|
|
101
90
|
}
|
|
@@ -127,13 +116,9 @@ export class BottomGear extends UICorePlugin {
|
|
|
127
116
|
}
|
|
128
117
|
|
|
129
118
|
private highDefinitionUpdate(isHd: boolean) {
|
|
130
|
-
trace(`${
|
|
119
|
+
trace(`${T} highDefinitionUpdate`, { isHd });
|
|
131
120
|
this.isHd = isHd;
|
|
132
|
-
|
|
133
|
-
this.$el.find('.gear-icon').html(gearHdIcon);
|
|
134
|
-
} else {
|
|
135
|
-
this.$el.find('.gear-icon').html(gearIcon);
|
|
136
|
-
}
|
|
121
|
+
this.$el.find('.gear-icon').html(isHd ? gearHdIcon : gearIcon);
|
|
137
122
|
}
|
|
138
123
|
|
|
139
124
|
/**
|
|
@@ -153,12 +138,16 @@ export class BottomGear extends UICorePlugin {
|
|
|
153
138
|
this.$el.html(BottomGear.template({ icon, items }));
|
|
154
139
|
|
|
155
140
|
mediaControl.getElement('gear')?.html(this.el);
|
|
156
|
-
|
|
157
|
-
mediaControl.trigger(GearEvents.MEDIACONTROL_GEAR_RENDERED);
|
|
141
|
+
mediaControl.trigger(MediaControlEvents.MEDIACONTROL_GEAR_RENDERED);
|
|
158
142
|
return this;
|
|
159
143
|
}
|
|
160
144
|
|
|
161
|
-
|
|
145
|
+
/**
|
|
146
|
+
* Re-renders the gear menu.
|
|
147
|
+
* It fires the {@link MediaControlEvents.MEDIACONTROL_GEAR_RENDERED | MEDIACONTROL_GEAR_RENDERED} event,
|
|
148
|
+
* which the plugins that attach to the gear menu can listen to to re-render themselves.
|
|
149
|
+
*/
|
|
150
|
+
refresh() {
|
|
162
151
|
this.render();
|
|
163
152
|
this.$el.find('.gear-wrapper').show();
|
|
164
153
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { MockedFunction, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { BottomGear } from '../BottomGear'
|
|
4
|
+
import { createMockCore, createMockMediaControl } from '../../../testUtils'
|
|
5
|
+
import { MediaControlEvents } from '../../media-control/MediaControl'
|
|
6
|
+
|
|
7
|
+
describe('BottomGear', () => {
|
|
8
|
+
let mediaControl: any
|
|
9
|
+
let core: any
|
|
10
|
+
let bottomGear: BottomGear
|
|
11
|
+
let onGearRendered: MockedFunction<() => void>
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
core = createMockCore()
|
|
14
|
+
mediaControl = createMockMediaControl(core)
|
|
15
|
+
core.getPlugin = vi
|
|
16
|
+
.fn()
|
|
17
|
+
.mockImplementation((name) =>
|
|
18
|
+
name === 'media_control' ? mediaControl : null,
|
|
19
|
+
)
|
|
20
|
+
bottomGear = new BottomGear(core)
|
|
21
|
+
onGearRendered = vi.fn()
|
|
22
|
+
mediaControl.on(MediaControlEvents.MEDIACONTROL_GEAR_RENDERED, onGearRendered, null)
|
|
23
|
+
bottomGear.render()
|
|
24
|
+
})
|
|
25
|
+
it('should render', () => {
|
|
26
|
+
expect(bottomGear.el.innerHTML).toMatchSnapshot()
|
|
27
|
+
})
|
|
28
|
+
it('should attach to media control', () => {
|
|
29
|
+
const gearElement = mediaControl.getElement('gear')
|
|
30
|
+
expect(gearElement[0].innerHTML).not.toEqual('')
|
|
31
|
+
expect(gearElement[0].innerHTML).toMatchSnapshot()
|
|
32
|
+
})
|
|
33
|
+
it('should emit event', () => {
|
|
34
|
+
expect(onGearRendered).toHaveBeenCalled()
|
|
35
|
+
})
|
|
36
|
+
})
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`BottomGear > should attach to media control 1`] = `
|
|
4
|
+
"<div class="bottom_gear" data-track-selector=""><div class="media-control-gear" data-="">
|
|
5
|
+
<button type="button" class="button-gear gplayer-lite-btn gcore-skin-button-color" data-gear-button="-1">
|
|
6
|
+
<span class="gear-icon">/assets/icons/new/gear.svg</span>
|
|
7
|
+
</button>
|
|
8
|
+
<div class="gear-wrapper gcore-skin-bg-color">
|
|
9
|
+
<ul class="gear-options-list">
|
|
10
|
+
|
|
11
|
+
<li data-quality=""></li>
|
|
12
|
+
|
|
13
|
+
<li data-rate=""></li>
|
|
14
|
+
|
|
15
|
+
<li data-nerd=""></li>
|
|
16
|
+
|
|
17
|
+
</ul>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
</div>"
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
exports[`BottomGear > should render 1`] = `
|
|
24
|
+
"<div class="media-control-gear" data-="">
|
|
25
|
+
<button type="button" class="button-gear gplayer-lite-btn gcore-skin-button-color" data-gear-button="-1">
|
|
26
|
+
<span class="gear-icon">/assets/icons/new/gear.svg</span>
|
|
27
|
+
</button>
|
|
28
|
+
<div class="gear-wrapper gcore-skin-bg-color">
|
|
29
|
+
<ul class="gear-options-list">
|
|
30
|
+
|
|
31
|
+
<li data-quality=""></li>
|
|
32
|
+
|
|
33
|
+
<li data-rate=""></li>
|
|
34
|
+
|
|
35
|
+
<li data-nerd=""></li>
|
|
36
|
+
|
|
37
|
+
</ul>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
"
|
|
41
|
+
`;
|
|
@@ -24,8 +24,8 @@ import '../../../assets/clappr-nerd-stats/clappr-nerd-stats.scss'
|
|
|
24
24
|
import pluginHtml from '../../../assets/clappr-nerd-stats/clappr-nerd-stats.ejs'
|
|
25
25
|
import buttonHtml from '../../../assets/clappr-nerd-stats/button.ejs'
|
|
26
26
|
import statsIcon from '../../../assets/icons/new/stats.svg'
|
|
27
|
-
import { BottomGear
|
|
28
|
-
import { MediaControl } from '../media-control/MediaControl.js'
|
|
27
|
+
import { BottomGear } from '../bottom-gear/BottomGear.js'
|
|
28
|
+
import { MediaControl, MediaControlEvents } from '../media-control/MediaControl.js'
|
|
29
29
|
import assert from 'assert'
|
|
30
30
|
|
|
31
31
|
const qualityClasses = [
|
|
@@ -229,7 +229,7 @@ export class ClapprNerdStats extends UICorePlugin {
|
|
|
229
229
|
this.listenToOnce(this.core, Events.CORE_READY, this.init)
|
|
230
230
|
this.listenTo(
|
|
231
231
|
mediaControl,
|
|
232
|
-
|
|
232
|
+
MediaControlEvents.MEDIACONTROL_GEAR_RENDERED,
|
|
233
233
|
this.addToBottomGear,
|
|
234
234
|
)
|
|
235
235
|
}
|
|
@@ -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
|
-
|
|
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(
|
|
68
|
-
|
|
69
|
-
|
|
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(
|
|
74
|
-
|
|
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
|
|
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
|
-
|
|
106
|
+
// TODO
|
|
85
107
|
this.core.mediaControl.$el
|
|
86
108
|
.addClass('dvr')
|
|
87
|
-
.find(
|
|
88
|
-
|
|
109
|
+
.find(
|
|
110
|
+
'.media-control-indicator[data-position], .media-control-indicator[data-duration]',
|
|
111
|
+
)
|
|
112
|
+
.hide()
|
|
89
113
|
} else {
|
|
90
|
-
this.core.mediaControl.$
|
|
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()
|
|
111
|
-
this.core.getPlugin('media_control').$el.removeClass('live')
|
|
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 =
|
|
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
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
-
|
|
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
|
}
|