stormcloud-video-player 0.2.14 → 0.2.16

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.
@@ -892,7 +892,7 @@ function createHlsAdPlayer(contentVideo, options) {
892
892
  const xmlDoc = parser.parseFromString(xmlString, "text/xml");
893
893
  const parserError = xmlDoc.querySelector("parsererror");
894
894
  if (parserError) {
895
- console.error("[HlsAdPlayer] XML parsing error:", parserError.textContent);
895
+ console.error("[HlsAdPlayer] XML parsing error (malformed VAST XML):", parserError.textContent);
896
896
  return null;
897
897
  }
898
898
  const adElement = xmlDoc.querySelector("Ad");
@@ -902,28 +902,45 @@ function createHlsAdPlayer(contentVideo, options) {
902
902
  }
903
903
  const adId = adElement.getAttribute("id") || "unknown";
904
904
  const title = ((_a = xmlDoc.querySelector("AdTitle")) == null ? void 0 : _a.textContent) || "Ad";
905
+ const isNoAdAvailable = adId === "empty" || title.toLowerCase().includes("no ad available") || title.toLowerCase() === "no ad available";
905
906
  const durationText = ((_b = xmlDoc.querySelector("Duration")) == null ? void 0 : _b.textContent) || "00:00:30";
906
907
  const durationParts = durationText.split(":");
907
908
  const duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
908
909
  const mediaFileElements = xmlDoc.querySelectorAll("MediaFile");
909
910
  const mediaFiles = [];
910
- mediaFileElements.forEach((mf) => {
911
+ console.log(`[HlsAdPlayer] Found ${mediaFileElements.length} MediaFile element(s) in VAST XML`);
912
+ mediaFileElements.forEach((mf, index) => {
911
913
  var _a2;
912
914
  const type = mf.getAttribute("type") || "";
915
+ const url = ((_a2 = mf.textContent) == null ? void 0 : _a2.trim()) || "";
916
+ const width = mf.getAttribute("width") || "";
917
+ const height = mf.getAttribute("height") || "";
918
+ console.log(`[HlsAdPlayer] MediaFile ${index}: type="${type}", url="${url}", width="${width}", height="${height}"`);
913
919
  if (type === "application/x-mpegURL" || type.includes("m3u8")) {
920
+ if (!url) {
921
+ console.warn(`[HlsAdPlayer] MediaFile ${index} has HLS type but empty URL`);
922
+ return;
923
+ }
914
924
  const bitrateAttr = mf.getAttribute("bitrate");
915
925
  const bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
916
926
  mediaFiles.push({
917
- url: ((_a2 = mf.textContent) == null ? void 0 : _a2.trim()) || "",
927
+ url,
918
928
  type,
919
- width: parseInt(mf.getAttribute("width") || "1920", 10),
920
- height: parseInt(mf.getAttribute("height") || "1080", 10),
929
+ width: parseInt(width || "1920", 10),
930
+ height: parseInt(height || "1080", 10),
921
931
  bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : void 0
922
932
  });
933
+ console.log(`[HlsAdPlayer] Added HLS MediaFile: ${url}`);
934
+ } else {
935
+ console.log(`[HlsAdPlayer] MediaFile ${index} ignored (type="${type}" is not HLS)`);
923
936
  }
924
937
  });
925
938
  if (mediaFiles.length === 0) {
926
- console.warn("[HlsAdPlayer] No HLS media files found in VAST XML");
939
+ if (isNoAdAvailable) {
940
+ console.warn("[HlsAdPlayer] No ads available (VAST response indicates no ads)");
941
+ } else {
942
+ console.warn("[HlsAdPlayer] No HLS media files found in VAST XML");
943
+ }
927
944
  return null;
928
945
  }
929
946
  const trackingUrls = {
@@ -1111,9 +1128,11 @@ function createHlsAdPlayer(contentVideo, options) {
1111
1128
  }
1112
1129
  const vastXml = await response.text();
1113
1130
  console.log("[HlsAdPlayer] VAST XML received");
1131
+ console.log("[HlsAdPlayer] VAST XML content (first 2000 chars):", vastXml.substring(0, 2e3));
1114
1132
  const ad = parseVastXml(vastXml);
1115
1133
  if (!ad) {
1116
- throw new Error("Failed to parse VAST XML or no ads available");
1134
+ console.warn("[HlsAdPlayer] No ads available from VAST response");
1135
+ return Promise.resolve();
1117
1136
  }
1118
1137
  currentAd = ad;
1119
1138
  console.log(`[HlsAdPlayer] Ad parsed: ${ad.title}, duration: ${ad.duration}s`);
@@ -1128,7 +1147,7 @@ function createHlsAdPlayer(contentVideo, options) {
1128
1147
  },
1129
1148
  async play() {
1130
1149
  if (!currentAd) {
1131
- console.warn("[HlsAdPlayer] Cannot play: No ad loaded");
1150
+ console.warn("[HlsAdPlayer] Cannot play: No ad loaded (no ads available)");
1132
1151
  return Promise.reject(new Error("No ad loaded"));
1133
1152
  }
1134
1153
  console.log("[HlsAdPlayer] Starting ad playback");
@@ -1759,6 +1778,8 @@ var StormcloudVideoPlayer = class {
1759
1778
  this.totalAdsInBreak = 0;
1760
1779
  this.showAds = false;
1761
1780
  this.isLiveStream = false;
1781
+ this.nativeHlsMode = false;
1782
+ this.videoSrcProtection = null;
1762
1783
  initializePolyfills();
1763
1784
  const browserOverrides = getBrowserConfigOverrides();
1764
1785
  this.config = { ...config, ...browserOverrides };
@@ -1779,7 +1800,9 @@ var StormcloudVideoPlayer = class {
1779
1800
  }
1780
1801
  if (adPlayerType === "hls") {
1781
1802
  if (this.config.debugAdTiming) {
1782
- console.log("[StormcloudVideoPlayer] Creating HLS ad player (AdStorm mode)");
1803
+ console.log(
1804
+ "[StormcloudVideoPlayer] Creating HLS ad player (AdStorm mode)"
1805
+ );
1783
1806
  }
1784
1807
  return createHlsAdPlayer(this.video, {
1785
1808
  continueLiveStreamDuringAds,
@@ -1788,7 +1811,9 @@ var StormcloudVideoPlayer = class {
1788
1811
  });
1789
1812
  } else {
1790
1813
  if (this.config.debugAdTiming) {
1791
- console.log("[StormcloudVideoPlayer] Creating Google IMA ad player (Default mode)");
1814
+ console.log(
1815
+ "[StormcloudVideoPlayer] Creating Google IMA ad player (Default mode)"
1816
+ );
1792
1817
  }
1793
1818
  return createImaController(this.video, {
1794
1819
  continueLiveStreamDuringAds
@@ -1812,11 +1837,13 @@ var StormcloudVideoPlayer = class {
1812
1837
  }
1813
1838
  this.initializeTracking();
1814
1839
  if (this.shouldUseNativeHls()) {
1840
+ this.nativeHlsMode = true;
1841
+ this.videoSrcProtection = this.config.src;
1815
1842
  this.video.src = this.config.src;
1816
1843
  this.isLiveStream = (_a = this.config.lowLatencyMode) != null ? _a : false;
1817
1844
  if (this.config.debugAdTiming) {
1818
1845
  console.log(
1819
- "[StormcloudVideoPlayer] allowNativeHls: true - VOD mode detected:",
1846
+ "[StormcloudVideoPlayer] Using native HLS playback - VOD mode:",
1820
1847
  {
1821
1848
  isLive: this.isLiveStream,
1822
1849
  allowNativeHls: this.config.allowNativeHls,
@@ -1964,7 +1991,9 @@ var StormcloudVideoPlayer = class {
1964
1991
  this.ima.initialize();
1965
1992
  this.ima.on("all_ads_completed", () => {
1966
1993
  if (this.config.debugAdTiming) {
1967
- console.log("[StormcloudVideoPlayer] IMA all_ads_completed event received");
1994
+ console.log(
1995
+ "[StormcloudVideoPlayer] IMA all_ads_completed event received"
1996
+ );
1968
1997
  }
1969
1998
  });
1970
1999
  this.ima.on("ad_error", () => {
@@ -2029,13 +2058,31 @@ var StormcloudVideoPlayer = class {
2029
2058
  this.video.addEventListener("timeupdate", () => {
2030
2059
  this.onTimeUpdate(this.video.currentTime);
2031
2060
  });
2061
+ this.video.addEventListener("emptied", () => {
2062
+ if (this.nativeHlsMode && this.videoSrcProtection && !this.ima.isAdPlaying()) {
2063
+ if (this.config.debugAdTiming) {
2064
+ console.log(
2065
+ "[StormcloudVideoPlayer] Video src was cleared, restoring:",
2066
+ this.videoSrcProtection
2067
+ );
2068
+ }
2069
+ const currentTime = this.video.currentTime;
2070
+ const wasPaused = this.video.paused;
2071
+ this.video.src = this.videoSrcProtection;
2072
+ this.video.currentTime = currentTime;
2073
+ if (!wasPaused) {
2074
+ this.video.play().catch(() => {
2075
+ });
2076
+ }
2077
+ }
2078
+ });
2032
2079
  }
2033
2080
  shouldUseNativeHls() {
2034
2081
  const streamType = this.getStreamType();
2035
2082
  if (streamType === "other") {
2036
2083
  return true;
2037
2084
  }
2038
- const canNative = this.video.canPlayType("application/vnd.apple.mpegURL");
2085
+ const canNative = this.video.canPlayType("application/vnd.apple.mpegurl");
2039
2086
  return !!(this.config.allowNativeHls && canNative);
2040
2087
  }
2041
2088
  onId3Tag(tag) {
@@ -2462,10 +2509,7 @@ var StormcloudVideoPlayer = class {
2462
2509
  var _a, _b, _c;
2463
2510
  const vastMode = this.config.vastMode || "default";
2464
2511
  if (this.config.debugAdTiming) {
2465
- console.log(
2466
- "[StormcloudVideoPlayer] VAST mode:",
2467
- vastMode
2468
- );
2512
+ console.log("[StormcloudVideoPlayer] VAST mode:", vastMode);
2469
2513
  }
2470
2514
  if (vastMode === "adstorm") {
2471
2515
  if (!this.config.licenseKey) {
@@ -2480,7 +2524,7 @@ var StormcloudVideoPlayer = class {
2480
2524
  this.apiVastTagUrl = vastEndpoint;
2481
2525
  if (this.config.debugAdTiming) {
2482
2526
  console.log(
2483
- "[StormcloudVideoPlayer] Using AdStorm VAST endpoint:",
2527
+ "[StormcloudVideoPlayer] Using AdStorm VAST endpoint (adstorm mode):",
2484
2528
  vastEndpoint
2485
2529
  );
2486
2530
  }
@@ -2583,10 +2627,7 @@ var StormcloudVideoPlayer = class {
2583
2627
  this.currentAdIndex = 0;
2584
2628
  this.totalAdsInBreak = 1;
2585
2629
  if (this.config.debugAdTiming) {
2586
- console.log(
2587
- "[StormcloudVideoPlayer] Using VAST endpoint:",
2588
- vastTagUrl
2589
- );
2630
+ console.log("[StormcloudVideoPlayer] Using VAST endpoint:", vastTagUrl);
2590
2631
  }
2591
2632
  } else if (tags && tags.length > 0) {
2592
2633
  vastTagUrl = tags[0];
@@ -2736,12 +2777,26 @@ var StormcloudVideoPlayer = class {
2736
2777
  this.startAdFailsafeTimer();
2737
2778
  try {
2738
2779
  await this.ima.requestAds(vastTagUrl);
2739
- if (this.config.debugAdTiming) {
2740
- console.log("[StormcloudVideoPlayer] Ad request successful, starting playback");
2741
- }
2742
- await this.ima.play();
2743
- if (this.config.debugAdTiming) {
2744
- console.log("[StormcloudVideoPlayer] Ad playback started successfully");
2780
+ try {
2781
+ if (this.config.debugAdTiming) {
2782
+ console.log(
2783
+ "[StormcloudVideoPlayer] Ad request completed, attempting playback"
2784
+ );
2785
+ }
2786
+ await this.ima.play();
2787
+ if (this.config.debugAdTiming) {
2788
+ console.log(
2789
+ "[StormcloudVideoPlayer] Ad playback started successfully"
2790
+ );
2791
+ }
2792
+ } catch (playError) {
2793
+ if (this.config.debugAdTiming) {
2794
+ console.log(
2795
+ "[StormcloudVideoPlayer] No ads available, skipping playback"
2796
+ );
2797
+ }
2798
+ this.handleAdFailure();
2799
+ return;
2745
2800
  }
2746
2801
  } catch (error) {
2747
2802
  if (this.config.debugAdTiming) {
@@ -2794,7 +2849,9 @@ var StormcloudVideoPlayer = class {
2794
2849
  });
2795
2850
  } else {
2796
2851
  if (this.config.debugAdTiming) {
2797
- console.log("[StormcloudVideoPlayer] Video is already playing, no resume needed");
2852
+ console.log(
2853
+ "[StormcloudVideoPlayer] Video is already playing, no resume needed"
2854
+ );
2798
2855
  }
2799
2856
  }
2800
2857
  }
@@ -2813,7 +2870,11 @@ var StormcloudVideoPlayer = class {
2813
2870
  if (this.config.debugAdTiming) {
2814
2871
  console.warn(
2815
2872
  "[StormcloudVideoPlayer] Failsafe timer triggered - forcing video resume",
2816
- { paused: this.video.paused, showAds: this.showAds, adPlaying: this.ima.isAdPlaying() }
2873
+ {
2874
+ paused: this.video.paused,
2875
+ showAds: this.showAds,
2876
+ adPlaying: this.ima.isAdPlaying()
2877
+ }
2817
2878
  );
2818
2879
  }
2819
2880
  this.handleAdFailure();
@@ -3006,10 +3067,20 @@ var HlsPlayer = class extends import_react2.Component {
3006
3067
  }
3007
3068
  };
3008
3069
  this.play = () => {
3009
- var _a, _b;
3070
+ var _a, _b, _c;
3010
3071
  if (this.props.videoElement) {
3011
- this.props.videoElement.play();
3012
- (_b = (_a = this.props).onPlay) == null ? void 0 : _b.call(_a);
3072
+ const video = this.props.videoElement;
3073
+ const hasValidSource = video.src || video.currentSrc && video.currentSrc !== "" || video.readyState >= 1;
3074
+ if (hasValidSource) {
3075
+ (_a = video.play()) == null ? void 0 : _a.catch((error) => {
3076
+ var _a2, _b2;
3077
+ console.error("[HlsPlayer] Failed to play:", error);
3078
+ (_b2 = (_a2 = this.props).onError) == null ? void 0 : _b2.call(_a2, error);
3079
+ });
3080
+ (_c = (_b = this.props).onPlay) == null ? void 0 : _c.call(_b);
3081
+ } else {
3082
+ console.warn("[HlsPlayer] Cannot play: video has no valid source");
3083
+ }
3013
3084
  }
3014
3085
  };
3015
3086
  this.pause = () => {
@@ -3178,8 +3249,19 @@ var FilePlayer = class extends import_react3.Component {
3178
3249
  };
3179
3250
  };
3180
3251
  this.play = () => {
3252
+ var _a;
3181
3253
  if (this.props.videoElement) {
3182
- this.props.videoElement.play();
3254
+ const video = this.props.videoElement;
3255
+ const hasValidSource = video.src || video.currentSrc && video.currentSrc !== "" || video.readyState >= 1;
3256
+ if (hasValidSource) {
3257
+ (_a = video.play()) == null ? void 0 : _a.catch((error) => {
3258
+ var _a2, _b;
3259
+ console.error("[FilePlayer] Failed to play:", error);
3260
+ (_b = (_a2 = this.props).onError) == null ? void 0 : _b.call(_a2, error);
3261
+ });
3262
+ } else {
3263
+ console.warn("[FilePlayer] Cannot play: video has no valid source");
3264
+ }
3183
3265
  }
3184
3266
  };
3185
3267
  this.pause = () => {