@gcorevideo/player 2.1.11 → 2.1.13

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/src/Player.ts CHANGED
@@ -5,36 +5,33 @@ import {
5
5
  Player as PlayerClappr,
6
6
  $,
7
7
  Loader,
8
- } from '@clappr/core';
9
- import assert from 'assert';
10
- import EventLite from "event-lite";
8
+ } from '@clappr/core'
9
+ import assert from 'assert'
10
+ import EventLite from 'event-lite'
11
11
 
12
12
  import type {
13
13
  CorePlayerEvents,
14
14
  CoreOptions,
15
15
  CorePluginOptions,
16
- } from "./internal.types.js";
16
+ } from './internal.types.js'
17
17
  import type {
18
18
  BitrateInfo,
19
19
  PlaybackType,
20
20
  PlayerPlugin,
21
21
  StreamMediaSource,
22
- } from "./types.js";
23
- import { reportError, trace } from "./trace/index.js";
24
- import {
25
- PlayerConfig,
26
- PlayerEvent,
27
- } from "./types.js";
28
- import DashPlayback from './plugins/dash-playback/DashPlayback.js';
29
- import HlsPlayback from './plugins/hls-playback/HlsPlayback.js';
22
+ } from './types.js'
23
+ import { reportError, trace } from './trace/index.js'
24
+ import { PlayerConfig, PlayerEvent } from './types.js'
25
+ import DashPlayback from './plugins/dash-playback/DashPlayback.js'
26
+ import HlsPlayback from './plugins/hls-playback/HlsPlayback.js'
30
27
 
31
- import '../assets/style/main.scss'; // TODO check if needed
28
+ import '../assets/style/main.scss' // TODO check if needed
32
29
 
33
30
  // TODO implement transport retry/failover and fallback logic
34
31
 
35
- type PlayerEventHandler<T extends PlayerEvent> = () => void;
32
+ type PlayerEventHandler<T extends PlayerEvent> = () => void
36
33
 
37
- const T = "GPlayer";
34
+ const T = 'GPlayer'
38
35
 
