stormcloud-video-player 0.8.47 → 0.8.49
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/dist/stormcloud-vp.min.js +2 -2
- package/lib/index.cjs +109 -53
- package/lib/index.cjs.map +1 -1
- package/lib/index.js +109 -53
- package/lib/index.js.map +1 -1
- package/lib/player/AdBreakOrchestrator.d.cts +1 -1
- package/lib/player/AdConfigManager.d.cts +1 -1
- package/lib/player/AdTimingService.d.cts +1 -1
- package/lib/player/HlsEngine.d.cts +1 -1
- package/lib/player/PlayerControls.d.cts +1 -1
- package/lib/player/Scte35CueManager.d.cts +1 -1
- package/lib/player/Scte35Parser.d.cts +1 -1
- package/lib/player/StormcloudVideoPlayer.cjs +109 -53
- package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/player/StormcloudVideoPlayer.d.cts +1 -1
- package/lib/player/playerTypes.d.cts +1 -1
- package/lib/players/HlsPlayer.cjs +109 -53
- package/lib/players/HlsPlayer.cjs.map +1 -1
- package/lib/players/HlsPlayer.d.cts +1 -1
- package/lib/players/index.cjs +109 -53
- package/lib/players/index.cjs.map +1 -1
- package/lib/sdk/hlsAdPlayer.cjs +109 -53
- package/lib/sdk/hlsAdPlayer.cjs.map +1 -1
- package/lib/sdk/hlsAdPlayer.d.cts +1 -1
- package/lib/types-iDjS8f_7.d.cts +133 -0
- package/lib/ui/StormcloudVideoPlayer.cjs +109 -53
- package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/ui/StormcloudVideoPlayer.d.cts +1 -1
- package/lib/utils/tracking.d.cts +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Component } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { S as StormcloudVideoPlayerConfig } from '../types-iDjS8f_7.cjs';
|
|
3
3
|
|
|
4
4
|
interface HlsPlayerProps extends StormcloudVideoPlayerConfig {
|
|
5
5
|
onMount?: (player: any) => void;
|
package/lib/players/index.cjs
CHANGED
|
@@ -461,9 +461,11 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
461
461
|
var pendingTimeouts = [];
|
|
462
462
|
var STALL_TIMEOUT_MS = 4e3;
|
|
463
463
|
var STALL_CHECK_INTERVAL_MS = 1e3;
|
|
464
|
+
var BLACKFRAME_MIN_PLAYBACK_S = 1.5;
|
|
464
465
|
var stallWatchdogId;
|
|
465
466
|
var lastAdProgressTime = 0;
|
|
466
467
|
var lastAdProgressPosition = 0;
|
|
468
|
+
var sawDecodedVideoFrame = false;
|
|
467
469
|
var trackingFired = {
|
|
468
470
|
impression: false,
|
|
469
471
|
start: false,
|
|
@@ -605,6 +607,61 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
605
607
|
var url = mediaFile.url.toLowerCase();
|
|
606
608
|
return type.startsWith("video/") || url.endsWith(".mp4") || url.includes(".mp4?");
|
|
607
609
|
}
|
|
610
|
+
function isAudioMediaFile(mediaFile) {
|
|
611
|
+
var type = mediaFile.type.toLowerCase();
|
|
612
|
+
var url = (mediaFile.url.toLowerCase().split("?")[0] || "").trim();
|
|
613
|
+
return type.startsWith("audio/") || url.endsWith(".mp3") || url.endsWith(".aac") || url.endsWith(".m4a") || url.endsWith(".ogg") || url.endsWith(".oga") || url.endsWith(".opus") || url.endsWith(".wav") || url.endsWith(".weba");
|
|
614
|
+
}
|
|
615
|
+
function collectVideoMediaFiles(scope, verbose) {
|
|
616
|
+
var mediaFileElements = scope.querySelectorAll("MediaFile");
|
|
617
|
+
var mediaFiles = [];
|
|
618
|
+
if (verbose) {
|
|
619
|
+
console.log("[HlsAdPlayer] Found ".concat(mediaFileElements.length, " MediaFile element(s) in VAST XML"));
|
|
620
|
+
}
|
|
621
|
+
mediaFileElements.forEach(function(mf, index) {
|
|
622
|
+
var _mf_textContent;
|
|
623
|
+
var type = mf.getAttribute("type") || "";
|
|
624
|
+
var url = ((_mf_textContent = mf.textContent) === null || _mf_textContent === void 0 ? void 0 : _mf_textContent.trim()) || "";
|
|
625
|
+
var width = mf.getAttribute("width") || "";
|
|
626
|
+
var height = mf.getAttribute("height") || "";
|
|
627
|
+
if (verbose) {
|
|
628
|
+
console.log("[HlsAdPlayer] MediaFile ".concat(index, ': type="').concat(type, '", url="').concat(url, '", width="').concat(width, '", height="').concat(height, '"'));
|
|
629
|
+
}
|
|
630
|
+
if (!url) {
|
|
631
|
+
if (verbose) {
|
|
632
|
+
console.warn("[HlsAdPlayer] MediaFile ".concat(index, " has empty URL"));
|
|
633
|
+
}
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
var bitrateAttr = mf.getAttribute("bitrate");
|
|
637
|
+
var bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
|
|
638
|
+
var mediaFile = {
|
|
639
|
+
url: url,
|
|
640
|
+
type: type,
|
|
641
|
+
width: parseInt(width || "1920", 10),
|
|
642
|
+
height: parseInt(height || "1080", 10),
|
|
643
|
+
bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : void 0
|
|
644
|
+
};
|
|
645
|
+
if (isAudioMediaFile(mediaFile)) {
|
|
646
|
+
console.warn("[HlsAdPlayer] MediaFile ".concat(index, ' skipped (audio-only, type="').concat(type, '") — audio ads are not played to avoid a black screen'));
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
var hasExplicitDimensions = mf.getAttribute("width") != null && mf.getAttribute("height") != null;
|
|
650
|
+
if (!isHlsMediaFile(mediaFile) && hasExplicitDimensions && (mediaFile.width <= 1 || mediaFile.height <= 1)) {
|
|
651
|
+
console.warn("[HlsAdPlayer] MediaFile ".concat(index, " skipped (degenerate dimensions ").concat(mediaFile.width, "x").concat(mediaFile.height, ', type="').concat(type, '") — likely an audio-only placeholder rendition'));
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
if (isHlsMediaFile(mediaFile) || isProgressiveMediaFile(mediaFile)) {
|
|
655
|
+
mediaFiles.push(mediaFile);
|
|
656
|
+
if (verbose) {
|
|
657
|
+
console.log("[HlsAdPlayer] Added ".concat(isHlsMediaFile(mediaFile) ? "HLS" : "progressive", " MediaFile: ").concat(url));
|
|
658
|
+
}
|
|
659
|
+
} else if (verbose) {
|
|
660
|
+
console.log("[HlsAdPlayer] MediaFile ".concat(index, ' ignored (type="').concat(type, '" is not supported)'));
|
|
661
|
+
}
|
|
662
|
+
});
|
|
663
|
+
return mediaFiles;
|
|
664
|
+
}
|
|
608
665
|
function createEmptyTrackingUrls() {
|
|
609
666
|
return {
|
|
610
667
|
impression: [],
|
|
@@ -692,37 +749,7 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
692
749
|
var durationText = ((_xmlDoc_querySelector3 = xmlDoc.querySelector("Duration")) === null || _xmlDoc_querySelector3 === void 0 ? void 0 : _xmlDoc_querySelector3.textContent) || "00:00:30";
|
|
693
750
|
var durationParts = durationText.split(":");
|
|
694
751
|
var duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
|
|
695
|
-
var
|
|
696
|
-
var mediaFiles = [];
|
|
697
|
-
console.log("[HlsAdPlayer] Found ".concat(mediaFileElements.length, " MediaFile element(s) in VAST XML"));
|
|
698
|
-
mediaFileElements.forEach(function(mf, index) {
|
|
699
|
-
var _mf_textContent;
|
|
700
|
-
var type = mf.getAttribute("type") || "";
|
|
701
|
-
var url = ((_mf_textContent = mf.textContent) === null || _mf_textContent === void 0 ? void 0 : _mf_textContent.trim()) || "";
|
|
702
|
-
var width = mf.getAttribute("width") || "";
|
|
703
|
-
var height = mf.getAttribute("height") || "";
|
|
704
|
-
console.log("[HlsAdPlayer] MediaFile ".concat(index, ': type="').concat(type, '", url="').concat(url, '", width="').concat(width, '", height="').concat(height, '"'));
|
|
705
|
-
var mediaFile = {
|
|
706
|
-
url: url,
|
|
707
|
-
type: type,
|
|
708
|
-
width: parseInt(width || "1920", 10),
|
|
709
|
-
height: parseInt(height || "1080", 10),
|
|
710
|
-
bitrate: void 0
|
|
711
|
-
};
|
|
712
|
-
if (!url) {
|
|
713
|
-
console.warn("[HlsAdPlayer] MediaFile ".concat(index, " has empty URL"));
|
|
714
|
-
return;
|
|
715
|
-
}
|
|
716
|
-
var bitrateAttr = mf.getAttribute("bitrate");
|
|
717
|
-
var bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
|
|
718
|
-
mediaFile.bitrate = bitrateValue && bitrateValue > 0 ? bitrateValue : void 0;
|
|
719
|
-
if (isHlsMediaFile(mediaFile) || isProgressiveMediaFile(mediaFile)) {
|
|
720
|
-
mediaFiles.push(mediaFile);
|
|
721
|
-
console.log("[HlsAdPlayer] Added ".concat(isHlsMediaFile(mediaFile) ? "HLS" : "progressive", " MediaFile: ").concat(url));
|
|
722
|
-
} else {
|
|
723
|
-
console.log("[HlsAdPlayer] MediaFile ".concat(index, ' ignored (type="').concat(type, '" is not supported)'));
|
|
724
|
-
}
|
|
725
|
-
});
|
|
752
|
+
var mediaFiles = collectVideoMediaFiles(xmlDoc, true);
|
|
726
753
|
if (mediaFiles.length === 0) {
|
|
727
754
|
if (isNoAdAvailable) {
|
|
728
755
|
console.warn("[HlsAdPlayer] No ads available (VAST response indicates no ads)");
|
|
@@ -770,28 +797,7 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
770
797
|
var durationText = ((_adElement_querySelector3 = adElement.querySelector("Duration")) === null || _adElement_querySelector3 === void 0 ? void 0 : _adElement_querySelector3.textContent) || "00:00:30";
|
|
771
798
|
var durationParts = durationText.split(":");
|
|
772
799
|
var duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
|
|
773
|
-
var
|
|
774
|
-
var mediaFiles = [];
|
|
775
|
-
mediaFileElements.forEach(function(mf) {
|
|
776
|
-
var _mf_textContent;
|
|
777
|
-
var type = mf.getAttribute("type") || "";
|
|
778
|
-
var url = ((_mf_textContent = mf.textContent) === null || _mf_textContent === void 0 ? void 0 : _mf_textContent.trim()) || "";
|
|
779
|
-
var width = mf.getAttribute("width") || "";
|
|
780
|
-
var height = mf.getAttribute("height") || "";
|
|
781
|
-
if (!url) return;
|
|
782
|
-
var bitrateAttr = mf.getAttribute("bitrate");
|
|
783
|
-
var bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
|
|
784
|
-
var mediaFile = {
|
|
785
|
-
url: url,
|
|
786
|
-
type: type,
|
|
787
|
-
width: parseInt(width || "1920", 10),
|
|
788
|
-
height: parseInt(height || "1080", 10),
|
|
789
|
-
bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : void 0
|
|
790
|
-
};
|
|
791
|
-
if (isHlsMediaFile(mediaFile) || isProgressiveMediaFile(mediaFile)) {
|
|
792
|
-
mediaFiles.push(mediaFile);
|
|
793
|
-
}
|
|
794
|
-
});
|
|
800
|
+
var mediaFiles = collectVideoMediaFiles(adElement, false);
|
|
795
801
|
if (mediaFiles.length === 0) {
|
|
796
802
|
if (isNoAdAvailable) {
|
|
797
803
|
console.warn("[HlsAdPlayer] Pod <Ad> indicates no ad available");
|
|
@@ -1112,6 +1118,14 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1112
1118
|
fireTrackingPixels(currentAd.trackingUrls.thirdQuartile);
|
|
1113
1119
|
}
|
|
1114
1120
|
};
|
|
1121
|
+
var onLoadedMetadata = function onLoadedMetadata() {
|
|
1122
|
+
if (!adPlaying || !adVideoElement) return;
|
|
1123
|
+
var videoWidth = adVideoElement.videoWidth, videoHeight = adVideoElement.videoHeight;
|
|
1124
|
+
if (videoWidth <= 1 || videoHeight <= 1) {
|
|
1125
|
+
console.warn("[HlsAdPlayer] Ad creative has no usable video dimensions (".concat(videoWidth, "x").concat(videoHeight, ") - skipping this creative"));
|
|
1126
|
+
handleVideoDecodeFailure();
|
|
1127
|
+
}
|
|
1128
|
+
};
|
|
1115
1129
|
var onPlaying = function onPlaying() {
|
|
1116
1130
|
startStallWatchdog();
|
|
1117
1131
|
if (!currentAd || trackingFired.start) return;
|
|
@@ -1163,6 +1177,10 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1163
1177
|
type: "timeupdate",
|
|
1164
1178
|
handler: onTimeUpdate
|
|
1165
1179
|
},
|
|
1180
|
+
{
|
|
1181
|
+
type: "loadedmetadata",
|
|
1182
|
+
handler: onLoadedMetadata
|
|
1183
|
+
},
|
|
1166
1184
|
{
|
|
1167
1185
|
type: "playing",
|
|
1168
1186
|
handler: onPlaying
|
|
@@ -1352,13 +1370,51 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1352
1370
|
}
|
|
1353
1371
|
handleAdError();
|
|
1354
1372
|
}
|
|
1373
|
+
function getDecodedVideoFrameCount(video) {
|
|
1374
|
+
try {
|
|
1375
|
+
if (typeof video.getVideoPlaybackQuality === "function") {
|
|
1376
|
+
var quality = video.getVideoPlaybackQuality();
|
|
1377
|
+
if (quality && typeof quality.totalVideoFrames === "number") {
|
|
1378
|
+
return quality.totalVideoFrames;
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
var legacyCount = video.webkitDecodedFrameCount;
|
|
1382
|
+
if (typeof legacyCount === "number") {
|
|
1383
|
+
return legacyCount;
|
|
1384
|
+
}
|
|
1385
|
+
} catch (error) {
|
|
1386
|
+
console.warn("[HlsAdPlayer] Unable to read decoded video frame count:", error);
|
|
1387
|
+
}
|
|
1388
|
+
return void 0;
|
|
1389
|
+
}
|
|
1390
|
+
function handleVideoDecodeFailure() {
|
|
1391
|
+
console.warn("[HlsAdPlayer] Ad audio is advancing but no video frames decoded (black screen) - skipping this creative");
|
|
1392
|
+
clearStallWatchdog();
|
|
1393
|
+
if (currentAd) {
|
|
1394
|
+
fireTrackingPixels(currentAd.trackingUrls.error);
|
|
1395
|
+
}
|
|
1396
|
+
if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
|
|
1397
|
+
return;
|
|
1398
|
+
}
|
|
1399
|
+
handleAdError();
|
|
1400
|
+
}
|
|
1355
1401
|
function startStallWatchdog() {
|
|
1356
1402
|
clearStallWatchdog();
|
|
1357
1403
|
noteAdProgress();
|
|
1404
|
+
sawDecodedVideoFrame = false;
|
|
1358
1405
|
stallWatchdogId = window.setInterval(function() {
|
|
1359
1406
|
if (!adPlaying || !adVideoElement) {
|
|
1360
1407
|
return;
|
|
1361
1408
|
}
|
|
1409
|
+
if (!sawDecodedVideoFrame && !adVideoElement.paused) {
|
|
1410
|
+
var decodedFrames = getDecodedVideoFrameCount(adVideoElement);
|
|
1411
|
+
if (decodedFrames !== void 0 && decodedFrames > 0) {
|
|
1412
|
+
sawDecodedVideoFrame = true;
|
|
1413
|
+
} else if (decodedFrames === 0 && adVideoElement.currentTime >= BLACKFRAME_MIN_PLAYBACK_S) {
|
|
1414
|
+
handleVideoDecodeFailure();
|
|
1415
|
+
return;
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1362
1418
|
if (adVideoElement.currentTime > lastAdProgressPosition + 0.05) {
|
|
1363
1419
|
noteAdProgress();
|
|
1364
1420
|
return;
|