stormcloud-video-player 0.2.36 → 0.3.1
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 +118 -0
- package/dist/stormcloud-vp.min.js +2 -2
- package/lib/index.cjs +235 -21
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +8 -0
- package/lib/index.d.ts +8 -0
- package/lib/index.js +235 -21
- package/lib/index.js.map +1 -1
- package/lib/player/StormcloudVideoPlayer.cjs +235 -21
- package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/player/StormcloudVideoPlayer.d.cts +8 -0
- package/lib/players/HlsPlayer.cjs +235 -21
- package/lib/players/HlsPlayer.cjs.map +1 -1
- package/lib/players/index.cjs +235 -21
- package/lib/players/index.cjs.map +1 -1
- package/lib/ui/StormcloudVideoPlayer.cjs +235 -21
- package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
- package/package.json +1 -1
package/lib/index.d.cts
CHANGED
|
@@ -116,6 +116,7 @@ declare class StormcloudVideoPlayer {
|
|
|
116
116
|
private ptsDriftEmaMs;
|
|
117
117
|
private adPodQueue;
|
|
118
118
|
private apiVastTagUrl;
|
|
119
|
+
private apiNumberAds;
|
|
119
120
|
private lastHeartbeatTime;
|
|
120
121
|
private heartbeatInterval;
|
|
121
122
|
private currentAdIndex;
|
|
@@ -137,6 +138,9 @@ declare class StormcloudVideoPlayer {
|
|
|
137
138
|
private adRequestWatchdogId;
|
|
138
139
|
private adRequestWatchdogToken;
|
|
139
140
|
private adFailsafeToken;
|
|
141
|
+
private fetchedAdDurations;
|
|
142
|
+
private targetAdBreakDurationMs;
|
|
143
|
+
private isAdaptiveMode;
|
|
140
144
|
constructor(config: StormcloudVideoPlayerConfig);
|
|
141
145
|
private createAdPlayer;
|
|
142
146
|
load(): Promise<void>;
|
|
@@ -157,6 +161,7 @@ declare class StormcloudVideoPlayer {
|
|
|
157
161
|
private fetchAdConfiguration;
|
|
158
162
|
getCurrentAdIndex(): number;
|
|
159
163
|
getTotalAdsInBreak(): number;
|
|
164
|
+
private generateVastUrlsWithCorrelators;
|
|
160
165
|
isAdPlaying(): boolean;
|
|
161
166
|
isShowingAds(): boolean;
|
|
162
167
|
getStreamType(): "hls" | "other";
|
|
@@ -184,6 +189,9 @@ declare class StormcloudVideoPlayer {
|
|
|
184
189
|
private logAdState;
|
|
185
190
|
private fetchAndParseVastXml;
|
|
186
191
|
private extractMediaUrlsFromVast;
|
|
192
|
+
private fetchVastDuration;
|
|
193
|
+
private calculateAdditionalAdsNeeded;
|
|
194
|
+
private addAdaptiveAdsToQueue;
|
|
187
195
|
private preloadMediaFile;
|
|
188
196
|
private preloadAllAdsInBackground;
|
|
189
197
|
private preloadSingleAd;
|
package/lib/index.d.ts
CHANGED
|
@@ -116,6 +116,7 @@ declare class StormcloudVideoPlayer {
|
|
|
116
116
|
private ptsDriftEmaMs;
|
|
117
117
|
private adPodQueue;
|
|
118
118
|
private apiVastTagUrl;
|
|
119
|
+
private apiNumberAds;
|
|
119
120
|
private lastHeartbeatTime;
|
|
120
121
|
private heartbeatInterval;
|
|
121
122
|
private currentAdIndex;
|
|
@@ -137,6 +138,9 @@ declare class StormcloudVideoPlayer {
|
|
|
137
138
|
private adRequestWatchdogId;
|
|
138
139
|
private adRequestWatchdogToken;
|
|
139
140
|
private adFailsafeToken;
|
|
141
|
+
private fetchedAdDurations;
|
|
142
|
+
private targetAdBreakDurationMs;
|
|
143
|
+
private isAdaptiveMode;
|
|
140
144
|
constructor(config: StormcloudVideoPlayerConfig);
|
|
141
145
|
private createAdPlayer;
|
|
142
146
|
load(): Promise<void>;
|
|
@@ -157,6 +161,7 @@ declare class StormcloudVideoPlayer {
|
|
|
157
161
|
private fetchAdConfiguration;
|
|
158
162
|
getCurrentAdIndex(): number;
|
|
159
163
|
getTotalAdsInBreak(): number;
|
|
164
|
+
private generateVastUrlsWithCorrelators;
|
|
160
165
|
isAdPlaying(): boolean;
|
|
161
166
|
isShowingAds(): boolean;
|
|
162
167
|
getStreamType(): "hls" | "other";
|
|
@@ -184,6 +189,9 @@ declare class StormcloudVideoPlayer {
|
|
|
184
189
|
private logAdState;
|
|
185
190
|
private fetchAndParseVastXml;
|
|
186
191
|
private extractMediaUrlsFromVast;
|
|
192
|
+
private fetchVastDuration;
|
|
193
|
+
private calculateAdditionalAdsNeeded;
|
|
194
|
+
private addAdaptiveAdsToQueue;
|
|
187
195
|
private preloadMediaFile;
|
|
188
196
|
private preloadAllAdsInBackground;
|
|
189
197
|
private preloadSingleAd;
|
package/lib/index.js
CHANGED
|
@@ -2157,6 +2157,9 @@ var StormcloudVideoPlayer = class {
|
|
|
2157
2157
|
this.activeAdRequestToken = null;
|
|
2158
2158
|
this.adRequestWatchdogToken = null;
|
|
2159
2159
|
this.adFailsafeToken = null;
|
|
2160
|
+
this.fetchedAdDurations = /* @__PURE__ */ new Map();
|
|
2161
|
+
this.targetAdBreakDurationMs = null;
|
|
2162
|
+
this.isAdaptiveMode = false;
|
|
2160
2163
|
initializePolyfills();
|
|
2161
2164
|
const browserOverrides = getBrowserConfigOverrides();
|
|
2162
2165
|
this.config = { ...config, ...browserOverrides };
|
|
@@ -2963,7 +2966,7 @@ var StormcloudVideoPlayer = class {
|
|
|
2963
2966
|
}
|
|
2964
2967
|
}
|
|
2965
2968
|
async fetchAdConfiguration() {
|
|
2966
|
-
var _a, _b, _c;
|
|
2969
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
2967
2970
|
const vastMode = this.config.vastMode || "default";
|
|
2968
2971
|
if (this.config.debugAdTiming) {
|
|
2969
2972
|
console.log("[StormcloudVideoPlayer] VAST mode:", vastMode);
|
|
@@ -3034,6 +3037,16 @@ var StormcloudVideoPlayer = class {
|
|
|
3034
3037
|
);
|
|
3035
3038
|
}
|
|
3036
3039
|
}
|
|
3040
|
+
const numberAds = (_g = (_f = (_e = (_d = data.response) == null ? void 0 : _d.options) == null ? void 0 : _e.vast) == null ? void 0 : _f.cue_tones) == null ? void 0 : _g.number_ads;
|
|
3041
|
+
if (numberAds != null && numberAds > 0) {
|
|
3042
|
+
this.apiNumberAds = numberAds;
|
|
3043
|
+
if (this.config.debugAdTiming) {
|
|
3044
|
+
console.log(
|
|
3045
|
+
"[StormcloudVideoPlayer] Number of ads per break from API:",
|
|
3046
|
+
this.apiNumberAds
|
|
3047
|
+
);
|
|
3048
|
+
}
|
|
3049
|
+
}
|
|
3037
3050
|
}
|
|
3038
3051
|
getCurrentAdIndex() {
|
|
3039
3052
|
return this.currentAdIndex;
|
|
@@ -3041,6 +3054,27 @@ var StormcloudVideoPlayer = class {
|
|
|
3041
3054
|
getTotalAdsInBreak() {
|
|
3042
3055
|
return this.totalAdsInBreak;
|
|
3043
3056
|
}
|
|
3057
|
+
generateVastUrlsWithCorrelators(baseUrl, count) {
|
|
3058
|
+
const urls = [];
|
|
3059
|
+
for (let i = 0; i < count; i++) {
|
|
3060
|
+
try {
|
|
3061
|
+
const url = new URL(baseUrl);
|
|
3062
|
+
const timestamp = Date.now();
|
|
3063
|
+
const random = Math.floor(Math.random() * 1e6);
|
|
3064
|
+
const uniqueCorrelator = `${timestamp}${random}${i}`;
|
|
3065
|
+
url.searchParams.set("correlator", uniqueCorrelator);
|
|
3066
|
+
urls.push(url.toString());
|
|
3067
|
+
} catch (error) {
|
|
3068
|
+
console.warn(
|
|
3069
|
+
"[StormcloudVideoPlayer] Failed to parse VAST URL:",
|
|
3070
|
+
baseUrl,
|
|
3071
|
+
error
|
|
3072
|
+
);
|
|
3073
|
+
urls.push(`${baseUrl}${baseUrl.includes("?") ? "&" : "?"}correlator=${Date.now()}${i}`);
|
|
3074
|
+
}
|
|
3075
|
+
}
|
|
3076
|
+
return urls;
|
|
3077
|
+
}
|
|
3044
3078
|
isAdPlaying() {
|
|
3045
3079
|
return this.inAdBreak && this.ima.isAdPlaying();
|
|
3046
3080
|
}
|
|
@@ -3079,7 +3113,52 @@ var StormcloudVideoPlayer = class {
|
|
|
3079
3113
|
const tags = this.selectVastTagsForBreak(scheduled);
|
|
3080
3114
|
let vastTagUrls = [];
|
|
3081
3115
|
if (this.apiVastTagUrl) {
|
|
3082
|
-
|
|
3116
|
+
let numberOfAds = 1;
|
|
3117
|
+
if (this.isLiveStream) {
|
|
3118
|
+
const adBreakDurationMs = _marker.durationSeconds != null ? _marker.durationSeconds * 1e3 : scheduled == null ? void 0 : scheduled.durationMs;
|
|
3119
|
+
if (adBreakDurationMs != null && adBreakDurationMs > 0) {
|
|
3120
|
+
this.isAdaptiveMode = true;
|
|
3121
|
+
this.targetAdBreakDurationMs = adBreakDurationMs;
|
|
3122
|
+
this.fetchedAdDurations.clear();
|
|
3123
|
+
numberOfAds = 2;
|
|
3124
|
+
if (this.config.debugAdTiming) {
|
|
3125
|
+
console.log(
|
|
3126
|
+
`[ADAPTIVE-POD] \u{1F4FA} LIVE MODE (ADAPTIVE): Target duration=${adBreakDurationMs}ms | Starting with ${numberOfAds} ads, will fetch actual durations and add more dynamically`
|
|
3127
|
+
);
|
|
3128
|
+
}
|
|
3129
|
+
} else {
|
|
3130
|
+
if (this.config.debugAdTiming) {
|
|
3131
|
+
console.warn(
|
|
3132
|
+
"[DEBUG-POD] \u26A0\uFE0F LIVE MODE: No duration available, defaulting to 1 ad"
|
|
3133
|
+
);
|
|
3134
|
+
}
|
|
3135
|
+
}
|
|
3136
|
+
} else {
|
|
3137
|
+
this.isAdaptiveMode = false;
|
|
3138
|
+
this.targetAdBreakDurationMs = null;
|
|
3139
|
+
this.fetchedAdDurations.clear();
|
|
3140
|
+
if (this.apiNumberAds && this.apiNumberAds > 1) {
|
|
3141
|
+
numberOfAds = this.apiNumberAds;
|
|
3142
|
+
if (this.config.debugAdTiming) {
|
|
3143
|
+
console.log(
|
|
3144
|
+
`[DEBUG-POD] \u{1F3AC} VOD MODE (FIXED): Using number_ads=${numberOfAds} from API`
|
|
3145
|
+
);
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3148
|
+
}
|
|
3149
|
+
if (numberOfAds > 1) {
|
|
3150
|
+
vastTagUrls = this.generateVastUrlsWithCorrelators(
|
|
3151
|
+
this.apiVastTagUrl,
|
|
3152
|
+
numberOfAds
|
|
3153
|
+
);
|
|
3154
|
+
if (this.config.debugAdTiming) {
|
|
3155
|
+
console.log(
|
|
3156
|
+
`[DEBUG-POD] \u{1F504} Generated ${vastTagUrls.length} initial VAST URLs with unique correlators`
|
|
3157
|
+
);
|
|
3158
|
+
}
|
|
3159
|
+
} else {
|
|
3160
|
+
vastTagUrls = [this.apiVastTagUrl];
|
|
3161
|
+
}
|
|
3083
3162
|
} else if (tags && tags.length > 0) {
|
|
3084
3163
|
vastTagUrls = tags;
|
|
3085
3164
|
} else {
|
|
@@ -3129,7 +3208,8 @@ var StormcloudVideoPlayer = class {
|
|
|
3129
3208
|
console.log("[DEBUG-POD] \u26A0\uFE0F No ads in pod");
|
|
3130
3209
|
return;
|
|
3131
3210
|
}
|
|
3132
|
-
|
|
3211
|
+
const waitTime = this.isAdaptiveMode ? 1500 : 500;
|
|
3212
|
+
await new Promise((resolve) => setTimeout(resolve, waitTime));
|
|
3133
3213
|
const firstPreloaded = this.findNextPreloadedAd();
|
|
3134
3214
|
if (!firstPreloaded) {
|
|
3135
3215
|
console.log("[DEBUG-POD] \u26A0\uFE0F No preloaded ads after wait, trying first ad");
|
|
@@ -3498,6 +3578,89 @@ var StormcloudVideoPlayer = class {
|
|
|
3498
3578
|
}
|
|
3499
3579
|
return mediaUrls;
|
|
3500
3580
|
}
|
|
3581
|
+
async fetchVastDuration(vastTagUrl) {
|
|
3582
|
+
var _a;
|
|
3583
|
+
try {
|
|
3584
|
+
const response = await fetch(vastTagUrl, { mode: "cors" });
|
|
3585
|
+
if (!response.ok) {
|
|
3586
|
+
if (this.config.debugAdTiming) {
|
|
3587
|
+
console.warn(
|
|
3588
|
+
`[ADAPTIVE-POD] Failed to fetch VAST: ${response.status}`
|
|
3589
|
+
);
|
|
3590
|
+
}
|
|
3591
|
+
return null;
|
|
3592
|
+
}
|
|
3593
|
+
const xmlText = await response.text();
|
|
3594
|
+
const parser = new DOMParser();
|
|
3595
|
+
const xmlDoc = parser.parseFromString(xmlText, "text/xml");
|
|
3596
|
+
const durationText = (_a = xmlDoc.querySelector("Duration")) == null ? void 0 : _a.textContent;
|
|
3597
|
+
if (!durationText) {
|
|
3598
|
+
if (this.config.debugAdTiming) {
|
|
3599
|
+
console.warn("[ADAPTIVE-POD] No Duration element found in VAST");
|
|
3600
|
+
}
|
|
3601
|
+
return null;
|
|
3602
|
+
}
|
|
3603
|
+
const durationParts = durationText.split(":");
|
|
3604
|
+
const durationSeconds = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
|
|
3605
|
+
return durationSeconds;
|
|
3606
|
+
} catch (error) {
|
|
3607
|
+
if (this.config.debugAdTiming) {
|
|
3608
|
+
console.warn(
|
|
3609
|
+
`[ADAPTIVE-POD] Error fetching VAST duration from ${vastTagUrl}:`,
|
|
3610
|
+
error
|
|
3611
|
+
);
|
|
3612
|
+
}
|
|
3613
|
+
return null;
|
|
3614
|
+
}
|
|
3615
|
+
}
|
|
3616
|
+
calculateAdditionalAdsNeeded() {
|
|
3617
|
+
if (!this.isAdaptiveMode || this.targetAdBreakDurationMs === null) {
|
|
3618
|
+
return 0;
|
|
3619
|
+
}
|
|
3620
|
+
let totalFetchedDurationMs = 0;
|
|
3621
|
+
for (const duration of this.fetchedAdDurations.values()) {
|
|
3622
|
+
totalFetchedDurationMs += duration * 1e3;
|
|
3623
|
+
}
|
|
3624
|
+
const remainingTimeMs = this.targetAdBreakDurationMs - totalFetchedDurationMs;
|
|
3625
|
+
if (remainingTimeMs <= 0) {
|
|
3626
|
+
if (this.config.debugAdTiming) {
|
|
3627
|
+
console.log(
|
|
3628
|
+
`[ADAPTIVE-POD] \u2705 Target duration reached: ${totalFetchedDurationMs}ms / ${this.targetAdBreakDurationMs}ms`
|
|
3629
|
+
);
|
|
3630
|
+
}
|
|
3631
|
+
return 0;
|
|
3632
|
+
}
|
|
3633
|
+
const fetchedCount = this.fetchedAdDurations.size;
|
|
3634
|
+
const averageDurationMs = fetchedCount > 0 ? totalFetchedDurationMs / fetchedCount : 30 * 1e3;
|
|
3635
|
+
const additionalAds = Math.ceil(remainingTimeMs / averageDurationMs);
|
|
3636
|
+
if (this.config.debugAdTiming) {
|
|
3637
|
+
console.log(
|
|
3638
|
+
`[ADAPTIVE-POD] \u{1F4CA} Need ${additionalAds} more ads | Fetched: ${totalFetchedDurationMs}ms / Target: ${this.targetAdBreakDurationMs}ms | Remaining: ${remainingTimeMs}ms | Avg duration: ${averageDurationMs}ms`
|
|
3639
|
+
);
|
|
3640
|
+
}
|
|
3641
|
+
return additionalAds;
|
|
3642
|
+
}
|
|
3643
|
+
async addAdaptiveAdsToQueue() {
|
|
3644
|
+
if (!this.isAdaptiveMode || !this.apiVastTagUrl) {
|
|
3645
|
+
return;
|
|
3646
|
+
}
|
|
3647
|
+
const additionalAds = this.calculateAdditionalAdsNeeded();
|
|
3648
|
+
if (additionalAds <= 0) {
|
|
3649
|
+
return;
|
|
3650
|
+
}
|
|
3651
|
+
const newUrls = this.generateVastUrlsWithCorrelators(
|
|
3652
|
+
this.apiVastTagUrl,
|
|
3653
|
+
additionalAds
|
|
3654
|
+
);
|
|
3655
|
+
if (this.config.debugAdTiming) {
|
|
3656
|
+
console.log(
|
|
3657
|
+
`[ADAPTIVE-POD] \u{1F504} Adding ${newUrls.length} additional VAST URLs to queue (will be preloaded sequentially)`
|
|
3658
|
+
);
|
|
3659
|
+
}
|
|
3660
|
+
this.adPodAllUrls.push(...newUrls);
|
|
3661
|
+
this.adPodQueue.push(...newUrls);
|
|
3662
|
+
this.totalAdsInBreak += newUrls.length;
|
|
3663
|
+
}
|
|
3501
3664
|
async preloadMediaFile(mediaUrl) {
|
|
3502
3665
|
if (this.preloadedMediaUrls.has(mediaUrl)) {
|
|
3503
3666
|
return;
|
|
@@ -3542,31 +3705,82 @@ var StormcloudVideoPlayer = class {
|
|
|
3542
3705
|
if (this.adPodAllUrls.length === 0) {
|
|
3543
3706
|
return;
|
|
3544
3707
|
}
|
|
3545
|
-
if (this.
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
);
|
|
3708
|
+
if (this.isAdaptiveMode) {
|
|
3709
|
+
if (this.config.debugAdTiming) {
|
|
3710
|
+
console.log(
|
|
3711
|
+
`[ADAPTIVE-POD] Starting sequential preload of ${this.adPodAllUrls.length} initial ads`
|
|
3712
|
+
);
|
|
3713
|
+
}
|
|
3714
|
+
const processedUrls = /* @__PURE__ */ new Set();
|
|
3715
|
+
while (true) {
|
|
3716
|
+
const nextUrl = this.adPodAllUrls.find((url) => !processedUrls.has(url));
|
|
3717
|
+
if (!nextUrl) {
|
|
3718
|
+
break;
|
|
3557
3719
|
}
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3720
|
+
processedUrls.add(nextUrl);
|
|
3721
|
+
try {
|
|
3722
|
+
await this.preloadSingleAd(nextUrl);
|
|
3723
|
+
} catch (error) {
|
|
3724
|
+
if (this.config.debugAdTiming) {
|
|
3725
|
+
console.warn(
|
|
3726
|
+
`[ADAPTIVE-POD] Preload failed for ${nextUrl}:`,
|
|
3727
|
+
error
|
|
3728
|
+
);
|
|
3729
|
+
}
|
|
3730
|
+
}
|
|
3731
|
+
if (this.calculateAdditionalAdsNeeded() === 0) {
|
|
3732
|
+
if (this.config.debugAdTiming) {
|
|
3733
|
+
console.log(
|
|
3734
|
+
`[ADAPTIVE-POD] \u2705 Target duration reached, stopping preload`
|
|
3735
|
+
);
|
|
3736
|
+
}
|
|
3737
|
+
break;
|
|
3738
|
+
}
|
|
3739
|
+
}
|
|
3740
|
+
if (this.config.debugAdTiming) {
|
|
3741
|
+
console.log(
|
|
3742
|
+
`[ADAPTIVE-POD] Sequential preloading completed (${processedUrls.size} ads preloaded)`
|
|
3743
|
+
);
|
|
3744
|
+
}
|
|
3745
|
+
} else {
|
|
3746
|
+
if (this.config.debugAdTiming) {
|
|
3747
|
+
console.log(
|
|
3748
|
+
`[StormcloudVideoPlayer] Starting parallel preload of ${this.adPodAllUrls.length} ads`
|
|
3749
|
+
);
|
|
3750
|
+
}
|
|
3751
|
+
const preloadPromises = this.adPodAllUrls.map(
|
|
3752
|
+
(vastTagUrl) => this.preloadSingleAd(vastTagUrl).catch((error) => {
|
|
3753
|
+
if (this.config.debugAdTiming) {
|
|
3754
|
+
console.warn(
|
|
3755
|
+
`[StormcloudVideoPlayer] Preload failed for ${vastTagUrl}:`,
|
|
3756
|
+
error
|
|
3757
|
+
);
|
|
3758
|
+
}
|
|
3759
|
+
})
|
|
3564
3760
|
);
|
|
3761
|
+
await Promise.all(preloadPromises);
|
|
3762
|
+
if (this.config.debugAdTiming) {
|
|
3763
|
+
console.log(
|
|
3764
|
+
`[StormcloudVideoPlayer] Background preloading completed for all ads`
|
|
3765
|
+
);
|
|
3766
|
+
}
|
|
3565
3767
|
}
|
|
3566
3768
|
}
|
|
3567
3769
|
async preloadSingleAd(vastTagUrl) {
|
|
3568
3770
|
if (!vastTagUrl) return;
|
|
3569
3771
|
try {
|
|
3772
|
+
if (this.isAdaptiveMode && !this.fetchedAdDurations.has(vastTagUrl)) {
|
|
3773
|
+
const duration = await this.fetchVastDuration(vastTagUrl);
|
|
3774
|
+
if (duration !== null) {
|
|
3775
|
+
this.fetchedAdDurations.set(vastTagUrl, duration);
|
|
3776
|
+
if (this.config.debugAdTiming) {
|
|
3777
|
+
console.log(
|
|
3778
|
+
`[ADAPTIVE-POD] \u2713 Fetched ad duration: ${duration}s (${this.fetchedAdDurations.size} ads fetched so far)`
|
|
3779
|
+
);
|
|
3780
|
+
}
|
|
3781
|
+
await this.addAdaptiveAdsToQueue();
|
|
3782
|
+
}
|
|
3783
|
+
}
|
|
3570
3784
|
if (this.ima.preloadAds && !this.ima.hasPreloadedAd(vastTagUrl)) {
|
|
3571
3785
|
if (!this.preloadingAdUrls.has(vastTagUrl)) {
|
|
3572
3786
|
if (this.config.debugAdTiming) {
|