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.
- package/README.md +92 -11
- package/dist/stormcloud-vp.min.js +2 -2
- package/lib/index.cjs +397 -256
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +2 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +397 -256
- package/lib/index.js.map +1 -1
- package/lib/player/StormcloudVideoPlayer.cjs +91 -30
- package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/player/StormcloudVideoPlayer.d.cts +2 -0
- package/lib/players/FilePlayer.cjs +12 -1
- package/lib/players/FilePlayer.cjs.map +1 -1
- package/lib/players/HlsPlayer.cjs +104 -33
- package/lib/players/HlsPlayer.cjs.map +1 -1
- package/lib/players/index.cjs +116 -34
- package/lib/players/index.cjs.map +1 -1
- package/lib/sdk/hlsAdPlayer.cjs +27 -8
- package/lib/sdk/hlsAdPlayer.cjs.map +1 -1
- package/lib/ui/StormcloudVideoPlayer.cjs +372 -252
- package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
- package/package.json +1 -1
package/lib/players/index.cjs
CHANGED
|
@@ -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.
|
|
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
|
|
927
|
+
url,
|
|
918
928
|
type,
|
|
919
|
-
width: parseInt(
|
|
920
|
-
height: parseInt(
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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]
|
|
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(
|
|
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.
|
|
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
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
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(
|
|
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
|
-
{
|
|
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
|
|
3012
|
-
|
|
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
|
|
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 = () => {
|