39
36
  const DEFAULT_OPTIONS: PlayerConfig = {
40
37
  autoPlay: false,
@@ -49,206 +46,228 @@ const DEFAULT_OPTIONS: PlayerConfig = {
49
46
  poster: '',
50
47
  }
51
48
 
52
- export type PlaybackModule = 'dash' | 'hls' | 'native';
49
+ export type PlaybackModule = 'dash' | 'hls' | 'native'
53
50
 
54
- type PluginOptions = Record<string, unknown>;
51
+ type PluginOptions = Record<string, unknown>
55
52
 
56
53
  /**
57
54
  * @beta
58
55
  */
59
56
  export class Player {
60
- private bitrateInfo: BitrateInfo | null = null;
57
+ private bitrateInfo: BitrateInfo | null = null
61
58
 
62
- private config: PlayerConfig = DEFAULT_OPTIONS;
59
+ private config: PlayerConfig = DEFAULT_OPTIONS
63
60
 
64
- private emitter = new EventLite();
61
+ private emitter = new EventLite()
65
62
 
66
- private player: PlayerClappr | null = null;
63
+ private player: PlayerClappr | null = null
67
64
 
68
- private ready = false;
65
+ private ready = false
69
66
 
70
- private tuneInTimerId: ReturnType<typeof setTimeout> | null = null;
67
+ private tuneInTimerId: ReturnType<typeof setTimeout> | null = null
71
68
 
72
- private tunedIn = false;
69
+ private tunedIn = false
73
70
 
74
71
  get activePlayback(): PlaybackModule | null {
75
72
  if (!this.player?.core.activePlayback) {
76
- return null;
73
+ return null
77
74
  }
78
75
  switch (this.player.core.activePlayback.name) {
79
76
  case 'dash':
80
- return 'dash';
77
+ return 'dash'
81
78
  case 'hls':
82
- return 'hls';
79
+ return 'hls'
83
80
  default:
84
- return 'native';
81
+ return 'native'
85
82
  }
86
83
  }
87
84
 
88
85
  get bitrate(): BitrateInfo | null {
89
- return this.bitrateInfo;
86
+ return this.bitrateInfo
90
87
  }
91
88
 
92
89
  get hd() {
93
- return this.player?.core.activePlayback?.isHighDefinitionInUse || false;
90
+ return this.player?.core.activePlayback?.isHighDefinitionInUse || false
94
91
  }
95
92
 
96
93
  get playbackType(): PlaybackType | undefined {
97
- return this.player?.core.activePlayback?.getPlaybackType();
94
+ return this.player?.core.activePlayback?.getPlaybackType()
98
95
  }
99
96
 
100
- constructor(
101
- config: PlayerConfig,
102
- ) {
103
- this.setConfig(config);
97
+ constructor(config: PlayerConfig) {
98
+ this.setConfig(config)
104
99
  }
105
100
 
106
101
  on<T extends PlayerEvent>(event: T, handler: PlayerEventHandler<T>) {
107
- this.emitter.on(event, handler);
102
+ this.emitter.on(event, handler)
108
103
  }
109
104
 
110
105
  off<T extends PlayerEvent>(event: T, handler: PlayerEventHandler<T>) {
111
- this.emitter.off(event, handler);
106
+ this.emitter.off(event, handler)
112
107
  }
113
108
 
114
109
  configure(config: Partial<PlayerConfig>) {
115
- this.setConfig(config);
110
+ this.setConfig(config)
116
111
  }
117
112
 
118
113
  private setConfig(config: Partial<PlayerConfig>) {
119
- this.config = $.extend(true, this.config, config);
114
+ this.config = $.extend(true, this.config, config)
120
115
  }
121
116
 
122
117
  async init(playerElement: HTMLElement) {
123
- assert.ok(!this.player, 'Player already initialized');
124
- assert.ok(playerElement, 'Player container element is required');
125
- if (
126
- this.config.debug === 'all' ||
127
- this.config.debug === 'clappr'
128
- ) {
129
- Log.setLevel(0);
118
+ assert.ok(!this.player, 'Player already initialized')
119
+ assert.ok(playerElement, 'Player container element is required')
120
+ if (this.config.debug === 'all' || this.config.debug === 'clappr') {
121
+ Log.setLevel(0)
130
122
  }
131
123
 
132
- trace(`${T} init`, {config: this.config});
124
+ trace(`${T} init`, {
125
+ config: this.config,
126
+ })
133
127
 
134
- this.configurePlaybacks();
135
- const coreOpts = this.buildCoreOptions(playerElement);
136
- const {
137
- core,
138
- container,
139
- } = Loader.registeredPlugins;
140
- trace(`${T} init`, { registeredPlaybacks: Loader.registeredPlaybacks.map(p => p.name) });
128
+ this.configurePlaybacks()
129
+ const coreOpts = this.buildCoreOptions(playerElement)
130
+ const { core, container } = Loader.registeredPlugins
131
+ trace(`${T} init`, {
132
+ registeredPlaybacks: Loader.registeredPlaybacks.map((p) => p.name),
133
+ })
141
134
  coreOpts.plugins = {
142
135
  core: Object.values(core),
143
136
  container: Object.values(container),
144
137
  playback: Loader.registeredPlaybacks,
145
- } as CorePluginOptions;
146
- return this.initPlayer(coreOpts);
138
+ } as CorePluginOptions
139
+ return this.initPlayer(coreOpts)
147
140
  }
148
141
 
149
142
  destroy() {
150
- trace(`${T} destroy`, { player: !!this.player });
143
+ trace(`${T} destroy`, {
144
+ player: !!this.player,
145
+ })
151
146
  if (this.player) {
152
- this.player.destroy();
153
- this.player = null;
147
+ this.player.destroy()
148
+ this.player = null
154
149
  }
155
- this.ready = false;
156
- this.tunedIn = false;
150
+ this.ready = false
151
+ this.tunedIn = false
157
152
  if (this.tuneInTimerId) {
158
- clearTimeout(this.tuneInTimerId);
159
- this.tuneInTimerId = null;
153
+ clearTimeout(this.tuneInTimerId)
154
+ this.tuneInTimerId = null
160
155
  }
161
- this.bitrateInfo = null;
156
+ this.bitrateInfo = null
162
157
  }
163
158
 
164
159
  pause() {
165
- assert.ok(this.player, 'Player not initialized');
166
- this.player.pause();
160
+ assert.ok(this.player, 'Player not initialized')
161
+ this.player.pause()
167
162
  }
168
163
 
169
164
  play() {
170
- assert.ok(this.player, 'Player not initialized');
171
- this.player.play();
165
+ assert.ok(this.player, 'Player not initialized')
166
+ this.player.play()
172
167
  }
173
168
 
174
169
  seekTo(time: number) {
175
- assert.ok(this.player, 'Player not initialized');
176
- this.player.seek(time);
170
+ assert.ok(this.player, 'Player not initialized')
171
+ this.player.seek(time)
177
172
  }
178
173
 
179
174
  stop() {
180
- assert.ok(this.player, 'Player not initialized');
181
- this.player.stop();
175
+ assert.ok(this.player, 'Player not initialized')
176
+ this.player.stop()
182
177
  }
183
178
 
184
179
  static registerPlugin(plugin: PlayerPlugin) {
185
- Loader.registerPlugin(plugin);
180
+ Loader.registerPlugin(plugin)
186
181
  }
187
182
 
188
183
  static unregisterPlugin(plugin: PlayerPlugin) {
189
- Loader.unregisterPlugin(plugin);
184
+ Loader.unregisterPlugin(plugin)
190
185
  }
191
186
 
192
187
  private initPlayer(coreOptions: CoreOptions) {
193
- trace(`${T} initPlayer`, {coreOptions});
188
+ trace(`${T} initPlayer`, {
189
+ coreOptions,
190
+ })
194
191
 
195
- assert.ok(!this.player, 'Player already initialized');
192
+ assert.ok(!this.player, 'Player already initialized')
196
193
 
197
- const player = new PlayerClappr(
198
- coreOptions
199
- );
200
- this.player = player;
194
+ const player = new PlayerClappr(coreOptions)
195
+ this.player = player
201
196
 
202
197
  // TODO checks if the whole thing is necessary
203
198
  this.tuneInTimerId = globalThis.setTimeout(() => {
204
- trace(`${T} tuneInTimer`, { ready: this.ready, tunedIn: this.tunedIn });
205
- this.tuneInTimerId = null;
206
- this.tuneIn();
207
- }, 4000);
199
+ trace(`${T} tuneInTimer`, {
200
+ ready: this.ready,
201
+ tunedIn: this.tunedIn,
202
+ })
203
+ this.tuneInTimerId = null
204
+ this.tuneIn()
205
+ }, 4000)
208
206
  }
209
207
 
210
208
  private async tuneIn() {
211
- assert.ok(this.player);
209
+ assert.ok(this.player)
212
210
  trace(`${T} tuneIn`, {
213
211
  ready: this.ready,
214
212
  tunedIn: this.tunedIn,
215
- });
213
+ })
216
214
  if (this.tunedIn) {
217
- return;
215
+ return
218
216
  }
