@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.
@@ -191,6 +191,8 @@ type IXlrEvents = {
191
191
  widgetEnd: (widgetId: number) => void;
192
192
  widgetError: (widgetId: number) => void;
193
193
  adRequest: (sspLayoutIndex: number) => void;
194
+ sspWidgetRequest: (media: IMedia) => void;
195
+ sspWidgetEnd: (impressionUrls: string[], errorUrls: string[], duration: number) => void;
194
196
  updateLoop: (inputLayouts: InputLayoutType[]) => void;
195
197
  updateOverlays: (overlays: InputLayoutType[]) => void;
196
198
  overlayStart: (overlay: ILayout) => void;
@@ -315,6 +317,9 @@ declare class Media implements IMedia {
315
317
  xml: Element | null;
316
318
  videoHandler?: IVideoMediaHandler;
317
319
  mediaTimer: ReturnType<typeof setInterval> | undefined;
320
+ sspImpressionUrls: string[] | undefined;
321
+ sspErrorUrls: string[] | undefined;
322
+ private isSspWidget;
318
323
  private mediaTimeCount;
319
324
  private xlr;
320
325
  private readonly statsBC;
@@ -324,6 +329,7 @@ declare class Media implements IMedia {
324
329
  private on;
325
330
  private init;
326
331
  run(): void;
332
+ setSspAdUrl(url: string, adMediaType: 'image' | 'video', impressionUrls?: string[], errorUrls?: string[]): void;
327
333
  stop(): Promise<void>;
328
334
  /**
329
335
  * Emits a command from the shell command widget.
@@ -376,6 +382,9 @@ interface IMedia {
376
382
  region: IRegion;
377
383
  render: string;
378
384
  run(): void;
385
+ setSspAdUrl(url: string, adMediaType: 'image' | 'video', impressionUrls?: string[], errorUrls?: string[]): void;
386
+ sspImpressionUrls: string[] | undefined;
387
+ sspErrorUrls: string[] | undefined;
379
388
  schemaVersion: string;
380
389
  singlePlay: boolean;
381
390
  state: MediaState;
@@ -424,6 +433,7 @@ interface IRegion {
424
433
  };
425
434
  playNextMedia(): void;
426
435
  playPreviousMedia(): void;
436
+ prepareMedia(media: IMedia): void;
427
437
  prepareMediaObjects(): void;
428
438
  prepareRegion(): void;
429
439
  ready: boolean;
@@ -752,6 +752,7 @@ var initialRegion = {
752
752
  options: {},
753
753
  playNextMedia: function playNextMedia() {},
754
754
  playPreviousMedia: function playPreviousMedia() {},
755
+ prepareMedia: function prepareMedia(_media) {},
755
756
  prepareMediaObjects: function prepareMediaObjects() {},
756
757
  prepareRegion: function prepareRegion() {},
757
758
  ready: false,
@@ -73982,6 +73983,9 @@ var Media = /*#__PURE__*/function () {
73982
73983
  _defineProperty(this, "xml", null);
73983
73984
  _defineProperty(this, "videoHandler", void 0);
73984
73985
  _defineProperty(this, "mediaTimer", void 0);
73986
+ _defineProperty(this, "sspImpressionUrls", undefined);
73987
+ _defineProperty(this, "sspErrorUrls", undefined);
73988
+ _defineProperty(this, "isSspWidget", false);
73985
73989
  _defineProperty(this, "mediaTimeCount", 0);
73986
73990
  _defineProperty(this, "xlr", {});
73987
73991
  _defineProperty(this, "statsBC", new BroadcastChannel('statsBC'));
@@ -74067,6 +74071,10 @@ var Media = /*#__PURE__*/function () {
74067
74071
  layoutId: media.region.layout.id
74068
74072
  });
74069
74073
  _this.xlr.emitter.emit('widgetEnd', parseInt(media.id));
74074
+ if (_this.isSspWidget) {
74075
+ var _this$sspImpressionUr, _this$sspErrorUrls;
74076
+ _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);
74077
+ }
74070
74078
  media.region.playNextMedia();
74071
74079
  });
74072
74080
  this.on('cancelled', function (media) {
@@ -74093,6 +74101,10 @@ var Media = /*#__PURE__*/function () {
74093
74101
  layoutId: media.region.layout.id
74094
74102
  });
74095
74103
  _this.xlr.emitter.emit('widgetEnd', parseInt(media.id));
74104
+ if (_this.isSspWidget) {
74105
+ var _this$sspImpressionUr2, _this$sspErrorUrls2;
74106
+ _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);
74107
+ }
74096
74108
  media.region.playNextMedia();
74097
74109
  });
74098
74110
  // Initialize Media object
