@gcorevideo/player 2.22.29 → 2.22.31

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 (54) hide show
  1. package/assets/media-control/container.scss +2 -3
  2. package/assets/poster/poster.ejs +3 -1
  3. package/assets/poster/poster.scss +3 -3
  4. package/assets/skip-time/skip-time.ejs +4 -4
  5. package/assets/skip-time/style.scss +4 -4
  6. package/assets/style/main.scss +1 -1
  7. package/dist/core.js +1 -1
  8. package/dist/index.css +573 -574
  9. package/dist/index.js +225 -230
  10. package/dist/player.d.ts +63 -33
  11. package/docs/api/{player.seektime.bindevents.md → player.clapprstats.clearmetrics.md} +3 -3
  12. package/docs/api/player.clapprstats.md +14 -0
  13. package/docs/api/player.extendedevents.md +14 -0
  14. package/docs/api/player.md +13 -2
  15. package/docs/api/player.seektime.attributes.md +0 -1
  16. package/docs/api/player.seektime.md +6 -197
  17. package/docs/api/{player.seektime.render.md → player.seektimesettings.md} +7 -7
  18. package/docs/api/player.skiptime.md +3 -184
  19. package/lib/plugins/poster/Poster.d.ts +24 -14
  20. package/lib/plugins/poster/Poster.d.ts.map +1 -1
  21. package/lib/plugins/poster/Poster.js +67 -97
  22. package/lib/plugins/skip-time/SkipTime.d.ts +25 -11
  23. package/lib/plugins/skip-time/SkipTime.d.ts.map +1 -1
  24. package/lib/plugins/skip-time/SkipTime.js +43 -17
  25. package/lib/testUtils.d.ts +13 -39
  26. package/lib/testUtils.d.ts.map +1 -1
  27. package/lib/testUtils.js +14 -65
  28. package/package.json +1 -1
  29. package/src/plugins/poster/Poster.ts +91 -110
  30. package/src/plugins/poster/__tests__/Poster.test.ts +119 -0
  31. package/src/plugins/poster/__tests__/__snapshots__/Poster.test.ts.snap +8 -0
  32. package/src/plugins/skip-time/SkipTime.ts +52 -25
  33. package/src/plugins/source-controller/__tests__/SourceController.test.ts +1 -2
  34. package/src/testUtils.ts +14 -86
  35. package/temp/player.api.json +295 -829
  36. package/tsconfig.tsbuildinfo +1 -1
  37. package/docs/api/player.seektime.durationshown.md +0 -14
  38. package/docs/api/player.seektime.getseektime.md +0 -20
  39. package/docs/api/player.seektime.islivestreamwithdvr.md +0 -14
  40. package/docs/api/player.seektime.mediacontrol.md +0 -14
  41. package/docs/api/player.seektime.mediacontrolcontainer.md +0 -14
  42. package/docs/api/player.seektime.shouldbevisible.md +0 -18
  43. package/docs/api/player.seektime.template.md +0 -14
  44. package/docs/api/player.seektime.update.md +0 -18
  45. package/docs/api/player.skiptime.attributes.md +0 -17
  46. package/docs/api/player.skiptime.bindevents.md +0 -18
  47. package/docs/api/player.skiptime.events.md +0 -18
  48. package/docs/api/player.skiptime.handlerewindclicks.md +0 -18
  49. package/docs/api/player.skiptime.render.md +0 -18
  50. package/docs/api/player.skiptime.setback.md +0 -18
  51. package/docs/api/player.skiptime.setforward.md +0 -18
  52. package/docs/api/player.skiptime.setmidclick.md +0 -18
  53. package/docs/api/player.skiptime.template.md +0 -14
  54. package/docs/api/player.skiptime.togglefullscreen.md +0 -18
@@ -1,9 +1,11 @@
1
1
  import { UICorePlugin, Browser, Playback, Events, template } from '@clappr/core';
2
+ import { trace } from '@gcorevideo/utils';
2
3
  import { CLAPPR_VERSION } from '../../build.js';
3
4
  import pluginHtml from '../../../assets/skip-time/skip-time.ejs';
4
5
  import '../../../assets/skip-time/style.scss';
6
+ const T = 'plugins.skip_time';
5
7
  /**
6
- * `PLUGIN` that adds skip controls to the media control UI.
8
+ * `PLUGIN` that allows skipping time by tapping on the left or right side of the video.
7
9
  * @beta
8
10
  */