219
- this.tunedIn = true;
220
- const player = this.player;
217
+ this.tunedIn = true
218
+ const player = this.player
221
219
  try {
222
- this.emitter.emit(PlayerEvent.Ready);
220
+ this.emitter.emit(PlayerEvent.Ready)
223
221
  } catch (e) {
224
- reportError(e);
222
+ reportError(e)
225
223
  }
226
224
  if (player.core.activeContainer) {
227
- this.bindBitrateChangeHandler();
225
+ this.bindBitrateChangeHandler()
228
226
  }
229
- player.core.on(ClapprEvents.CORE_ACTIVE_CONTAINER_CHANGED, () => {
230
- this.bindBitrateChangeHandler();
231
- }, null);
232
- if (
233
- Browser.isiOS &&
234
- player.core.activePlayback
235
- ) {
236
- player.core.activePlayback.$el.on(
237
- 'webkitendfullscreen',
238
- () => {
239
- try {
240
- player.core.handleFullscreenChange();
241
- } catch (e) {
242
- reportError(e);
243
- }
244
- },
245
- );
227
+ player.core.on(
228
+ ClapprEvents.CORE_ACTIVE_CONTAINER_CHANGED,
229
+ () => {
230
+ this.bindBitrateChangeHandler()
231
+ },
232
+ null,
233
+ )
234
+ if (Browser.isiOS && player.core.activePlayback) {
235
+ player.core.activePlayback.$el.on('webkitendfullscreen', () => {
236
+ try {
237
+ player.core.handleFullscreenChange()
238
+ } catch (e) {
239
+ reportError(e)
240
+ }
241
+ })
246
242
  }
243
+ player.core.on(
244
+ ClapprEvents.CORE_SCREEN_ORIENTATION_CHANGED,
245
+ ({ orientation }: { orientation: 'landscape' | 'portrait' }) => {
246
+ trace(`${T} CORE_SCREEN_ORIENTATION_CHANGED`, { orientation })
247
+ },
248
+ null,
249
+ )
250
+ player.core.on(
251
+ ClapprEvents.CORE_RESIZE,
252
+ ({ width, height }: { width: number; height: number }) => {
253
+ trace(`${T} CORE_RESIZE`, {
254
+ width,
255
+ height,
256
+ })
257
+ },
258
+ null,
259
+ )
247
260
  if (this.config.autoPlay) {
248
261
  setTimeout(() => {
249
- trace(`${T} autoPlay`, { player: !!this.player, container: !!this.player?.core.activeContainer, playback: this.player?.core.activePlayback.name });
250
- assert(this.player);
251
- this.player.play({ autoPlay: true });
262
+ trace(`${T} autoPlay`, {
263
+ player: !!this.player,
264
+ container: !!this.player?.core.activeContainer,
265
+ playback: this.player?.core.activePlayback.name,
266
+ })
267
+ assert(this.player)
268
+ this.player.play({
269
+ autoPlay: true,
270
+ })
252
271
  }, 0)
253
272
  }
254
273
  }