@@ -74193,26 +74205,33 @@ var Media = /*#__PURE__*/function () {
74193
74205
  if (this.mediaType === 'image' || this.mediaType === 'video') {
74194
74206
  resourceUrlParams.mediaType = this.mediaType;
74195
74207
  }
74196
- var tmpUrl = '';
74197
- if (this.xlr.config.platform === ConsumerPlatform.CMS) {
74198
- tmpUrl = composeResourceUrlByPlatform(this.xlr.config, resourceUrlParams);
74199
- } else if (this.xlr.config.platform === ConsumerPlatform.CHROMEOS) {
74200
- tmpUrl = composeResourceUrl(this.xlr.config, resourceUrlParams);
74201
- if (this.mediaType === 'image' || this.mediaType === 'video' || this.mediaType === 'audio') {
74202
- tmpUrl = composeMediaUrl(resourceUrlParams);
74208
+ // SSP widget: URL is not known until the consumer resolves an ad at play-time.
74209
+ // Skip all URL composition and leave url as null.
74210
+ if (this.mediaType === 'ssp') {
74211
+ this.url = null;
74212
+ this.isSspWidget = true;
74213
+ } else {
74214
+ var tmpUrl = '';
74215
+ if (this.xlr.config.platform === ConsumerPlatform.CMS) {
74216
+ tmpUrl = composeResourceUrlByPlatform(this.xlr.config, resourceUrlParams);
74217
+ } else if (this.xlr.config.platform === ConsumerPlatform.CHROMEOS) {
74218
+ tmpUrl = composeResourceUrl(this.xlr.config, resourceUrlParams);
74219
+ if (this.mediaType === 'image' || this.mediaType === 'video' || this.mediaType === 'audio') {
74220
+ tmpUrl = composeMediaUrl(resourceUrlParams);
74221
+ // this is an SSP Layout
74222
+ if (this.region.layout.layoutId === -1) {
74223
+ tmpUrl = this.uri;
74224
+ }
74225
+ }
74226
+ } else if (this.xlr.config.platform === ConsumerPlatform.ELECTRON) {
74227
+ tmpUrl = composeResourceUrlByPlatform(this.xlr.config, resourceUrlParams);
74203
74228
  // this is an SSP Layout
74204
74229
  if (this.region.layout.layoutId === -1) {
74205
74230
  tmpUrl = this.uri;
74206
74231
  }
74207
74232
  }
74208
- } else if (this.xlr.config.platform === ConsumerPlatform.ELECTRON) {
74209
- tmpUrl = composeResourceUrlByPlatform(this.xlr.config, resourceUrlParams);
74210
- // this is an SSP Layout
74211
- if (this.region.layout.layoutId === -1) {
74212
- tmpUrl = this.uri;
74213
- }
74233
+ this.url = tmpUrl;
74214
74234
  }
74215
- this.url = tmpUrl;
74216
74235
  // Loop if media has loop, or if region has loop and a single media
74217
74236
  this.loop = this.options['loop'] == '1' || this.region.options['loop'] == '1' && this.region.totalMediaObjects == 1;
74218
74237
  this.html = createMediaElement(this);
@@ -74329,8 +74348,39 @@ var Media = /*#__PURE__*/function () {
74329
74348
  }
74330
74349
  return null;
74331
74350
  };
74351
+ // SSP widget: if the consumer did not resolve an ad during the preload window
74352
+ // (i.e. setSspAdUrl was never called), skip this widget and advance normally.
74353
+ if (this.mediaType === 'ssp') {
74354
+ console.debug('??? XLR.debug >> Media.run() > SSP widget: no ad resolved during preload, skipping');
74355
+ this.emitter.emit('end', this);
74356
+ return;
74357
+ }
74332
74358
  showCurrentMedia();
74333
74359
  }
74360
+ }, {
74361
+ key: "setSspAdUrl",
74362
+ value: function setSspAdUrl(url, adMediaType, impressionUrls, errorUrls) {
74363
+ // Ignore if the media has already been skipped or cancelled before the ad arrived.
74364
+ if (this.state !== MediaState.IDLE) {
74365
+ console.debug('??? XLR.debug >> Media::setSspAdUrl - ignoring, media is no longer idle', {
74366
+ state: this.state
74367
+ });
74368
+ return;
74369
+ }
74370
+ // Remove the placeholder <div> so the correct element type can take its place.
74371
+ if (this.html) {
74372
+ this.html.remove();
74373
+ this.html = null;
74374
+ }
74375
+ this.url = url;
74376
+ this.mediaType = adMediaType;
74377
+ this.sspImpressionUrls = impressionUrls;
74378
+ this.sspErrorUrls = errorUrls;
74379
+ // Re-create the element now that mediaType is known, then prepare and append to region DOM.
74380
+ // Visibility and playback are handled by run() when this media's turn comes.
74381
+ this.html = createMediaElement(this);
74382
+ this.region.prepareMedia(this);
74383
+ }
74334
74384
  }, {
74335
74385
  key: "stop",
74336
74386
  value: function () {
@@ -74583,6 +74633,13 @@ var Region = /*#__PURE__*/function () {
74583
74633
  }, {
74584
74634
  key: "prepareMedia",
74585
74635
  value: function prepareMedia(media) {
74636
+ // SSP widget: signal the consumer to fetch an ad before this media's turn to play.
74637
+ // The consumer calls media.setSspAdUrl() to resolve it; if it never arrives,
74638
+ // Media.run() skips the widget and advances normally.
74639
+ if (media.mediaType === 'ssp') {
74640
+ this.xlr.emitter.emit('sspWidgetRequest', media);
74641
+ return;
74642
+ }
74586
74643
  if (media.mediaType === 'video') {
74587
74644
  prepareVideoMedia(media, this);
74588
74645
  } else if (media.mediaType === 'image' && media.url !== null) {
@@ -74799,7 +74856,12 @@ var Region = /*#__PURE__*/function () {
74799
74856
  }
74800
74857
  };
74801
74858
  if (oldMedia) {
74802
- hideOldMedia();
74859
+ // Skip hiding old media when it is the same object as new media
74860
+ // (single-media loop): removing it would also remove the element
74861
+ // that is about to be shown, leaving the region blank.
74862
+ if (oldMedia !== newMedia) {
74863
+ hideOldMedia();
74864
+ }
74803
74865
  newMedia.run();
74804
74866
  } else {
74805
74867
  newMedia.run();