9
11
  export class SkipTime extends UICorePlugin {
@@ -16,39 +18,56 @@ export class SkipTime extends UICorePlugin {
16
18
  get container() {
17
19
  return this.core && this.core.activeContainer;
18
20
  }
19
- get template() {
20
- return template(pluginHtml);
21
- }
21
+ static template = template(pluginHtml);
22
+ /**
23
+ * @internal
24
+ */
22
25
  get attributes() {
23
26
  return {
24
- class: this.name + '_plugin',
25
- 'data-skip-time': '',
27
+ class: 'mc-skip-time',
26
28
  };
27
29
  }
28
30
  position = 'mid';
31
+ /**
32
+ * @internal
33
+ */
29
34
  get events() {
30
35
  return {
31
- 'click [data-skip-left]': 'setBack',
32
- 'click [data-skip-mid]': 'setMidClick',
33
- 'click [data-skip-right]': 'setForward',
36
+ 'click #mc-skip-left': 'setBack',
37
+ 'click #mc-skip-mid': 'setMidClick',
38
+ 'click #mc-skip-right': 'setForward',
34
39
  };
35
40
  }
41
+ /**
42
+ * @internal
43
+ */
36
44
  bindEvents() {
37
45
  this.listenTo(this.core, Events.CORE_READY, this.render);
38
- if (!this.container) {
39
- return;
40
- }
46
+ this.listenTo(this.core, Events.CORE_ACTIVE_CONTAINER_CHANGED, this.onContainerChanged);
47
+ }
48
+ onContainerChanged() {
41
49
  this.listenTo(this.container, Events.CONTAINER_DBLCLICK, this.handleRewindClicks);
50
+ this.mount();
42
51
  }
43
52
  setBack() {
53
+ trace(`${T} setBack`);
44
54
  this.position = 'left';
45
55
  }
46
56
  handleRewindClicks() {
57
+ trace(`${T} handleRewindClicks`, {
58
+ position: this.position,
59
+ });
47
60
  if (this.core.getPlaybackType() === Playback.LIVE &&
48
61
  !this.container.isDvrEnabled()) {
49
62
  this.toggleFullscreen();
50
63
  return;
51
64
  }
65
+ this.handleSkip();
66
+ }
67
+ handleSkip() {
68
+ trace(`${T} handleSkip`, {
69
+ position: this.position,
70
+ });
52
71
  if (Browser.isMobile) {
53
72
  if (this.position === 'left') {
54
73
  const seekPos = this.container.getCurrentTime() - 10;
@@ -70,22 +89,29 @@ export class SkipTime extends UICorePlugin {
70
89
  }
71
90
  }
72
91
  setMidClick() {
92
+ trace(`${T} setMidClick`);
73
93
  this.position = 'mid';
74
94
  }
75
95
  setForward() {
96
+ trace(`${T} setForward`);
76
97
  this.position = 'right';
77
98
  }
78
99
  toggleFullscreen() {
100
+ trace(`${T} toggleFullscreen`);
79
101
  this.trigger(Events.MEDIACONTROL_FULLSCREEN, this.name);
80
102
  this.container.fullscreen();
81
103
  this.core.toggleFullscreen();
82
104
  }
105
+ /**
106
+ * @internal
107
+ */
83
108
  render() {
84
- this.$el.html(template(pluginHtml));
85
- if (this.core.activeContainer) {
86
- this.core.activeContainer.$el.append(this.el);
87
- }
88
- this.bindEvents();
109
+ trace(`${T} render`);
110
+ this.$el.html(SkipTime.template());
89
111
  return this;
90
112
  }
113
+ mount() {
114
+ trace(`${T} mount`);
115
+ this.core.activeContainer.$el.append(this.el);
116
+ }
91
117
  }
@@ -1,39 +1,5 @@
1
1
  import { UICorePlugin } from '@clappr/core';
2
2
  import Events from 'eventemitter3';
3
- /**
4
- * @internal
5
- * @deprecated
6
- * TODO use createMockPlayback() instead
7
- */
8
- export declare class _MockPlayback extends Events {
9
- protected options: any;
10
- readonly i18n: any;
11
- protected playerError?: any | undefined;
12
- constructor(options: any, i18n: any, playerError?: any | undefined);
13
- get name(): string;
14
- consent(): void;
15
- play(): void;
16
- pause(): void;
17
- stop(): void;
18
- destroy(): void;
19
- seek(): void;
20
- seekPercentage(): void;
21
- getDuration(): number;
22
- enterPiP(): void;
23
- exitPiP(): void;
24
- getPlaybackType(): string;
25
- getStartTimeOffset(): number;
26
- getCurrentTime(): number;
27
- isHighDefinitionInUse(): boolean;
28
- mute(): void;
29
- unmute(): void;
30
- volume(): void;
31
- configure(): void;
32
- attemptAutoPlay(): boolean;
33
- canAutoPlay(): boolean;
34
- onResize(): boolean;
35
- trigger(event: string, ...args: any[]): void;
36
- }
37
3
  export declare function createMockCore(options?: Record<string, unknown>, container?: any): Events<string | symbol, any> & {
38
4
  el: HTMLDivElement;
39
5
  $el: any;
@@ -68,11 +34,12 @@ export declare function createMockPlayback(name?: string): Events<string | symbo
68
34
  el: HTMLVideoElement;
69
35
  dvrEnabled: boolean;
70
36
  dvrInUse: boolean;
37
+ isAudioOnly: boolean;
71
38
  levels: never[];
72
- consent(): void;
73
- play(): void;
74
- pause(): void;
75
- stop(): void;
39
+ consent: import("vitest").Mock<(...args: any[]) => any>;
40
+ play: import("vitest").Mock<(...args: any[]) => any>;
41
+ pause: import("vitest").Mock<(...args: any[]) => any>;
42
+ stop: import("vitest").Mock<(...args: any[]) => any>;
76
43
  destroy: import("vitest").Mock<(...args: any[]) => any>;
77
44
  seek: import("vitest").Mock<(...args: any[]) => any>;
78
45
  seekPercentage: import("vitest").Mock<(...args: any[]) => any>;
@@ -97,13 +64,20 @@ export declare function createMockPlayback(name?: string): Events<string | symbo
97
64
  export declare function createMockContainer(options?: Record<string, unknown>, playback?: any): Events<string | symbol, any> & {
98
65
  el: any;
99
66
  playback: any;
100
- options: Record<string, unknown>;
67
+ options: {
68
+ [x: string]: unknown;
69
+ };
101
70
  $el: any;
71
+ disableMediaControl: import("vitest").Mock<(...args: any[]) => any>;
72
+ enableMediaControl: import("vitest").Mock<(...args: any[]) => any>;
73
+ enterPiP: import("vitest").Mock<(...args: any[]) => any>;
74
+ exitPiP: import("vitest").Mock<(...args: any[]) => any>;
102
75
  getDuration: import("vitest").Mock<(...args: any[]) => any>;
103
76
  getPlugin: import("vitest").Mock<(...args: any[]) => any>;
104
77
  getPlaybackType: import("vitest").Mock<(...args: any[]) => any>;
105
78
  isDvrInUse: import("vitest").Mock<(...args: any[]) => any>;
106
79
  isDvrEnabled: import("vitest").Mock<(...args: any[]) => any>;
80
+ isHighDefinitionInUse: import("vitest").Mock<(...args: any[]) => any>;
107
81
  isPlaying: import("vitest").Mock<(...args: any[]) => any>;
108
82
  play: import("vitest").Mock<(...args: any[]) => any>;
109
83
  seek: import("vitest").Mock<(...args: any[]) => any>;
@@ -1 +1 @@
1
- {"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../src/testUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,YAAY,EAAE,MAAM,cAAc,CAAA;AACxD,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,CAC5B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,SAAS,GAAE,GAAkC;;;;;;;;;;;;;;;;EAqB9C;AAED,wBAAgB,gBAAgB;;;EAK/B;AAED,wBAAgB,mBAAmB;;;;;;EAKlC;AAED,wBAAgB,kBAAkB,CAAC,IAAI,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkC/C;AAED,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,QAAQ,GAAE,GAA0B;;;;;;;;;;;;;;;;EAqBrC;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,GAAG,gBAe/C;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,GAAG,OAe7C"}
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;AAGlC,wBAAgB,cAAc,CAC5B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,SAAS,GAAE,GAAkC;;;;;;;;;;;;;;;;EAqB9C;AAED,wBAAgB,gBAAgB;;;EAK/B;AAED,wBAAgB,mBAAmB;;;;;;EAKlC;AAED,wBAAgB,kBAAkB,CAAC,IAAI,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmC/C;AAED,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,QAAQ,GAAE,GAA0B;;;;;;;;;;;;;;;;;;;;;;;EA4BrC;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,GAAG,gBAe/C;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,GAAG,OAe7C"}
package/lib/testUtils.js CHANGED
@@ -1,65 +1,6 @@
1
- import { $, Playback, UICorePlugin } from '@clappr/core';
1
+ import { $, UICorePlugin } from '@clappr/core';
2
2
  import Events from 'eventemitter3';
3
3
  import { vi } from 'vitest';
4
- /**
5
- * @internal
6
- * @deprecated
7
- * TODO use createMockPlayback() instead
8
- */
9
- export class _MockPlayback extends Events {
10
- options;
11
- i18n;
12
- playerError;
13
- constructor(options, i18n, playerError) {
14
- super();
15
- this.options = options;
16
- this.i18n = i18n;
17
- this.playerError = playerError;
18
- }
19
- get name() {
20
- return 'mock';
21
- }
22
- consent() { }
23
- play() { }
24
- pause() { }
25
- stop() { }
26
- destroy() { }
27
- seek() { }
28
- seekPercentage() { }
29
- getDuration() {
30
- return 100;
31
- }
32
- enterPiP() { }
33
- exitPiP() { }
34
- getPlaybackType() {
35
- return Playback.LIVE;
36
- }
37
- getStartTimeOffset() {
38
- return 0;
39
- }
40
- getCurrentTime() {
41
- return 0;
42
- }
43
- isHighDefinitionInUse() {
44
- return false;
45
- }
46
- mute() { }
47
- unmute() { }
48
- volume() { }
49
- configure() { }
50
- attemptAutoPlay() {
51
- return true;
52
- }
53
- canAutoPlay() {
54
- return true;
55
- }
56
- onResize() {
57
- return true;
58
- }
59
- trigger(event, ...args) {
60
- this.emit(event, ...args);
61
- }
62
- }
63
4
  export function createMockCore(options = {}, container = createMockContainer(options)) {
64
5
  const el = document.createElement('div');
65
6
  const emitter = new Events();
@@ -101,11 +42,12 @@ export function createMockPlayback(name = 'mock') {
101
42
  el: document.createElement('video'),
102
43
  dvrEnabled: false,
103
44
  dvrInUse: false,
45
+ isAudioOnly: false,
104
46
  levels: [],
105
- consent() { },
106
- play() { },
107
- pause() { },
108
- stop() { },
47
+ consent: vi.fn(),
48
+ play: vi.fn(),
49
+ pause: vi.fn(),
50
+ stop: vi.fn(),
109
51
  destroy: vi.fn(),
110
52
  seek: vi.fn(),
111
53
  seekPercentage: vi.fn(),
@@ -134,13 +76,20 @@ export function createMockContainer(options = {}, playback = createMockPlayback(
134
76
  return Object.assign(emitter, {
135
77
  el,
136
78
  playback,
137
- options,
79
+ options: {
80
+ ...options,
81
+ },
138
82
  $el: $(el),
83
+ disableMediaControl: vi.fn(),
84
+ enableMediaControl: vi.fn(),
85
+ enterPiP: vi.fn(),
86
+ exitPiP: vi.fn(),
139
87
  getDuration: vi.fn().mockReturnValue(0),
140
88
  getPlugin: vi.fn(),
141
89
  getPlaybackType: vi.fn(),
142
90
  isDvrInUse: vi.fn().mockReturnValue(false),
143
91
  isDvrEnabled: vi.fn().mockReturnValue(false),
92
+ isHighDefinitionInUse: vi.fn().mockReturnValue(false),
144
93
  isPlaying: vi.fn().mockReturnValue(false),
145
94
  play: vi.fn(),
146
95
  seek: vi.fn(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gcorevideo/player",
3
- "version": "2.22.29",
3
+ "version": "2.22.31",
4
4
  "description": "Gcore JavaScript video player",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -8,7 +8,6 @@ import {
8
8
  PlayerError,
9
9
  UIContainerPlugin,
10
10
  template,
11
- $,
12
11
  } from '@clappr/core'
13
12
  import { trace } from '@gcorevideo/utils'
14
13
 
@@ -20,25 +19,38 @@ import posterHTML from '../../../assets/poster/poster.ejs'
20
19
  import playIcon from '../../../assets/icons/new/play.svg'
21
20
  import { PlaybackError } from '../../playback.types.js'
22
21
 
22
+ export type PosterPluginSettings = {
23
+ /**
24
+ * Custom CSS background
25
+ */
26
+ custom?: string
27
+ /**
28
+ * Whether to show the poster image when the playback is noop (i.e., when there is no appropriate video playback engine for current media sources set or the media sources are not set at all)
29
+ */
30
+ showForNoOp?: boolean
31
+ /**
32
+ * Poster image URL
33
+ */
34
+ url?: string
35
+ /**
36
+ * Whether to show the poster after playback has ended @default true
37
+ */
38
+ showOnVideoEnd?: boolean
39
+ }
40
+
23
41
  const T = 'plugins.poster'
24
42
 
25
43
  /**
26
44
  * `PLUGIN` that displays a poster image in the background and a big play button on top when playback is stopped
27
45
  * @beta
28
46
  * @remarks
29
- * When the playback is stopped, media control UI is disabled.
47
+ * When the playback is stopped or not yet started, the media control UI is disabled and hidden.
48
+ * Media control gets activated once the metadata is loaded after playback is initiated.
49
+ * This plugin displays a big play button on top of the poster image to allow user to start playback.
30
50
  * Note that the poster image, if specified via the player config, will be used to update video element's poster attribute by the
31
51
  * HTML5-video-based playback module.
32
52
  *
33
- * Configuration options:
34
- *
35
- * - `poster.custom` - custom CSS background
36
- *
37
- * - `poster.showForNoOp` - whether to show the poster when the playback is not started
38
- *
39
- * - `poster.url` - the URL of the poster image
40
- *
41
- * - `poster.showOnVideoEnd` - whether to show the poster when the playback is ended
53
+ * Configuration options - {@link PosterPluginSettings}
42
54
  *
43
55
  * @example
44
56
  * ```ts
@@ -56,14 +68,12 @@ export class Poster extends UIContainerPlugin {
56
68
 
57
69
  private hasFatalError = false
58
70
 
59
- private hasStartedPlaying = false
71
+ private playing = false
60
72
 
61
73
  private playRequested = false
62
74
 
63
75
  private $playButton: ZeptoResult | null = null
64
76
 
65
- private $playWrapper: ZeptoResult | null = null
66
-
67
77
  /**
68
78
  * @internal
69
79
  */
@@ -87,18 +97,20 @@ export class Poster extends UIContainerPlugin {
87
97
  const showForNoOp = !!this.options.poster?.showForNoOp
88
98
  return (
89
99
  this.container.playback.name !== 'html_img' &&
90
- (this.container.playback.getPlaybackType() !== Playback.NO_OP ||
91
- showForNoOp)
100
+ (!this.isNoOp || showForNoOp)
92
101
  )
93
102
  }
94
103
 
104
+ private get isNoOp() {
105
+ return this.container.playback.getPlaybackType() === Playback.NO_OP
106
+ }
107
+
95
108
  /**
96
109
  * @internal
97
110
  */
98
111
  override get attributes() {
99
112
  return {
100
113
  class: 'player-poster',
101
- 'data-poster': '',
102
114
  }
103
115
  }
104
116
 
@@ -111,10 +123,6 @@ export class Poster extends UIContainerPlugin {
111
123
  }
112
124
  }
113
125
 
114
- private get showOnVideoEnd() {
115
- return this.options.poster?.showOnVideoEnd !== false
116
- }
117
-
118
126
  /**
119
127
  * @internal
120
128
  */
@@ -127,20 +135,27 @@ export class Poster extends UIContainerPlugin {
127
135
  Events.CONTAINER_STATE_BUFFERFULL,
128
136
  this.update,
129
137
  )
130
- this.listenTo(this.container, Events.CONTAINER_OPTIONS_CHANGE, this.render)
138
+ this.listenTo(this.container, Events.CONTAINER_OPTIONS_CHANGE, this.update)
131
139
  this.listenTo(this.container, Events.CONTAINER_ERROR, this.onError)
132
- this.showOnVideoEnd &&
140
+ // TODO check if this event is always accompanied with the CONTAINER_STOP
141
+ if (this.options.poster?.showOnVideoEnd !== false) {
133
142
  this.listenTo(this.container, Events.CONTAINER_ENDED, this.onStop)
143
+ }
134
144
  this.listenTo(this.container, Events.CONTAINER_READY, this.render)
135
- this.listenTo(this.container, Events.PLAYBACK_PLAY_INTENT, this.onPlayIntent)
145
+ this.listenTo(
146
+ this.container.playback,
147
+ Events.PLAYBACK_PLAY_INTENT,
148
+ this.onPlayIntent,
149
+ )
136
150
  }
137
151
 
138
152
  /**
139
153
  * Reenables earlier disabled plugin
140
154
  */
141
155
  override enable() {
156
+ trace(`${T} enable`)
142
157
  super.enable()
143
- this.hasStartedPlaying = this.container.playback.isPlaying()
158
+ this.playing = this.container.playback.isPlaying()
144
159
  this.update()
145
160
  }
146
161
 
@@ -149,7 +164,7 @@ export class Poster extends UIContainerPlugin {
149
164
  */
150
165
  override disable() {
151
166
  trace(`${T} disable`)
152
- this.hasStartedPlaying = false
167
+ this.playing = false
153
168
  this.playRequested = false
154
169
  super.disable()
155
170
  }
@@ -159,19 +174,16 @@ export class Poster extends UIContainerPlugin {
159
174
  error,
160
175
  enabled: this.enabled,
161
176
  })
162
- this.hasFatalError = error.level === PlayerError.Levels.FATAL
163
-
164
177
  if (this.hasFatalError) {
165
- this.hasStartedPlaying = false
166
- if (!this.playRequested) {
167
- this.showPlayButton()
168
- }
178
+ return
169
179
  }
180
+ this.hasFatalError = error.level === PlayerError.Levels.FATAL
181
+ // this.hasFatalError is reset on container recreate
170
182
  }
171
183
 
172
184
  private onPlay() {
173
185
  trace(`${T} onPlay`)
174
- this.hasStartedPlaying = true
186
+ this.playing = true
175
187
  this.playRequested = false
176
188
  this.update()
177
189
  }
@@ -183,24 +195,23 @@ export class Poster extends UIContainerPlugin {
183
195
  }
184
196
 
185
197
  private onStop() {
186
- trace(`${T} onStop`, {
187
- enabled: this.enabled,
188
- })
189
- this.hasStartedPlaying = false
198
+ trace(`${T} onStop`)
199
+ this.playing = false
190
200
  this.playRequested = false
191
201
  this.update()
192
202
  }
193
203
 
194
- private updatePlayButton(show: boolean) {
195
- trace(`${T} updatePlayButton`, {
196
- show,
197
- chromeless: this.options.chromeless,
198
- allowUserInteraction: this.options.allowUserInteraction,
199
- })
200
- if (
201
- show &&
202
- (!this.options.chromeless || this.options.allowUserInteraction)
203
- ) {
204
+ private updatePlayButton() {
205
+ trace(`${T} updatePlayButton`)
206
+ const show =
207
+ !this.isNoOp &&
208
+ !(this.options.chromeless && !this.options.allowUserInteraction) &&
209
+ !this.playRequested &&
210
+ !this.playing &&
211
+ !this.container.buffering &&
212
+ !this.hasFatalError &&
213
+ !this.options.disableMediaControl
214
+ if (show) {
204
215
  this.showPlayButton()
205
216
  } else {
206
217
  this.hidePlayButton()
@@ -208,40 +219,31 @@ export class Poster extends UIContainerPlugin {
208
219
  }
209
220
 
210
221
  private showPlayButton() {
211
- if (this.options.disableMediaControl) {
212
- return
213
- }
214
- if (this.hasFatalError && !this.options.disableErrorScreen) {
215
- return
216
- }
217
-
218
- this.$playButton?.show()
222
+ trace(`${T} showPlayButton`)
223
+ this.$el.find('#poster-play').show()
219
224
  this.$el.addClass('clickable')
220
225
  this.container.$el.addClass('container-with-poster-clickable')
221
226
  }
222
227
 
223
228
  private hidePlayButton() {
224
- this.$playButton.hide()
229
+ trace(`${T} hidePlayButton`)
230
+ this.$el.find('#poster-play').hide()
225
231
  this.$el.removeClass('clickable')
226
232
  }
227
233
 
228
- private clicked() {
229
- trace(`${T} clicked`, {
230
- hasStartedPlaying: this.hasStartedPlaying,
231
- chromeless: this.options.chromeless,
232
- allowUserInteraction: this.options.allowUserInteraction,
233
- })
234
+ private clicked(e: MouseEvent) {
235
+ trace(`${T} clicked`)
236
+ e.preventDefault()
237
+ e.stopPropagation()
238
+ if (this.options.chromeless && !this.options.allowUserInteraction) {
239
+ return
240
+ }
234
241
  // Let "click_to_pause" plugin handle click event if media has started playing
235
- if (!this.hasStartedPlaying) {
236
- if (!this.options.chromeless || this.options.allowUserInteraction) {
237
- this.playRequested = true
238
- this.update()
239
- this.container.playback.consent()
240
- this.container.playback.play()
241
- }
242
+ if (!this.playing) {
243
+ this.playRequested = true
244
+ this.update()
245
+ this.container.play()
242
246
  }
243
-
244
- return false
245
247
  }
246
248
 
247
249
  private shouldHideOnPlay() {
@@ -250,27 +252,15 @@ export class Poster extends UIContainerPlugin {
250
252
  }
251
253
 
252
254
  private update() {
253
- trace(`${T} update`, {
254
- shouldRender: this.shouldRender,
255
- })
256
- if (!this.shouldRender) {
257
- return
258
- }
255
+ trace(`${T} update`)
259
256
 
260
- const showPlayButton =
261
- !this.playRequested &&
262
- !this.hasStartedPlaying &&
263
- !this.container.buffering
264
-
265
- this.updatePlayButton(showPlayButton)
257
+ this.updatePlayButton()
266
258
  this.updatePoster()
267
259
  }
268
260
 
269
261
  private updatePoster() {
270
- trace(`${T} updatePoster`, {
271
- hasStartedPlaying: this.hasStartedPlaying,
272
- })
273
- if (!this.hasStartedPlaying) {
262
+ trace(`${T} updatePoster`)
263
+ if (!this.playing) {
274
264
  this.showPoster()
275
265
  } else {
276
266
  this.hidePoster()
@@ -283,9 +273,7 @@ export class Poster extends UIContainerPlugin {
283
273
  }
284
274
 
285
275
  private hidePoster() {
286
- trace(`${T} hidePoster`, {
287
- shouldHideOnPlay: this.shouldHideOnPlay(),
288
- })
276
+ trace(`${T} hidePoster`)
289
277
  if (!this.options.disableMediaControl) {
290
278
  this.container.enableMediaControl()
291
279
  }
@@ -304,34 +292,27 @@ export class Poster extends UIContainerPlugin {
304
292
 
305
293
  this.$el.html(Poster.template())
306
294
 
307
- const isRegularPoster =
308
- this.options.poster && this.options.poster.custom === undefined
295
+ const isCustomPoster = this.options.poster?.custom !== undefined
309
296
 
310
- if (isRegularPoster) {
311
- const posterUrl = this.options.poster.url || this.options.poster
312
-
313
- this.$el.css({ 'background-image': 'url(' + posterUrl + ')' })
314
- } else if (this.options.poster) {
297
+ if (isCustomPoster) {
315
298
  this.$el.css({ background: this.options.poster.custom })
299
+ } else {
300
+ const posterUrl =
301
+ typeof this.options.poster === 'string'
302
+ ? this.options.poster
303
+ : this.options.poster?.url
304
+ if (posterUrl) {
305
+ this.$el.css({ 'background-image': 'url(' + posterUrl + ')' })
306
+ }
316
307
  }
317
308
 
318
309
  this.container.$el.removeClass('container-with-poster-clickable')
319
310
  this.container.$el.append(this.el)
320
- this.$playWrapper = this.$el.find('.play-wrapper')
321
- this.$playWrapper.addClass('control-need-disable')
322
- this.$playButton = $(
323
- "<div class='circle-poster gcore-skin-button-color gcore-skin-border-color'></div>",
324
- )
325
- this.$playWrapper.append(this.$playButton)
326
- this.$playButton.append(playIcon)
311
+ this.$el.find('#poster-play').append(playIcon)
327
312
 
328
- if (this.options.autoPlay) {
329
- this.$playButton.hide()
313
+ if (this.options.autoPlay || this.isNoOp) {
314
+ this.$el.find('#poster-play').hide()
330
315
  }
331
- this.$playButton.addClass('poster-icon')
332
- this.$playButton.attr('data-poster', '')
333
-
334
- this.update()
335
316
 
336
317
  return this
337
318
  }