@gcorevideo/player 2.20.4 → 2.20.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/error-screen/error_screen.ejs +3 -1
- package/dist/core.js +407 -205
- package/dist/index.css +1285 -1285
- package/dist/index.js +550 -386
- package/dist/plugins/index.css +966 -966
- package/dist/plugins/index.js +121 -162
- package/lib/Player.d.ts.map +1 -1
- package/lib/Player.js +2 -2
- package/lib/playback/BasePlayback.d.ts +11 -0
- package/lib/playback/BasePlayback.d.ts.map +1 -0
- package/lib/playback/BasePlayback.js +33 -0
- package/lib/playback/dash-playback/DashPlayback.d.ts +3 -2
- package/lib/playback/dash-playback/DashPlayback.d.ts.map +1 -1
- package/lib/playback/dash-playback/DashPlayback.js +7 -7
- package/lib/playback/hls-playback/HlsPlayback.d.ts +2 -2
- package/lib/playback/hls-playback/HlsPlayback.d.ts.map +1 -1
- package/lib/playback/hls-playback/HlsPlayback.js +8 -5
- package/lib/playback/utils.d.ts +2 -0
- package/lib/playback/utils.d.ts.map +1 -0
- package/lib/playback/utils.js +1 -0
- package/lib/playback.types.d.ts +10 -3
- package/lib/playback.types.d.ts.map +1 -1
- package/lib/playback.types.js +3 -3
- package/lib/plugins/context-menu/ContextMenu.d.ts.map +1 -1
- package/lib/plugins/context-menu/ContextMenu.js +1 -2
- package/lib/plugins/error-screen/ErrorScreen.d.ts +39 -24
- package/lib/plugins/error-screen/ErrorScreen.d.ts.map +1 -1
- package/lib/plugins/error-screen/ErrorScreen.js +69 -136
- package/lib/plugins/media-control/MediaControl.d.ts +1 -1
- package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
- package/lib/plugins/media-control/MediaControl.js +16 -8
- package/lib/plugins/multi-camera/MultiCamera.d.ts.map +1 -1
- package/lib/plugins/multi-camera/MultiCamera.js +2 -3
- package/lib/plugins/poster/Poster.js +1 -1
- package/lib/plugins/source-controller/SourceController.d.ts +2 -1
- package/lib/plugins/source-controller/SourceController.d.ts.map +1 -1
- package/lib/plugins/source-controller/SourceController.js +12 -6
- package/lib/plugins/spinner-three-bounce/SpinnerThreeBounce.d.ts +2 -1
- package/lib/plugins/spinner-three-bounce/SpinnerThreeBounce.d.ts.map +1 -1
- package/lib/plugins/spinner-three-bounce/SpinnerThreeBounce.js +19 -3
- package/lib/testUtils.d.ts +66 -2
- package/lib/testUtils.d.ts.map +1 -1
- package/lib/testUtils.js +95 -2
- package/package.json +2 -2
- package/src/Player.ts +2 -2
- package/src/__tests__/Player.test.ts +2 -3
- package/src/playback/BasePlayback.ts +41 -0
- package/src/playback/dash-playback/DashPlayback.ts +12 -17
- package/src/playback/hls-playback/HlsPlayback.ts +9 -7
- package/src/playback.types.ts +11 -3
- package/src/plugins/context-menu/ContextMenu.ts +1 -2
- package/src/plugins/error-screen/ErrorScreen.ts +120 -195
- package/src/plugins/error-screen/__tests__/ErrorScreen.test.ts +113 -0
- package/src/plugins/error-screen/__tests__/__snapshots__/ErrorScreen.test.ts.snap +20 -0
- package/src/plugins/level-selector/__tests__/LevelSelector.test.ts +32 -57
- package/src/plugins/media-control/MediaControl.ts +16 -8
- package/src/plugins/multi-camera/MultiCamera.ts +2 -3
- package/src/plugins/poster/Poster.ts +1 -1
- package/src/plugins/source-controller/SourceController.ts +20 -14
- package/src/plugins/source-controller/__tests__/SourceController.test.ts +29 -46
- package/src/plugins/spinner-three-bounce/SpinnerThreeBounce.ts +20 -3
- package/src/testUtils.ts +100 -3
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Events as ClapprEvents, CorePlugin, } from '@clappr/core';
|
|
2
|
-
import { PlaybackErrorCode
|
|
2
|
+
import { PlaybackErrorCode } from '../../playback.types.js';
|
|
3
3
|
import { trace } from '@gcorevideo/utils';
|
|
4
4
|
import { SpinnerEvents } from '../spinner-three-bounce/SpinnerThreeBounce.js';
|
|
5
5
|
import { CLAPPR_VERSION } from '../../build.js';
|
|
@@ -100,10 +100,15 @@ export class SourceController extends CorePlugin {
|
|
|
100
100
|
*/
|
|
101
101
|
bindEvents() {
|
|
102
102
|
super.bindEvents();
|
|
103
|
-
this.listenTo(this.core, ClapprEvents.
|
|
103
|
+
this.listenTo(this.core, ClapprEvents.CORE_READY, this.onCoreReady);
|
|
104
|
+
this.listenTo(this.core, ClapprEvents.CORE_ACTIVE_CONTAINER_CHANGED, this.onActiveContainerChanged);
|
|
104
105
|
}
|
|
105
|
-
|
|
106
|
-
trace(`${T}
|
|
106
|
+
onCoreReady() {
|
|
107
|
+
trace(`${T} onCoreReady`);
|
|
108
|
+
this.core.getPlugin('error_screen')?.disable(); // TODO test
|
|
109
|
+
}
|
|
110
|
+
onActiveContainerChanged() {
|
|
111
|
+
trace(`${T} onActiveContainerChanged`, {
|
|
107
112
|
retrying: this.active,
|
|
108
113
|
currentSource: this.sourcesList[this.currentSourceIndex],
|
|
109
114
|
});
|
|
@@ -119,7 +124,7 @@ export class SourceController extends CorePlugin {
|
|
|
119
124
|
this.bindContainerEventListeners();
|
|
120
125
|
if (this.active) {
|
|
121
126
|
this.core.activeContainer?.getPlugin('poster_custom')?.disable();
|
|
122
|
-
spinner?.show();
|
|
127
|
+
spinner?.show(0);
|
|
123
128
|
}
|
|
124
129
|
}
|
|
125
130
|
bindContainerEventListeners() {
|
|
@@ -136,7 +141,7 @@ export class SourceController extends CorePlugin {
|
|
|
136
141
|
switch (error.code) {
|
|
137
142
|
case PlaybackErrorCode.MediaSourceUnavailable:
|
|
138
143
|
this.core.activeContainer?.getPlugin('poster_custom')?.disable();
|
|
139
|
-
this.retryPlayback();
|
|
144
|
+
setTimeout(() => this.retryPlayback(), 0);
|
|
140
145
|
break;
|
|
141
146
|
// TODO handle other errors
|
|
142
147
|
default:
|
|
@@ -166,6 +171,7 @@ export class SourceController extends CorePlugin {
|
|
|
166
171
|
currentSource: this.sourcesList[this.currentSourceIndex],
|
|
167
172
|
});
|
|
168
173
|
this.active = true;
|
|
174
|
+
this.core.activeContainer?.getPlugin('spinner')?.show(0);
|
|
169
175
|
this.getNextMediaSource().then((nextSource) => {
|
|
170
176
|
trace(`${T} retryPlayback syncing...`, {
|
|
171
177
|
nextSource,
|
|
@@ -34,6 +34,7 @@ export declare class SpinnerThreeBounce extends UIContainerPlugin {
|
|
|
34
34
|
'data-spinner': string;
|
|
35
35
|
class: string;
|
|
36
36
|
};
|
|
37
|
+
private hideTimeout;
|
|
37
38
|
private showTimeout;
|
|
38
39
|
private template;
|
|
39
40
|
private hasFatalError;
|
|
@@ -47,7 +48,7 @@ export declare class SpinnerThreeBounce extends UIContainerPlugin {
|
|
|
47
48
|
/**
|
|
48
49
|
* Shows the spinner
|
|
49
50
|
*/
|
|
50
|
-
show(): void;
|
|
51
|
+
show(delay?: number): void;
|
|
51
52
|
/**
|
|
52
53
|
* Hides the spinner
|
|
53
54
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpinnerThreeBounce.d.ts","sourceRoot":"","sources":["../../../src/plugins/spinner-three-bounce/SpinnerThreeBounce.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,SAAS,EAA0B,iBAAiB,EAAY,MAAM,cAAc,CAAC;AAK9F,OAAO,mDAAmD,CAAC;AAM3D;;GAEG;AACH,oBAAY,aAAa;IACvB;;;OAGG;IACH,IAAI,yBAAyB;CAC9B;AAED;;;;;GAKG;AACH,qBAAa,kBAAmB,SAAQ,iBAAiB;IACvD;;OAEG;IACH,IAAI,IAAI,WAEP;IAED;;OAEG;IACH,IAAI,gBAAgB;;MAEnB;IAED;;OAEG;IACH,IAAa,UAAU;;;MAKtB;IAED,OAAO,CAAC,WAAW,CAAwB;IAE3C,OAAO,CAAC,QAAQ,CAAyB;IAEzC,OAAO,CAAC,aAAa,CAAQ;IAE7B,OAAO,CAAC,YAAY,CAAQ;gBAEhB,SAAS,EAAE,SAAS;IAWhC,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,MAAM;IAKd,OAAO,CAAC,MAAM;IAUd,OAAO,CAAC,OAAO;IAef;;OAEG;IACH,IAAI;
|
|
1
|
+
{"version":3,"file":"SpinnerThreeBounce.d.ts","sourceRoot":"","sources":["../../../src/plugins/spinner-three-bounce/SpinnerThreeBounce.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,SAAS,EAA0B,iBAAiB,EAAY,MAAM,cAAc,CAAC;AAK9F,OAAO,mDAAmD,CAAC;AAM3D;;GAEG;AACH,oBAAY,aAAa;IACvB;;;OAGG;IACH,IAAI,yBAAyB;CAC9B;AAED;;;;;GAKG;AACH,qBAAa,kBAAmB,SAAQ,iBAAiB;IACvD;;OAEG;IACH,IAAI,IAAI,WAEP;IAED;;OAEG;IACH,IAAI,gBAAgB;;MAEnB;IAED;;OAEG;IACH,IAAa,UAAU;;;MAKtB;IAED,OAAO,CAAC,WAAW,CAAwB;IAE3C,OAAO,CAAC,WAAW,CAAwB;IAE3C,OAAO,CAAC,QAAQ,CAAyB;IAEzC,OAAO,CAAC,aAAa,CAAQ;IAE7B,OAAO,CAAC,YAAY,CAAQ;gBAEhB,SAAS,EAAE,SAAS;IAWhC,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,MAAM;IAKd,OAAO,CAAC,MAAM;IAUd,OAAO,CAAC,OAAO;IAef;;OAEG;IACH,IAAI,CAAC,KAAK,SAAM;IAchB;;OAEG;IACH,IAAI;IAaJ;;OAEG;IACM,MAAM;CAmBhB"}
|
|
@@ -47,6 +47,7 @@ export class SpinnerThreeBounce extends UIContainerPlugin {
|
|
|
47
47
|
'class': 'spinner-three-bounce'
|
|
48
48
|
};
|
|
49
49
|
}
|
|
50
|
+
hideTimeout = null;
|
|
50
51
|
showTimeout = null;
|
|
51
52
|
template = template(spinnerHTML);
|
|
52
53
|
hasFatalError = false;
|
|
@@ -102,8 +103,18 @@ export class SpinnerThreeBounce extends UIContainerPlugin {
|
|
|
102
103
|
/**
|
|
103
104
|
* Shows the spinner
|
|
104
105
|
*/
|
|
105
|
-
show() {
|
|
106
|
-
|
|
106
|
+
show(delay = 300) {
|
|
107
|
+
trace(`${T} show`);
|
|
108
|
+
if (this.showTimeout === null) {
|
|
109
|
+
if (this.hideTimeout !== null) {
|
|
110
|
+
clearTimeout(this.hideTimeout);
|
|
111
|
+
this.hideTimeout = null;
|
|
112
|
+
}
|
|
113
|
+
this.showTimeout = setTimeout(() => {
|
|
114
|
+
this.showTimeout = null;
|
|
115
|
+
this.$el.show();
|
|
116
|
+
}, delay);
|
|
117
|
+
}
|
|
107
118
|
}
|
|
108
119
|
/**
|
|
109
120
|
* Hides the spinner
|
|
@@ -113,7 +124,12 @@ export class SpinnerThreeBounce extends UIContainerPlugin {
|
|
|
113
124
|
clearTimeout(this.showTimeout);
|
|
114
125
|
this.showTimeout = null;
|
|
115
126
|
}
|
|
116
|
-
this
|
|
127
|
+
this.hideTimeout = setTimeout(() => {
|
|
128
|
+
this.hideTimeout = null;
|
|
129
|
+
if (this.showTimeout === null) {
|
|
130
|
+
this.$el.hide();
|
|
131
|
+
}
|
|
132
|
+
}, 0);
|
|
117
133
|
}
|
|
118
134
|
/**
|
|
119
135
|
* @internal
|
package/lib/testUtils.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import Events from 'eventemitter3';
|
|
2
2
|
/**
|
|
3
3
|
* @internal
|
|
4
|
+
* @deprecated
|
|
5
|
+
* TODO use createMockPlayback() instead
|
|
4
6
|
*/
|
|
5
|
-
export declare class _MockPlayback extends
|
|
7
|
+
export declare class _MockPlayback extends Events {
|
|
6
8
|
protected options: any;
|
|
7
9
|
readonly i18n: any;
|
|
8
10
|
protected playerError?: any | undefined;
|
|
@@ -31,4 +33,66 @@ export declare class _MockPlayback extends EventLite {
|
|
|
31
33
|
onResize(): boolean;
|
|
32
34
|
trigger(event: string, ...args: any[]): void;
|
|
33
35
|
}
|
|
36
|
+
export declare function createMockCore(options?: Record<string, unknown>, container?: any): Events<string | symbol, any> & {
|
|
37
|
+
el: HTMLDivElement;
|
|
38
|
+
$el: {
|
|
39
|
+
0: HTMLDivElement;
|
|
40
|
+
append: import("vitest").Mock<(...args: any[]) => any>;
|
|
41
|
+
};
|
|
42
|
+
activePlayback: any;
|
|
43
|
+
activeContainer: any;
|
|
44
|
+
options: {
|
|
45
|
+
[x: string]: unknown;
|
|
46
|
+
};
|
|
47
|
+
configure: import("vitest").Mock<(...args: any[]) => any>;
|
|
48
|
+
getPlugin: import("vitest").Mock<(...args: any[]) => any>;
|
|
49
|
+
load: import("vitest").Mock<(...args: any[]) => any>;
|
|
50
|
+
};
|
|
51
|
+
export declare function createMockPlugin(): Events<string | symbol, any> & {
|
|
52
|
+
enable: import("vitest").Mock<(...args: any[]) => any>;
|
|
53
|
+
disable: import("vitest").Mock<(...args: any[]) => any>;
|
|
54
|
+
};
|
|
55
|
+
export declare function createSpinnerPlugin(): Events<string | symbol, any> & {
|
|
56
|
+
enable: import("vitest").Mock<(...args: any[]) => any>;
|
|
57
|
+
disable: import("vitest").Mock<(...args: any[]) => any>;
|
|
58
|
+
} & {
|
|
59
|
+
show: import("vitest").Mock<(...args: any[]) => any>;
|
|
60
|
+
hide: import("vitest").Mock<(...args: any[]) => any>;
|
|
61
|
+
};
|
|
62
|
+
export declare function createMockPlayback(name?: string): Events<string | symbol, any> & {
|
|
63
|
+
name: string;
|
|
64
|
+
currentLevel: number;
|
|
65
|
+
levels: never[];
|
|
66
|
+
consent(): void;
|
|
67
|
+
play(): void;
|
|
68
|
+
pause(): void;
|
|
69
|
+
stop(): void;
|
|
70
|
+
destroy(): void;
|
|
71
|
+
seek(): void;
|
|
72
|
+
seekPercentage(): void;
|
|
73
|
+
getDuration(): 100;
|
|
74
|
+
enterPiP(): void;
|
|
75
|
+
exitPiP(): void;
|
|
76
|
+
getPlaybackType(): "live";
|
|
77
|
+
getStartTimeOffset(): 0;
|
|
78
|
+
getCurrentTime(): 0;
|
|
79
|
+
isHighDefinitionInUse(): false;
|
|
80
|
+
mute(): void;
|
|
81
|
+
unmute(): void;
|
|
82
|
+
volume(): void;
|
|
83
|
+
configure(): void;
|
|
84
|
+
attemptAutoPlay(): true;
|
|
85
|
+
canAutoPlay(): true;
|
|
86
|
+
onResize(): true;
|
|
87
|
+
trigger(event: string, ...args: any[]): void;
|
|
88
|
+
};
|
|
89
|
+
export declare function createMockContainer(playback?: any): Events<string | symbol, any> & {
|
|
90
|
+
$el: {
|
|
91
|
+
html: import("vitest").Mock<(...args: any[]) => any>;
|
|
92
|
+
0: HTMLDivElement;
|
|
93
|
+
};
|
|
94
|
+
el: HTMLDivElement;
|
|
95
|
+
getPlugin: import("vitest").Mock<(...args: any[]) => any>;
|
|
96
|
+
playback: any;
|
|
97
|
+
};
|
|
34
98
|
//# 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,
|
|
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;;;;;;;;;;;;;;EAiB3G;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;;;;;;;;EAWvE"}
|
package/lib/testUtils.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import Events from 'eventemitter3';
|
|
2
|
+
import { vi } from 'vitest';
|
|
2
3
|
/**
|
|
3
4
|
* @internal
|
|
5
|
+
* @deprecated
|
|
6
|
+
* TODO use createMockPlayback() instead
|
|
4
7
|
*/
|
|
5
|
-
export class _MockPlayback extends
|
|
8
|
+
export class _MockPlayback extends Events {
|
|
6
9
|
options;
|
|
7
10
|
i18n;
|
|
8
11
|
playerError;
|
|
@@ -56,3 +59,93 @@ export class _MockPlayback extends EventLite {
|
|
|
56
59
|
this.emit(event, ...args);
|
|
57
60
|
}
|
|
58
61
|
}
|
|
62
|
+
export function createMockCore(options = {}, container = createMockContainer()) {
|
|
63
|
+
const el = document.createElement('div');
|
|
64
|
+
return Object.assign(new Events(), {
|
|
65
|
+
el,
|
|
66
|
+
$el: {
|
|
67
|
+
[0]: el,
|
|
68
|
+
append: vi.fn(),
|
|
69
|
+
},
|
|
70
|
+
activePlayback: container.playback,
|
|
71
|
+
activeContainer: container,
|
|
72
|
+
options: {
|
|
73
|
+
...options,
|
|
74
|
+
},
|
|
75
|
+
configure: vi.fn(),
|
|
76
|
+
getPlugin: vi.fn(),
|
|
77
|
+
load: vi.fn(),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
export function createMockPlugin() {
|
|
81
|
+
return Object.assign(new Events(), {
|
|
82
|
+
enable: vi.fn(),
|
|
83
|
+
disable: vi.fn(),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
export function createSpinnerPlugin() {
|
|
87
|
+
return Object.assign(createMockPlugin(), {
|
|
88
|
+
show: vi.fn(),
|
|
89
|
+
hide: vi.fn(),
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
export function createMockPlayback(name = 'mock') {
|
|
93
|
+
const emitter = new Events();
|
|
94
|
+
return Object.assign(emitter, {
|
|
95
|
+
name,
|
|
96
|
+
currentLevel: -1,
|
|
97
|
+
levels: [],
|
|
98
|
+
consent() { },
|
|
99
|
+
play() { },
|
|
100
|
+
pause() { },
|
|
101
|
+
stop() { },
|
|
102
|
+
destroy() { },
|
|
103
|
+
seek() { },
|
|
104
|
+
seekPercentage() { },
|
|
105
|
+
getDuration() {
|
|
106
|
+
return 100;
|
|
107
|
+
},
|
|
108
|
+
enterPiP() { },
|
|
109
|
+
exitPiP() { },
|
|
110
|
+
getPlaybackType() {
|
|
111
|
+
return 'live';
|
|
112
|
+
},
|
|
113
|
+
getStartTimeOffset() {
|
|
114
|
+
return 0;
|
|
115
|
+
},
|
|
116
|
+
getCurrentTime() {
|
|
117
|
+
return 0;
|
|
118
|
+
},
|
|
119
|
+
isHighDefinitionInUse() {
|
|
120
|
+
return false;
|
|
121
|
+
},
|
|
122
|
+
mute() { },
|
|
123
|
+
unmute() { },
|
|
124
|
+
volume() { },
|
|
125
|
+
configure() { },
|
|
126
|
+
attemptAutoPlay() {
|
|
127
|
+
return true;
|
|
128
|
+
},
|
|
129
|
+
canAutoPlay() {
|
|
130
|
+
return true;
|
|
131
|
+
},
|
|
132
|
+
onResize() {
|
|
133
|
+
return true;
|
|
134
|
+
},
|
|
135
|
+
trigger(event, ...args) {
|
|
136
|
+
emitter.emit(event, ...args);
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
export function createMockContainer(playback = createMockPlayback()) {
|
|
141
|
+
const el = document.createElement('div');
|
|
142
|
+
return Object.assign(new Events(), {
|
|
143
|
+
$el: {
|
|
144
|
+
html: vi.fn(),
|
|
145
|
+
[0]: el,
|
|
146
|
+
},
|
|
147
|
+
el,
|
|
148
|
+
getPlugin: vi.fn(),
|
|
149
|
+
playback,
|
|
150
|
+
});
|
|
151
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gcorevideo/player",
|
|
3
|
-
"version": "2.20.
|
|
3
|
+
"version": "2.20.6",
|
|
4
4
|
"description": "Gcore JavaScript video player",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"@types/node": "^22.10.1",
|
|
43
43
|
"@types/sinonjs__fake-timers": "^8.1.5",
|
|
44
44
|
"assert": "^2.1.0",
|
|
45
|
+
"eventemitter3": "^5.0.1",
|
|
45
46
|
"jsdom": "^26.0.0",
|
|
46
47
|
"nodemon": "^3.1.9",
|
|
47
48
|
"rollup": "^4.27.4",
|
|
@@ -57,7 +58,6 @@
|
|
|
57
58
|
"@gcorevideo/utils": "^0.0.1",
|
|
58
59
|
"@sentry/types": "^8.47.0",
|
|
59
60
|
"dashjs": "^4.7.4",
|
|
60
|
-
"event-lite": "^1.0.0",
|
|
61
61
|
"hls.js": "^1.5.17",
|
|
62
62
|
"human-format": "^1.2.1",
|
|
63
63
|
"mousetrap": "^1.6.5",
|
package/src/Player.ts
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from '@clappr/core'
|
|
9
9
|
import { reportError, trace } from '@gcorevideo/utils'
|
|
10
10
|
import assert from 'assert'
|
|
11
|
-
import
|
|
11
|
+
import EventEmitter from 'eventemitter3'
|
|
12
12
|
|
|
13
13
|
import type {
|
|
14
14
|
CorePlayerEvents,
|
|
@@ -84,7 +84,7 @@ type PluginOptions = Record<string, unknown>
|
|
|
84
84
|
export class Player {
|
|
85
85
|
private config: PlayerConfig = DEFAULT_OPTIONS
|
|
86
86
|
|
|
87
|
-
private emitter = new
|
|
87
|
+
private emitter = new EventEmitter()
|
|
88
88
|
|
|
89
89
|
private player: PlayerClappr | null = null
|
|
90
90
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import Events from 'eventemitter3'
|
|
1
2
|
import {
|
|
2
3
|
afterEach,
|
|
3
4
|
beforeEach,
|
|
@@ -9,8 +10,6 @@ import {
|
|
|
9
10
|
} from 'vitest'
|
|
10
11
|
import { LogTracer, setTracer } from '@gcorevideo/utils'
|
|
11
12
|
import { Loader, Player as PlayerClappr } from '@clappr/core'
|
|
12
|
-
import EventLite from 'event-lite'
|
|
13
|
-
|
|
14
13
|
import { Player } from '../Player'
|
|
15
14
|
import { CorePluginConstructor, TransportPreference } from '../types'
|
|
16
15
|
import { canPlayDash, canPlayHls } from '../playback'
|
|
@@ -18,7 +17,7 @@ import { isDashSource, isHlsSource } from '../utils/mediaSources'
|
|
|
18
17
|
|
|
19
18
|
function createMockClapprPlayer(): MockedObject<typeof PlayerClappr> {
|
|
20
19
|
return {
|
|
21
|
-
core: Object.assign(new
|
|
20
|
+
core: Object.assign(new Events(), {
|
|
22
21
|
activeContainer: null,
|
|
23
22
|
activePlayback: null,
|
|
24
23
|
load: vi.fn(),
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ErrorOptions, Events, HTML5Video, PlayerError } from '@clappr/core'
|
|
2
|
+
|
|
3
|
+
import { PlaybackErrorCode } from '../playback.types.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* This class adds common behaviors to all playback modules.
|
|
7
|
+
* @internal
|
|
8
|
+
* TODO use custom HTML5Video playback with this layer applied
|
|
9
|
+
*/
|
|
10
|
+
export class BasePlayback extends HTML5Video {
|
|
11
|
+
createError(errorData: any, options?: ErrorOptions) {
|
|
12
|
+
const i18n =
|
|
13
|
+
this.i18n ||
|
|
14
|
+
// @ts-ignore
|
|
15
|
+
(this.core && this.core.i18n) ||
|
|
16
|
+
// @ts-ignore
|
|
17
|
+
(this.container && this.container.i18n)
|
|
18
|
+
|
|
19
|
+
if (
|
|
20
|
+
i18n &&
|
|
21
|
+
!errorData.UI &&
|
|
22
|
+
errorData.code === PlaybackErrorCode.MediaSourceUnavailable
|
|
23
|
+
) {
|
|
24
|
+
const defaultUI = {
|
|
25
|
+
title: i18n.t('no_broadcast'),
|
|
26
|
+
message: '',
|
|
27
|
+
}
|
|
28
|
+
errorData.UI = defaultUI
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (errorData.level === PlayerError.Levels.FATAL) {
|
|
32
|
+
this.trigger(Events.PLAYBACK_MEDIACONTROL_DISABLE)
|
|
33
|
+
}
|
|
34
|
+
return super.createError(errorData, options)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
override _onPlaying() {
|
|
38
|
+
super._onPlaying()
|
|
39
|
+
this.trigger(Events.PLAYBACK_MEDIACONTROL_ENABLE)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -2,15 +2,7 @@
|
|
|
2
2
|
// Use of this source code is governed by a BSD-style
|
|
3
3
|
// license that can be found in the LICENSE file.
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
Events,
|
|
7
|
-
HTML5Video,
|
|
8
|
-
Log,
|
|
9
|
-
Playback,
|
|
10
|
-
PlayerError,
|
|
11
|
-
Utils,
|
|
12
|
-
$,
|
|
13
|
-
} from '@clappr/core'
|
|
5
|
+
import { Events, Log, Playback, PlayerError, Utils, $ } from '@clappr/core'
|
|
14
6
|
import { trace } from '@gcorevideo/utils'
|
|
15
7
|
import assert from 'assert'
|
|
16
8
|
import DASHJS, {
|
|
@@ -32,6 +24,7 @@ import {
|
|
|
32
24
|
TimeValue,
|
|
33
25
|
} from '../../playback.types.js'
|
|
34
26
|
import { isDashSource } from '../../utils/mediaSources.js'
|
|
27
|
+
import { BasePlayback } from '../BasePlayback.js'
|
|
35
28
|
|
|
36
29
|
const AUTO = -1
|
|
37
30
|
|
|
@@ -53,7 +46,7 @@ type LocalTimeCorrelation = {
|
|
|
53
46
|
const T = 'playback.dash'
|
|
54
47
|
|
|
55
48
|
// @ts-expect-error
|
|
56
|
-
export default class DashPlayback extends
|
|
49
|
+
export default class DashPlayback extends BasePlayback {
|
|
57
50
|
_levels: QualityLevel[] | null = null
|
|
58
51
|
|
|
59
52
|
_currentLevel: number | null = null
|
|
@@ -470,11 +463,14 @@ export default class DashPlayback extends HTML5Video {
|
|
|
470
463
|
error: Pick<PlaybackError, 'code' | 'message' | 'description' | 'level'>,
|
|
471
464
|
) {
|
|
472
465
|
trace(`${T} triggerError`, { error })
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
466
|
+
|
|
467
|
+
// this triggers Events.ERROR to be handled by the UI
|
|
468
|
+
this.trigger(
|
|
469
|
+
Events.PLAYBACK_ERROR,
|
|
470
|
+
this.createError(error, {
|
|
471
|
+
useCodePrefix: false,
|
|
472
|
+
}),
|
|
473
|
+
)
|
|
478
474
|
// only reset the dash player in 10ms async, so that the rest of the
|
|
479
475
|
// calling function finishes
|
|
480
476
|
setTimeout(() => {
|
|
@@ -525,7 +521,7 @@ export default class DashPlayback extends HTML5Video {
|
|
|
525
521
|
)
|
|
526
522
|
}
|
|
527
523
|
|
|
528
|
-
_onProgress() {
|
|
524
|
+
override _onProgress() {
|
|
529
525
|
if (!this._dash) {
|
|
530
526
|
return
|
|
531
527
|
}
|
|
@@ -558,7 +554,6 @@ export default class DashPlayback extends HTML5Video {
|
|
|
558
554
|
if (!this._dash) {
|
|
559
555
|
return
|
|
560
556
|
}
|
|
561
|
-
|
|
562
557
|
super.pause()
|
|
563
558
|
if (this.dvrEnabled) {
|
|
564
559
|
this._updateDvr(true)
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
// Copyright 2014 Globo.com Player authors. All rights reserved.
|
|
2
2
|
// Use of this source code is governed by a BSD-style
|
|
3
|
-
// license that can be found
|
|
3
|
+
// license that can be found on https://github.com/clappr/hlsjs-playback/blob/main/LICENSE
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
6
|
Events,
|
|
7
|
-
HTML5Video,
|
|
8
7
|
Log,
|
|
9
8
|
Playback,
|
|
10
9
|
PlayerError,
|
|
@@ -37,10 +36,11 @@ import {
|
|
|
37
36
|
import { PlaybackType } from '../../types.js'
|
|
38
37
|
import { isHlsSource } from '../../utils/mediaSources.js'
|
|
39
38
|
import { TimerId } from '../../utils/types.js'
|
|
39
|
+
import { BasePlayback } from '../BasePlayback.js'
|
|
40
40
|
|
|
41
41
|
import { CLAPPR_VERSION } from '../../build.js'
|
|
42
42
|
|
|
43
|
-
const { now
|
|
43
|
+
const { now } = Utils
|
|
44
44
|
|
|
45
45
|
const AUTO = -1
|
|
46
46
|
const DEFAULT_RECOVER_ATTEMPTS = 16
|
|
@@ -78,7 +78,7 @@ type CustomListener = {
|
|
|
78
78
|
type ErrorInfo = Record<string, unknown>
|
|
79
79
|
|
|
80
80
|
// @ts-expect-error
|
|
81
|
-
export default class HlsPlayback extends
|
|
81
|
+
export default class HlsPlayback extends BasePlayback {
|
|
82
82
|
private _ccIsSetup = false
|
|
83
83
|
|
|
84
84
|
private _ccTracksUpdated = false
|
|
@@ -763,7 +763,7 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
763
763
|
this.trigger(Events.PLAYBACK_TIMEUPDATE, update, this.name)
|
|
764
764
|
}
|
|
765
765
|
|
|
766
|
-
_onDurationChange() {
|
|
766
|
+
override _onDurationChange() {
|
|
767
767
|
const duration = this.getDuration()
|
|
768
768
|
|
|
769
769
|
if (this._lastDuration === duration) {
|
|
@@ -773,7 +773,7 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
773
773
|
super._onDurationChange() // will call _onTimeUpdate
|
|
774
774
|
}
|
|
775
775
|
|
|
776
|
-
_onProgress() {
|
|
776
|
+
override _onProgress() {
|
|
777
777
|
if (!(this.el as HTMLMediaElement).buffered.length) {
|
|
778
778
|
return
|
|
779
779
|
}
|
|
@@ -1104,7 +1104,9 @@ export default class HlsPlayback extends HTML5Video {
|
|
|
1104
1104
|
}
|
|
1105
1105
|
|
|
1106
1106
|
private triggerError(error: PlaybackError) {
|
|
1107
|
-
this.trigger(Events.PLAYBACK_ERROR, error
|
|
1107
|
+
this.trigger(Events.PLAYBACK_ERROR, this.createError(error, {
|
|
1108
|
+
useCodePrefix: false,
|
|
1109
|
+
}))
|
|
1108
1110
|
this.stop()
|
|
1109
1111
|
}
|
|
1110
1112
|
}
|
package/src/playback.types.ts
CHANGED
|
@@ -64,15 +64,15 @@ export enum PlaybackErrorCode {
|
|
|
64
64
|
/**
|
|
65
65
|
* An unknown or uncategorised error.
|
|
66
66
|
*/
|
|
67
|
-
Generic =
|
|
67
|
+
Generic = 'GENERIC_ERROR',
|
|
68
68
|
/**
|
|
69
69
|
* The media source is not available. Typically a network error.
|
|
70
70
|
*/
|
|
71
|
-
MediaSourceUnavailable =
|
|
71
|
+
MediaSourceUnavailable = 'MEDIA_SOURCE_UNAVAILABLE',
|
|
72
72
|
/**
|
|
73
73
|
* The media source is not accessible due to some protection policy.
|
|
74
74
|
*/
|
|
75
|
-
MediaSourceAccessDenied =
|
|
75
|
+
MediaSourceAccessDenied = 'MEDIA_SOURCE_ACCESS_DENIED',
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
/**
|
|
@@ -120,4 +120,12 @@ export interface PlaybackError {
|
|
|
120
120
|
* Component subsystem of the error origin
|
|
121
121
|
*/
|
|
122
122
|
scope: PlayerComponentType
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* UI description of the error.
|
|
126
|
+
*/
|
|
127
|
+
UI?: {
|
|
128
|
+
title: string
|
|
129
|
+
message: string
|
|
130
|
+
}
|
|
123
131
|
}
|
|
@@ -98,7 +98,7 @@ export class ContextMenu extends UIContainerPlugin {
|
|
|
98
98
|
this._url = this.options.contextMenu.url
|
|
99
99
|
}
|
|
100
100
|
this.render()
|
|
101
|
-
this.
|
|
101
|
+
$('body').on('click', this.hideOnBodyClick)
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
/**
|
|
@@ -111,7 +111,6 @@ export class ContextMenu extends UIContainerPlugin {
|
|
|
111
111
|
this.toggleContextMenu,
|
|
112
112
|
)
|
|
113
113
|
this.listenTo(this.container, Events.CONTAINER_CLICK, this.hide)
|
|
114
|
-
$('body').on('click', this.hideOnBodyClick)
|
|
115
114
|
}
|
|
116
115
|
|
|
117
116
|
/**
|