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,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as Scte35Marker, S as StormcloudVideoPlayerConfig, A as AdController } from '../types-iDjS8f_7.cjs';
|
|
2
2
|
import { AdTimingService } from './AdTimingService.cjs';
|
|
3
3
|
import { AdConfigManager } from './AdConfigManager.cjs';
|
|
4
4
|
import { Scte35CueManager } from './Scte35CueManager.cjs';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { b as AdBreak,
|
|
1
|
+
import { b as AdBreak, S as StormcloudVideoPlayerConfig, A as AdController } from '../types-iDjS8f_7.cjs';
|
|
2
2
|
import { PalNonceManager } from '../sdk/pal.cjs';
|
|
3
3
|
import { VastConsentSignals } from '../utils/vastMacros.cjs';
|
|
4
4
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { S as StormcloudVideoPlayerConfig, a as Scte35Marker, A as AdController } from '../types-iDjS8f_7.cjs';
|
|
2
2
|
|
|
3
3
|
interface AdTimingCallbacks {
|
|
4
4
|
onAdStopTimerFired(): void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Hls from 'hls.js';
|
|
2
|
-
import {
|
|
2
|
+
import { S as StormcloudVideoPlayerConfig, a as Scte35Marker } from '../types-iDjS8f_7.cjs';
|
|
3
3
|
import { Scte35CueContext } from './playerTypes.cjs';
|
|
4
4
|
import { Scte35CueManager } from './Scte35CueManager.cjs';
|
|
5
5
|
import { AdTimingService } from './AdTimingService.cjs';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as AdController } from '../types-
|
|
1
|
+
import { A as AdController } from '../types-iDjS8f_7.cjs';
|
|
2
2
|
|
|
3
3
|
declare function getAdAudioVolume(adPlayer: AdController): number;
|
|
4
4
|
declare function toggleMute(video: HTMLVideoElement, adPlayer: AdController, debug: boolean): void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as Scte35Marker, I as Id3TagInfo } from '../types-iDjS8f_7.cjs';
|
|
2
2
|
|
|
3
3
|
declare function parseCueOutDuration(value: string): number | undefined;
|
|
4
4
|
declare function parseCueOutCont(value: string): {
|
|
@@ -374,9 +374,11 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
374
374
|
var pendingTimeouts = [];
|
|
375
375
|
var STALL_TIMEOUT_MS = 4e3;
|
|
376
376
|
var STALL_CHECK_INTERVAL_MS = 1e3;
|
|
377
|
+
var BLACKFRAME_MIN_PLAYBACK_S = 1.5;
|
|
377
378
|
var stallWatchdogId;
|
|
378
379
|
var lastAdProgressTime = 0;
|
|
379
380
|
var lastAdProgressPosition = 0;
|
|
381
|
+
var sawDecodedVideoFrame = false;
|
|
380
382
|
var trackingFired = {
|
|
381
383
|
impression: false,
|
|
382
384
|
start: false,
|
|
@@ -518,6 +520,61 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
518
520
|
var url = mediaFile.url.toLowerCase();
|
|
519
521
|
return type.startsWith("video/") || url.endsWith(".mp4") || url.includes(".mp4?");
|
|
520
522
|
}
|
|
523
|
+
function isAudioMediaFile(mediaFile) {
|
|
524
|
+
var type = mediaFile.type.toLowerCase();
|
|
525
|
+
var url = (mediaFile.url.toLowerCase().split("?")[0] || "").trim();
|
|
526
|
+
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");
|
|
527
|
+
}
|
|
528
|
+
function collectVideoMediaFiles(scope, verbose) {
|
|
529
|
+
var mediaFileElements = scope.querySelectorAll("MediaFile");
|
|
530
|
+
var mediaFiles = [];
|
|
531
|
+
if (verbose) {
|
|
532
|
+
console.log("[HlsAdPlayer] Found ".concat(mediaFileElements.length, " MediaFile element(s) in VAST XML"));
|
|
533
|
+
}
|
|
534
|
+
mediaFileElements.forEach(function(mf, index) {
|
|
535
|
+
var _mf_textContent;
|
|
536
|
+
var type = mf.getAttribute("type") || "";
|
|
537
|
+
var url = ((_mf_textContent = mf.textContent) === null || _mf_textContent === void 0 ? void 0 : _mf_textContent.trim()) || "";
|
|
538
|
+
var width = mf.getAttribute("width") || "";
|
|
539
|
+
var height = mf.getAttribute("height") || "";
|
|
540
|
+
if (verbose) {
|
|
541
|
+
console.log("[HlsAdPlayer] MediaFile ".concat(index, ': type="').concat(type, '", url="').concat(url, '", width="').concat(width, '", height="').concat(height, '"'));
|
|
542
|
+
}
|
|
543
|
+
if (!url) {
|
|
544
|
+
if (verbose) {
|
|
545
|
+
console.warn("[HlsAdPlayer] MediaFile ".concat(index, " has empty URL"));
|
|
546
|
+
}
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
var bitrateAttr = mf.getAttribute("bitrate");
|
|
550
|
+
var bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
|
|
551
|
+
var mediaFile = {
|
|
552
|
+
url: url,
|
|
553
|
+
type: type,
|
|
554
|
+
width: parseInt(width || "1920", 10),
|
|
555
|
+
height: parseInt(height || "1080", 10),
|
|
556
|
+
bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : void 0
|
|
557
|
+
};
|
|
558
|
+
if (isAudioMediaFile(mediaFile)) {
|
|
559
|
+
console.warn("[HlsAdPlayer] MediaFile ".concat(index, ' skipped (audio-only, type="').concat(type, '") — audio ads are not played to avoid a black screen'));
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
var hasExplicitDimensions = mf.getAttribute("width") != null && mf.getAttribute("height") != null;
|
|
563
|
+
if (!isHlsMediaFile(mediaFile) && hasExplicitDimensions && (mediaFile.width <= 1 || mediaFile.height <= 1)) {
|
|
564
|
+
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'));
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
if (isHlsMediaFile(mediaFile) || isProgressiveMediaFile(mediaFile)) {
|
|
568
|
+
mediaFiles.push(mediaFile);
|
|
569
|
+
if (verbose) {
|
|
570
|
+
console.log("[HlsAdPlayer] Added ".concat(isHlsMediaFile(mediaFile) ? "HLS" : "progressive", " MediaFile: ").concat(url));
|
|
571
|
+
}
|
|
572
|
+
} else if (verbose) {
|
|
573
|
+
console.log("[HlsAdPlayer] MediaFile ".concat(index, ' ignored (type="').concat(type, '" is not supported)'));
|
|
574
|
+
}
|
|
575
|
+
});
|
|
576
|
+
return mediaFiles;
|
|
577
|
+
}
|
|
521
578
|
function createEmptyTrackingUrls() {
|
|
522
579
|
return {
|
|
523
580
|
impression: [],
|
|
@@ -605,37 +662,7 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
605
662
|
var durationText = ((_xmlDoc_querySelector3 = xmlDoc.querySelector("Duration")) === null || _xmlDoc_querySelector3 === void 0 ? void 0 : _xmlDoc_querySelector3.textContent) || "00:00:30";
|
|
606
663
|
var durationParts = durationText.split(":");
|
|
607
664
|
var duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
|
|
608
|
-
var
|
|
609
|
-
var mediaFiles = [];
|
|
610
|
-
console.log("[HlsAdPlayer] Found ".concat(mediaFileElements.length, " MediaFile element(s) in VAST XML"));
|
|
611
|
-
mediaFileElements.forEach(function(mf, index) {
|
|
612
|
-
var _mf_textContent;
|
|
613
|
-
var type = mf.getAttribute("type") || "";
|
|
614
|
-
var url = ((_mf_textContent = mf.textContent) === null || _mf_textContent === void 0 ? void 0 : _mf_textContent.trim()) || "";
|
|
615
|
-
var width = mf.getAttribute("width") || "";
|
|
616
|
-
var height = mf.getAttribute("height") || "";
|
|
617
|
-
console.log("[HlsAdPlayer] MediaFile ".concat(index, ': type="').concat(type, '", url="').concat(url, '", width="').concat(width, '", height="').concat(height, '"'));
|
|
618
|
-
var mediaFile = {
|
|
619
|
-
url: url,
|
|
620
|
-
type: type,
|
|
621
|
-
width: parseInt(width || "1920", 10),
|
|
622
|
-
height: parseInt(height || "1080", 10),
|
|
623
|
-
bitrate: void 0
|
|
624
|
-
};
|
|
625
|
-
if (!url) {
|
|
626
|
-
console.warn("[HlsAdPlayer] MediaFile ".concat(index, " has empty URL"));
|
|
627
|
-
return;
|
|
628
|
-
}
|
|
629
|
-
var bitrateAttr = mf.getAttribute("bitrate");
|
|
630
|
-
var bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
|
|
631
|
-
mediaFile.bitrate = bitrateValue && bitrateValue > 0 ? bitrateValue : void 0;
|
|
632
|
-
if (isHlsMediaFile(mediaFile) || isProgressiveMediaFile(mediaFile)) {
|
|
633
|
-
mediaFiles.push(mediaFile);
|
|
634
|
-
console.log("[HlsAdPlayer] Added ".concat(isHlsMediaFile(mediaFile) ? "HLS" : "progressive", " MediaFile: ").concat(url));
|
|
635
|
-
} else {
|
|
636
|
-
console.log("[HlsAdPlayer] MediaFile ".concat(index, ' ignored (type="').concat(type, '" is not supported)'));
|
|
637
|
-
}
|
|
638
|
-
});
|
|
665
|
+
var mediaFiles = collectVideoMediaFiles(xmlDoc, true);
|
|
639
666
|
if (mediaFiles.length === 0) {
|
|
640
667
|
if (isNoAdAvailable) {
|
|
641
668
|
console.warn("[HlsAdPlayer] No ads available (VAST response indicates no ads)");
|
|
@@ -683,28 +710,7 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
683
710
|
var durationText = ((_adElement_querySelector3 = adElement.querySelector("Duration")) === null || _adElement_querySelector3 === void 0 ? void 0 : _adElement_querySelector3.textContent) || "00:00:30";
|
|
684
711
|
var durationParts = durationText.split(":");
|
|
685
712
|
var duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
|
|
686
|
-
var
|
|
687
|
-
var mediaFiles = [];
|
|
688
|
-
mediaFileElements.forEach(function(mf) {
|
|
689
|
-
var _mf_textContent;
|
|
690
|
-
var type = mf.getAttribute("type") || "";
|
|
691
|
-
var url = ((_mf_textContent = mf.textContent) === null || _mf_textContent === void 0 ? void 0 : _mf_textContent.trim()) || "";
|
|
692
|
-
var width = mf.getAttribute("width") || "";
|
|
693
|
-
var height = mf.getAttribute("height") || "";
|
|
694
|
-
if (!url) return;
|
|
695
|
-
var bitrateAttr = mf.getAttribute("bitrate");
|
|
696
|
-
var bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
|
|
697
|
-
var mediaFile = {
|
|
698
|
-
url: url,
|
|
699
|
-
type: type,
|
|
700
|
-
width: parseInt(width || "1920", 10),
|
|
701
|
-
height: parseInt(height || "1080", 10),
|
|
702
|
-
bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : void 0
|
|
703
|
-
};
|
|
704
|
-
if (isHlsMediaFile(mediaFile) || isProgressiveMediaFile(mediaFile)) {
|
|
705
|
-
mediaFiles.push(mediaFile);
|
|
706
|
-
}
|
|
707
|
-
});
|
|
713
|
+
var mediaFiles = collectVideoMediaFiles(adElement, false);
|
|
708
714
|
if (mediaFiles.length === 0) {
|
|
709
715
|
if (isNoAdAvailable) {
|
|
710
716
|
console.warn("[HlsAdPlayer] Pod <Ad> indicates no ad available");
|
|
@@ -1025,6 +1031,14 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1025
1031
|
fireTrackingPixels(currentAd.trackingUrls.thirdQuartile);
|
|
1026
1032
|
}
|
|
1027
1033
|
};
|
|
1034
|
+
var onLoadedMetadata = function onLoadedMetadata() {
|
|
1035
|
+
if (!adPlaying || !adVideoElement) return;
|
|
1036
|
+
var videoWidth = adVideoElement.videoWidth, videoHeight = adVideoElement.videoHeight;
|
|
1037
|
+
if (videoWidth <= 1 || videoHeight <= 1) {
|
|
1038
|
+
console.warn("[HlsAdPlayer] Ad creative has no usable video dimensions (".concat(videoWidth, "x").concat(videoHeight, ") - skipping this creative"));
|
|
1039
|
+
handleVideoDecodeFailure();
|
|
1040
|
+
}
|
|
1041
|
+
};
|
|
1028
1042
|
var onPlaying = function onPlaying() {
|
|
1029
1043
|
startStallWatchdog();
|
|
1030
1044
|
if (!currentAd || trackingFired.start) return;
|
|
@@ -1076,6 +1090,10 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1076
1090
|
type: "timeupdate",
|
|
1077
1091
|
handler: onTimeUpdate
|
|
1078
1092
|
},
|
|
1093
|
+
{
|
|
1094
|
+
type: "loadedmetadata",
|
|
1095
|
+
handler: onLoadedMetadata
|
|
1096
|
+
},
|
|
1079
1097
|
{
|
|
1080
1098
|
type: "playing",
|
|
1081
1099
|
handler: onPlaying
|
|
@@ -1265,13 +1283,51 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1265
1283
|
}
|
|
1266
1284
|
handleAdError();
|
|
1267
1285
|
}
|
|
1286
|
+
function getDecodedVideoFrameCount(video) {
|
|
1287
|
+
try {
|
|
1288
|
+
if (typeof video.getVideoPlaybackQuality === "function") {
|
|
1289
|
+
var quality = video.getVideoPlaybackQuality();
|
|
1290
|
+
if (quality && typeof quality.totalVideoFrames === "number") {
|
|
1291
|
+
return quality.totalVideoFrames;
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
var legacyCount = video.webkitDecodedFrameCount;
|
|
1295
|
+
if (typeof legacyCount === "number") {
|
|
1296
|
+
return legacyCount;
|
|
1297
|
+
}
|
|
1298
|
+
} catch (error) {
|
|
1299
|
+
console.warn("[HlsAdPlayer] Unable to read decoded video frame count:", error);
|
|
1300
|
+
}
|
|
1301
|
+
return void 0;
|
|
1302
|
+
}
|
|
1303
|
+
function handleVideoDecodeFailure() {
|
|
1304
|
+
console.warn("[HlsAdPlayer] Ad audio is advancing but no video frames decoded (black screen) - skipping this creative");
|
|
1305
|
+
clearStallWatchdog();
|
|
1306
|
+
if (currentAd) {
|
|
1307
|
+
fireTrackingPixels(currentAd.trackingUrls.error);
|
|
1308
|
+
}
|
|
1309
|
+
if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
|
|
1310
|
+
return;
|
|
1311
|
+
}
|
|
1312
|
+
handleAdError();
|
|
1313
|
+
}
|
|
1268
1314
|
function startStallWatchdog() {
|
|
1269
1315
|
clearStallWatchdog();
|
|
1270
1316
|
noteAdProgress();
|
|
1317
|
+
sawDecodedVideoFrame = false;
|
|
1271
1318
|
stallWatchdogId = window.setInterval(function() {
|
|
1272
1319
|
if (!adPlaying || !adVideoElement) {
|
|
1273
1320
|
return;
|
|
1274
1321
|
}
|
|
1322
|
+
if (!sawDecodedVideoFrame && !adVideoElement.paused) {
|
|
1323
|
+
var decodedFrames = getDecodedVideoFrameCount(adVideoElement);
|
|
1324
|
+
if (decodedFrames !== void 0 && decodedFrames > 0) {
|
|
1325
|
+
sawDecodedVideoFrame = true;
|
|
1326
|
+
} else if (decodedFrames === 0 && adVideoElement.currentTime >= BLACKFRAME_MIN_PLAYBACK_S) {
|
|
1327
|
+
handleVideoDecodeFailure();
|
|
1328
|
+
return;
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1275
1331
|
if (adVideoElement.currentTime > lastAdProgressPosition + 0.05) {
|
|
1276
1332
|
noteAdProgress();
|
|
1277
1333
|
return;
|