stormcloud-video-player 0.6.1 → 0.6.2

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/lib/index.d.cts CHANGED
@@ -35,6 +35,7 @@ interface StormcloudVideoPlayerConfig {
35
35
  disableAds?: boolean;
36
36
  disableFiller?: boolean;
37
37
  adTransitionGapMs?: number;
38
+ singlePipelineMode?: boolean;
38
39
  }
39
40
  interface ClientInfo {
40
41
  brand: string;
@@ -4008,6 +4009,7 @@ interface VastAdLayerOptions {
4008
4009
  mainHlsInstance?: Hls;
4009
4010
  smartTVMode?: boolean;
4010
4011
  singleElementMode?: boolean;
4012
+ forceMP4Ads?: boolean;
4011
4013
  debug?: boolean;
4012
4014
  }
4013
4015
  interface VastAdLayerOptionsUpdate {
package/lib/index.d.ts CHANGED
@@ -35,6 +35,7 @@ interface StormcloudVideoPlayerConfig {
35
35
  disableAds?: boolean;
36
36
  disableFiller?: boolean;
37
37
  adTransitionGapMs?: number;
38
+ singlePipelineMode?: boolean;
38
39
  }
39
40
  interface ClientInfo {
40
41
  brand: string;
@@ -4008,6 +4009,7 @@ interface VastAdLayerOptions {
4008
4009
  mainHlsInstance?: Hls;
4009
4010
  smartTVMode?: boolean;
4010
4011
  singleElementMode?: boolean;
4012
+ forceMP4Ads?: boolean;
4011
4013
  debug?: boolean;
4012
4014
  }
4013
4015
  interface VastAdLayerOptionsUpdate {
package/lib/index.js CHANGED
@@ -944,7 +944,7 @@ function resolveBidToVastAd(winner, logPrefix) {
944
944
  return Promise.resolve(null);
945
945
  }
946
946
  function createVastAdLayer(contentVideo, options) {
947
- var _ref, _ref1, _ref2, _ref3;
947
+ var _ref, _ref1, _ref2, _ref3, _ref4;
948
948
  var adPlaying = false;
949
949
  var originalMutedState = false;
950
950
  var originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));
@@ -953,7 +953,8 @@ function createVastAdLayer(contentVideo, options) {
953
953
  var continueLiveStreamDuringAds = (_ref = options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds) !== null && _ref !== void 0 ? _ref : false;
954
954
  var smartTVMode = (_ref1 = options === null || options === void 0 ? void 0 : options.smartTVMode) !== null && _ref1 !== void 0 ? _ref1 : false;
955
955
  var singleElementMode = (_ref2 = options === null || options === void 0 ? void 0 : options.singleElementMode) !== null && _ref2 !== void 0 ? _ref2 : false;
956
- var debug = (_ref3 = options === null || options === void 0 ? void 0 : options.debug) !== null && _ref3 !== void 0 ? _ref3 : false;
956
+ var forceMP4Ads = (_ref3 = options === null || options === void 0 ? void 0 : options.forceMP4Ads) !== null && _ref3 !== void 0 ? _ref3 : smartTVMode || singleElementMode;
957
+ var debug = (_ref4 = options === null || options === void 0 ? void 0 : options.debug) !== null && _ref4 !== void 0 ? _ref4 : false;
957
958
  var adVideoElement;
958
959
  var adHls;
959
960
  var adContainerEl;
@@ -1024,14 +1025,26 @@ function createVastAdLayer(contentVideo, options) {
1024
1025
  var _ref;
1025
1026
  var _scoredFiles_;
1026
1027
  if (mediaFiles.length === 0) throw new Error("No media files available");
1027
- var firstFile = mediaFiles[0];
1028
- if (mediaFiles.length === 1) return firstFile;
1028
+ var candidates = mediaFiles;
1029
+ if (forceMP4Ads) {
1030
+ var mp4Only = candidates.filter(function(f) {
1031
+ return !isHlsMediaFile(f);
1032
+ });
1033
+ if (mp4Only.length > 0) {
1034
+ candidates = mp4Only;
1035
+ if (debug) console.log("".concat(LOG, " forceMP4Ads: filtered to ").concat(mp4Only.length, " MP4-only file(s)"));
1036
+ } else if (debug) {
1037
+ console.warn("".concat(LOG, " forceMP4Ads: no MP4 files available, falling back to all media files"));
1038
+ }
1039
+ }
1040
+ var firstFile = candidates[0];
1041
+ if (candidates.length === 1) return firstFile;
1029
1042
  var mainQuality = getMainStreamQuality();
1030
1043
  if (!mainQuality) {
1031
1044
  if (debug) console.log("".concat(LOG, " No main stream quality info, using first media file"));
1032
1045
  return firstFile;
1033
1046
  }
1034
- var scoredFiles = mediaFiles.map(function(file) {
1047
+ var scoredFiles = candidates.map(function(file) {
1035
1048
  var widthDiff = Math.abs(file.width - mainQuality.width);
1036
1049
  var heightDiff = Math.abs(file.height - mainQuality.height);
1037
1050
  var resolutionDiff = widthDiff + heightDiff;
@@ -1248,6 +1261,16 @@ function createVastAdLayer(contentVideo, options) {
1248
1261
  }
1249
1262
  function startPlayback(mediaFile) {
1250
1263
  if (!adVideoElement) return;
1264
+ if (singleElementMode && isHlsMediaFile(mediaFile)) {
1265
+ var mp4Fallback = currentAd === null || currentAd === void 0 ? void 0 : currentAd.mediaFiles.find(function(f) {
1266
+ return !isHlsMediaFile(f);
1267
+ });
1268
+ if (mp4Fallback) {
1269
+ if (debug) console.log("".concat(LOG, " singleElementMode: HLS ad blocked, using MP4 fallback"));
1270
+ startNativePlayback(mp4Fallback);
1271
+ return;
1272
+ }
1273
+ }
1251
1274
  if (isHlsMediaFile(mediaFile)) {
1252
1275
  startHlsPlayback(mediaFile);
1253
1276
  } else {
@@ -2946,10 +2969,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2946
2969
  debug: !!config.debugAdTiming
2947
2970
  } : {});
2948
2971
  var browserForAdLayer = detectBrowser();
2972
+ var isSinglePipeline = browserForAdLayer.isSmartTV || !!this.config.singlePipelineMode;
2949
2973
  this.adLayer = createVastAdLayer(this.video, {
2950
2974
  continueLiveStreamDuringAds: false,
2951
- smartTVMode: browserForAdLayer.isSmartTV,
2952
- singleElementMode: browserForAdLayer.isSmartTV,
2975
+ smartTVMode: isSinglePipeline,
2976
+ singleElementMode: isSinglePipeline,
2977
+ forceMP4Ads: isSinglePipeline,
2953
2978
  debug: !!config.debugAdTiming
2954
2979
  });
2955
2980
  }
@@ -3595,6 +3620,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3595
3620
  if (_this.fillerVideo) {
3596
3621
  _this.fillerVideo.style.display = "none";
3597
3622
  }
3623
+ if (!_this.adLayer.isAdPlaying()) {
3624
+ if (_this.config.debugAdTiming) {
3625
+ console.log("[StormcloudVideoPlayer] Filler video failed \u2014 restoring main video");
3626
+ }
3627
+ _this.adLayer.hidePlaceholder();
3628
+ if (_this.video.paused && _this.video.readyState >= 2) {
3629
+ var _this_video_play;
3630
+ (_this_video_play = _this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
3631
+ }
3632
+ }
3598
3633
  });
3599
3634
  if (this.config.debugAdTiming) {
3600
3635
  console.log("[StormcloudVideoPlayer] Showing filler video layer");
@@ -4311,6 +4346,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4311
4346
  if (!this.isLiveStream) {
4312
4347
  return false;
4313
4348
  }
4349
+ if (this.config.singlePipelineMode) {
4350
+ return false;
4351
+ }
4314
4352
  var browser = detectBrowser();
4315
4353
  if (browser.isSmartTV) {
4316
4354
  return false;
@@ -5461,32 +5499,56 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5461
5499
  this.video.volume = restoredVolume;
5462
5500
  }
5463
5501
  var browser = detectBrowser();
5464
- var isSmartTV = browser.tizenVersion !== void 0 || browser.webOSVersion !== void 0;
5502
+ var isSmartTV = browser.tizenVersion !== void 0 || browser.webOSVersion !== void 0 || !!this.config.singlePipelineMode;
5465
5503
  if (isSmartTV && this.hls) {
5466
5504
  var hlsRef = this.hls;
5467
5505
  var savedMuted = restoredMuted;
5468
5506
  var savedVolume = restoredVolume;
5507
+ var videoRef = this.video;
5508
+ var debugEnabled = this.config.debugAdTiming;
5509
+ var tryPlay = function tryPlay1(attempt) {
5510
+ var _videoRef_play;
5511
+ if (_this.inAdBreak || _this.adLayer.isAdPlaying()) return;
5512
+ (_videoRef_play = videoRef.play()) === null || _videoRef_play === void 0 ? void 0 : _videoRef_play.catch(function() {
5513
+ if (attempt < 3) {
5514
+ if (debugEnabled) {
5515
+ console.log("[StormcloudVideoPlayer] Smart TV: play() retry ".concat(attempt + 1, "/3 in ").concat(500 * (attempt + 1), "ms"));
5516
+ }
5517
+ setTimeout(function() {
5518
+ return tryPlay(attempt + 1);
5519
+ }, 500 * (attempt + 1));
5520
+ }
5521
+ });
5522
+ };
5469
5523
  var onManifestParsedRestore = function onManifestParsedRestore1() {
5470
5524
  hlsRef.off(Hls2.Events.MANIFEST_PARSED, onManifestParsedRestore);
5471
5525
  if (!_this.inAdBreak && !_this.adLayer.isAdPlaying()) {
5472
- var _this_video_play;
5473
- if (_this.video.muted !== savedMuted) _this.video.muted = savedMuted;
5474
- if (Math.abs(_this.video.volume - savedVolume) > 0.01) _this.video.volume = savedVolume;
5475
- if (_this.config.debugAdTiming) {
5526
+ if (videoRef.muted !== savedMuted) videoRef.muted = savedMuted;
5527
+ if (Math.abs(videoRef.volume - savedVolume) > 0.01) videoRef.volume = savedVolume;
5528
+ if (debugEnabled) {
5476
5529
  console.log("[StormcloudVideoPlayer] Smart TV: audio state restored on MANIFEST_PARSED after re-attach");
5477
5530
  }
5478
5531
  hlsRef.startLoad(-1);
5479
- (_this_video_play = _this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
5480
- if (_this.config.debugAdTiming) {
5532
+ tryPlay(0);
5533
+ if (debugEnabled) {
5481
5534
  console.log("[StormcloudVideoPlayer] Smart TV: seeking to live edge and resuming playback after re-attach");
5482
5535
  }
5483
5536
  }
5484
5537
  };
5485
5538
  hlsRef.on(Hls2.Events.MANIFEST_PARSED, onManifestParsedRestore);
5486
- this.hls.attachMedia(this.video);
5487
- if (this.config.debugAdTiming) {
5488
- console.log("[StormcloudVideoPlayer] Smart TV: re-attached HLS to video element after ad break to restore media pipeline");
5539
+ var pipelineDelayMs = 300;
5540
+ if (debugEnabled) {
5541
+ console.log("[StormcloudVideoPlayer] Smart TV: waiting ".concat(pipelineDelayMs, "ms for hardware pipeline release before re-attach"));
5489
5542
  }
5543
+ setTimeout(function() {
5544
+ if (_this.inAdBreak || _this.adLayer.isAdPlaying()) return;
5545
+ if (_this.hls) {
5546
+ _this.hls.attachMedia(_this.video);
5547
+ if (debugEnabled) {
5548
+ console.log("[StormcloudVideoPlayer] Smart TV: re-attached HLS to video element after ad break to restore media pipeline");
5549
+ }
5550
+ }
5551
+ }, pipelineDelayMs);
5490
5552
  } else {
5491
5553
  if (this.shouldContinueLiveStreamDuringAds()) {
5492
5554
  var _this_video_play;
@@ -5560,6 +5622,15 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5560
5622
  }
5561
5623
  this.showPlaceholderLayer();
5562
5624
  this.adLayer.showPlaceholder();
5625
+ } else if (this.inAdBreak) {
5626
+ if (this.config.debugAdTiming) {
5627
+ console.log("[CONTINUOUS-FETCH] Ad failure with no filler \u2014 restoring main video temporarily");
5628
+ }
5629
+ this.adLayer.hidePlaceholder();
5630
+ if (!this.adLayer.isAdPlaying() && this.video.paused && this.video.readyState >= 2) {
5631
+ var _this_video_play;
5632
+ (_this_video_play = this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
5633
+ }
5563
5634
  }
5564
5635
  }
5565
5636
  },