stormcloud-video-player 0.8.59 → 0.8.61
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/LICENSE +21 -21
- package/README.md +1369 -1369
- package/dist/stormcloud-vp.min.js +3 -1
- package/lib/Player.cjs +548 -0
- package/lib/Player.cjs.map +1 -0
- package/lib/Player.d.cts +146 -0
- package/lib/{index.js → StormcloudPlayer.cjs} +1193 -1908
- package/lib/StormcloudPlayer.cjs.map +1 -0
- package/lib/{index.d.ts → StormcloudPlayer.d.cts} +7 -400
- package/lib/index.cjs +1064 -280
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +18 -4032
- package/lib/patterns.cjs +111 -0
- package/lib/patterns.cjs.map +1 -0
- package/lib/patterns.d.cts +14 -0
- package/lib/player/AdBreakOrchestrator.cjs +51 -16
- package/lib/player/AdBreakOrchestrator.cjs.map +1 -1
- package/lib/player/AdBreakOrchestrator.d.cts +3 -1
- package/lib/player/AdConfigManager.cjs +206 -26
- package/lib/player/AdConfigManager.cjs.map +1 -1
- package/lib/player/AdConfigManager.d.cts +1 -1
- package/lib/player/AdTimingService.cjs.map +1 -1
- package/lib/player/AdTimingService.d.cts +1 -1
- package/lib/player/HlsEngine.cjs.map +1 -1
- package/lib/player/HlsEngine.d.cts +1 -1
- package/lib/player/PlaceholderLayer.cjs.map +1 -1
- package/lib/player/PlayerControls.cjs.map +1 -1
- package/lib/player/PlayerControls.d.cts +1 -1
- package/lib/player/Scte35CueManager.cjs.map +1 -1
- package/lib/player/Scte35CueManager.d.cts +1 -1
- package/lib/player/Scte35Parser.cjs.map +1 -1
- package/lib/player/Scte35Parser.d.cts +1 -1
- package/lib/player/StormcloudVideoPlayer.cjs +1060 -278
- package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/player/StormcloudVideoPlayer.d.cts +1 -1
- package/lib/player/playerTypes.cjs.map +1 -1
- package/lib/player/playerTypes.d.cts +1 -1
- package/lib/players/FilePlayer.cjs.map +1 -1
- package/lib/players/HlsPlayer.cjs +1060 -278
- package/lib/players/HlsPlayer.cjs.map +1 -1
- package/lib/players/HlsPlayer.d.cts +1 -1
- package/lib/players/index.cjs +1060 -278
- package/lib/players/index.cjs.map +1 -1
- package/lib/props.cjs +186 -0
- package/lib/props.cjs.map +1 -0
- package/lib/props.d.cts +62 -0
- package/lib/sdk/hlsAdPlayer.cjs +884 -234
- package/lib/sdk/hlsAdPlayer.cjs.map +1 -1
- package/lib/sdk/hlsAdPlayer.d.cts +1 -1
- package/lib/sdk/pal.cjs +9 -5
- package/lib/sdk/pal.cjs.map +1 -1
- package/lib/sdk/pal.d.cts +1 -0
- package/lib/types.cjs +49 -0
- package/lib/types.cjs.map +1 -0
- package/lib/{types-52ASml2N.d.cts → types.d.cts} +48 -1
- package/lib/ui/StormcloudVideoPlayer.cjs +1064 -280
- package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/ui/StormcloudVideoPlayer.d.cts +1 -1
- package/lib/utils/browserCompat.cjs.map +1 -1
- package/lib/utils/ctvVastSignals.cjs +178 -19
- package/lib/utils/ctvVastSignals.cjs.map +1 -1
- package/lib/utils/devUrl.cjs.map +1 -1
- package/lib/utils/polyfills.cjs.map +1 -1
- package/lib/utils/tracking.cjs +45 -16
- package/lib/utils/tracking.cjs.map +1 -1
- package/lib/utils/tracking.d.cts +1 -1
- package/lib/utils/trackingIngest.cjs.map +1 -1
- package/lib/utils/vastEnvironmentSignals.cjs +192 -20
- package/lib/utils/vastEnvironmentSignals.cjs.map +1 -1
- package/lib/utils/vastEnvironmentSignals.d.cts +13 -2
- package/lib/utils/vastMacros.cjs +50 -4
- package/lib/utils/vastMacros.cjs.map +1 -1
- package/lib/utils/vastMacros.d.cts +2 -0
- package/lib/utils/vastTrackingMacros.cjs +5 -0
- package/lib/utils/vastTrackingMacros.cjs.map +1 -1
- package/lib/utils/vastTrackingMacros.d.cts +2 -0
- package/lib/utils.cjs +292 -0
- package/lib/utils.cjs.map +1 -0
- package/lib/utils.d.cts +17 -0
- package/package.json +91 -91
- package/rollup.config.js +90 -90
- package/lib/index.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AdBreak, StormcloudVideoPlayerConfig, AdController } from '../types.cjs';
|
|
2
2
|
import { PalNonceManager } from '../sdk/pal.cjs';
|
|
3
3
|
import { VastConsentSignals } from '../utils/vastMacros.cjs';
|
|
4
4
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/ubuntu24-new/Dev/stormcloud-vp/lib/player/AdTimingService.cjs","../../src/player/AdTimingService.ts"],"names":["__defProp","Object","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","getOwnPropertyNames","__hasOwnProp","prototype","hasOwnProperty","__export","target","all","name","get","enumerable","__copyProps","to","from","except","desc","key","call","__toCommonJS","mod","value","AdTimingService_exports","AdTimingService","module","exports","config","video","callbacks","adRequestWatchdogToken","adFailsafeToken","ptsDriftEmaMs","adBreakPlayedDurationMs","adBreakEpoch","adRequestTokenCounter","activeAdRequestToken","currentAdIndex","totalAdsInBreak","totalAdRequestsInBreak","maxTotalAdRequestsPerBreak","lastAdRequestTime","consecutiveFailures","minAdRequestIntervalMs","backoffBaseMs","maxBackoffMs","defaultMinRemainingMsToStartAd","temporaryFailureUrls","Map","temporaryFailureCooldownMs","globalConsecutiveNoFills","globalNoFillThreshold","globalNoFillCooldownUntil","globalNoFillBackoffBaseMs","globalNoFillBackoffMaxMs","globalMinGamIntervalMs","debug","debugAdTiming","scheduleAdStopCountdown","remainingMs","clearAdStopTimer","ms","Math","max","floor","ensureAdStoppedByTimer","adStopTimerId","window","setTimeout","clearTimeout","onAdStopTimerFired","scheduleAdStartIn","delayMs","type","marker","cueKey","clearAdStartTimer","onAdStartTimerFired","adStartTimerId","updatePtsDrift","ptsSecondsSample","sampleMs","currentTime","Number","isFinite","abs","alpha","resolveScteBreakStartWallClockMs","nowWallClockMs","Date","now","ptsSeconds","nowMs","estimatedCurrentPtsMs","deltaMs","setAdBreakDurationBoundary","durationMs","expectedAdBreakDurationMs","currentAdBreakStartWallClockMs","scteAdBreakEndWallClockMs","scheduleAdStopAtBreakBoundary"],"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/AdTimingService.ts\nvar AdTimingService_exports = {};\n__export(AdTimingService_exports, {\n AdTimingService: () => AdTimingService\n});\nmodule.exports = __toCommonJS(AdTimingService_exports);\nvar AdTimingService = class {\n constructor(config, video, callbacks) {\n this.adRequestWatchdogToken = null;\n this.adFailsafeToken = null;\n this.ptsDriftEmaMs = 0;\n this.adBreakPlayedDurationMs = 0;\n this.adBreakEpoch = 0;\n this.adRequestTokenCounter = 0;\n this.activeAdRequestToken = null;\n this.currentAdIndex = 0;\n this.totalAdsInBreak = 0;\n this.totalAdRequestsInBreak = 0;\n this.maxTotalAdRequestsPerBreak = 10;\n this.lastAdRequestTime = 0;\n this.consecutiveFailures = 0;\n this.maxConsecutiveFailures = 5;\n this.minAdRequestIntervalMs = 3e3;\n this.backoffBaseMs = 1e3;\n this.maxBackoffMs = 15e3;\n this.defaultMinRemainingMsToStartAd = 4e3;\n this.failedVastUrls = /* @__PURE__ */ new Set();\n this.temporaryFailureUrls = /* @__PURE__ */ new Map();\n this.temporaryFailureCooldownMs = 3e4;\n this.globalConsecutiveNoFills = 0;\n this.globalNoFillThreshold = 3;\n this.globalNoFillCooldownUntil = 0;\n this.globalNoFillBackoffBaseMs = 5e3;\n this.globalNoFillBackoffMaxMs = 6e4;\n this.globalLastGamRequestTime = 0;\n this.globalMinGamIntervalMs = 3e3;\n this.config = config;\n this.video = video;\n this.callbacks = callbacks;\n }\n get debug() {\n return !!this.config.debugAdTiming;\n }\n // --- Ad stop timer ---\n scheduleAdStopCountdown(remainingMs) {\n this.clearAdStopTimer();\n const ms = Math.max(0, Math.floor(remainingMs));\n if (ms === 0) {\n this.ensureAdStoppedByTimer();\n return;\n }\n this.adStopTimerId = window.setTimeout(() => {\n this.ensureAdStoppedByTimer();\n }, ms);\n }\n clearAdStopTimer() {\n if (this.adStopTimerId != null) {\n clearTimeout(this.adStopTimerId);\n this.adStopTimerId = void 0;\n }\n }\n ensureAdStoppedByTimer() {\n this.adStopTimerId = void 0;\n this.callbacks.onAdStopTimerFired();\n }\n // --- Ad start timer ---\n scheduleAdStartIn(delayMs, marker = { type: \"start\" }, cueKey) {\n this.clearAdStartTimer();\n const ms = Math.max(0, Math.floor(delayMs));\n if (ms === 0) {\n this.callbacks.onAdStartTimerFired(marker, cueKey);\n return;\n }\n this.adStartTimerId = window.setTimeout(() => {\n this.callbacks.onAdStartTimerFired(marker, cueKey);\n }, ms);\n }\n clearAdStartTimer() {\n if (this.adStartTimerId != null) {\n clearTimeout(this.adStartTimerId);\n this.adStartTimerId = void 0;\n }\n }\n // --- PTS drift ---\n updatePtsDrift(ptsSecondsSample) {\n const sampleMs = (this.video.currentTime - ptsSecondsSample) * 1e3;\n if (!Number.isFinite(sampleMs) || Math.abs(sampleMs) > 6e4) return;\n const alpha = 0.1;\n this.ptsDriftEmaMs = this.ptsDriftEmaMs * (1 - alpha) + sampleMs * alpha;\n }\n resolveScteBreakStartWallClockMs(marker) {\n const nowWallClockMs = Date.now();\n if (typeof marker.ptsSeconds !== \"number\") {\n return nowWallClockMs;\n }\n const nowMs = this.video.currentTime * 1e3;\n const estimatedCurrentPtsMs = nowMs - this.ptsDriftEmaMs;\n const deltaMs = marker.ptsSeconds * 1e3 - estimatedCurrentPtsMs;\n if (!Number.isFinite(deltaMs)) {\n return nowWallClockMs;\n }\n return nowWallClockMs + Math.floor(deltaMs);\n }\n // --- Duration boundary ---\n setAdBreakDurationBoundary(durationMs) {\n this.expectedAdBreakDurationMs = durationMs;\n if (durationMs != null && this.currentAdBreakStartWallClockMs != null) {\n this.scteAdBreakEndWallClockMs = this.currentAdBreakStartWallClockMs + durationMs;\n } else {\n this.scteAdBreakEndWallClockMs = void 0;\n }\n }\n scheduleAdStopAtBreakBoundary() {\n if (this.expectedAdBreakDurationMs == null) {\n return;\n }\n this.scheduleAdStopCountdown(this.getWallClockRemainingAdMs());\n }\n // --- Duration budget ---\n getWallClockRemainingAdMs() {\n const endWallClockMs = this.getAdBreakEndWallClockMs();\n if (endWallClockMs != null) {\n return Math.max(0, endWallClockMs - Date.now());\n }\n return 0;\n }\n getAdBreakEndWallClockMs() {\n if (this.scteAdBreakEndWallClockMs != null) {\n return this.scteAdBreakEndWallClockMs;\n }\n if (this.expectedAdBreakDurationMs == null || this.currentAdBreakStartWallClockMs == null) {\n return void 0;\n }\n return this.currentAdBreakStartWallClockMs + this.expectedAdBreakDurationMs;\n }\n getDurationBudgetRemainingMs() {\n if (this.expectedAdBreakDurationMs == null) {\n return 0;\n }\n return Math.max(0, this.expectedAdBreakDurationMs - this.adBreakPlayedDurationMs);\n }\n getLoadedAdDurationMs(adController) {\n const durationSec = adController.getLoadedAdDuration?.();\n if (durationSec == null || durationSec <= 0) {\n return 0;\n }\n return Math.round(durationSec * 1e3);\n }\n adFitsRemainingBudget(durationMs) {\n if (durationMs <= 0) {\n return true;\n }\n return durationMs <= this.getDurationBudgetRemainingMs();\n }\n logAdDurationDecision(accepted, durationMs, adController) {\n if (!this.debug) {\n return;\n }\n const remainingBudget = this.getDurationBudgetRemainingMs();\n const adId = adController.getLoadedAdId?.() ?? \"unknown\";\n if (accepted) {\n console.log(\n `[AD-DURATION] Accepted ad id=${adId}, duration=${durationMs}ms, budget remaining after play=${Math.max(0, remainingBudget - durationMs)}ms`\n );\n } else {\n console.log(\n `[AD-DURATION] Rejected ad id=${adId}, duration=${durationMs}ms exceeds remaining budget=${remainingBudget}ms \\u2014 requesting another ad`\n );\n }\n }\n recordPlayedAdDuration(adController) {\n const durationMs = this.getLoadedAdDurationMs(adController);\n if (durationMs <= 0) {\n return;\n }\n this.adBreakPlayedDurationMs += durationMs;\n if (this.debug) {\n console.log(\n `[AD-DURATION] Played ${durationMs}ms \\u2014 total played=${this.adBreakPlayedDurationMs}ms / ${this.expectedAdBreakDurationMs ?? \"?\"}ms`\n );\n }\n }\n ensureLoadedAdFitsBudget(adController) {\n const durationMs = this.getLoadedAdDurationMs(adController);\n const fits = this.adFitsRemainingBudget(durationMs);\n this.logAdDurationDecision(fits, durationMs, adController);\n return fits;\n }\n rejectLoadedAdForDuration(adController) {\n try {\n adController.destroy();\n } catch {\n }\n }\n markAdStarted() {\n this.currentAdIndex++;\n this.totalAdsInBreak = this.currentAdIndex;\n this.totalAdRequestsInBreak++;\n this.lastAdRequestTime = Date.now();\n }\n notePodAdStarted() {\n this.currentAdIndex++;\n this.totalAdsInBreak = this.currentAdIndex;\n }\n getRemainingAdMs() {\n const wallClockRemaining = this.getWallClockRemainingAdMs();\n const budgetRemaining = this.getDurationBudgetRemainingMs();\n if (this.expectedAdBreakDurationMs == null) {\n return wallClockRemaining;\n }\n return Math.min(wallClockRemaining, budgetRemaining);\n }\n getMinRemainingMsToStartAd() {\n const configured = this.config.minRemainingMsToStartAd;\n if (typeof configured === \"number\" && configured >= 0) {\n return configured;\n }\n return this.defaultMinRemainingMsToStartAd;\n }\n hasTimeToStartAnotherAd() {\n const minRemaining = this.getMinRemainingMsToStartAd();\n return this.getWallClockRemainingAdMs() > minRemaining && this.getDurationBudgetRemainingMs() > minRemaining;\n }\n // --- Circuit breaker ---\n isTemporaryAdError(error) {\n const message = error?.message?.toLowerCase() || \"\";\n if (message.includes(\"no ads available\") || message.includes(\"no fill\") || message.includes(\"nofill\")) {\n return true;\n }\n if (message.includes(\"timeout\")) {\n return true;\n }\n if (message.includes(\"rate limit\") || message.includes(\"too many requests\")) {\n return true;\n }\n if (message.includes(\"ad playback error\")) {\n return true;\n }\n return false;\n }\n isUrlInCooldown(vastTagUrl) {\n const failureTime = this.temporaryFailureUrls.get(vastTagUrl);\n if (failureTime == null) {\n return false;\n }\n const elapsed = Date.now() - failureTime;\n if (elapsed >= this.temporaryFailureCooldownMs) {\n this.temporaryFailureUrls.delete(vastTagUrl);\n return false;\n }\n return true;\n }\n cleanupTemporaryFailures() {\n const now = Date.now();\n for (const [url, timestamp] of this.temporaryFailureUrls) {\n if (now - timestamp >= this.temporaryFailureCooldownMs) {\n this.temporaryFailureUrls.delete(url);\n }\n }\n }\n isGamInCooldown() {\n return Date.now() < this.globalNoFillCooldownUntil;\n }\n recordGamNoFill() {\n this.globalConsecutiveNoFills++;\n if (this.globalConsecutiveNoFills >= this.globalNoFillThreshold) {\n const exponent = this.globalConsecutiveNoFills - this.globalNoFillThreshold;\n const backoff = Math.min(\n this.globalNoFillBackoffBaseMs * Math.pow(2, exponent),\n this.globalNoFillBackoffMaxMs\n );\n this.globalNoFillCooldownUntil = Date.now() + backoff;\n if (this.debug) {\n console.log(\n `[CIRCUIT-BREAKER] GAM cooldown activated: ${backoff}ms (${this.globalConsecutiveNoFills} consecutive no-fills)`\n );\n }\n }\n }\n resetGamNoFillCounter() {\n if (this.globalConsecutiveNoFills > 0 && this.debug) {\n console.log(\n `[CIRCUIT-BREAKER] Resetting no-fill counter (was ${this.globalConsecutiveNoFills})`\n );\n }\n this.globalConsecutiveNoFills = 0;\n this.globalNoFillCooldownUntil = 0;\n }\n async enforceGlobalRateLimit() {\n const now = Date.now();\n const elapsed = now - this.globalLastGamRequestTime;\n if (elapsed < this.globalMinGamIntervalMs) {\n const waitMs = this.globalMinGamIntervalMs - elapsed;\n if (this.debug) {\n console.log(`[RATE-LIMIT] Waiting ${waitMs}ms before next GAM request`);\n }\n await new Promise((resolve) => setTimeout(resolve, waitMs));\n }\n this.globalLastGamRequestTime = Date.now();\n }\n // --- Watchdog ---\n startAdRequestWatchdog(token) {\n this.clearAdRequestWatchdog();\n const timeoutMs = this.config.adFailsafeTimeoutMs ?? 1e4;\n this.adRequestWatchdogToken = token;\n this.adRequestWatchdogId = window.setTimeout(() => {\n if (this.adRequestWatchdogToken !== token) {\n return;\n }\n this.adRequestWatchdogId = void 0;\n this.adRequestWatchdogToken = null;\n if (this.activeAdRequestToken === token) {\n this.activeAdRequestToken = null;\n }\n this.logAdState(\"ad_request_timeout\", { token, timeoutMs });\n this.callbacks.onWatchdogTimeout();\n }, timeoutMs);\n this.logAdState(\"ad_request_watchdog_started\", { token, timeoutMs });\n }\n clearAdRequestWatchdog() {\n if (this.adRequestWatchdogId != null) {\n clearTimeout(this.adRequestWatchdogId);\n this.adRequestWatchdogId = void 0;\n }\n if (this.adRequestWatchdogToken != null) {\n this.logAdState(\"ad_request_watchdog_cleared\", {\n token: this.adRequestWatchdogToken\n });\n this.adRequestWatchdogToken = null;\n }\n }\n // --- Failsafe ---\n startAdFailsafeTimer(token) {\n this.clearAdFailsafeTimer();\n const failsafeMs = this.config.adFailsafeTimeoutMs ?? 1e4;\n this.adFailsafeToken = token;\n this.adFailsafeTimerId = window.setTimeout(() => {\n if (this.adFailsafeToken !== token) {\n return;\n }\n this.adFailsafeTimerId = void 0;\n this.adFailsafeToken = null;\n if (this.activeAdRequestToken === token) {\n this.activeAdRequestToken = null;\n }\n this.logAdState(\"ad_failsafe_triggered\", {\n token,\n failsafeMs,\n videoPaused: this.video.paused\n });\n this.callbacks.onFailsafeTimeout();\n }, failsafeMs);\n this.logAdState(\"ad_failsafe_started\", { token, failsafeMs });\n }\n clearAdFailsafeTimer() {\n if (this.adFailsafeTimerId != null) {\n clearTimeout(this.adFailsafeTimerId);\n this.logAdState(\"ad_failsafe_cleared\", { token: this.adFailsafeToken });\n this.adFailsafeTimerId = void 0;\n }\n this.adFailsafeToken = null;\n }\n logAdState(event, extra = {}) {\n if (!this.debug) {\n return;\n }\n const { inAdBreak, showAds, adPlaying } = this.callbacks.getAdState();\n console.log(\"[StormcloudVideoPlayer][AdState]\", {\n event,\n timestamp: (/* @__PURE__ */ new Date()).toISOString(),\n showAds,\n adPlaying,\n inAdBreak,\n activeAdRequestToken: this.activeAdRequestToken,\n ...extra\n });\n }\n // --- Reset for ad break end ---\n resetForBreakEnd() {\n this.clearAdStopTimer();\n this.clearAdStartTimer();\n this.clearAdRequestWatchdog();\n this.clearAdFailsafeTimer();\n this.activeAdRequestToken = null;\n this.expectedAdBreakDurationMs = void 0;\n this.currentAdBreakStartWallClockMs = void 0;\n this.scteAdBreakEndWallClockMs = void 0;\n this.adBreakPlayedDurationMs = 0;\n this.currentAdIndex = 0;\n this.totalAdsInBreak = 0;\n this.consecutiveFailures = 0;\n this.globalConsecutiveNoFills = 0;\n this.adBreakEpoch++;\n }\n destroy() {\n this.clearAdStopTimer();\n this.clearAdStartTimer();\n this.clearAdFailsafeTimer();\n this.clearAdRequestWatchdog();\n }\n};\n// Annotate the CommonJS export names for ESM import in node:\n0 && (module.exports = {\n AdTimingService\n});\n","import type { AdController, StormcloudVideoPlayerConfig, Scte35Marker } from \"../types\";\n\nexport interface AdTimingCallbacks {\n onAdStopTimerFired(): void;\n onAdStartTimerFired(marker: Scte35Marker, cueKey: string | undefined): void;\n onWatchdogTimeout(): void;\n onFailsafeTimeout(): void;\n getAdState(): { inAdBreak: boolean; showAds: boolean; adPlaying: boolean };\n}\n\nexport class AdTimingService {\n private adStopTimerId: number | undefined;\n private adStartTimerId: number | undefined;\n private adFailsafeTimerId: number | undefined;\n private adRequestWatchdogId: number | undefined;\n private adRequestWatchdogToken: number | null = null;\n private adFailsafeToken: number | null = null;\n\n ptsDriftEmaMs = 0;\n expectedAdBreakDurationMs: number | undefined;\n currentAdBreakStartWallClockMs: number | undefined;\n scteAdBreakEndWallClockMs: number | undefined;\n adBreakPlayedDurationMs: number = 0;\n adBreakEpoch: number = 0;\n\n adRequestTokenCounter = 0;\n activeAdRequestToken: number | null = null;\n currentAdIndex: number = 0;\n totalAdsInBreak: number = 0;\n totalAdRequestsInBreak: number = 0;\n readonly maxTotalAdRequestsPerBreak: number = 10;\n lastAdRequestTime: number = 0;\n consecutiveFailures: number = 0;\n readonly maxConsecutiveFailures: number = 5;\n readonly minAdRequestIntervalMs: number = 3000;\n readonly backoffBaseMs: number = 1000;\n readonly maxBackoffMs: number = 15000;\n private readonly defaultMinRemainingMsToStartAd: number = 4000;\n\n failedVastUrls: Set<string> = new Set();\n temporaryFailureUrls: Map<string, number> = new Map();\n private readonly temporaryFailureCooldownMs: number = 30000;\n\n private globalConsecutiveNoFills: number = 0;\n private readonly globalNoFillThreshold: number = 3;\n private globalNoFillCooldownUntil: number = 0;\n private readonly globalNoFillBackoffBaseMs: number = 5000;\n private readonly globalNoFillBackoffMaxMs: number = 60000;\n private globalLastGamRequestTime: number = 0;\n private readonly globalMinGamIntervalMs: number = 3000;\n\n private config: StormcloudVideoPlayerConfig;\n private video: HTMLVideoElement;\n private callbacks: AdTimingCallbacks;\n\n constructor(\n config: StormcloudVideoPlayerConfig,\n video: HTMLVideoElement,\n callbacks: AdTimingCallbacks\n ) {\n this.config = config;\n this.video = video;\n this.callbacks = callbacks;\n }\n\n get debug(): boolean {\n return !!this.config.debugAdTiming;\n }\n\n // --- Ad stop timer ---\n\n scheduleAdStopCountdown(remainingMs: number): void {\n this.clearAdStopTimer();\n const ms = Math.max(0, Math.floor(remainingMs));\n if (ms === 0) {\n this.ensureAdStoppedByTimer();\n return;\n }\n this.adStopTimerId = window.setTimeout(() => {\n this.ensureAdStoppedByTimer();\n }, ms) as unknown as number;\n }\n\n clearAdStopTimer(): void {\n if (this.adStopTimerId != null) {\n clearTimeout(this.adStopTimerId);\n this.adStopTimerId = undefined;\n }\n }\n\n private ensureAdStoppedByTimer(): void {\n this.adStopTimerId = undefined;\n this.callbacks.onAdStopTimerFired();\n }\n\n // --- Ad start timer ---\n\n scheduleAdStartIn(\n delayMs: number,\n marker: Scte35Marker = { type: \"start\" } as Scte35Marker,\n cueKey?: string\n ): void {\n this.clearAdStartTimer();\n const ms = Math.max(0, Math.floor(delayMs));\n if (ms === 0) {\n this.callbacks.onAdStartTimerFired(marker, cueKey);\n return;\n }\n this.adStartTimerId = window.setTimeout(() => {\n this.callbacks.onAdStartTimerFired(marker, cueKey);\n }, ms) as unknown as number;\n }\n\n clearAdStartTimer(): void {\n if (this.adStartTimerId != null) {\n clearTimeout(this.adStartTimerId);\n this.adStartTimerId = undefined;\n }\n }\n\n // --- PTS drift ---\n\n updatePtsDrift(ptsSecondsSample: number): void {\n const sampleMs = (this.video.currentTime - ptsSecondsSample) * 1000;\n if (!Number.isFinite(sampleMs) || Math.abs(sampleMs) > 60000) return;\n const alpha = 0.1;\n this.ptsDriftEmaMs = this.ptsDriftEmaMs * (1 - alpha) + sampleMs * alpha;\n }\n\n resolveScteBreakStartWallClockMs(marker: Scte35Marker): number {\n const nowWallClockMs = Date.now();\n if (typeof marker.ptsSeconds !== \"number\") {\n return nowWallClockMs;\n }\n\n const nowMs = this.video.currentTime * 1000;\n const estimatedCurrentPtsMs = nowMs - this.ptsDriftEmaMs;\n const deltaMs = marker.ptsSeconds * 1000 - estimatedCurrentPtsMs;\n if (!Number.isFinite(deltaMs)) {\n return nowWallClockMs;\n }\n\n return nowWallClockMs + Math.floor(deltaMs);\n }\n\n // --- Duration boundary ---\n\n setAdBreakDurationBoundary(durationMs: number | undefined): void {\n this.expectedAdBreakDurationMs = durationMs;\n if (\n durationMs != null &&\n this.currentAdBreakStartWallClockMs != null\n ) {\n this.scteAdBreakEndWallClockMs =\n this.currentAdBreakStartWallClockMs + durationMs;\n } else {\n this.scteAdBreakEndWallClockMs = undefined;\n }\n }\n\n scheduleAdStopAtBreakBoundary(): void {\n if (this.expectedAdBreakDurationMs == null) {\n return;\n }\n this.scheduleAdStopCountdown(this.getWallClockRemainingAdMs());\n }\n\n // --- Duration budget ---\n\n getWallClockRemainingAdMs(): number {\n const endWallClockMs = this.getAdBreakEndWallClockMs();\n if (endWallClockMs != null) {\n return Math.max(0, endWallClockMs - Date.now());\n }\n return 0;\n }\n\n getAdBreakEndWallClockMs(): number | undefined {\n if (this.scteAdBreakEndWallClockMs != null) {\n return this.scteAdBreakEndWallClockMs;\n }\n if (\n this.expectedAdBreakDurationMs == null ||\n this.currentAdBreakStartWallClockMs == null\n ) {\n return undefined;\n }\n return this.currentAdBreakStartWallClockMs + this.expectedAdBreakDurationMs;\n }\n\n getDurationBudgetRemainingMs(): number {\n if (this.expectedAdBreakDurationMs == null) {\n return 0;\n }\n return Math.max(0, this.expectedAdBreakDurationMs - this.adBreakPlayedDurationMs);\n }\n\n getLoadedAdDurationMs(adController: AdController): number {\n const durationSec = adController.getLoadedAdDuration?.();\n if (durationSec == null || durationSec <= 0) {\n return 0;\n }\n return Math.round(durationSec * 1000);\n }\n\n adFitsRemainingBudget(durationMs: number): boolean {\n if (durationMs <= 0) {\n return true;\n }\n return durationMs <= this.getDurationBudgetRemainingMs();\n }\n\n logAdDurationDecision(\n accepted: boolean,\n durationMs: number,\n adController: AdController\n ): void {\n if (!this.debug) {\n return;\n }\n const remainingBudget = this.getDurationBudgetRemainingMs();\n const adId = adController.getLoadedAdId?.() ?? \"unknown\";\n if (accepted) {\n console.log(\n `[AD-DURATION] Accepted ad id=${adId}, duration=${durationMs}ms, budget remaining after play=${Math.max(0, remainingBudget - durationMs)}ms`\n );\n } else {\n console.log(\n `[AD-DURATION] Rejected ad id=${adId}, duration=${durationMs}ms exceeds remaining budget=${remainingBudget}ms — requesting another ad`\n );\n }\n }\n\n recordPlayedAdDuration(adController: AdController): void {\n const durationMs = this.getLoadedAdDurationMs(adController);\n if (durationMs <= 0) {\n return;\n }\n this.adBreakPlayedDurationMs += durationMs;\n if (this.debug) {\n console.log(\n `[AD-DURATION] Played ${durationMs}ms — total played=${this.adBreakPlayedDurationMs}ms / ${this.expectedAdBreakDurationMs ?? \"?\"}ms`\n );\n }\n }\n\n ensureLoadedAdFitsBudget(adController: AdController): boolean {\n const durationMs = this.getLoadedAdDurationMs(adController);\n const fits = this.adFitsRemainingBudget(durationMs);\n this.logAdDurationDecision(fits, durationMs, adController);\n return fits;\n }\n\n rejectLoadedAdForDuration(adController: AdController): void {\n try {\n adController.destroy();\n } catch {}\n }\n\n markAdStarted(): void {\n this.currentAdIndex++;\n this.totalAdsInBreak = this.currentAdIndex;\n this.totalAdRequestsInBreak++;\n this.lastAdRequestTime = Date.now();\n }\n\n notePodAdStarted(): void {\n this.currentAdIndex++;\n this.totalAdsInBreak = this.currentAdIndex;\n }\n\n getRemainingAdMs(): number {\n const wallClockRemaining = this.getWallClockRemainingAdMs();\n const budgetRemaining = this.getDurationBudgetRemainingMs();\n if (this.expectedAdBreakDurationMs == null) {\n return wallClockRemaining;\n }\n return Math.min(wallClockRemaining, budgetRemaining);\n }\n\n getMinRemainingMsToStartAd(): number {\n const configured = this.config.minRemainingMsToStartAd;\n if (typeof configured === \"number\" && configured >= 0) {\n return configured;\n }\n return this.defaultMinRemainingMsToStartAd;\n }\n\n hasTimeToStartAnotherAd(): boolean {\n const minRemaining = this.getMinRemainingMsToStartAd();\n return (\n this.getWallClockRemainingAdMs() > minRemaining &&\n this.getDurationBudgetRemainingMs() > minRemaining\n );\n }\n\n // --- Circuit breaker ---\n\n isTemporaryAdError(error: Error): boolean {\n const message = error?.message?.toLowerCase() || \"\";\n\n if (message.includes(\"no ads available\") || message.includes(\"no fill\") || message.includes(\"nofill\")) {\n return true;\n }\n if (message.includes(\"timeout\")) {\n return true;\n }\n if (message.includes(\"rate limit\") || message.includes(\"too many requests\")) {\n return true;\n }\n if (message.includes(\"ad playback error\")) {\n return true;\n }\n return false;\n }\n\n isUrlInCooldown(vastTagUrl: string): boolean {\n const failureTime = this.temporaryFailureUrls.get(vastTagUrl);\n if (failureTime == null) {\n return false;\n }\n\n const elapsed = Date.now() - failureTime;\n if (elapsed >= this.temporaryFailureCooldownMs) {\n this.temporaryFailureUrls.delete(vastTagUrl);\n return false;\n }\n\n return true;\n }\n\n cleanupTemporaryFailures(): void {\n const now = Date.now();\n for (const [url, timestamp] of this.temporaryFailureUrls) {\n if (now - timestamp >= this.temporaryFailureCooldownMs) {\n this.temporaryFailureUrls.delete(url);\n }\n }\n }\n\n isGamInCooldown(): boolean {\n return Date.now() < this.globalNoFillCooldownUntil;\n }\n\n recordGamNoFill(): void {\n this.globalConsecutiveNoFills++;\n\n if (this.globalConsecutiveNoFills >= this.globalNoFillThreshold) {\n const exponent = this.globalConsecutiveNoFills - this.globalNoFillThreshold;\n const backoff = Math.min(\n this.globalNoFillBackoffBaseMs * Math.pow(2, exponent),\n this.globalNoFillBackoffMaxMs\n );\n this.globalNoFillCooldownUntil = Date.now() + backoff;\n\n if (this.debug) {\n console.log(\n `[CIRCUIT-BREAKER] GAM cooldown activated: ${backoff}ms (${this.globalConsecutiveNoFills} consecutive no-fills)`\n );\n }\n }\n }\n\n resetGamNoFillCounter(): void {\n if (this.globalConsecutiveNoFills > 0 && this.debug) {\n console.log(\n `[CIRCUIT-BREAKER] Resetting no-fill counter (was ${this.globalConsecutiveNoFills})`\n );\n }\n this.globalConsecutiveNoFills = 0;\n this.globalNoFillCooldownUntil = 0;\n }\n\n async enforceGlobalRateLimit(): Promise<void> {\n const now = Date.now();\n const elapsed = now - this.globalLastGamRequestTime;\n if (elapsed < this.globalMinGamIntervalMs) {\n const waitMs = this.globalMinGamIntervalMs - elapsed;\n if (this.debug) {\n console.log(`[RATE-LIMIT] Waiting ${waitMs}ms before next GAM request`);\n }\n await new Promise(resolve => setTimeout(resolve, waitMs));\n }\n this.globalLastGamRequestTime = Date.now();\n }\n\n // --- Watchdog ---\n\n startAdRequestWatchdog(token: number): void {\n this.clearAdRequestWatchdog();\n\n const timeoutMs = this.config.adFailsafeTimeoutMs ?? 10000;\n this.adRequestWatchdogToken = token;\n this.adRequestWatchdogId = window.setTimeout(() => {\n if (this.adRequestWatchdogToken !== token) {\n return;\n }\n\n this.adRequestWatchdogId = undefined;\n this.adRequestWatchdogToken = null;\n if (this.activeAdRequestToken === token) {\n this.activeAdRequestToken = null;\n }\n\n this.logAdState(\"ad_request_timeout\", { token, timeoutMs });\n this.callbacks.onWatchdogTimeout();\n }, timeoutMs) as unknown as number;\n\n this.logAdState(\"ad_request_watchdog_started\", { token, timeoutMs });\n }\n\n clearAdRequestWatchdog(): void {\n if (this.adRequestWatchdogId != null) {\n clearTimeout(this.adRequestWatchdogId);\n this.adRequestWatchdogId = undefined;\n }\n\n if (this.adRequestWatchdogToken != null) {\n this.logAdState(\"ad_request_watchdog_cleared\", {\n token: this.adRequestWatchdogToken,\n });\n this.adRequestWatchdogToken = null;\n }\n }\n\n // --- Failsafe ---\n\n startAdFailsafeTimer(token: number): void {\n this.clearAdFailsafeTimer();\n\n const failsafeMs = this.config.adFailsafeTimeoutMs ?? 10000;\n this.adFailsafeToken = token;\n\n this.adFailsafeTimerId = window.setTimeout(() => {\n if (this.adFailsafeToken !== token) {\n return;\n }\n\n this.adFailsafeTimerId = undefined;\n this.adFailsafeToken = null;\n\n if (this.activeAdRequestToken === token) {\n this.activeAdRequestToken = null;\n }\n\n this.logAdState(\"ad_failsafe_triggered\", {\n token,\n failsafeMs,\n videoPaused: this.video.paused,\n });\n\n this.callbacks.onFailsafeTimeout();\n }, failsafeMs) as unknown as number;\n\n this.logAdState(\"ad_failsafe_started\", { token, failsafeMs });\n }\n\n clearAdFailsafeTimer(): void {\n if (this.adFailsafeTimerId != null) {\n clearTimeout(this.adFailsafeTimerId);\n this.logAdState(\"ad_failsafe_cleared\", { token: this.adFailsafeToken });\n this.adFailsafeTimerId = undefined;\n }\n\n this.adFailsafeToken = null;\n }\n\n logAdState(event: string, extra: Record<string, unknown> = {}): void {\n if (!this.debug) {\n return;\n }\n\n const { inAdBreak, showAds, adPlaying } = this.callbacks.getAdState();\n\n console.log(\"[StormcloudVideoPlayer][AdState]\", {\n event,\n timestamp: new Date().toISOString(),\n showAds,\n adPlaying,\n inAdBreak,\n activeAdRequestToken: this.activeAdRequestToken,\n ...extra,\n });\n }\n\n // --- Reset for ad break end ---\n\n resetForBreakEnd(): void {\n this.clearAdStopTimer();\n this.clearAdStartTimer();\n this.clearAdRequestWatchdog();\n this.clearAdFailsafeTimer();\n this.activeAdRequestToken = null;\n this.expectedAdBreakDurationMs = undefined;\n this.currentAdBreakStartWallClockMs = undefined;\n this.scteAdBreakEndWallClockMs = undefined;\n this.adBreakPlayedDurationMs = 0;\n this.currentAdIndex = 0;\n this.totalAdsInBreak = 0;\n this.consecutiveFailures = 0;\n this.globalConsecutiveNoFills = 0;\n this.adBreakEpoch++;\n }\n\n destroy(): void {\n this.clearAdStopTimer();\n this.clearAdStartTimer();\n this.clearAdFailsafeTimer();\n this.clearAdRequestWatchdog();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["d:\\project\\stormcloud-vp\\lib\\player\\AdTimingService.cjs"],"names":["__defProp","Object","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","getOwnPropertyNames","__hasOwnProp","prototype","hasOwnProperty","__export","target","all","name","get","enumerable","__copyProps","to","from","except","desc","key","call","__toCommonJS","mod","value","AdTimingService_exports","AdTimingService","module","exports","config","video","callbacks","adRequestWatchdogToken","adFailsafeToken","ptsDriftEmaMs","adBreakPlayedDurationMs","adBreakEpoch","adRequestTokenCounter","activeAdRequestToken","currentAdIndex","totalAdsInBreak","totalAdRequestsInBreak","maxTotalAdRequestsPerBreak","lastAdRequestTime","consecutiveFailures","maxConsecutiveFailures","minAdRequestIntervalMs","backoffBaseMs","maxBackoffMs","defaultMinRemainingMsToStartAd","failedVastUrls","Set","temporaryFailureUrls","Map","temporaryFailureCooldownMs","globalConsecutiveNoFills","globalNoFillThreshold","globalNoFillCooldownUntil","globalNoFillBackoffBaseMs","globalNoFillBackoffMaxMs","globalLastGamRequestTime","globalMinGamIntervalMs","debug","debugAdTiming","scheduleAdStopCountdown","remainingMs","clearAdStopTimer","ms","Math","max","floor","ensureAdStoppedByTimer","adStopTimerId","window","setTimeout","clearTimeout","onAdStopTimerFired","scheduleAdStartIn","delayMs","marker","type","cueKey","clearAdStartTimer","onAdStartTimerFired","adStartTimerId","updatePtsDrift","ptsSecondsSample","sampleMs","currentTime","Number","isFinite","abs","alpha","resolveScteBreakStartWallClockMs","nowWallClockMs","Date","now","ptsSeconds","nowMs","estimatedCurrentPtsMs","deltaMs","setAdBreakDurationBoundary","durationMs","expectedAdBreakDurationMs","currentAdBreakStartWallClockMs","scteAdBreakEndWallClockMs","scheduleAdStopAtBreakBoundary","getWallClockRemainingAdMs","endWallClockMs","getAdBreakEndWallClockMs","getDurationBudgetRemainingMs","getLoadedAdDurationMs","adController","durationSec","getLoadedAdDuration","round","adFitsRemainingBudget","logAdDurationDecision","accepted","remainingBudget","adId","getLoadedAdId","console","log","recordPlayedAdDuration","ensureLoadedAdFitsBudget","fits","rejectLoadedAdForDuration","destroy","markAdStarted","notePodAdStarted","getRemainingAdMs","wallClockRemaining","budgetRemaining","min","getMinRemainingMsToStartAd","configured","minRemainingMsToStartAd","hasTimeToStartAnotherAd","minRemaining","isTemporaryAdError","error","message","toLowerCase","includes","isUrlInCooldown","vastTagUrl","failureTime","elapsed","delete","cleanupTemporaryFailures","url","timestamp","isGamInCooldown","recordGamNoFill","exponent","backoff","pow","resetGamNoFillCounter","enforceGlobalRateLimit","waitMs","Promise","resolve","startAdRequestWatchdog","token","clearAdRequestWatchdog","timeoutMs","adFailsafeTimeoutMs","adRequestWatchdogId","logAdState","onWatchdogTimeout","startAdFailsafeTimer","clearAdFailsafeTimer","failsafeMs","adFailsafeTimerId","videoPaused","paused","onFailsafeTimeout","event","extra","getAdState","inAdBreak","showAds","adPlaying","toISOString","resetForBreakEnd"],"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/AdTimingService.ts\nvar AdTimingService_exports = {};\n__export(AdTimingService_exports, {\n AdTimingService: () => AdTimingService\n});\nmodule.exports = __toCommonJS(AdTimingService_exports);\nvar AdTimingService = class {\n constructor(config, video, callbacks) {\n this.adRequestWatchdogToken = null;\n this.adFailsafeToken = null;\n this.ptsDriftEmaMs = 0;\n this.adBreakPlayedDurationMs = 0;\n this.adBreakEpoch = 0;\n this.adRequestTokenCounter = 0;\n this.activeAdRequestToken = null;\n this.currentAdIndex = 0;\n this.totalAdsInBreak = 0;\n this.totalAdRequestsInBreak = 0;\n this.maxTotalAdRequestsPerBreak = 10;\n this.lastAdRequestTime = 0;\n this.consecutiveFailures = 0;\n this.maxConsecutiveFailures = 5;\n this.minAdRequestIntervalMs = 3e3;\n this.backoffBaseMs = 1e3;\n this.maxBackoffMs = 15e3;\n this.defaultMinRemainingMsToStartAd = 4e3;\n this.failedVastUrls = /* @__PURE__ */ new Set();\n this.temporaryFailureUrls = /* @__PURE__ */ new Map();\n this.temporaryFailureCooldownMs = 3e4;\n this.globalConsecutiveNoFills = 0;\n this.globalNoFillThreshold = 3;\n this.globalNoFillCooldownUntil = 0;\n this.globalNoFillBackoffBaseMs = 5e3;\n this.globalNoFillBackoffMaxMs = 6e4;\n this.globalLastGamRequestTime = 0;\n this.globalMinGamIntervalMs = 3e3;\n this.config = config;\n this.video = video;\n this.callbacks = callbacks;\n }\n get debug() {\n return !!this.config.debugAdTiming;\n }\n // --- Ad stop timer ---\n scheduleAdStopCountdown(remainingMs) {\n this.clearAdStopTimer();\n const ms = Math.max(0, Math.floor(remainingMs));\n if (ms === 0) {\n this.ensureAdStoppedByTimer();\n return;\n }\n this.adStopTimerId = window.setTimeout(() => {\n this.ensureAdStoppedByTimer();\n }, ms);\n }\n clearAdStopTimer() {\n if (this.adStopTimerId != null) {\n clearTimeout(this.adStopTimerId);\n this.adStopTimerId = void 0;\n }\n }\n ensureAdStoppedByTimer() {\n this.adStopTimerId = void 0;\n this.callbacks.onAdStopTimerFired();\n }\n // --- Ad start timer ---\n scheduleAdStartIn(delayMs, marker = { type: \"start\" }, cueKey) {\n this.clearAdStartTimer();\n const ms = Math.max(0, Math.floor(delayMs));\n if (ms === 0) {\n this.callbacks.onAdStartTimerFired(marker, cueKey);\n return;\n }\n this.adStartTimerId = window.setTimeout(() => {\n this.callbacks.onAdStartTimerFired(marker, cueKey);\n }, ms);\n }\n clearAdStartTimer() {\n if (this.adStartTimerId != null) {\n clearTimeout(this.adStartTimerId);\n this.adStartTimerId = void 0;\n }\n }\n // --- PTS drift ---\n updatePtsDrift(ptsSecondsSample) {\n const sampleMs = (this.video.currentTime - ptsSecondsSample) * 1e3;\n if (!Number.isFinite(sampleMs) || Math.abs(sampleMs) > 6e4) return;\n const alpha = 0.1;\n this.ptsDriftEmaMs = this.ptsDriftEmaMs * (1 - alpha) + sampleMs * alpha;\n }\n resolveScteBreakStartWallClockMs(marker) {\n const nowWallClockMs = Date.now();\n if (typeof marker.ptsSeconds !== \"number\") {\n return nowWallClockMs;\n }\n const nowMs = this.video.currentTime * 1e3;\n const estimatedCurrentPtsMs = nowMs - this.ptsDriftEmaMs;\n const deltaMs = marker.ptsSeconds * 1e3 - estimatedCurrentPtsMs;\n if (!Number.isFinite(deltaMs)) {\n return nowWallClockMs;\n }\n return nowWallClockMs + Math.floor(deltaMs);\n }\n // --- Duration boundary ---\n setAdBreakDurationBoundary(durationMs) {\n this.expectedAdBreakDurationMs = durationMs;\n if (durationMs != null && this.currentAdBreakStartWallClockMs != null) {\n this.scteAdBreakEndWallClockMs = this.currentAdBreakStartWallClockMs + durationMs;\n } else {\n this.scteAdBreakEndWallClockMs = void 0;\n }\n }\n scheduleAdStopAtBreakBoundary() {\n if (this.expectedAdBreakDurationMs == null) {\n return;\n }\n this.scheduleAdStopCountdown(this.getWallClockRemainingAdMs());\n }\n // --- Duration budget ---\n getWallClockRemainingAdMs() {\n const endWallClockMs = this.getAdBreakEndWallClockMs();\n if (endWallClockMs != null) {\n return Math.max(0, endWallClockMs - Date.now());\n }\n return 0;\n }\n getAdBreakEndWallClockMs() {\n if (this.scteAdBreakEndWallClockMs != null) {\n return this.scteAdBreakEndWallClockMs;\n }\n if (this.expectedAdBreakDurationMs == null || this.currentAdBreakStartWallClockMs == null) {\n return void 0;\n }\n return this.currentAdBreakStartWallClockMs + this.expectedAdBreakDurationMs;\n }\n getDurationBudgetRemainingMs() {\n if (this.expectedAdBreakDurationMs == null) {\n return 0;\n }\n return Math.max(0, this.expectedAdBreakDurationMs - this.adBreakPlayedDurationMs);\n }\n getLoadedAdDurationMs(adController) {\n const durationSec = adController.getLoadedAdDuration?.();\n if (durationSec == null || durationSec <= 0) {\n return 0;\n }\n return Math.round(durationSec * 1e3);\n }\n adFitsRemainingBudget(durationMs) {\n if (durationMs <= 0) {\n return true;\n }\n return durationMs <= this.getDurationBudgetRemainingMs();\n }\n logAdDurationDecision(accepted, durationMs, adController) {\n if (!this.debug) {\n return;\n }\n const remainingBudget = this.getDurationBudgetRemainingMs();\n const adId = adController.getLoadedAdId?.() ?? \"unknown\";\n if (accepted) {\n console.log(\n `[AD-DURATION] Accepted ad id=${adId}, duration=${durationMs}ms, budget remaining after play=${Math.max(0, remainingBudget - durationMs)}ms`\n );\n } else {\n console.log(\n `[AD-DURATION] Rejected ad id=${adId}, duration=${durationMs}ms exceeds remaining budget=${remainingBudget}ms \\u2014 requesting another ad`\n );\n }\n }\n recordPlayedAdDuration(adController) {\n const durationMs = this.getLoadedAdDurationMs(adController);\n if (durationMs <= 0) {\n return;\n }\n this.adBreakPlayedDurationMs += durationMs;\n if (this.debug) {\n console.log(\n `[AD-DURATION] Played ${durationMs}ms \\u2014 total played=${this.adBreakPlayedDurationMs}ms / ${this.expectedAdBreakDurationMs ?? \"?\"}ms`\n );\n }\n }\n ensureLoadedAdFitsBudget(adController) {\n const durationMs = this.getLoadedAdDurationMs(adController);\n const fits = this.adFitsRemainingBudget(durationMs);\n this.logAdDurationDecision(fits, durationMs, adController);\n return fits;\n }\n rejectLoadedAdForDuration(adController) {\n try {\n adController.destroy();\n } catch {\n }\n }\n markAdStarted() {\n this.currentAdIndex++;\n this.totalAdsInBreak = this.currentAdIndex;\n this.totalAdRequestsInBreak++;\n this.lastAdRequestTime = Date.now();\n }\n notePodAdStarted() {\n this.currentAdIndex++;\n this.totalAdsInBreak = this.currentAdIndex;\n }\n getRemainingAdMs() {\n const wallClockRemaining = this.getWallClockRemainingAdMs();\n const budgetRemaining = this.getDurationBudgetRemainingMs();\n if (this.expectedAdBreakDurationMs == null) {\n return wallClockRemaining;\n }\n return Math.min(wallClockRemaining, budgetRemaining);\n }\n getMinRemainingMsToStartAd() {\n const configured = this.config.minRemainingMsToStartAd;\n if (typeof configured === \"number\" && configured >= 0) {\n return configured;\n }\n return this.defaultMinRemainingMsToStartAd;\n }\n hasTimeToStartAnotherAd() {\n const minRemaining = this.getMinRemainingMsToStartAd();\n return this.getWallClockRemainingAdMs() > minRemaining && this.getDurationBudgetRemainingMs() > minRemaining;\n }\n // --- Circuit breaker ---\n isTemporaryAdError(error) {\n const message = error?.message?.toLowerCase() || \"\";\n if (message.includes(\"no ads available\") || message.includes(\"no fill\") || message.includes(\"nofill\")) {\n return true;\n }\n if (message.includes(\"timeout\")) {\n return true;\n }\n if (message.includes(\"rate limit\") || message.includes(\"too many requests\")) {\n return true;\n }\n if (message.includes(\"ad playback error\")) {\n return true;\n }\n return false;\n }\n isUrlInCooldown(vastTagUrl) {\n const failureTime = this.temporaryFailureUrls.get(vastTagUrl);\n if (failureTime == null) {\n return false;\n }\n const elapsed = Date.now() - failureTime;\n if (elapsed >= this.temporaryFailureCooldownMs) {\n this.temporaryFailureUrls.delete(vastTagUrl);\n return false;\n }\n return true;\n }\n cleanupTemporaryFailures() {\n const now = Date.now();\n for (const [url, timestamp] of this.temporaryFailureUrls) {\n if (now - timestamp >= this.temporaryFailureCooldownMs) {\n this.temporaryFailureUrls.delete(url);\n }\n }\n }\n isGamInCooldown() {\n return Date.now() < this.globalNoFillCooldownUntil;\n }\n recordGamNoFill() {\n this.globalConsecutiveNoFills++;\n if (this.globalConsecutiveNoFills >= this.globalNoFillThreshold) {\n const exponent = this.globalConsecutiveNoFills - this.globalNoFillThreshold;\n const backoff = Math.min(\n this.globalNoFillBackoffBaseMs * Math.pow(2, exponent),\n this.globalNoFillBackoffMaxMs\n );\n this.globalNoFillCooldownUntil = Date.now() + backoff;\n if (this.debug) {\n console.log(\n `[CIRCUIT-BREAKER] GAM cooldown activated: ${backoff}ms (${this.globalConsecutiveNoFills} consecutive no-fills)`\n );\n }\n }\n }\n resetGamNoFillCounter() {\n if (this.globalConsecutiveNoFills > 0 && this.debug) {\n console.log(\n `[CIRCUIT-BREAKER] Resetting no-fill counter (was ${this.globalConsecutiveNoFills})`\n );\n }\n this.globalConsecutiveNoFills = 0;\n this.globalNoFillCooldownUntil = 0;\n }\n async enforceGlobalRateLimit() {\n const now = Date.now();\n const elapsed = now - this.globalLastGamRequestTime;\n if (elapsed < this.globalMinGamIntervalMs) {\n const waitMs = this.globalMinGamIntervalMs - elapsed;\n if (this.debug) {\n console.log(`[RATE-LIMIT] Waiting ${waitMs}ms before next GAM request`);\n }\n await new Promise((resolve) => setTimeout(resolve, waitMs));\n }\n this.globalLastGamRequestTime = Date.now();\n }\n // --- Watchdog ---\n startAdRequestWatchdog(token) {\n this.clearAdRequestWatchdog();\n const timeoutMs = this.config.adFailsafeTimeoutMs ?? 1e4;\n this.adRequestWatchdogToken = token;\n this.adRequestWatchdogId = window.setTimeout(() => {\n if (this.adRequestWatchdogToken !== token) {\n return;\n }\n this.adRequestWatchdogId = void 0;\n this.adRequestWatchdogToken = null;\n if (this.activeAdRequestToken === token) {\n this.activeAdRequestToken = null;\n }\n this.logAdState(\"ad_request_timeout\", { token, timeoutMs });\n this.callbacks.onWatchdogTimeout();\n }, timeoutMs);\n this.logAdState(\"ad_request_watchdog_started\", { token, timeoutMs });\n }\n clearAdRequestWatchdog() {\n if (this.adRequestWatchdogId != null) {\n clearTimeout(this.adRequestWatchdogId);\n this.adRequestWatchdogId = void 0;\n }\n if (this.adRequestWatchdogToken != null) {\n this.logAdState(\"ad_request_watchdog_cleared\", {\n token: this.adRequestWatchdogToken\n });\n this.adRequestWatchdogToken = null;\n }\n }\n // --- Failsafe ---\n startAdFailsafeTimer(token) {\n this.clearAdFailsafeTimer();\n const failsafeMs = this.config.adFailsafeTimeoutMs ?? 1e4;\n this.adFailsafeToken = token;\n this.adFailsafeTimerId = window.setTimeout(() => {\n if (this.adFailsafeToken !== token) {\n return;\n }\n this.adFailsafeTimerId = void 0;\n this.adFailsafeToken = null;\n if (this.activeAdRequestToken === token) {\n this.activeAdRequestToken = null;\n }\n this.logAdState(\"ad_failsafe_triggered\", {\n token,\n failsafeMs,\n videoPaused: this.video.paused\n });\n this.callbacks.onFailsafeTimeout();\n }, failsafeMs);\n this.logAdState(\"ad_failsafe_started\", { token, failsafeMs });\n }\n clearAdFailsafeTimer() {\n if (this.adFailsafeTimerId != null) {\n clearTimeout(this.adFailsafeTimerId);\n this.logAdState(\"ad_failsafe_cleared\", { token: this.adFailsafeToken });\n this.adFailsafeTimerId = void 0;\n }\n this.adFailsafeToken = null;\n }\n logAdState(event, extra = {}) {\n if (!this.debug) {\n return;\n }\n const { inAdBreak, showAds, adPlaying } = this.callbacks.getAdState();\n console.log(\"[StormcloudVideoPlayer][AdState]\", {\n event,\n timestamp: (/* @__PURE__ */ new Date()).toISOString(),\n showAds,\n adPlaying,\n inAdBreak,\n activeAdRequestToken: this.activeAdRequestToken,\n ...extra\n });\n }\n // --- Reset for ad break end ---\n resetForBreakEnd() {\n this.clearAdStopTimer();\n this.clearAdStartTimer();\n this.clearAdRequestWatchdog();\n this.clearAdFailsafeTimer();\n this.activeAdRequestToken = null;\n this.expectedAdBreakDurationMs = void 0;\n this.currentAdBreakStartWallClockMs = void 0;\n this.scteAdBreakEndWallClockMs = void 0;\n this.adBreakPlayedDurationMs = 0;\n this.currentAdIndex = 0;\n this.totalAdsInBreak = 0;\n this.consecutiveFailures = 0;\n this.globalConsecutiveNoFills = 0;\n this.adBreakEpoch++;\n }\n destroy() {\n this.clearAdStopTimer();\n this.clearAdStartTimer();\n this.clearAdFailsafeTimer();\n this.clearAdRequestWatchdog();\n }\n};\n// Annotate the CommonJS export names for ESM import in node:\n0 && (module.exports = {\n AdTimingService\n});\n"]}
|