@xibosignage/xibo-layout-renderer 1.0.26 → 1.0.27

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.
@@ -50,6 +50,9 @@ export declare class Media implements IMedia {
50
50
  xml: Element | null;
51
51
  videoHandler?: IVideoMediaHandler;
52
52
  mediaTimer: ReturnType<typeof setInterval> | undefined;
53
+ sspImpressionUrls: string[] | undefined;
54
+ sspErrorUrls: string[] | undefined;
55
+ private isSspWidget;
53
56
  private mediaTimeCount;
54
57
  private xlr;
55
58
  private readonly statsBC;
@@ -59,6 +62,7 @@ export declare class Media implements IMedia {
59
62
  private on;
60
63
  private init;
61
64
  run(): void;
65
+ setSspAdUrl(url: string, adMediaType: 'image' | 'video', impressionUrls?: string[], errorUrls?: string[]): void;
62
66
  stop(): Promise<void>;
63
67
  /**
64
68
  * Emits a command from the shell command widget.
@@ -42,6 +42,9 @@ export interface IMedia {
42
42
  region: IRegion;
43
43
  render: string;
44
44
  run(): void;
45
+ setSspAdUrl(url: string, adMediaType: 'image' | 'video', impressionUrls?: string[], errorUrls?: string[]): void;
46
+ sspImpressionUrls: string[] | undefined;
47
+ sspErrorUrls: string[] | undefined;
45
48
  schemaVersion: string;
46
49
  singlePlay: boolean;
47
50
  state: MediaState;
@@ -35,6 +35,7 @@ export interface IRegion {
35
35
  };
36
36
  playNextMedia(): void;
37
37
  playPreviousMedia(): void;
38
+ prepareMedia(media: IMedia): void;
38
39
  prepareMediaObjects(): void;
39
40
  prepareRegion(): void;
40
41
  ready: boolean;
@@ -1,5 +1,6 @@
1
1
  import { Emitter, Unsubscribe } from 'nanoevents';
2
2
  import { ILayout, InputLayoutType, OptionsType } from '../Layout';
3
+ import { IMedia } from '../Media';
3
4
  import { OverlayLayoutManager } from "../../Modules/Layout/OverlayLayoutManager";
4
5
  export type PrepareLayoutsType = {
5
6
  moveNext?: boolean;
@@ -17,6 +18,8 @@ export type IXlrEvents = {
17
18
  widgetEnd: (widgetId: number) => void;
18
19
  widgetError: (widgetId: number) => void;
19
20
  adRequest: (sspLayoutIndex: number) => void;
21
+ sspWidgetRequest: (media: IMedia) => void;
22
+ sspWidgetEnd: (impressionUrls: string[], errorUrls: string[], duration: number) => void;
20
23
  updateLoop: (inputLayouts: InputLayoutType[]) => void;
21
24
  updateOverlays: (overlays: InputLayoutType[]) => void;
22
25
  overlayStart: (overlay: ILayout) => void;
@@ -756,6 +756,7 @@ var initialRegion = {
756
756
  options: {},
757
757
  playNextMedia: function playNextMedia() {},
758
758
  playPreviousMedia: function playPreviousMedia() {},
759
+ prepareMedia: function prepareMedia(_media) {},
759
760
  prepareMediaObjects: function prepareMediaObjects() {},
760
761
  prepareRegion: function prepareRegion() {},
761
762
  ready: false,
@@ -73986,6 +73987,9 @@ var Media = /*#__PURE__*/function () {
73986
73987
  _defineProperty(this, "xml", null);
73987
73988
  _defineProperty(this, "videoHandler", void 0);
73988
73989
  _defineProperty(this, "mediaTimer", void 0);
73990
+ _defineProperty(this, "sspImpressionUrls", undefined);
73991
+ _defineProperty(this, "sspErrorUrls", undefined);
73992
+ _defineProperty(this, "isSspWidget", false);
73989
73993
  _defineProperty(this, "mediaTimeCount", 0);
73990
73994
  _defineProperty(this, "xlr", {});
73991
73995
  _defineProperty(this, "statsBC", new BroadcastChannel('statsBC'));
@@ -74071,6 +74075,10 @@ var Media = /*#__PURE__*/function () {
74071
74075
  layoutId: media.region.layout.id
74072
74076
  });
74073
74077
  _this.xlr.emitter.emit('widgetEnd', parseInt(media.id));
74078
+ if (_this.isSspWidget) {
74079
+ var _this$sspImpressionUr, _this$sspErrorUrls;
74080
+ _this.xlr.emitter.emit('sspWidgetEnd', (_this$sspImpressionUr = _this.sspImpressionUrls) !== null && _this$sspImpressionUr !== void 0 ? _this$sspImpressionUr : [], (_this$sspErrorUrls = _this.sspErrorUrls) !== null && _this$sspErrorUrls !== void 0 ? _this$sspErrorUrls : [], _this.sspImpressionUrls ? _this.duration : 0);
74081
+ }
74074
74082
  media.region.playNextMedia();
74075
74083
  });