@@ -257,53 +276,63 @@ export class Player {
257
276
  onReady: () => {
258
277
  trace(`${T} onReady`, {
259
278
  ready: this.ready,
260
- });
279
+ })
261
280
  if (this.ready) {
262
- return;
281
+ return
263
282
  }
264
- this.ready = true;
283
+ this.ready = true
265
284
  if (this.tuneInTimerId) {
266
- clearTimeout(this.tuneInTimerId);
267
- this.tuneInTimerId = null;
285
+ clearTimeout(this.tuneInTimerId)
286
+ this.tuneInTimerId = null
268
287
  }
269
- setTimeout(() => this.tuneIn(), 0);
288
+ setTimeout(() => this.tuneIn(), 0)
289
+ },
290
+ onResize: (newSize: { width: number; height: number }) => {
291
+ trace(`${T} CORE_RESIZE`, {
292
+ newSize,
293
+ })
270
294
  },
271
295
  onPlay: () => {
272
296
  try {
273
- this.emitter.emit(PlayerEvent.Play);
297
+ this.emitter.emit(PlayerEvent.Play)
274
298
  } catch (e) {
275
- reportError(e);
299
+ reportError(e)
276
300
  }
277
301
  },
278
302
  onPause: () => {
279
303
  try {
280
- this.emitter.emit(PlayerEvent.Pause);
304
+ this.emitter.emit(PlayerEvent.Pause)
281
305
  } catch (e) {
282
- reportError(e);
306
+ reportError(e)
283
307
  }
284
308
  },
285
309
  onEnded: () => {
286
310
  try {
287
- this.emitter.emit(PlayerEvent.Ended);
311
+ this.emitter.emit(PlayerEvent.Ended)
288
312
  } catch (e) {
289
- reportError(e);
313
+ reportError(e)
290
314
  }
291
315
  },
292
316
  onStop: () => {
293
317
  try {
294
- this.emitter.emit(PlayerEvent.Stop);
318
+ this.emitter.emit(PlayerEvent.Stop)
295
319
  } catch (e) {
296
- reportError(e);
320
+ reportError(e)
297
321
  }
298
322
  },
299
- };
323
+ }
300
324
 
301
325
  private buildCoreOptions(playerElement: HTMLElement): CoreOptions {
302
- const multisources = this.config.multisources;
303
- const mainSource = this.config.playbackType === 'live' ? multisources.find(ms => ms.live !== false) : multisources[0];
304
- const mediaSources = mainSource ? this.buildMediaSourcesList(mainSource) : [];
326
+ const multisources = this.config.multisources
327
+ const mainSource =
328
+ this.config.playbackType === 'live'
329
+ ? multisources.find((ms) => ms.live !== false)
330
+ : multisources[0]
331
+ const mediaSources = mainSource
332
+ ? this.buildMediaSourcesList(mainSource)
333
+ : []
305
334
  // const mainSourceUrl = mediaSources[0];
306
- const poster = mainSource?.poster ?? this.config.poster;
335
+ const poster = mainSource?.poster ?? this.config.poster
307
336
 
308
337
  const coreOptions: CoreOptions & PluginOptions = {
309
338
  ...this.config.pluginSettings,
@@ -332,73 +361,80 @@ export class Player {
332
361
  // source: mainSourceUrl,
333
362
  sources: mediaSources,
334
363
  strings: this.config.strings,
335
- };
336
- return coreOptions;
364
+ }
365
+ return coreOptions
337
366
  }
