stormcloud-video-player 0.8.29 → 0.8.30
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 +78 -1045
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +0 -3
- package/lib/index.d.ts +0 -3
- package/lib/index.js +78 -1046
- package/lib/index.js.map +1 -1
- package/lib/player/AdBreakOrchestrator.cjs +57 -490
- package/lib/player/AdBreakOrchestrator.cjs.map +1 -1
- package/lib/player/AdBreakOrchestrator.d.cts +8 -7
- package/lib/player/AdConfigManager.cjs +12 -53
- package/lib/player/AdConfigManager.cjs.map +1 -1
- package/lib/player/AdConfigManager.d.cts +4 -5
- 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 +78 -1045
- package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/player/StormcloudVideoPlayer.d.cts +1 -3
- package/lib/player/playerTypes.d.cts +1 -1
- package/lib/players/HlsPlayer.cjs +78 -1045
- package/lib/players/HlsPlayer.cjs.map +1 -1
- package/lib/players/HlsPlayer.d.cts +1 -1
- package/lib/players/index.cjs +78 -1045
- package/lib/players/index.cjs.map +1 -1
- package/lib/sdk/hlsAdPlayer.d.cts +1 -1
- package/lib/{types-Xgz2_W1C.d.cts → types-CSHvCbhZ.d.cts} +0 -1
- package/lib/ui/StormcloudVideoPlayer.cjs +78 -1045
- 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/lib/utils/vastMacros.cjs +10 -15
- package/lib/utils/vastMacros.cjs.map +1 -1
- package/lib/utils/vastMacros.d.cts +0 -1
- package/package.json +1 -1
- package/lib/player/AdPreloadPool.cjs +0 -673
- package/lib/player/AdPreloadPool.cjs.map +0 -1
- package/lib/player/AdPreloadPool.d.cts +0 -37
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/ubuntu24-new/Dev/stormcloud-vp/lib/player/AdPreloadPool.cjs","../../src/player/AdPreloadPool.ts"],"names":["__hasOwnProp","call","to","key","except","__defProp","Object","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","getOwnPropertyNames","prototype","hasOwnProperty","__export","name","all","target","get","enumerable","__copyProps","from","desc","poolActive","__toCommonJS","mod","value","AdPreloadPool_exports","AdPreloadPool","deps","pool","maxPoolSize","loopRunning","active","startPreloadPool","baseVastUrl","initialUrls","startLoopImmediately","debug","console","log","url","length","preloadAdIntoPool"],"mappings":"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","sourcesContent":["\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/player/AdPreloadPool.ts\nvar AdPreloadPool_exports = {};\n__export(AdPreloadPool_exports, {\n AdPreloadPool: () => AdPreloadPool\n});\nmodule.exports = __toCommonJS(AdPreloadPool_exports);\nvar AdPreloadPool = class {\n constructor(deps) {\n this.pool = [];\n this.maxPoolSize = 2;\n this.poolActive = false;\n this.loopRunning = false;\n this.deps = deps;\n }\n get active() {\n return this.poolActive;\n }\n set active(value) {\n this.poolActive = value;\n }\n get isLoopRunning() {\n return this.loopRunning;\n }\n startPreloadPool(baseVastUrl, initialUrls, startLoopImmediately = true) {\n if (this.poolActive) {\n if (this.deps.debug) {\n console.log(\"[PRELOAD-POOL] Already active, skipping duplicate start\");\n }\n return;\n }\n this.poolActive = true;\n if (this.deps.debug) {\n console.log(`[PRELOAD-POOL] Starting preload pool EARLY (target size: ${this.maxPoolSize})`);\n console.log(`[PRELOAD-POOL] Ad break hasn't started yet, but preloading ads in advance`);\n }\n for (const url of initialUrls) {\n if (this.pool.length < this.maxPoolSize) {\n this.preloadAdIntoPool(url);\n }\n }\n if (startLoopImmediately) {\n this.preloadPoolLoop(baseVastUrl);\n } else if (this.deps.debug) {\n console.log(\n \"[PRELOAD-POOL] Pre-break mode: preloaded once, waiting for SCTE start to continue fetching\"\n );\n }\n }\n async preloadAdIntoPool(vastUrl) {\n const timing = this.deps.timing;\n if (timing.isGamInCooldown()) {\n if (this.deps.debug) {\n console.log(\"[CIRCUIT-BREAKER] GAM in cooldown, skipping preload\");\n }\n return;\n }\n if (this.pool.some((entry) => entry.vastUrl === vastUrl) || timing.failedVastUrls.has(vastUrl) || timing.isUrlInCooldown(vastUrl)) {\n return;\n }\n if (this.pool.length >= this.maxPoolSize) {\n return;\n }\n if (this.deps.debug) {\n console.log(`[PRELOAD-POOL] Preloading ad into pool: ${vastUrl}`);\n }\n const epoch = timing.adBreakEpoch;\n const loadPromise = (async () => {\n let hasAdError = false;\n let adErrorPayload = null;\n let errorListenerCleanup = null;\n try {\n const continueLiveStreamDuringAds = this.deps.shouldContinueLiveStreamDuringAds();\n const preloadAd = this.deps.createAdPlayer(continueLiveStreamDuringAds);\n preloadAd.initialize();\n const errorListener = (payload) => {\n hasAdError = true;\n adErrorPayload = payload;\n };\n preloadAd.on(\"ad_error\", errorListener);\n errorListenerCleanup = () => preloadAd.off(\"ad_error\", errorListener);\n await timing.enforceGlobalRateLimit();\n await preloadAd.requestAds(vastUrl);\n preloadAd.pause();\n await new Promise((resolve) => setTimeout(resolve, 1500));\n preloadAd.pause();\n if (hasAdError) {\n const isNoFill = adErrorPayload?.isNoFill || adErrorPayload?.code === 303 || adErrorPayload?.vastErrorCode === 303;\n if (errorListenerCleanup) {\n errorListenerCleanup();\n }\n preloadAd.destroy();\n timing.recordGamNoFill();\n if (isNoFill) {\n if (this.deps.debug) {\n console.log(`[PRELOAD-POOL] Ad preload returned no-fill: ${vastUrl}`);\n }\n timing.temporaryFailureUrls.set(vastUrl, Date.now());\n } else {\n if (this.deps.debug) {\n console.log(`[PRELOAD-POOL] Ad preload failed with error: ${vastUrl}`, adErrorPayload);\n }\n if (adErrorPayload && !timing.isTemporaryAdError(adErrorPayload)) {\n timing.failedVastUrls.add(vastUrl);\n } else {\n timing.temporaryFailureUrls.set(vastUrl, Date.now());\n }\n }\n return;\n }\n if (!this.poolActive || epoch !== timing.adBreakEpoch) {\n if (this.deps.debug) {\n console.log(\n \"[PRELOAD-POOL] Discarding preloaded ad - break ended during fetch\"\n );\n }\n if (errorListenerCleanup) {\n errorListenerCleanup();\n }\n try {\n preloadAd.destroy();\n } catch {\n }\n return;\n }\n const poolEntry = {\n vastUrl,\n adController: preloadAd,\n loadedAt: Date.now(),\n isReady: true,\n loadPromise: Promise.resolve()\n };\n const loadedDuration = preloadAd.getLoadedAdDuration?.();\n if (loadedDuration != null && loadedDuration > 0) {\n poolEntry.durationSeconds = loadedDuration;\n }\n const lateErrorListener = (payload) => {\n const index = this.pool.findIndex((entry) => entry.vastUrl === vastUrl);\n if (index >= 0) {\n this.pool.splice(index, 1);\n if (this.deps.debug) {\n console.log(`[PRELOAD-POOL] Late error detected, removed from pool: ${vastUrl}`, payload);\n }\n try {\n preloadAd.destroy();\n } catch {\n }\n }\n };\n preloadAd.on(\"ad_error\", lateErrorListener);\n this.pool.push(poolEntry);\n if (this.deps.debug) {\n console.log(`[PRELOAD-POOL] Ad preloaded (no errors detected within timeout) (pool size: ${this.pool.length}/${this.maxPoolSize}, duration=${poolEntry.durationSeconds ?? \"?\"}s)`);\n }\n if (errorListenerCleanup) {\n errorListenerCleanup();\n }\n } catch (error) {\n if (errorListenerCleanup) {\n errorListenerCleanup();\n }\n timing.recordGamNoFill();\n if (this.deps.debug) {\n console.warn(`[PRELOAD-POOL] Failed to preload ad: ${vastUrl}`, error);\n }\n if (error instanceof Error && !timing.isTemporaryAdError(error)) {\n timing.failedVastUrls.add(vastUrl);\n } else if (error instanceof Error && timing.isTemporaryAdError(error)) {\n timing.temporaryFailureUrls.set(vastUrl, Date.now());\n }\n }\n })();\n loadPromise.catch(() => {\n });\n }\n async preloadPoolLoop(baseVastUrl) {\n if (this.loopRunning) {\n return;\n }\n this.loopRunning = true;\n const epoch = this.deps.timing.adBreakEpoch;\n if (this.deps.debug) {\n console.log(\"[PRELOAD-POOL] Starting continuous preload loop\");\n }\n while (this.poolActive && epoch === this.deps.timing.adBreakEpoch) {\n if (this.deps.timing.isGamInCooldown()) {\n if (this.deps.debug) {\n console.log(\"[CIRCUIT-BREAKER] GAM in cooldown, stopping preload pool loop\");\n }\n break;\n }\n if (!this.deps.isInAdBreak() && this.pool.length >= this.maxPoolSize) {\n await new Promise((resolve) => setTimeout(resolve, 2e3));\n continue;\n }\n if (!this.deps.isInAdBreak() && this.deps.getPendingAdBreak() === null) {\n if (this.deps.debug) {\n console.log(\"[PRELOAD-POOL] Ad break cancelled, stopping preload pool\");\n }\n break;\n }\n while (this.pool.length < this.maxPoolSize) {\n if (!this.poolActive || epoch !== this.deps.timing.adBreakEpoch || this.deps.timing.isGamInCooldown()) {\n break;\n }\n if (this.deps.isInAdBreak() && !this.deps.timing.hasTimeToStartAnotherAd()) {\n if (this.deps.debug) {\n console.log(\"[PRELOAD-POOL] Not enough ad break time left, stopping preload\");\n }\n break;\n }\n const newUrls = this.deps.generateVastUrlsWithCorrelators(baseVastUrl, 1);\n const newUrl = newUrls[0];\n if (newUrl && !this.deps.timing.failedVastUrls.has(newUrl) && !this.deps.timing.isUrlInCooldown(newUrl)) {\n await this.preloadAdIntoPool(newUrl);\n }\n await new Promise((resolve) => setTimeout(resolve, 1e3));\n }\n await new Promise((resolve) => setTimeout(resolve, 2e3));\n }\n this.loopRunning = false;\n if (this.deps.debug) {\n console.log(\"[PRELOAD-POOL] Preload loop ended\");\n }\n }\n getPreloadedAd() {\n if (this.pool.length === 0) {\n return null;\n }\n const entry = this.pool.shift();\n if (!entry || !entry.isReady) {\n return null;\n }\n if (this.deps.debug) {\n console.log(`[PRELOAD-POOL] Using preloaded ad from pool (${this.pool.length} remaining)`);\n }\n return {\n vastUrl: entry.vastUrl,\n adController: entry.adController\n };\n }\n stop() {\n this.poolActive = false;\n this.loopRunning = false;\n for (const entry of this.pool) {\n try {\n entry.adController.destroy();\n } catch (error) {\n if (this.deps.debug) {\n console.warn(\"[PRELOAD-POOL] Error destroying preloaded controller:\", error);\n }\n }\n }\n this.pool = [];\n if (this.deps.debug) {\n console.log(\"[PRELOAD-POOL] Preload pool stopped and cleaned up\");\n }\n }\n};\n// Annotate the CommonJS export names for ESM import in node:\n0 && (module.exports = {\n AdPreloadPool\n});\n","import type { AdController, Scte35Marker } from \"../types\";\nimport type { AdTimingService } from \"./AdTimingService\";\n\nexport interface AdPreloadPoolDeps {\n debug: boolean;\n createAdPlayer(continueLiveStreamDuringAds: boolean): AdController;\n shouldContinueLiveStreamDuringAds(): boolean;\n timing: AdTimingService;\n generateVastUrlsWithCorrelators(baseUrl: string, count: number): string[];\n isInAdBreak(): boolean;\n getPendingAdBreak(): { marker: Scte35Marker; vastUrls: string[]; isFetching: boolean } | null;\n}\n\nexport class AdPreloadPool {\n private pool: Array<{\n vastUrl: string;\n adController: AdController;\n loadedAt: number;\n isReady: boolean;\n loadPromise: Promise<void>;\n durationSeconds?: number;\n }> = [];\n private readonly maxPoolSize: number = 2;\n private poolActive: boolean = false;\n private loopRunning: boolean = false;\n\n private deps: AdPreloadPoolDeps;\n\n constructor(deps: AdPreloadPoolDeps) {\n this.deps = deps;\n }\n\n get active(): boolean {\n return this.poolActive;\n }\n\n set active(value: boolean) {\n this.poolActive = value;\n }\n\n get isLoopRunning(): boolean {\n return this.loopRunning;\n }\n\n startPreloadPool(\n baseVastUrl: string,\n initialUrls: string[],\n startLoopImmediately: boolean = true\n ): void {\n if (this.poolActive) {\n if (this.deps.debug) {\n console.log(\"[PRELOAD-POOL] Already active, skipping duplicate start\");\n }\n return;\n }\n\n this.poolActive = true;\n\n if (this.deps.debug) {\n console.log(`[PRELOAD-POOL] Starting preload pool EARLY (target size: ${this.maxPoolSize})`);\n console.log(`[PRELOAD-POOL] Ad break hasn't started yet, but preloading ads in advance`);\n }\n\n for (const url of initialUrls) {\n if (this.pool.length < this.maxPoolSize) {\n this.preloadAdIntoPool(url);\n }\n }\n\n if (startLoopImmediately) {\n this.preloadPoolLoop(baseVastUrl);\n } else if (this.deps.debug) {\n console.log(\n \"[PRELOAD-POOL] Pre-break mode: preloaded once, waiting for SCTE start to continue fetching\"\n );\n }\n }\n\n private async preloadAdIntoPool(vastUrl: string): Promise<void> {\n const timing = this.deps.timing;\n\n if (timing.isGamInCooldown()) {\n if (this.deps.debug) {\n console.log(\"[CIRCUIT-BREAKER] GAM in cooldown, skipping preload\");\n }\n return;\n }\n\n if (\n this.pool.some(entry => entry.vastUrl === vastUrl) ||\n timing.failedVastUrls.has(vastUrl) ||\n timing.isUrlInCooldown(vastUrl)\n ) {\n return;\n }\n\n if (this.pool.length >= this.maxPoolSize) {\n return;\n }\n\n if (this.deps.debug) {\n console.log(`[PRELOAD-POOL] Preloading ad into pool: ${vastUrl}`);\n }\n\n const epoch = timing.adBreakEpoch;\n const loadPromise = (async () => {\n let hasAdError = false;\n let adErrorPayload: any = null;\n let errorListenerCleanup: (() => void) | null = null;\n\n try {\n const continueLiveStreamDuringAds = this.deps.shouldContinueLiveStreamDuringAds();\n const preloadAd = this.deps.createAdPlayer(continueLiveStreamDuringAds);\n preloadAd.initialize();\n\n const errorListener = (payload?: any) => {\n hasAdError = true;\n adErrorPayload = payload;\n };\n preloadAd.on(\"ad_error\", errorListener);\n errorListenerCleanup = () => preloadAd.off(\"ad_error\", errorListener);\n\n await timing.enforceGlobalRateLimit();\n await preloadAd.requestAds(vastUrl);\n\n preloadAd.pause();\n\n await new Promise(resolve => setTimeout(resolve, 1500));\n\n preloadAd.pause();\n\n if (hasAdError) {\n const isNoFill = adErrorPayload?.isNoFill ||\n adErrorPayload?.code === 303 ||\n adErrorPayload?.vastErrorCode === 303;\n\n if (errorListenerCleanup) {\n errorListenerCleanup();\n }\n preloadAd.destroy();\n\n timing.recordGamNoFill();\n\n if (isNoFill) {\n if (this.deps.debug) {\n console.log(`[PRELOAD-POOL] Ad preload returned no-fill: ${vastUrl}`);\n }\n timing.temporaryFailureUrls.set(vastUrl, Date.now());\n } else {\n if (this.deps.debug) {\n console.log(`[PRELOAD-POOL] Ad preload failed with error: ${vastUrl}`, adErrorPayload);\n }\n if (adErrorPayload && !timing.isTemporaryAdError(adErrorPayload as Error)) {\n timing.failedVastUrls.add(vastUrl);\n } else {\n timing.temporaryFailureUrls.set(vastUrl, Date.now());\n }\n }\n return;\n }\n\n if (!this.poolActive || epoch !== timing.adBreakEpoch) {\n if (this.deps.debug) {\n console.log(\n \"[PRELOAD-POOL] Discarding preloaded ad - break ended during fetch\"\n );\n }\n if (errorListenerCleanup) {\n errorListenerCleanup();\n }\n try {\n preloadAd.destroy();\n } catch {}\n return;\n }\n\n const poolEntry: {\n vastUrl: string;\n adController: AdController;\n loadedAt: number;\n isReady: boolean;\n loadPromise: Promise<void>;\n durationSeconds?: number;\n } = {\n vastUrl,\n adController: preloadAd,\n loadedAt: Date.now(),\n isReady: true,\n loadPromise: Promise.resolve(),\n };\n const loadedDuration = preloadAd.getLoadedAdDuration?.();\n if (loadedDuration != null && loadedDuration > 0) {\n poolEntry.durationSeconds = loadedDuration;\n }\n\n const lateErrorListener = (payload?: any) => {\n const index = this.pool.findIndex(entry => entry.vastUrl === vastUrl);\n if (index >= 0) {\n this.pool.splice(index, 1);\n if (this.deps.debug) {\n console.log(`[PRELOAD-POOL] Late error detected, removed from pool: ${vastUrl}`, payload);\n }\n try {\n preloadAd.destroy();\n } catch {}\n }\n };\n preloadAd.on(\"ad_error\", lateErrorListener);\n\n this.pool.push(poolEntry);\n\n if (this.deps.debug) {\n console.log(`[PRELOAD-POOL] Ad preloaded (no errors detected within timeout) (pool size: ${this.pool.length}/${this.maxPoolSize}, duration=${poolEntry.durationSeconds ?? \"?\"}s)`);\n }\n\n if (errorListenerCleanup) {\n errorListenerCleanup();\n }\n } catch (error) {\n if (errorListenerCleanup) {\n errorListenerCleanup();\n }\n\n timing.recordGamNoFill();\n\n if (this.deps.debug) {\n console.warn(`[PRELOAD-POOL] Failed to preload ad: ${vastUrl}`, error);\n }\n\n if (error instanceof Error && !timing.isTemporaryAdError(error)) {\n timing.failedVastUrls.add(vastUrl);\n } else if (error instanceof Error && timing.isTemporaryAdError(error)) {\n timing.temporaryFailureUrls.set(vastUrl, Date.now());\n }\n }\n })();\n\n loadPromise.catch(() => {});\n }\n\n async preloadPoolLoop(baseVastUrl: string): Promise<void> {\n if (this.loopRunning) {\n return;\n }\n\n this.loopRunning = true;\n const epoch = this.deps.timing.adBreakEpoch;\n\n if (this.deps.debug) {\n console.log(\"[PRELOAD-POOL] Starting continuous preload loop\");\n }\n\n while (this.poolActive && epoch === this.deps.timing.adBreakEpoch) {\n if (this.deps.timing.isGamInCooldown()) {\n if (this.deps.debug) {\n console.log(\"[CIRCUIT-BREAKER] GAM in cooldown, stopping preload pool loop\");\n }\n break;\n }\n\n if (!this.deps.isInAdBreak() && this.pool.length >= this.maxPoolSize) {\n await new Promise(resolve => setTimeout(resolve, 2000));\n continue;\n }\n\n if (!this.deps.isInAdBreak() && this.deps.getPendingAdBreak() === null) {\n if (this.deps.debug) {\n console.log(\"[PRELOAD-POOL] Ad break cancelled, stopping preload pool\");\n }\n break;\n }\n\n while (this.pool.length < this.maxPoolSize) {\n if (\n !this.poolActive ||\n epoch !== this.deps.timing.adBreakEpoch ||\n this.deps.timing.isGamInCooldown()\n ) {\n break;\n }\n\n if (this.deps.isInAdBreak() && !this.deps.timing.hasTimeToStartAnotherAd()) {\n if (this.deps.debug) {\n console.log(\"[PRELOAD-POOL] Not enough ad break time left, stopping preload\");\n }\n break;\n }\n\n const newUrls = this.deps.generateVastUrlsWithCorrelators(baseVastUrl, 1);\n const newUrl = newUrls[0];\n\n if (newUrl && !this.deps.timing.failedVastUrls.has(newUrl) && !this.deps.timing.isUrlInCooldown(newUrl)) {\n await this.preloadAdIntoPool(newUrl);\n }\n\n await new Promise(resolve => setTimeout(resolve, 1000));\n }\n\n await new Promise(resolve => setTimeout(resolve, 2000));\n }\n\n this.loopRunning = false;\n\n if (this.deps.debug) {\n console.log(\"[PRELOAD-POOL] Preload loop ended\");\n }\n }\n\n getPreloadedAd(): { vastUrl: string; adController: AdController } | null {\n if (this.pool.length === 0) {\n return null;\n }\n\n const entry = this.pool.shift();\n if (!entry || !entry.isReady) {\n return null;\n }\n\n if (this.deps.debug) {\n console.log(`[PRELOAD-POOL] Using preloaded ad from pool (${this.pool.length} remaining)`);\n }\n\n return {\n vastUrl: entry.vastUrl,\n adController: entry.adController,\n };\n }\n\n stop(): void {\n this.poolActive = false;\n this.loopRunning = false;\n\n for (const entry of this.pool) {\n try {\n entry.adController.destroy();\n } catch (error) {\n if (this.deps.debug) {\n console.warn(\"[PRELOAD-POOL] Error destroying preloaded controller:\", error);\n }\n }\n }\n\n this.pool = [];\n\n if (this.deps.debug) {\n console.log(\"[PRELOAD-POOL] Preload pool stopped and cleaned up\");\n }\n }\n}\n"]}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { A as AdController, S as Scte35Marker } from '../types-Xgz2_W1C.cjs';
|
|
2
|
-
import { AdTimingService } from './AdTimingService.cjs';
|
|
3
|
-
|
|
4
|
-
interface AdPreloadPoolDeps {
|
|
5
|
-
debug: boolean;
|
|
6
|
-
createAdPlayer(continueLiveStreamDuringAds: boolean): AdController;
|
|
7
|
-
shouldContinueLiveStreamDuringAds(): boolean;
|
|
8
|
-
timing: AdTimingService;
|
|
9
|
-
generateVastUrlsWithCorrelators(baseUrl: string, count: number): string[];
|
|
10
|
-
isInAdBreak(): boolean;
|
|
11
|
-
getPendingAdBreak(): {
|
|
12
|
-
marker: Scte35Marker;
|
|
13
|
-
vastUrls: string[];
|
|
14
|
-
isFetching: boolean;
|
|
15
|
-
} | null;
|
|
16
|
-
}
|
|
17
|
-
declare class AdPreloadPool {
|
|
18
|
-
private pool;
|
|
19
|
-
private readonly maxPoolSize;
|
|
20
|
-
private poolActive;
|
|
21
|
-
private loopRunning;
|
|
22
|
-
private deps;
|
|
23
|
-
constructor(deps: AdPreloadPoolDeps);
|
|
24
|
-
get active(): boolean;
|
|
25
|
-
set active(value: boolean);
|
|
26
|
-
get isLoopRunning(): boolean;
|
|
27
|
-
startPreloadPool(baseVastUrl: string, initialUrls: string[], startLoopImmediately?: boolean): void;
|
|
28
|
-
private preloadAdIntoPool;
|
|
29
|
-
preloadPoolLoop(baseVastUrl: string): Promise<void>;
|
|
30
|
-
getPreloadedAd(): {
|
|
31
|
-
vastUrl: string;
|
|
32
|
-
adController: AdController;
|
|
33
|
-
} | null;
|
|
34
|
-
stop(): void;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export { AdPreloadPool, type AdPreloadPoolDeps };
|