74076
74084
  this.on('cancelled', function (media) {
@@ -74097,6 +74105,10 @@ var Media = /*#__PURE__*/function () {
74097
74105
  layoutId: media.region.layout.id
74098
74106
  });
74099
74107
  _this.xlr.emitter.emit('widgetEnd', parseInt(media.id));
74108
+ if (_this.isSspWidget) {
74109
+ var _this$sspImpressionUr2, _this$sspErrorUrls2;
74110
+ _this.xlr.emitter.emit('sspWidgetEnd', (_this$sspImpressionUr2 = _this.sspImpressionUrls) !== null && _this$sspImpressionUr2 !== void 0 ? _this$sspImpressionUr2 : [], (_this$sspErrorUrls2 = _this.sspErrorUrls) !== null && _this$sspErrorUrls2 !== void 0 ? _this$sspErrorUrls2 : [], _this.sspImpressionUrls ? _this.duration : 0);
74111
+ }
74100
74112
  media.region.playNextMedia();
74101
74113
  });
74102
74114
  // Initialize Media object
@@ -74197,26 +74209,33 @@ var Media = /*#__PURE__*/function () {
74197
74209
  if (this.mediaType === 'image' || this.mediaType === 'video') {
74198
74210
  resourceUrlParams.mediaType = this.mediaType;
74199
74211
  }
74200
- var tmpUrl = '';
74201
- if (this.xlr.config.platform === exports.ConsumerPlatform.CMS) {
74202
- tmpUrl = composeResourceUrlByPlatform(this.xlr.config, resourceUrlParams);
74203
- } else if (this.xlr.config.platform === exports.ConsumerPlatform.CHROMEOS) {
74204
- tmpUrl = composeResourceUrl(this.xlr.config, resourceUrlParams);
74205
- if (this.mediaType === 'image' || this.mediaType === 'video' || this.mediaType === 'audio') {
74206
- tmpUrl = composeMediaUrl(resourceUrlParams);
74212
+ // SSP widget: URL is not known until the consumer resolves an ad at play-time.
74213
+ // Skip all URL composition and leave url as null.
74214
+ if (this.mediaType === 'ssp') {
74215
+ this.url = null;
74216
+ this.isSspWidget = true;
74217
+ } else {
74218
+ var tmpUrl = '';
74219
+ if (this.xlr.config.platform === exports.ConsumerPlatform.CMS) {
74220
+ tmpUrl = composeResourceUrlByPlatform(this.xlr.config, resourceUrlParams);
74221
+ } else if (this.xlr.config.platform === exports.ConsumerPlatform.CHROMEOS) {
74222
+ tmpUrl = composeResourceUrl(this.xlr.config, resourceUrlParams);
74223
+ if (this.mediaType === 'image' || this.mediaType === 'video' || this.mediaType === 'audio') {
74224
+ tmpUrl = composeMediaUrl(resourceUrlParams);
74225
+ // this is an SSP Layout
74226
+ if (this.region.layout.layoutId === -1) {
74227
+ tmpUrl = this.uri;
74228
+ }
74229
+ }
74230
+ } else if (this.xlr.config.platform === exports.ConsumerPlatform.ELECTRON) {
74231
+ tmpUrl = composeResourceUrlByPlatform(this.xlr.config, resourceUrlParams);
74207
74232
  // this is an SSP Layout
74208
74233
  if (this.region.layout.layoutId === -1) {
74209
74234
  tmpUrl = this.uri;
74210
74235
  }
74211
74236
  }
74212
- } else if (this.xlr.config.platform === exports.ConsumerPlatform.ELECTRON) {
74213
- tmpUrl = composeResourceUrlByPlatform(this.xlr.config, resourceUrlParams);
74214
- // this is an SSP Layout
74215
- if (this.region.layout.layoutId === -1) {
74216
- tmpUrl = this.uri;
74217
- }
74237
+ this.url = tmpUrl;
74218
74238
  }
74219
- this.url = tmpUrl;
74220
74239
  // Loop if media has loop, or if region has loop and a single media
74221
74240
  this.loop = this.options['loop'] == '1' || this.region.options['loop'] == '1' && this.region.totalMediaObjects == 1;
74222
74241
  this.html = createMediaElement(this);
@@ -74333,8 +74352,39 @@ var Media = /*#__PURE__*/function () {
74333
74352
  }
74334
74353
  return null;
74335
74354
  };
74355
+ // SSP widget: if the consumer did not resolve an ad during the preload window
74356
+ // (i.e. setSspAdUrl was never called), skip this widget and advance normally.
74357
+ if (this.mediaType === 'ssp') {
74358
+ console.debug('??? XLR.debug >> Media.run() > SSP widget: no ad resolved during preload, skipping');
74359
+ this.emitter.emit('end', this);
74360
+ return;
74361
+ }
74336
74362
  showCurrentMedia();
74337
74363
  }
74364
+ }, {
74365
+ key: "setSspAdUrl",
74366
+ value: function setSspAdUrl(url, adMediaType, impressionUrls, errorUrls) {
74367
+ // Ignore if the media has already been skipped or cancelled before the ad arrived.
74368
+ if (this.state !== MediaState.IDLE) {
74369
+ console.debug('??? XLR.debug >> Media::setSspAdUrl - ignoring, media is no longer idle', {
74370
+ state: this.state
74371
+ });
74372
+ return;
74373
+ }
74374
+ // Remove the placeholder <div> so the correct element type can take its place.
74375
+ if (this.html) {
74376
+ this.html.remove();
74377
+ this.html = null;
74378
+ }
74379
+ this.url = url;
74380
+ this.mediaType = adMediaType;
74381
+ this.sspImpressionUrls = impressionUrls;
74382
+ this.sspErrorUrls = errorUrls;
74383
+ // Re-create the element now that mediaType is known, then prepare and append to region DOM.
74384
+ // Visibility and playback are handled by run() when this media's turn comes.
74385
+ this.html = createMediaElement(this);
74386
+ this.region.prepareMedia(this);
74387
+ }
74338
74388
  }, {
74339
74389
  key: "stop",
74340
74390
  value: function () {
@@ -74587,6 +74637,13 @@ var Region = /*#__PURE__*/function () {
74587
74637
  }, {
74588
74638
  key: "prepareMedia",
74589
74639
  value: function prepareMedia(media) {
74640
+ // SSP widget: signal the consumer to fetch an ad before this media's turn to play.
74641
+ // The consumer calls media.setSspAdUrl() to resolve it; if it never arrives,
74642
+ // Media.run() skips the widget and advances normally.
74643
+ if (media.mediaType === 'ssp') {
74644
+ this.xlr.emitter.emit('sspWidgetRequest', media);
74645
+ return;
74646
+ }
74590
74647
  if (media.mediaType === 'video') {
74591
74648
  prepareVideoMedia(media, this);
74592
74649
  } else if (media.mediaType === 'image' && media.url !== null) {
@@ -74803,7 +74860,12 @@ var Region = /*#__PURE__*/function () {
74803
74860
  }
74804
74861
  };
74805
74862
  if (oldMedia) {
74806
- hideOldMedia();
74863
+ // Skip hiding old media when it is the same object as new media
74864
+ // (single-media loop): removing it would also remove the element
74865
+ // that is about to be shown, leaving the region blank.
74866
+ if (oldMedia !== newMedia) {
74867
+ hideOldMedia();
74868
+ }
74807
74869
  newMedia.run();
74808
74870
  } else {
74809
74871
  newMedia.run();