338
367
 
339
368
  private configurePlaybacks() {
340
- Loader.registerPlayback(DashPlayback);
341
- Loader.registerPlayback(HlsPlayback);
369
+ Loader.registerPlayback(DashPlayback)
370
+ Loader.registerPlayback(HlsPlayback)
342
371
  }
343
372
 
344
373
  private bindBitrateChangeHandler() {
345
- this.player?.core.activeContainer.on(ClapprEvents.CONTAINER_BITRATE, (bitrate: BitrateInfo) => {
346
- this.bitrateInfo = bitrate;
347
- });
374
+ this.player?.core.activeContainer.on(
375
+ ClapprEvents.CONTAINER_BITRATE,
376
+ (bitrate: BitrateInfo) => {
377
+ this.bitrateInfo = bitrate
378
+ },
379
+ )
348
380
  }
349
381
 
350
382
  private buildMediaSourcesList(ms: StreamMediaSource): string[] {
351
- const msl: string[] = [];
352
- const sources: Record<'dash' | 'master' | 'hls' | 'mpegts', string | null> = {
353
- dash: ms.sourceDash,
354
- master: ms.source,
355
- hls: ms.hlsCmafUrl,
356
- mpegts: ms.hlsMpegtsUrl,
357
- }
383
+ const msl: string[] = []
384
+ const sources: Record<'dash' | 'master' | 'hls' | 'mpegts', string | null> =
385
+ {
386
+ dash: ms.sourceDash,
387
+ master: ms.source,
388
+ hls: ms.hlsCmafUrl,
389
+ mpegts: ms.hlsMpegtsUrl,
390
+ }
358
391
  switch (this.config.priorityTransport) {
359
392
  case 'dash':
360
- addDash();
361
- break;
393
+ addDash()
394
+ break
362
395
  case 'hls':
363
- addHls();
364
- break;
396
+ addHls()
397
+ break
365
398
  case 'mpegts':
366
- addMpegts();
367
- break;
399
+ addMpegts()
400
+ break
368
401
  case 'auto':
369
- addDash();
370
- addHls();
371
- break;
402
+ addDash()
403
+ addHls()
404
+ break
372
405
  }
373
- Object.values(sources).forEach(s => {
406
+ Object.values(sources).forEach((s) => {
374
407
  if (s) {
375
- msl.push(s);
408
+ msl.push(s)
376
409
  }
377
- });
378
- return msl;
410
+ })
411
+ return msl
379
412
 
380
413
  function addMpegts() {
381
414
  if (sources.mpegts) {
382
- msl.push(sources.mpegts);
383
- sources.mpegts = null;
415
+ msl.push(sources.mpegts)
416
+ sources.mpegts = null
384
417
  }
385
418
  }
386
419
 
387
420
  function addHls() {
388
421
  if (sources.hls && HlsPlayback.canPlay(sources.hls)) {
389
- msl.push(sources.hls);
390
- sources.hls = null;
422
+ msl.push(sources.hls)
423
+ sources.hls = null
391
424
  }
392
- if (sources.master?.endsWith('.m3u8') && HlsPlayback.canPlay(sources.master)) {
393
- msl.push(sources.master);
394
- sources.master = null;
425
+ if (
426
+ sources.master?.endsWith('.m3u8') &&
427
+ HlsPlayback.canPlay(sources.master)
428
+ ) {
429
+ msl.push(sources.master)
430
+ sources.master = null
395
431
  }
396
432
  }
397
433
 
398
434
  function addDash() {
399
435
  if (sources.dash && DashPlayback.canPlay(sources.dash)) {
400
- msl.push(sources.dash);
401
- sources.dash = null;
436
+ msl.push(sources.dash)
437
+ sources.dash = null
402
438
  }
403
439
  }
404
440
  }