stormcloud-video-player 0.7.12 → 0.7.13

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/ubuntu24-new/Dev/stormcloud-vp/lib/player/StormcloudVideoPlayer.cjs","../../src/player/StormcloudVideoPlayer.ts","../../src/sdk/vastParser.ts","../../src/sdk/adstormPlayer.ts","../../src/utils/tracking.ts","../../src/utils/polyfills.ts","../../src/utils/browserCompat.ts"],"names":["__create","Object","create","__defProp","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","getOwnPropertyNames","__getProtoOf","getPrototypeOf","__hasOwnProp","prototype","hasOwnProperty","__export","target","all","name","get","enumerable","__copyProps","to","from","except","desc","key","call","__toESM","mod","isNodeMode","__esModule","value","__toCommonJS","StormcloudVideoPlayer_exports","StormcloudVideoPlayer","exports","import_hls","require","firePixelWithRetry","url","retries","delayMs","logPrefix","attempt","fetch","method","mode","cache","keepalive","Promise","r","setTimeout","Math","pow","console","warn","fireTrackingPixels","urls","sessionId","length","forEach","trackingUrl","includes","catch","img","Image","onerror","src","log","error","SUPPORTED_VIDEO_EXTENSIONS","UNSUPPORTED_VIDEO_EXTENSIONS","REQUEST_TIMEOUT_MS","REQUEST_MAX_RETRIES","REQUEST_RETRY_BACKOFF_MS","AD_LAYER_Z_INDEX","COUNTDOWN_Z_INDEX","STALL_TIMEOUT_MS","pathname","replace","getFileExtension","URL","lastDot","slice","toLowerCase","lastIndexOf","ext","split","isUnsupportedFormat","indexOf","replaceFlvExtension","isSupportedFormat","mimeType","adCountdownEl","createAdStormPlayer","licenseKey","contentVideo","options","debug","originalMutedState","originalVolume","max","min","volume","listeners","Map","adContainerEl","currentAd","tornDown","continueLiveStreamDuringAds","adStallTimerId","adCountdownTimerId","adHideTimerId","lastCountdownSecond","adListenersBound","parentPositionOverridden","adHandlers","timeupdate","adVideoElement","destroyed","progress","currentTime","duration","trackingFired","firstQuartile","trackingUrls","midpoint","thirdQuartile","updateAdCountdown","playing","clearAdStallTimer","start","startAdCountdown","ended","complete","handleAdComplete","impression","e","handleAdError","waiting","adPlaying","volumechange","muted","mute","unmute","pause","play","resume","set","event","preloadSlots","args","emit","payload","Array","fn","addEventListener","clearTimeout","clearAdCountdownTimer","clearInterval","remainingSec","ceil","textContent","durationSec","currentTimeSec","setInterval","generateSessionId","Date","now","random","toString","bindAdEventListeners","unbindAdEventListeners","removeEventListener","teardownCurrentPlayback","removeAttribute","load","buildVastUrl","durationSeconds","baseUrl","parseVastXml","xmlString","ads","parser","DOMParser","xmlDoc","parseFromString","parserError","querySelector","adElements","querySelectorAll","adElement","adId","getAttribute","title","durationText","durationParts","parseInt","mediaFileElements","parseFloat","mediaFiles","mf","type","trim","width","height","bitrate","originalUrl","push","el","eventKey","clickThrough","id","selectBestMediaFile","mp4Files","filter","candidates","targetWidth","videoWidth","targetHeight","videoHeight","sort","a","b","diffA","abs","diffB","createAdVideoElement","video","document","createElement","style","position","left","top","objectFit","backgroundColor","zIndex","playsInline","preload","setAdPlayingFlag","isPlaying","dataset","stormcloudAdPlaying","setupAdEventListeners","opacity","display","pointerEvents","visibility","fetchVastOnce","vastUrl","controller","timeoutId","requestInit","response","xmlText","AbortController","abort","credentials","headers","Accept","referrerPolicy","signal","ok","Error","status","statusText","text","fetchVast","lastError","delay","resolve","assignCurrentAd","getDurationSecondsFromContext","requestContext","ctx","remainingBreakSec","breakDurationSec","Number","isNaN","requestAdFromApi","ad","initialize","parent","parentElement","computed","window","getComputedStyle","countdown","container","right","bottom","alignItems","justifyContent","transition","isolation","padding","borderRadius","fontFamily","fontSize","appendChild","requestAds","parsed","reject","mediaFile","offsetHeight","stop","paused","destroy","remove","removeChild","clear","updateOptions","opts","playAd","message","preloadAd","arg1","arg2","token","playPreloaded","slot","delete","hasPreloaded","has","cancelPreload","isAdPlaying","resize","on","listener","Set","add","off","updateOriginalMutedState","nextVolume","getOriginalMutedState","getOriginalVolume","setAdVolume","getAdVolume","showPlaceholder","background","color","lineHeight","hidePlaceholder","cachedBrowserId","getClientInfo","screen","navigator","ua","userAgent","platform","vendor","maxTouchPoints","memory","deviceMemory","hardwareConcurrency","screenInfo","availWidth","availHeight","orientation","pixelDepth","deviceType","brand","os","model","isSmartTV","isAndroid","isWebView","isWebApp","webosMatch","match","tizenMatch","tvMatch","test","androidModelMatch","outerHeight","outerWidth","matchMedia","matches","standalone","angle","location","substring","domain","hostname","origin","path","language","cookieEnabled","doNotTrack","referrer","visibilityState","getBrowserID","clientInfo","fingerprintString","encodedData","utf8","buffer","i","hashBuffer","hashArray","hashHex","hash","char","fallbackHash","timestamp","JSON","stringify","crypto","subtle","digest","Uint8Array","TextEncoder","encode","unescape","encodeURIComponent","charCodeAt","map","padStart","padEnd","TRACK_URL","sendTrackRequest","body","json","sendInitialTracking","browserId","trackingData","sendAdLoadedTracking","adLoadedInfo","sendAdImpressionTracking","adImpressionInfo","sendHeartbeat","heartbeatData","toISOString","polyfillURLSearchParams","URLSearchParams","URLSearchParamsPolyfill","init","params","parseQueryString","append","query","cleanQuery","startsWith","param","decodedKey","safeDecodeURIComponent","decodedValue","str","decodeURIComponent","values","String","getAll","callback","parts","join","polyfillTextEncoder","TextEncoderPolyfill","encoding","charcode","polyfillPromiseFinally","finally","constructor","then","reason","polyfillObjectAssign","assign","sources","TypeError","nextSource","nextKey","polyfillArrayFrom","arrayLike","mapFn","thisArg","items","len","result","search","pos","polyfillStringEndsWith","endsWith","polyfillStringIncludes","initializePolyfills","polyfillStringStartsWith","getChromeVersion","getWebKitVersion","userAgentData","getPlatform","version","majorVersion","isLegacyTV","supportsIMA","supportsModernJS","recommendedAdPlayer","webOSVersion","tizenVersion","chromeVersionNum","chromeVersion","webkitVersion","imaSupport","supportsGoogleIMA","overrides","browser","logBrowserInfo","allowNativeHls","DEBUG_HISTORY_LIMIT","pendingNextAdBids","continuousFetchLoopPromise","attached","inAdBreak","processedAdInsertionUpdatedAt","currentAdIndex","adPodQueue","lastHeartbeatTime","totalAdsInBreak","showAds","nativeHlsMode","videoSrcProtection","bufferedSegmentsCount","shouldAutoplayAfterBuffering","hasInitialBufferCompleted","activeAdRequestToken","adRequestWatchdogToken","adFailsafeToken","continuousFetchingActive","isInAdTransition","maxPlaceholderDurationMs","isShowingPlaceholder","lastAdInsertionPoint","totalAdRequestsInBreak","maxTotalAdRequestsPerBreak","pendingAdBreak","savedMutedStateBeforeAd","consecutiveFailures","maxConsecutiveFailures","lastAdRequestTime","minAdRequestIntervalMs","backoffBaseMs","maxBackoffMs","MIN_AD_REMAINING_MS","adRequestTimeoutMs","adRequestMaxRetries","adRequestRetryBackoffMs","preloadedTokens","debugLogEntries","adInsertionDebugHistory","browserOverrides","getBrowserConfigOverrides","config","videoElement","adTransitionGapMs","debugAdTiming","browserForAdLayer","detectBrowser","isSinglePipeline","singlePipelineMode","adLayer","shouldContinueLiveStreamDuringAds","adRequest","context","disableAds","bidder","cpm","impId","creativeId","currency","attach","initializeTracking","shouldUseNativeHls","isLive","isLiveStream","adBehavior","mainHlsInstance","autoplay","hls","Hls","enableWorker","backBufferLength","liveDurationInfinity","lowLatencyMode","maxLiveSyncPlaybackRate","liveSyncDuration","maxBufferSize","maxBufferHole","highBufferWatchdogPeriod","nudgeOffset","nudgeMaxRetry","startPosition","Events","MEDIA_ATTACHED","loadSource","MANIFEST_PARSED","_","data","levels","some","level","minSegments","minSegmentsBeforePlay","projectId","startAdInsertionPolling","LEVEL_LOADED","err","FRAG_CHANGED","_evt","frag","updated_at","segmentName","segment_ts_name","fragmentMatchesSegment","offsetMs","offset_seconds","pushAdInsertionDebug","offsetSeconds","detail","sn","clearAdInsertionOffsetTimer","adInsertionOffsetTimerId","handleAdStart","FRAG_PARSING_USERDATA","samples","sample","bytes","isSCTE35","segName","relurl","ERROR","fatal","ErrorTypes","NETWORK_ERROR","startLoad","MEDIA_ERROR","recoverMediaError","attachMedia","getAdSource","attachAdLayerEventListeners","source","adIndex","errorPayload","errorMessage","errorCode","code","vastErrorCode","cause","innerError","causeMessage","pushDebugLog","handleAdFailure","clearAdFailsafeTimer","clearAdRequestWatchdog","disableFiller","expectedAdBreakDurationMs","adStopTimerId","scheduleAdStopCountdown","getRemainingAdMs","stopFillerBreakTimer","hidePlaceholderLayer","remaining","breakMuted","breakVolume","syncMainContentAudioWhenVisible","shift","remainingNow","showPlaceholderLayer","bids","freshBids","remainingFinal","startContinuousFetchLoop","handleAdPodComplete","ensureFillerVideo","filler","loop","fillerVideo","readyState","startFillerBreakTimer","durationMs","fillerBreakTimerId","timeUpdateHandler","onTimeUpdate","emptiedHandler","wasPaused","streamType","getStreamType","canNative","canPlayType","heartbeatInterval","sendHeartbeatIfNeeded","getCurrentAdIndex","getTotalAdsInBreak","getRemainingAdSeconds","remainingMs","isFinite","MAX_SAFE_INTEGER","isShowingAds","adLayerShowing","shouldShowNativeControls","showCustomControls"],"mappings":"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","sourcesContent":["\"use strict\";\nvar __create = Object.create;\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __getProtoOf = Object.getPrototypeOf;\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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(\n // If the importer is in node compatibility mode or this is not an ESM\n // file that has been converted to a CommonJS file using a Babel-\n // compatible transform (i.e. \"__esModule\" has not been set), then set\n // \"default\" to the CommonJS \"module.exports\" for node compatibility.\n isNodeMode || !mod || !mod.__esModule ? __defProp(target, \"default\", { value: mod, enumerable: true }) : target,\n mod\n));\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/player/StormcloudVideoPlayer.ts\nvar StormcloudVideoPlayer_exports = {};\n__export(StormcloudVideoPlayer_exports, {\n StormcloudVideoPlayer: () => StormcloudVideoPlayer\n});\nmodule.exports = __toCommonJS(StormcloudVideoPlayer_exports);\nvar import_hls = __toESM(require(\"hls.js\"), 1);\n\n// src/sdk/vastParser.ts\nasync function firePixelWithRetry(url, retries = 2, delayMs = 500, logPrefix = \"[VastParser]\") {\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n await fetch(url, {\n method: \"GET\",\n mode: \"no-cors\",\n cache: \"no-cache\",\n keepalive: true\n });\n return;\n } catch {\n if (attempt < retries) {\n await new Promise((r) => setTimeout(r, delayMs * Math.pow(2, attempt)));\n } else {\n console.warn(`${logPrefix} Tracking pixel failed after ${retries + 1} attempts: ${url}`);\n }\n }\n }\n}\nfunction fireTrackingPixels(urls, sessionId, logPrefix = \"[VastParser]\") {\n if (!urls || urls.length === 0) return;\n urls.forEach((url) => {\n try {\n let trackingUrl = url;\n if (sessionId) {\n trackingUrl = `${trackingUrl}${trackingUrl.includes(\"?\") ? \"&\" : \"?\"}session_id=${sessionId}`;\n }\n if (typeof fetch !== \"undefined\") {\n firePixelWithRetry(trackingUrl, 2, 500, logPrefix).catch(() => {\n });\n } else {\n const img = new Image(1, 1);\n img.onerror = () => {\n };\n img.src = trackingUrl;\n }\n console.log(`${logPrefix} Fired tracking pixel: ${trackingUrl}`);\n } catch (error) {\n console.warn(`${logPrefix} Error firing tracking pixel:`, error);\n }\n });\n}\n\n// src/sdk/adstormPlayer.ts\nvar SUPPORTED_VIDEO_EXTENSIONS = [\".mp4\", \".webm\", \".ogg\", \".m3u8\", \".ts\"];\nvar UNSUPPORTED_VIDEO_EXTENSIONS = [\".flv\", \".f4v\", \".swf\", \".wmv\", \".avi\", \".mov\", \".mkv\"];\nvar REQUEST_TIMEOUT_MS = 5e3;\nvar REQUEST_MAX_RETRIES = 3;\nvar REQUEST_RETRY_BACKOFF_MS = 1500;\nvar AD_LAYER_Z_INDEX = \"30\";\nvar COUNTDOWN_Z_INDEX = \"31\";\nvar STALL_TIMEOUT_MS = 8e3;\nfunction getFileExtension(url) {\n try {\n const pathname = new URL(url, \"http://dummy\").pathname;\n const lastDot = pathname.lastIndexOf(\".\");\n if (lastDot === -1) return \"\";\n return pathname.slice(lastDot).toLowerCase();\n } catch {\n const lastDot = url.lastIndexOf(\".\");\n if (lastDot === -1) return \"\";\n const ext = url.slice(lastDot).split(/[?#]/)[0];\n return (ext || \"\").toLowerCase();\n }\n}\nfunction isUnsupportedFormat(url) {\n const ext = getFileExtension(url);\n return UNSUPPORTED_VIDEO_EXTENSIONS.indexOf(ext) !== -1;\n}\nfunction replaceFlvExtension(url) {\n const ext = getFileExtension(url);\n if (ext === \".flv\") {\n return url.replace(/\\.flv(\\?|$)/i, \".mp4$1\");\n }\n return url;\n}\nfunction isSupportedFormat(url, mimeType) {\n if (isUnsupportedFormat(url)) {\n return false;\n }\n const ext = getFileExtension(url);\n if (SUPPORTED_VIDEO_EXTENSIONS.indexOf(ext) !== -1) {\n return true;\n }\n if (ext === \"\" || ext === \".\") {\n return mimeType.includes(\"video/mp4\") || mimeType.includes(\"video/webm\") || mimeType.includes(\"m3u8\") || mimeType.includes(\"application/x-mpegurl\");\n }\n return false;\n}\nfunction createAdStormPlayer(contentVideo, options) {\n const { licenseKey, debug = false } = options;\n let adPlaying = false;\n let originalMutedState = false;\n let originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));\n const listeners = /* @__PURE__ */ new Map();\n let adVideoElement;\n let adContainerEl;\n let adCountdownEl;\n let currentAd;\n let destroyed = false;\n let tornDown = false;\n let continueLiveStreamDuringAds = false;\n let sessionId;\n let adStallTimerId;\n let adCountdownTimerId;\n let adHideTimerId;\n let lastCountdownSecond = -1;\n let adListenersBound = false;\n let parentPositionOverridden = false;\n const adHandlers = {\n timeupdate: () => {\n if (!currentAd || !adVideoElement || destroyed || tornDown) return;\n const progress = adVideoElement.currentTime / currentAd.duration;\n if (progress >= 0.25 && !trackingFired.firstQuartile) {\n trackingFired.firstQuartile = true;\n fireTrackingPixels2(currentAd.trackingUrls.firstQuartile);\n }\n if (progress >= 0.5 && !trackingFired.midpoint) {\n trackingFired.midpoint = true;\n fireTrackingPixels2(currentAd.trackingUrls.midpoint);\n }\n if (progress >= 0.75 && !trackingFired.thirdQuartile) {\n trackingFired.thirdQuartile = true;\n fireTrackingPixels2(currentAd.trackingUrls.thirdQuartile);\n }\n updateAdCountdown();\n },\n playing: () => {\n clearAdStallTimer();\n if (!currentAd || trackingFired.start || destroyed || tornDown) return;\n trackingFired.start = true;\n fireTrackingPixels2(currentAd.trackingUrls.start);\n startAdCountdown();\n log(\"Ad started playing\");\n },\n ended: () => {\n if (!currentAd || trackingFired.complete || destroyed || tornDown) return;\n trackingFired.complete = true;\n fireTrackingPixels2(currentAd.trackingUrls.complete);\n log(\"Ad completed\");\n handleAdComplete();\n },\n error: (e) => {\n if (destroyed || tornDown) return;\n console.error(\"[AdStormPlayer] Ad video error:\", e);\n if (currentAd) fireTrackingPixels2(currentAd.trackingUrls.error);\n handleAdError();\n },\n waiting: () => {\n clearAdStallTimer();\n adStallTimerId = setTimeout(() => {\n adStallTimerId = void 0;\n if (!adPlaying || destroyed || tornDown) return;\n console.warn(\"[AdStormPlayer] Ad playback stalled too long\");\n handleAdError();\n }, STALL_TIMEOUT_MS);\n },\n volumechange: () => {\n if (!currentAd || !adVideoElement || destroyed || tornDown) return;\n if (adVideoElement.muted || adVideoElement.volume <= 0) {\n fireTrackingPixels2(currentAd.trackingUrls.mute);\n } else {\n fireTrackingPixels2(currentAd.trackingUrls.unmute);\n }\n },\n pause: () => {\n if (!currentAd || !adVideoElement || destroyed || tornDown) return;\n if (!adVideoElement.ended) {\n fireTrackingPixels2(currentAd.trackingUrls.pause);\n }\n },\n play: () => {\n if (!currentAd || !adVideoElement || destroyed || tornDown) return;\n if (adVideoElement.currentTime > 0) {\n fireTrackingPixels2(currentAd.trackingUrls.resume);\n }\n }\n };\n let trackingFired = {\n impression: false,\n start: false,\n firstQuartile: false,\n midpoint: false,\n thirdQuartile: false,\n complete: false\n };\n const preloadSlots = /* @__PURE__ */ new Map();\n function log(...args) {\n if (debug) {\n console.log(\"[AdStormPlayer]\", ...args);\n }\n }\n function emit(event, payload) {\n const set = listeners.get(event);\n if (!set) return;\n for (const fn of Array.from(set)) {\n try {\n fn(payload);\n } catch (error) {\n console.warn(`[AdStormPlayer] Error in event listener for ${event}:`, error);\n }\n }\n }\n function fireTrackingPixels2(urls) {\n fireTrackingPixels(urls, sessionId, \"[AdStormPlayer]\");\n }\n function clearAdStallTimer() {\n if (adStallTimerId) {\n clearTimeout(adStallTimerId);\n adStallTimerId = void 0;\n }\n }\n function clearAdCountdownTimer() {\n if (adCountdownTimerId) {\n clearInterval(adCountdownTimerId);\n adCountdownTimerId = void 0;\n }\n lastCountdownSecond = -1;\n }\n function updateAdCountdown() {\n if (!adCountdownEl || !adVideoElement || !currentAd || !adPlaying) return;\n const remainingSec = Math.max(\n 0,\n Math.ceil((currentAd.duration || 0) - adVideoElement.currentTime)\n );\n if (remainingSec === lastCountdownSecond) return;\n lastCountdownSecond = remainingSec;\n adCountdownEl.textContent = `Ad ${remainingSec}s`;\n emit(\"ad_countdown\", {\n remainingSec,\n durationSec: currentAd.duration,\n currentTimeSec: adVideoElement.currentTime\n });\n }\n function startAdCountdown() {\n clearAdCountdownTimer();\n updateAdCountdown();\n adCountdownTimerId = setInterval(updateAdCountdown, 250);\n }\n function generateSessionId() {\n return `adstorm-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;\n }\n function bindAdEventListeners() {\n if (!adVideoElement || adListenersBound) return;\n adVideoElement.addEventListener(\"timeupdate\", adHandlers.timeupdate);\n adVideoElement.addEventListener(\"playing\", adHandlers.playing);\n adVideoElement.addEventListener(\"ended\", adHandlers.ended);\n adVideoElement.addEventListener(\"error\", adHandlers.error);\n adVideoElement.addEventListener(\"waiting\", adHandlers.waiting);\n adVideoElement.addEventListener(\"volumechange\", adHandlers.volumechange);\n adVideoElement.addEventListener(\"pause\", adHandlers.pause);\n adVideoElement.addEventListener(\"play\", adHandlers.play);\n adListenersBound = true;\n }\n function unbindAdEventListeners() {\n if (!adVideoElement || !adListenersBound) return;\n adVideoElement.removeEventListener(\"timeupdate\", adHandlers.timeupdate);\n adVideoElement.removeEventListener(\"playing\", adHandlers.playing);\n adVideoElement.removeEventListener(\"ended\", adHandlers.ended);\n adVideoElement.removeEventListener(\"error\", adHandlers.error);\n adVideoElement.removeEventListener(\"waiting\", adHandlers.waiting);\n adVideoElement.removeEventListener(\"volumechange\", adHandlers.volumechange);\n adVideoElement.removeEventListener(\"pause\", adHandlers.pause);\n adVideoElement.removeEventListener(\"play\", adHandlers.play);\n adListenersBound = false;\n }\n function teardownCurrentPlayback() {\n unbindAdEventListeners();\n clearAdStallTimer();\n clearAdCountdownTimer();\n if (!adVideoElement) return;\n adVideoElement.pause();\n adVideoElement.removeAttribute(\"src\");\n adVideoElement.load();\n }\n function buildVastUrl(durationSeconds) {\n const baseUrl = `https://adstorm.co/api-adstorm-dev/adstorm/nab/vast/pod`;\n return `${baseUrl}?duration=${Math.ceil(durationSeconds)}`;\n }\n function parseVastXml(xmlString) {\n const ads = [];\n try {\n const parser = new DOMParser();\n const xmlDoc = parser.parseFromString(xmlString, \"text/xml\");\n const parserError = xmlDoc.querySelector(\"parsererror\");\n if (parserError) {\n console.error(\"[AdStormPlayer] XML parsing error:\", parserError.textContent);\n return [];\n }\n const adElements = xmlDoc.querySelectorAll(\"Ad\");\n adElements.forEach((adElement) => {\n const adId = adElement.getAttribute(\"id\") || \"unknown\";\n const title = adElement.querySelector(\"AdTitle\")?.textContent || \"Ad\";\n const durationText = adElement.querySelector(\"Duration\")?.textContent || \"00:00:30\";\n const durationParts = durationText.split(\":\");\n const duration = parseInt(durationParts[0] || \"0\", 10) * 3600 + parseInt(durationParts[1] || \"0\", 10) * 60 + parseFloat(durationParts[2] || \"0\");\n const mediaFileElements = adElement.querySelectorAll(\"MediaFile\");\n const mediaFiles = [];\n mediaFileElements.forEach((mf) => {\n const type = mf.getAttribute(\"type\") || \"\";\n let url = mf.textContent?.trim() || \"\";\n const width = parseInt(mf.getAttribute(\"width\") || \"1920\", 10);\n const height = parseInt(mf.getAttribute(\"height\") || \"1080\", 10);\n const bitrate = mf.getAttribute(\"bitrate\") ? parseInt(mf.getAttribute(\"bitrate\"), 10) : void 0;\n if (!url) {\n log(`Skipping empty MediaFile URL`);\n return;\n }\n const originalUrl = url;\n url = replaceFlvExtension(url);\n if (url !== originalUrl) {\n log(`Converted FLV to MP4: ${originalUrl} -> ${url}`);\n }\n if (isUnsupportedFormat(url)) {\n const ext = getFileExtension(url);\n log(`Skipping unsupported format: ${url} (extension: ${ext}, declared type: ${type})`);\n return;\n }\n if (isSupportedFormat(url, type)) {\n mediaFiles.push({ url, type, width, height, bitrate });\n log(`Found media file: ${url} (${type}, ${width}x${height})`);\n } else {\n log(`Skipping incompatible media file: ${url} (type: ${type})`);\n }\n });\n if (mediaFiles.length === 0) {\n log(\"No valid media files found in ad:\", adId);\n return;\n }\n const trackingUrls = {\n impression: [],\n start: [],\n firstQuartile: [],\n midpoint: [],\n thirdQuartile: [],\n complete: [],\n mute: [],\n unmute: [],\n pause: [],\n resume: [],\n error: []\n };\n adElement.querySelectorAll(\"Impression\").forEach((el) => {\n const url = el.textContent?.trim();\n if (url) trackingUrls.impression.push(url);\n });\n adElement.querySelectorAll(\"Tracking\").forEach((el) => {\n const event = el.getAttribute(\"event\");\n const url = el.textContent?.trim();\n if (event && url) {\n const eventKey = event;\n if (trackingUrls[eventKey]) {\n trackingUrls[eventKey].push(url);\n }\n }\n });\n const clickThrough = adElement.querySelector(\"ClickThrough\")?.textContent?.trim();\n ads.push({\n id: adId,\n title,\n duration,\n mediaFiles,\n trackingUrls,\n clickThrough\n });\n log(`Parsed ad: ${title}, duration: ${duration}s, media files: ${mediaFiles.length}`);\n });\n } catch (error) {\n console.error(\"[AdStormPlayer] Error parsing VAST XML:\", error);\n }\n return ads;\n }\n function selectBestMediaFile(mediaFiles) {\n if (mediaFiles.length === 0) return null;\n if (mediaFiles.length === 1) return mediaFiles[0];\n const mp4Files = mediaFiles.filter((mf) => mf.type.includes(\"video/mp4\"));\n const candidates = mp4Files.length > 0 ? mp4Files : mediaFiles;\n const targetWidth = contentVideo.videoWidth || 1280;\n const targetHeight = contentVideo.videoHeight || 720;\n candidates.sort((a, b) => {\n const diffA = Math.abs(a.width - targetWidth) + Math.abs(a.height - targetHeight);\n const diffB = Math.abs(b.width - targetWidth) + Math.abs(b.height - targetHeight);\n return diffA - diffB;\n });\n return candidates[0] || null;\n }\n function createAdVideoElement() {\n const video = document.createElement(\"video\");\n video.style.position = \"absolute\";\n video.style.left = \"0\";\n video.style.top = \"0\";\n video.style.width = \"100%\";\n video.style.height = \"100%\";\n video.style.objectFit = \"contain\";\n video.style.backgroundColor = \"#000\";\n video.style.zIndex = \"1\";\n video.playsInline = true;\n video.preload = \"auto\";\n video.muted = originalMutedState;\n video.volume = originalMutedState ? 0 : originalVolume;\n return video;\n }\n function setAdPlayingFlag(isPlaying) {\n if (isPlaying) {\n contentVideo.dataset.stormcloudAdPlaying = \"true\";\n } else {\n delete contentVideo.dataset.stormcloudAdPlaying;\n }\n }\n function setupAdEventListeners() {\n bindAdEventListeners();\n }\n function handleAdComplete() {\n if (destroyed || tornDown) return;\n log(\"Handling ad completion\");\n adPlaying = false;\n setAdPlayingFlag(false);\n clearAdStallTimer();\n clearAdCountdownTimer();\n if (adContainerEl) {\n adContainerEl.style.opacity = \"0\";\n adHideTimerId = setTimeout(() => {\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n }, 300);\n }\n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n contentVideo.muted = originalMutedState;\n contentVideo.volume = originalVolume;\n currentAd = void 0;\n emit(\"content_resume\");\n emit(\"all_ads_completed\");\n }\n function handleAdError() {\n if (destroyed || tornDown) return;\n log(\"Handling ad error\");\n if (!adPlaying) return;\n adPlaying = false;\n setAdPlayingFlag(false);\n clearAdStallTimer();\n clearAdCountdownTimer();\n contentVideo.muted = originalMutedState;\n contentVideo.volume = originalVolume;\n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n currentAd = void 0;\n emit(\"ad_error\");\n emit(\"content_resume\");\n }\n async function fetchVastOnce(durationSeconds) {\n const vastUrl = buildVastUrl(durationSeconds);\n log(\"Fetching VAST from:\", vastUrl);\n const controller = typeof AbortController !== \"undefined\" ? new AbortController() : null;\n const timeoutId = setTimeout(() => controller?.abort(), REQUEST_TIMEOUT_MS);\n try {\n const requestInit = {\n method: \"GET\",\n mode: \"cors\",\n credentials: \"omit\",\n headers: {\n Accept: \"application/xml, text/xml, */*\"\n },\n referrerPolicy: \"no-referrer-when-downgrade\"\n };\n if (controller) {\n requestInit.signal = controller.signal;\n }\n const response = await fetch(vastUrl, requestInit);\n if (!response.ok) {\n throw new Error(`Failed to fetch VAST: ${response.status} ${response.statusText}`);\n }\n const xmlText = await response.text();\n log(\"VAST response received, length:\", xmlText.length);\n return parseVastXml(xmlText);\n } finally {\n clearTimeout(timeoutId);\n }\n }\n async function fetchVast(durationSeconds) {\n let lastError;\n for (let attempt = 1; attempt <= REQUEST_MAX_RETRIES; attempt++) {\n try {\n const ads = await fetchVastOnce(durationSeconds);\n if (ads.length > 0) return ads;\n log(`No ad returned from VAST on attempt ${attempt}/${REQUEST_MAX_RETRIES}`);\n } catch (error) {\n lastError = error;\n if (error?.name === \"AbortError\") {\n console.warn(\n `[AdStormPlayer] VAST request timed out (${REQUEST_TIMEOUT_MS}ms), attempt ${attempt}/${REQUEST_MAX_RETRIES}`\n );\n } else {\n console.warn(`[AdStormPlayer] VAST request failed on attempt ${attempt}/${REQUEST_MAX_RETRIES}:`, error);\n }\n }\n if (attempt < REQUEST_MAX_RETRIES) {\n const delay = REQUEST_RETRY_BACKOFF_MS * attempt;\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n if (lastError instanceof Error) {\n throw lastError;\n }\n return [];\n }\n function getDurationSecondsFromContext(requestContext) {\n if (!requestContext || typeof requestContext !== \"object\") {\n return 30;\n }\n const ctx = requestContext;\n const value = ctx.remainingBreakSec ?? ctx.breakDurationSec;\n if (typeof value !== \"number\" || Number.isNaN(value)) {\n return 30;\n }\n return Math.max(1, Math.ceil(value));\n }\n async function requestAdFromApi(requestContext) {\n const durationSeconds = getDurationSecondsFromContext(requestContext);\n const ads = await fetchVast(durationSeconds);\n return ads[0] || null;\n }\n function assignCurrentAd(ad) {\n currentAd = ad;\n sessionId = generateSessionId();\n trackingFired = {\n impression: false,\n start: false,\n firstQuartile: false,\n midpoint: false,\n thirdQuartile: false,\n complete: false\n };\n fireTrackingPixels2(currentAd.trackingUrls.impression);\n trackingFired.impression = true;\n emit(\"ad_impression\");\n }\n return {\n initialize() {\n log(\"Initializing\");\n if (!adContainerEl) {\n const parent = contentVideo.parentElement;\n if (parent) {\n const computed = window.getComputedStyle(parent).position;\n if (computed === \"static\") {\n parent.style.position = \"relative\";\n parentPositionOverridden = true;\n }\n }\n const container = document.createElement(\"div\");\n container.style.position = \"absolute\";\n container.style.left = \"0\";\n container.style.top = \"0\";\n container.style.right = \"0\";\n container.style.bottom = \"0\";\n container.style.display = \"none\";\n container.style.alignItems = \"center\";\n container.style.justifyContent = \"center\";\n container.style.pointerEvents = \"none\";\n container.style.zIndex = AD_LAYER_Z_INDEX;\n container.style.backgroundColor = \"#000\";\n container.style.transition = \"opacity 0.3s ease-in-out\";\n container.style.opacity = \"0\";\n container.style.isolation = \"isolate\";\n const countdown = document.createElement(\"div\");\n countdown.style.position = \"absolute\";\n countdown.style.left = \"12px\";\n countdown.style.top = \"12px\";\n countdown.style.padding = \"4px 8px\";\n countdown.style.borderRadius = \"4px\";\n countdown.style.background = \"rgba(0,0,0,0.75)\";\n countdown.style.color = \"#fff\";\n countdown.style.fontFamily = \"sans-serif\";\n countdown.style.fontSize = \"12px\";\n countdown.style.lineHeight = \"1.2\";\n countdown.style.pointerEvents = \"none\";\n countdown.style.zIndex = COUNTDOWN_Z_INDEX;\n countdown.textContent = \"Ad\";\n container.appendChild(countdown);\n contentVideo.parentElement?.appendChild(container);\n adContainerEl = container;\n adCountdownEl = countdown;\n }\n },\n async requestAds(duration) {\n log(\"Requesting ads for duration:\", duration);\n if (adPlaying) {\n return Promise.reject(new Error(\"Ad already playing\"));\n }\n if (destroyed) {\n return Promise.reject(new Error(\"Player has been destroyed\"));\n }\n try {\n tornDown = false;\n let durationSeconds = 30;\n const parsed = parseInt(duration || \"\", 10);\n if (!isNaN(parsed) && parsed > 0) {\n durationSeconds = parsed;\n }\n const ads = await fetchVast(durationSeconds);\n if (ads.length === 0) {\n log(\"No ads available from VAST response\");\n emit(\"ad_error\");\n return Promise.resolve();\n }\n assignCurrentAd(ads[0]);\n log(`Ad loaded: ${currentAd.title}, duration: ${currentAd.duration}s`);\n return Promise.resolve();\n } catch (error) {\n console.error(\"[AdStormPlayer] Error requesting ads:\", error);\n emit(\"ad_error\");\n return Promise.reject(error);\n }\n },\n async play() {\n if (!currentAd) {\n return Promise.reject(new Error(\"No ad loaded\"));\n }\n if (destroyed) {\n return Promise.reject(new Error(\"Player has been destroyed\"));\n }\n log(\"Starting ad playback\");\n try {\n tornDown = false;\n if (adHideTimerId) {\n clearTimeout(adHideTimerId);\n adHideTimerId = void 0;\n }\n if (!adVideoElement) {\n adVideoElement = createAdVideoElement();\n adContainerEl?.appendChild(adVideoElement);\n } else {\n teardownCurrentPlayback();\n }\n setupAdEventListeners();\n trackingFired = {\n impression: trackingFired.impression,\n start: false,\n firstQuartile: false,\n midpoint: false,\n thirdQuartile: false,\n complete: false\n };\n contentVideo.style.transition = \"opacity 0.3s ease-in-out\";\n contentVideo.style.opacity = \"0\";\n setTimeout(() => {\n contentVideo.style.visibility = \"hidden\";\n }, 300);\n contentVideo.muted = true;\n contentVideo.volume = 0;\n if (!continueLiveStreamDuringAds) {\n contentVideo.pause();\n }\n adPlaying = true;\n setAdPlayingFlag(true);\n if (adVideoElement) {\n adVideoElement.volume = originalMutedState ? 0 : originalVolume;\n adVideoElement.muted = originalMutedState;\n }\n if (adContainerEl) {\n adContainerEl.style.display = \"flex\";\n adContainerEl.style.pointerEvents = \"auto\";\n adContainerEl.offsetHeight;\n adContainerEl.style.opacity = \"1\";\n }\n emit(\"content_pause\");\n const mediaFile = selectBestMediaFile(currentAd.mediaFiles);\n if (!mediaFile) {\n throw new Error(\"No media file available\");\n }\n log(\"Playing media file:\", mediaFile.url);\n adVideoElement.src = mediaFile.url;\n adVideoElement.load();\n await adVideoElement.play();\n return Promise.resolve();\n } catch (error) {\n console.error(\"[AdStormPlayer] Error playing ad:\", error);\n handleAdError();\n return Promise.reject(error);\n }\n },\n async stop() {\n log(\"Stopping ad\");\n tornDown = true;\n adPlaying = false;\n setAdPlayingFlag(false);\n clearAdStallTimer();\n clearAdCountdownTimer();\n if (adContainerEl) {\n adContainerEl.style.opacity = \"0\";\n adHideTimerId = setTimeout(() => {\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n }, 300);\n }\n teardownCurrentPlayback();\n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n contentVideo.muted = originalMutedState;\n contentVideo.volume = originalVolume;\n currentAd = void 0;\n return Promise.resolve();\n },\n pause() {\n if (!adPlaying || !adVideoElement) return;\n try {\n if (!adVideoElement.paused) adVideoElement.pause();\n } catch (error) {\n console.warn(\"[AdStormPlayer] Error pausing ad:\", error);\n }\n },\n resume() {\n if (!adPlaying || !adVideoElement) return;\n try {\n if (adVideoElement.paused) adVideoElement.play().catch(() => {\n });\n } catch (error) {\n console.warn(\"[AdStormPlayer] Error resuming ad:\", error);\n }\n },\n destroy() {\n log(\"Destroying\");\n destroyed = true;\n tornDown = true;\n adPlaying = false;\n setAdPlayingFlag(false);\n clearAdStallTimer();\n clearAdCountdownTimer();\n if (adHideTimerId) {\n clearTimeout(adHideTimerId);\n adHideTimerId = void 0;\n }\n contentVideo.muted = originalMutedState;\n contentVideo.volume = originalVolume;\n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n teardownCurrentPlayback();\n adVideoElement?.remove();\n adVideoElement = void 0;\n if (adContainerEl?.parentElement) {\n adContainerEl.parentElement.removeChild(adContainerEl);\n }\n adContainerEl = void 0;\n adCountdownEl = void 0;\n currentAd = void 0;\n sessionId = void 0;\n preloadSlots.clear();\n listeners.clear();\n if (parentPositionOverridden && contentVideo.parentElement) {\n contentVideo.parentElement.style.position = \"\";\n parentPositionOverridden = false;\n }\n },\n updateOptions(opts) {\n if (opts.continueLiveStreamDuringAds !== void 0) {\n continueLiveStreamDuringAds = opts.continueLiveStreamDuringAds;\n }\n },\n async playAd(requestContext) {\n if (destroyed) return Promise.reject(new Error(\"Player has been destroyed\"));\n if (!currentAd) {\n const ad = await requestAdFromApi(requestContext);\n if (!ad) {\n emit(\"ad_error\", { message: \"No valid ad from AdStorm API\" });\n return Promise.reject(new Error(\"No valid ad from AdStorm API\"));\n }\n assignCurrentAd(ad);\n }\n return this.play();\n },\n async preloadAd(arg1, arg2) {\n if (destroyed) return;\n const token = typeof arg1 === \"string\" ? arg1 : typeof arg2 === \"string\" ? arg2 : void 0;\n if (!token) return;\n if (currentAd) {\n preloadSlots.set(token, { ad: currentAd });\n currentAd = void 0;\n return;\n }\n const requestContext = typeof arg1 === \"string\" ? arg2 : arg1;\n const ad = await requestAdFromApi(requestContext);\n if (!ad) return;\n preloadSlots.set(token, { ad });\n },\n async playPreloaded(token) {\n if (destroyed) return Promise.reject(new Error(\"Player has been destroyed\"));\n const slot = preloadSlots.get(token);\n if (!slot) {\n return Promise.reject(new Error(`No preloaded ad for token ${token}`));\n }\n preloadSlots.delete(token);\n assignCurrentAd(slot.ad);\n return this.play();\n },\n hasPreloaded(token) {\n return preloadSlots.has(token);\n },\n cancelPreload(token) {\n preloadSlots.delete(token);\n },\n isAdPlaying() {\n return adPlaying;\n },\n resize(width, height) {\n log(`Resizing to ${width}x${height}`);\n if (adContainerEl) {\n adContainerEl.style.width = `${width}px`;\n adContainerEl.style.height = `${height}px`;\n }\n if (adVideoElement) {\n adVideoElement.style.width = `${width}px`;\n adVideoElement.style.height = `${height}px`;\n }\n },\n on(event, listener) {\n if (!listeners.has(event)) listeners.set(event, /* @__PURE__ */ new Set());\n listeners.get(event).add(listener);\n },\n off(event, listener) {\n listeners.get(event)?.delete(listener);\n },\n updateOriginalMutedState(muted, volume) {\n const nextVolume = typeof volume === \"number\" && !Number.isNaN(volume) ? Math.max(0, Math.min(1, volume)) : originalVolume;\n log(`updateOriginalMutedState: muted=${muted}, volume=${nextVolume}`);\n originalMutedState = muted;\n originalVolume = nextVolume;\n },\n getOriginalMutedState() {\n return originalMutedState;\n },\n getOriginalVolume() {\n return originalVolume;\n },\n setAdVolume(volume) {\n if (adVideoElement && adPlaying) {\n adVideoElement.volume = Math.max(0, Math.min(1, volume));\n adVideoElement.muted = volume === 0;\n }\n },\n getAdVolume() {\n if (adVideoElement && adPlaying) {\n return adVideoElement.volume;\n }\n return 1;\n },\n showPlaceholder() {\n if (!adContainerEl) {\n const parent = contentVideo.parentElement;\n if (parent) {\n const computed = window.getComputedStyle(parent).position;\n if (computed === \"static\") {\n parent.style.position = \"relative\";\n parentPositionOverridden = true;\n }\n }\n const container = document.createElement(\"div\");\n container.style.position = \"absolute\";\n container.style.left = \"0\";\n container.style.top = \"0\";\n container.style.right = \"0\";\n container.style.bottom = \"0\";\n container.style.display = \"none\";\n container.style.alignItems = \"center\";\n container.style.justifyContent = \"center\";\n container.style.pointerEvents = \"none\";\n container.style.zIndex = AD_LAYER_Z_INDEX;\n container.style.backgroundColor = \"#000\";\n container.style.isolation = \"isolate\";\n const countdown = document.createElement(\"div\");\n countdown.style.position = \"absolute\";\n countdown.style.left = \"12px\";\n countdown.style.top = \"12px\";\n countdown.style.padding = \"4px 8px\";\n countdown.style.borderRadius = \"4px\";\n countdown.style.background = \"rgba(0,0,0,0.75)\";\n countdown.style.color = \"#fff\";\n countdown.style.fontFamily = \"sans-serif\";\n countdown.style.fontSize = \"12px\";\n countdown.style.lineHeight = \"1.2\";\n countdown.style.pointerEvents = \"none\";\n countdown.style.zIndex = COUNTDOWN_Z_INDEX;\n countdown.textContent = \"Ad\";\n container.appendChild(countdown);\n contentVideo.parentElement?.appendChild(container);\n adContainerEl = container;\n adCountdownEl = countdown;\n }\n if (adContainerEl) {\n adContainerEl.style.display = \"flex\";\n adContainerEl.style.opacity = \"1\";\n adContainerEl.style.pointerEvents = \"auto\";\n }\n },\n hidePlaceholder() {\n if (adContainerEl) {\n adContainerEl.style.opacity = \"0\";\n setTimeout(() => {\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n }, 300);\n }\n }\n };\n}\n\n// src/utils/tracking.ts\nvar cachedBrowserId = null;\nfunction getClientInfo() {\n const ua = navigator.userAgent;\n const platform = navigator.platform;\n const vendor = navigator.vendor || \"\";\n const maxTouchPoints = navigator.maxTouchPoints || 0;\n const memory = navigator.deviceMemory || null;\n const hardwareConcurrency = navigator.hardwareConcurrency || 1;\n const screenInfo = {\n width: screen?.width,\n height: screen?.height,\n availWidth: screen?.availWidth,\n availHeight: screen?.availHeight,\n orientation: screen?.orientation?.type || \"\",\n pixelDepth: screen?.pixelDepth\n };\n let deviceType = \"desktop\";\n let brand = \"Unknown\";\n let os = \"Unknown\";\n let model = \"\";\n let isSmartTV = false;\n let isAndroid = false;\n let isWebView = false;\n let isWebApp = false;\n if (ua.includes(\"Web0S\")) {\n brand = \"LG\";\n os = \"webOS\";\n isSmartTV = true;\n deviceType = \"tv\";\n const webosMatch = ua.match(/Web0S\\/([^\\s]+)/);\n model = webosMatch ? `webOS ${webosMatch[1]}` : \"webOS TV\";\n } else if (ua.includes(\"Tizen\")) {\n brand = \"Samsung\";\n os = \"Tizen\";\n isSmartTV = true;\n deviceType = \"tv\";\n const tizenMatch = ua.match(/Tizen\\/([^\\s]+)/);\n const tvMatch = ua.match(/(?:Smart-TV|SMART-TV|TV)/i) ? \"Smart TV\" : \"\";\n model = tizenMatch ? `Tizen ${tizenMatch[1]} ${tvMatch}`.trim() : \"Tizen TV\";\n } else if (ua.includes(\"Philips\")) {\n brand = \"Philips\";\n os = \"Saphi\";\n isSmartTV = true;\n deviceType = \"tv\";\n } else if (ua.includes(\"Sharp\") || ua.includes(\"AQUOS\")) {\n brand = \"Sharp\";\n os = \"Android TV\";\n isSmartTV = true;\n deviceType = \"tv\";\n } else if (ua.includes(\"Android\") && (ua.includes(\"Sony\") || vendor.includes(\"Sony\"))) {\n brand = \"Sony\";\n os = \"Android TV\";\n isSmartTV = true;\n deviceType = \"tv\";\n } else if (ua.includes(\"Android\") && (ua.includes(\"NetCast\") || ua.includes(\"LG\"))) {\n brand = \"LG\";\n os = \"Android TV\";\n isSmartTV = true;\n deviceType = \"tv\";\n } else if (ua.includes(\" Roku\") || ua.includes(\"Roku/\")) {\n brand = \"Roku\";\n os = \"Roku OS\";\n isSmartTV = true;\n deviceType = \"tv\";\n } else if (ua.includes(\"AppleTV\")) {\n brand = \"Apple\";\n os = \"tvOS\";\n isSmartTV = true;\n deviceType = \"tv\";\n }\n if (ua.includes(\"Android\")) {\n isAndroid = true;\n os = \"Android\";\n deviceType = /Mobile/.test(ua) ? \"mobile\" : \"tablet\";\n if (ua.includes(\"Android\") && (maxTouchPoints === 0 || ua.includes(\"Google TV\") || ua.includes(\"XiaoMi\"))) {\n deviceType = \"tv\";\n isSmartTV = true;\n brand = brand === \"Unknown\" ? \"Android TV\" : brand;\n }\n const androidModelMatch = ua.match(/\\(([^)]*Android[^)]*)\\)/);\n if (androidModelMatch && androidModelMatch[1]) {\n model = androidModelMatch[1];\n }\n }\n if (/iPad|iPhone|iPod/.test(ua)) {\n os = \"iOS\";\n deviceType = \"mobile\";\n brand = \"Apple\";\n if (navigator.maxTouchPoints > 1 && /iPad/.test(ua)) {\n deviceType = \"tablet\";\n }\n }\n if (!isAndroid && !isSmartTV && !/Mobile/.test(ua)) {\n if (ua.includes(\"Windows\")) {\n os = \"Windows\";\n deviceType = \"desktop\";\n } else if (ua.includes(\"Mac\") && !/iPhone/.test(ua)) {\n os = \"macOS\";\n deviceType = \"desktop\";\n if (maxTouchPoints > 1) deviceType = \"tablet\";\n } else if (ua.includes(\"Linux\")) {\n os = \"Linux\";\n deviceType = \"desktop\";\n }\n }\n if (brand === \"Unknown\") {\n if (vendor.includes(\"Google\") || ua.includes(\"Chrome\")) brand = \"Google\";\n if (vendor.includes(\"Apple\")) brand = \"Apple\";\n if (vendor.includes(\"Samsung\") || ua.includes(\"SM-\")) brand = \"Samsung\";\n }\n isWebView = /wv|WebView|Linux; U;/.test(ua);\n if (window?.outerHeight === 0 && window?.outerWidth === 0) {\n isWebView = true;\n }\n isWebApp = window.matchMedia(\"(display-mode: standalone)\").matches || window.navigator.standalone === true || window.screen?.orientation?.angle !== void 0;\n return {\n brand,\n os,\n model: model || ua.substring(0, 50) + \"...\",\n deviceType,\n isSmartTV,\n isAndroid,\n isWebView,\n isWebApp,\n domain: window.location.hostname,\n origin: window.location.origin,\n path: window.location.pathname,\n userAgent: ua,\n vendor,\n platform,\n screen: screenInfo,\n hardwareConcurrency,\n deviceMemory: memory,\n maxTouchPoints,\n language: navigator.language,\n languages: navigator.languages?.join(\",\") || \"\",\n cookieEnabled: navigator.cookieEnabled,\n doNotTrack: navigator.doNotTrack || \"\",\n referrer: document.referrer,\n visibilityState: document.visibilityState\n };\n}\nasync function getBrowserID(clientInfo) {\n if (cachedBrowserId) {\n return cachedBrowserId;\n }\n const fingerprintString = JSON.stringify(clientInfo);\n if (typeof crypto !== \"undefined\" && crypto.subtle && crypto.subtle.digest) {\n try {\n await crypto.subtle.digest(\"SHA-256\", new Uint8Array([1, 2, 3]));\n let encodedData;\n if (typeof TextEncoder !== \"undefined\") {\n encodedData = new TextEncoder().encode(fingerprintString);\n } else {\n const utf8 = unescape(encodeURIComponent(fingerprintString));\n const buffer = new Uint8Array(utf8.length);\n for (let i = 0; i < utf8.length; i++) {\n buffer[i] = utf8.charCodeAt(i);\n }\n encodedData = buffer;\n }\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", encodedData);\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n const hashHex = hashArray.map((b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n cachedBrowserId = hashHex;\n return hashHex;\n } catch (error) {\n console.warn(\n \"[StormcloudVideoPlayer] crypto.subtle.digest not supported, using fallback hash\"\n );\n }\n }\n let hash = 0;\n for (let i = 0; i < fingerprintString.length; i++) {\n const char = fingerprintString.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash;\n }\n const fallbackHash = Math.abs(hash).toString(16).padStart(8, \"0\");\n const timestamp = Date.now().toString(16).padStart(12, \"0\");\n const random = Math.random().toString(16).substring(2, 14).padStart(12, \"0\");\n cachedBrowserId = (fallbackHash + timestamp + random).padEnd(64, \"0\");\n return cachedBrowserId;\n}\nvar TRACK_URL = \"https://adstorm.co/api-adstorm-dev/adstorm/player-tracking/track\";\nasync function sendTrackRequest(licenseKey, body) {\n const headers = {\n \"Content-Type\": \"application/json\"\n };\n if (licenseKey) {\n headers[\"Authorization\"] = `Bearer ${licenseKey}`;\n }\n const response = await fetch(TRACK_URL, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body)\n });\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n await response.json();\n}\nasync function sendInitialTracking(licenseKey) {\n try {\n const clientInfo = getClientInfo();\n const browserId = await getBrowserID(clientInfo);\n const trackingData = {\n browserId,\n ...clientInfo\n };\n const headers = {\n \"Content-Type\": \"application/json\"\n };\n if (licenseKey) {\n headers[\"Authorization\"] = `Bearer ${licenseKey}`;\n }\n const response = await fetch(TRACK_URL, {\n method: \"POST\",\n headers,\n body: JSON.stringify(trackingData)\n });\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n await response.json();\n } catch (error) {\n console.error(\n \"[StormcloudVideoPlayer] Error sending initial tracking data:\",\n error\n );\n }\n}\nasync function sendAdLoadedTracking(licenseKey, adLoadedInfo) {\n try {\n const clientInfo = getClientInfo();\n const browserId = await getBrowserID(clientInfo);\n const trackingData = { browserId, ...clientInfo };\n await sendTrackRequest(licenseKey, {\n ...trackingData,\n licenseKey,\n adLoadedInfo\n });\n } catch (error) {\n console.error(\n \"[StormcloudVideoPlayer] Error sending ad loaded tracking:\",\n error\n );\n }\n}\nasync function sendAdImpressionTracking(licenseKey, adImpressionInfo) {\n try {\n const clientInfo = getClientInfo();\n const browserId = await getBrowserID(clientInfo);\n const trackingData = { browserId, ...clientInfo };\n await sendTrackRequest(licenseKey, {\n ...trackingData,\n licenseKey,\n adImpressionInfo\n });\n } catch (error) {\n console.error(\n \"[StormcloudVideoPlayer] Error sending ad impression tracking:\",\n error\n );\n }\n}\nasync function sendHeartbeat(licenseKey) {\n try {\n const clientInfo = getClientInfo();\n const browserId = await getBrowserID(clientInfo);\n const heartbeatData = {\n browserId,\n timestamp: (/* @__PURE__ */ new Date()).toISOString()\n };\n const headers = {\n \"Content-Type\": \"application/json\"\n };\n if (licenseKey) {\n headers[\"Authorization\"] = `Bearer ${licenseKey}`;\n }\n const response = await fetch(\n \"https://adstorm.co/api-adstorm-dev/adstorm/player-tracking/heartbeat\",\n {\n method: \"POST\",\n headers,\n body: JSON.stringify(heartbeatData)\n }\n );\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n await response.json();\n } catch (error) {\n console.error(\"[StormcloudVideoPlayer] Error sending heartbeat:\", error);\n }\n}\n\n// src/utils/polyfills.ts\nfunction polyfillURLSearchParams() {\n if (typeof URLSearchParams !== \"undefined\") {\n return;\n }\n class URLSearchParamsPolyfill {\n constructor(init) {\n this.params = /* @__PURE__ */ new Map();\n if (typeof init === \"string\") {\n this.parseQueryString(init);\n } else if (init instanceof URLSearchParamsPolyfill) {\n init.forEach((value, key) => {\n this.append(key, value);\n });\n }\n }\n parseQueryString(query) {\n const cleanQuery = query.startsWith(\"?\") ? query.slice(1) : query;\n if (!cleanQuery) return;\n cleanQuery.split(\"&\").forEach((param) => {\n const [key, value] = param.split(\"=\");\n if (key) {\n const decodedKey = this.safeDecodeURIComponent(key);\n const decodedValue = value ? this.safeDecodeURIComponent(value) : \"\";\n this.append(decodedKey, decodedValue);\n }\n });\n }\n safeDecodeURIComponent(str) {\n try {\n return decodeURIComponent(str.replace(/\\+/g, \" \"));\n } catch (e) {\n return str;\n }\n }\n append(name, value) {\n const values = this.params.get(name) || [];\n values.push(String(value));\n this.params.set(name, values);\n }\n delete(name) {\n this.params.delete(name);\n }\n get(name) {\n const values = this.params.get(name);\n return values && values.length > 0 && values[0] !== void 0 ? values[0] : null;\n }\n getAll(name) {\n return this.params.get(name) || [];\n }\n has(name) {\n return this.params.has(name);\n }\n set(name, value) {\n this.params.set(name, [String(value)]);\n }\n forEach(callback) {\n this.params.forEach((values, key) => {\n values.forEach((value) => {\n callback(value, key, this);\n });\n });\n }\n toString() {\n const parts = [];\n this.params.forEach((values, key) => {\n values.forEach((value) => {\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);\n });\n });\n return parts.join(\"&\");\n }\n }\n window.URLSearchParams = URLSearchParamsPolyfill;\n}\nfunction polyfillTextEncoder() {\n if (typeof TextEncoder !== \"undefined\") {\n return;\n }\n class TextEncoderPolyfill {\n constructor() {\n this.encoding = \"utf-8\";\n }\n encode(str) {\n const utf8 = [];\n for (let i = 0; i < str.length; i++) {\n let charcode = str.charCodeAt(i);\n if (charcode < 128) {\n utf8.push(charcode);\n } else if (charcode < 2048) {\n utf8.push(192 | charcode >> 6, 128 | charcode & 63);\n } else if (charcode < 55296 || charcode >= 57344) {\n utf8.push(\n 224 | charcode >> 12,\n 128 | charcode >> 6 & 63,\n 128 | charcode & 63\n );\n } else {\n i++;\n charcode = 65536 + ((charcode & 1023) << 10 | str.charCodeAt(i) & 1023);\n utf8.push(\n 240 | charcode >> 18,\n 128 | charcode >> 12 & 63,\n 128 | charcode >> 6 & 63,\n 128 | charcode & 63\n );\n }\n }\n return new Uint8Array(utf8);\n }\n }\n window.TextEncoder = TextEncoderPolyfill;\n}\nfunction polyfillPromiseFinally() {\n if (typeof Promise !== \"undefined\" && !Promise.prototype.finally) {\n Promise.prototype.finally = function(callback) {\n const constructor = this.constructor;\n return this.then(\n (value) => constructor.resolve(callback()).then(() => value),\n (reason) => constructor.resolve(callback()).then(() => {\n throw reason;\n })\n );\n };\n }\n}\nfunction polyfillObjectAssign() {\n if (typeof Object.assign !== \"function\") {\n Object.assign = function(target, ...sources) {\n if (target == null) {\n throw new TypeError(\"Cannot convert undefined or null to object\");\n }\n const to = Object(target);\n for (let i = 0; i < sources.length; i++) {\n const nextSource = sources[i];\n if (nextSource != null) {\n for (const nextKey in nextSource) {\n if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {\n to[nextKey] = nextSource[nextKey];\n }\n }\n }\n }\n return to;\n };\n }\n}\nfunction polyfillArrayFrom() {\n if (!Array.from) {\n Array.from = function(arrayLike, mapFn, thisArg) {\n const items = Object(arrayLike);\n if (arrayLike == null) {\n throw new TypeError(\"Array.from requires an array-like object\");\n }\n const len = items.length >>> 0;\n const result = new Array(len);\n for (let i = 0; i < len; i++) {\n if (mapFn) {\n result[i] = mapFn.call(thisArg, items[i], i);\n } else {\n result[i] = items[i];\n }\n }\n return result;\n };\n }\n}\nfunction polyfillStringStartsWith() {\n if (!String.prototype.startsWith) {\n String.prototype.startsWith = function(search, pos) {\n pos = !pos || pos < 0 ? 0 : +pos;\n return this.substring(pos, pos + search.length) === search;\n };\n }\n}\nfunction polyfillStringEndsWith() {\n if (!String.prototype.endsWith) {\n String.prototype.endsWith = function(search, length) {\n if (length === void 0 || length > this.length) {\n length = this.length;\n }\n return this.substring(length - search.length, length) === search;\n };\n }\n}\nfunction polyfillStringIncludes() {\n if (!String.prototype.includes) {\n String.prototype.includes = function(search, start) {\n if (typeof start !== \"number\") {\n start = 0;\n }\n if (start + search.length > this.length) {\n return false;\n }\n return this.indexOf(search, start) !== -1;\n };\n }\n}\nfunction initializePolyfills() {\n polyfillObjectAssign();\n polyfillArrayFrom();\n polyfillStringStartsWith();\n polyfillStringEndsWith();\n polyfillStringIncludes();\n polyfillURLSearchParams();\n polyfillTextEncoder();\n polyfillPromiseFinally();\n}\n\n// src/utils/browserCompat.ts\nfunction getChromeVersion(ua) {\n const match = ua.match(/Chrome\\/(\\d+)/);\n return match && match[1] ? parseInt(match[1], 10) : 0;\n}\nfunction getWebKitVersion(ua) {\n const match = ua.match(/AppleWebKit\\/(\\d+)/);\n return match && match[1] ? parseInt(match[1], 10) : 0;\n}\nfunction getPlatform() {\n if (\"userAgentData\" in navigator && navigator.userAgentData?.platform) {\n return navigator.userAgentData.platform;\n }\n const ua = navigator.userAgent;\n if (/Mac|iPhone|iPad|iPod/i.test(ua)) {\n return /iPhone|iPad|iPod/i.test(ua) ? \"iPhone\" : \"MacIntel\";\n }\n if (/Win/i.test(ua)) {\n return \"Win32\";\n }\n if (/Linux/i.test(ua)) {\n return /Android/i.test(ua) ? \"Linux armv8l\" : \"Linux x86_64\";\n }\n if (/CrOS/i.test(ua)) {\n return \"CrOS\";\n }\n return navigator.platform || \"Unknown\";\n}\nfunction detectBrowser() {\n const ua = navigator.userAgent;\n const platform = getPlatform();\n let name = \"Unknown\";\n let version = \"0\";\n let majorVersion = 0;\n let isSmartTV = false;\n let isLegacyTV = false;\n let supportsIMA = true;\n let supportsModernJS = true;\n let recommendedAdPlayer = \"ima\";\n let webOSVersion;\n let tizenVersion;\n let chromeVersionNum;\n const chromeVersion = getChromeVersion(ua);\n const webkitVersion = getWebKitVersion(ua);\n chromeVersionNum = chromeVersion > 0 ? chromeVersion : void 0;\n if (/Web0S|webOS|LG Browser|LGSTB/i.test(ua)) {\n name = \"LG WebOS\";\n isSmartTV = true;\n let match = ua.match(/Web0S[/\\s]*([\\d.]+)/i) || ua.match(/webOS[/\\s]*([\\d.]+)/i);\n if (!match || !match[1]) {\n match = ua.match(/webOSTV[/\\s-]*([\\d.]+)/i) || ua.match(/webOS\\.TV[/\\s-]*([\\d.]+)/i);\n }\n if (match && match[1]) {\n version = match[1];\n const parts = version.split(\".\");\n majorVersion = parts[0] ? parseInt(parts[0], 10) : 0;\n webOSVersion = majorVersion;\n } else if (chromeVersion > 0) {\n if (chromeVersion >= 79) {\n webOSVersion = 6;\n version = \"6.0\";\n majorVersion = 6;\n } else if (chromeVersion >= 68) {\n webOSVersion = 5;\n version = \"5.0\";\n majorVersion = 5;\n } else if (chromeVersion >= 53) {\n webOSVersion = 4;\n version = \"4.0\";\n majorVersion = 4;\n } else if (chromeVersion >= 38) {\n webOSVersion = 3;\n version = \"3.0\";\n majorVersion = 3;\n } else {\n webOSVersion = 2;\n version = \"2.0\";\n majorVersion = 2;\n }\n } else {\n version = \"Unknown\";\n webOSVersion = void 0;\n }\n if (webOSVersion !== void 0 && webOSVersion >= 4) {\n supportsIMA = true;\n recommendedAdPlayer = \"ima\";\n isLegacyTV = false;\n } else if (webOSVersion !== void 0 && webOSVersion >= 3) {\n if (chromeVersion >= 53) {\n supportsIMA = true;\n recommendedAdPlayer = \"ima\";\n isLegacyTV = false;\n } else {\n supportsIMA = false;\n recommendedAdPlayer = \"hls\";\n isLegacyTV = true;\n }\n } else if (chromeVersion >= 53) {\n supportsIMA = true;\n recommendedAdPlayer = \"ima\";\n isLegacyTV = false;\n } else {\n supportsIMA = false;\n recommendedAdPlayer = \"hls\";\n isLegacyTV = true;\n }\n } else if (/Tizen/i.test(ua)) {\n name = \"Samsung Tizen\";\n isSmartTV = true;\n const match = ua.match(/Tizen[/\\s]*([\\d.]+)/i);\n version = match && match[1] ? match[1] : \"Unknown\";\n if (version !== \"Unknown\") {\n const parts = version.split(\".\");\n majorVersion = parts[0] ? parseInt(parts[0], 10) : 0;\n tizenVersion = majorVersion;\n }\n if (tizenVersion !== void 0 && tizenVersion >= 4) {\n supportsIMA = true;\n recommendedAdPlayer = \"ima\";\n isLegacyTV = false;\n } else if (tizenVersion !== void 0 && tizenVersion >= 3 && chromeVersion >= 47) {\n supportsIMA = true;\n recommendedAdPlayer = \"ima\";\n isLegacyTV = false;\n } else if (chromeVersion >= 53) {\n supportsIMA = true;\n recommendedAdPlayer = \"ima\";\n isLegacyTV = false;\n } else {\n supportsIMA = false;\n recommendedAdPlayer = \"hls\";\n isLegacyTV = true;\n }\n } else if (/SMART-TV|SmartTV/i.test(ua)) {\n name = \"Smart TV\";\n isSmartTV = true;\n if (chromeVersion >= 53) {\n supportsIMA = true;\n recommendedAdPlayer = \"ima\";\n } else {\n supportsIMA = false;\n recommendedAdPlayer = \"hls\";\n isLegacyTV = true;\n }\n } else if (/NetCast/i.test(ua)) {\n name = \"LG NetCast\";\n isSmartTV = true;\n isLegacyTV = true;\n supportsIMA = false;\n recommendedAdPlayer = \"hls\";\n } else if (/BRAVIA/i.test(ua)) {\n name = \"Sony BRAVIA\";\n isSmartTV = true;\n if (chromeVersion >= 53) {\n supportsIMA = true;\n recommendedAdPlayer = \"ima\";\n } else {\n supportsIMA = false;\n recommendedAdPlayer = \"hls\";\n isLegacyTV = true;\n }\n } else {\n if (chromeVersion > 0) {\n name = \"Chrome\";\n version = chromeVersion.toString();\n majorVersion = chromeVersion;\n if (chromeVersion < 50) {\n supportsIMA = false;\n supportsModernJS = false;\n recommendedAdPlayer = \"hls\";\n }\n }\n if (webkitVersion > 0 && webkitVersion < 600) {\n supportsModernJS = false;\n if (chromeVersion < 50) {\n supportsIMA = false;\n recommendedAdPlayer = \"hls\";\n }\n }\n }\n if (typeof Promise === \"undefined\" || typeof Map === \"undefined\" || typeof Set === \"undefined\") {\n supportsModernJS = false;\n supportsIMA = false;\n recommendedAdPlayer = \"hls\";\n }\n if (typeof URLSearchParams === \"undefined\") {\n supportsModernJS = false;\n }\n return {\n name,\n version,\n majorVersion,\n isSmartTV,\n isLegacyTV,\n platform,\n supportsIMA,\n supportsModernJS,\n recommendedAdPlayer,\n webOSVersion,\n tizenVersion,\n chromeVersion: chromeVersionNum\n };\n}\nfunction supportsGoogleIMA() {\n const browser = detectBrowser();\n if (browser.isLegacyTV) {\n return false;\n }\n if (typeof document === \"undefined\" || typeof document.createElement !== \"function\") {\n return false;\n }\n try {\n const video = document.createElement(\"video\");\n if (!video) {\n return false;\n }\n } catch (e) {\n return false;\n }\n if (typeof Promise === \"undefined\") {\n return false;\n }\n return browser.supportsIMA;\n}\nfunction logBrowserInfo(debug = false) {\n if (!debug) return;\n const browser = detectBrowser();\n const imaSupport = supportsGoogleIMA();\n console.log(\"[StormcloudVideoPlayer] Browser Compatibility Info:\", {\n browser: `${browser.name} ${browser.version}`,\n platform: browser.platform,\n isSmartTV: browser.isSmartTV,\n isLegacyTV: browser.isLegacyTV,\n supportsIMA: imaSupport,\n supportsModernJS: browser.supportsModernJS,\n recommendedAdPlayer: browser.recommendedAdPlayer,\n ...browser.webOSVersion !== void 0 ? { webOSVersion: browser.webOSVersion } : {},\n ...browser.tizenVersion !== void 0 ? { tizenVersion: browser.tizenVersion } : {},\n ...browser.chromeVersion !== void 0 ? { chromeVersion: browser.chromeVersion } : {},\n userAgent: navigator.userAgent\n });\n}\nfunction getBrowserConfigOverrides() {\n const browser = detectBrowser();\n const overrides = {};\n if (browser.isSmartTV) {\n overrides.allowNativeHls = true;\n }\n return overrides;\n}\n\n// src/player/StormcloudVideoPlayer.ts\nvar DEBUG_HISTORY_LIMIT = 120;\nvar StormcloudVideoPlayer = class {\n constructor(config) {\n this.pendingNextAdBids = null;\n this.continuousFetchLoopPromise = null;\n this.attached = false;\n this.inAdBreak = false;\n this.adPodQueue = [];\n this.lastHeartbeatTime = 0;\n this.currentAdIndex = 0;\n this.totalAdsInBreak = 0;\n this.showAds = false;\n this.isLiveStream = false;\n this.nativeHlsMode = false;\n this.videoSrcProtection = null;\n this.bufferedSegmentsCount = 0;\n this.shouldAutoplayAfterBuffering = false;\n this.hasInitialBufferCompleted = false;\n this.activeAdRequestToken = null;\n this.adRequestWatchdogToken = null;\n this.adFailsafeToken = null;\n this.continuousFetchingActive = false;\n this.isInAdTransition = false;\n this.maxPlaceholderDurationMs = 5e3;\n this.isShowingPlaceholder = false;\n this.lastAdInsertionPoint = null;\n this.processedAdInsertionUpdatedAt = null;\n this.totalAdRequestsInBreak = 0;\n this.maxTotalAdRequestsPerBreak = 20;\n this.pendingAdBreak = null;\n this.savedMutedStateBeforeAd = null;\n this.consecutiveFailures = 0;\n this.maxConsecutiveFailures = 5;\n this.lastAdRequestTime = 0;\n this.minAdRequestIntervalMs = 2500;\n this.backoffBaseMs = 1e3;\n this.maxBackoffMs = 15e3;\n this.MIN_AD_REMAINING_MS = 15e3;\n this.adRequestTimeoutMs = 5e3;\n this.adRequestMaxRetries = 3;\n this.adRequestRetryBackoffMs = 1500;\n this.preloadedTokens = [];\n this.debugLogEntries = [];\n this.adInsertionDebugHistory = [];\n initializePolyfills();\n const browserOverrides = getBrowserConfigOverrides();\n this.config = { ...browserOverrides, ...config };\n this.video = config.videoElement;\n this.adTransitionGapMs = this.config.adTransitionGapMs ?? 100;\n logBrowserInfo(config.debugAdTiming);\n const browserForAdLayer = detectBrowser();\n const isSinglePipeline = browserForAdLayer.isSmartTV || !!this.config.singlePipelineMode;\n this.adLayer = createAdStormPlayer(this.video, {\n licenseKey: this.config.licenseKey || \"\",\n debug: !!config.debugAdTiming\n });\n this.adLayer.updateOptions({\n continueLiveStreamDuringAds: !isSinglePipeline && this.shouldContinueLiveStreamDuringAds()\n });\n }\n async adRequest(context) {\n if (this.config.disableAds) return [];\n const durationSeconds = Math.max(\n 1,\n Math.ceil(context?.remainingBreakSec ?? context?.breakDurationSec ?? 30)\n );\n await this.adLayer.requestAds(String(durationSeconds));\n return [\n {\n bidder: \"adstorm-direct\",\n cpm: 0,\n width: 0,\n height: 0,\n adId: \"adstorm\",\n impId: \"\",\n creativeId: \"adstorm\",\n currency: \"USD\",\n durationSec: durationSeconds\n }\n ];\n }\n async load() {\n if (!this.attached) {\n this.attach();\n }\n this.initializeTracking();\n if (this.shouldUseNativeHls()) {\n this.nativeHlsMode = true;\n this.videoSrcProtection = this.config.src;\n this.video.src = this.config.src;\n this.isLiveStream = this.config.lowLatencyMode ?? false;\n if (this.config.debugAdTiming) {\n console.log(\n \"[StormcloudVideoPlayer] Using native HLS playback - VOD mode:\",\n {\n isLive: this.isLiveStream,\n allowNativeHls: this.config.allowNativeHls,\n adBehavior: \"vod (main video pauses during ads)\"\n }\n );\n }\n if (!this.config.disableAds) {\n this.adLayer.updateOptions({ continueLiveStreamDuringAds: false, mainHlsInstance: null });\n }\n if (this.config.autoplay) {\n await this.video.play()?.catch(() => {\n });\n }\n return;\n }\n this.hls = new import_hls.default({\n enableWorker: true,\n backBufferLength: 30,\n liveDurationInfinity: true,\n lowLatencyMode: !!this.config.lowLatencyMode,\n maxLiveSyncPlaybackRate: this.config.lowLatencyMode ? 1.5 : 1,\n ...this.config.lowLatencyMode ? { liveSyncDuration: 2 } : {},\n maxBufferLength: 30,\n maxMaxBufferLength: 600,\n maxBufferSize: 60 * 1e3 * 1e3,\n maxBufferHole: 0.5,\n highBufferWatchdogPeriod: 2,\n nudgeOffset: 0.1,\n nudgeMaxRetry: 3,\n startPosition: -1\n });\n this.hls.on(import_hls.default.Events.MEDIA_ATTACHED, () => {\n this.hls?.loadSource(this.config.src);\n });\n this.hls.on(import_hls.default.Events.MANIFEST_PARSED, async (_, data) => {\n if (this.config.allowNativeHls === false) {\n this.isLiveStream = true;\n } else {\n this.isLiveStream = this.hls?.levels?.some(\n (level) => level?.details?.live === true || level?.details?.type === \"LIVE\"\n ) ?? false;\n }\n if (this.config.debugAdTiming) {\n const adBehavior = this.shouldContinueLiveStreamDuringAds() ? \"live (main video continues muted during ads)\" : \"vod (main video pauses during ads)\";\n console.log(\"[StormcloudVideoPlayer] Stream type detected:\", {\n isLive: this.isLiveStream,\n allowNativeHls: this.config.allowNativeHls,\n adBehavior\n });\n }\n if (!this.config.disableAds) {\n this.adLayer.updateOptions({\n continueLiveStreamDuringAds: this.shouldContinueLiveStreamDuringAds(),\n mainHlsInstance: this.hls ?? null\n });\n }\n this.bufferedSegmentsCount = 0;\n this.hasInitialBufferCompleted = false;\n this.shouldAutoplayAfterBuffering = !!this.config.autoplay;\n const minSegments = this.config.minSegmentsBeforePlay ?? 2;\n if (this.config.debugAdTiming) {\n console.log(\n \"[StormcloudVideoPlayer] Waiting for\",\n minSegments,\n \"segments to buffer before playback\"\n );\n }\n if (minSegments === 0 || !this.config.autoplay) {\n this.hasInitialBufferCompleted = true;\n if (this.config.autoplay) {\n await this.video.play()?.catch(() => {\n });\n }\n }\n if (!this.config.disableAds && this.config.projectId) {\n this.startAdInsertionPolling();\n }\n });\n this.hls.on(import_hls.default.Events.LEVEL_LOADED, () => {\n if (this.inAdBreak || this.pendingAdBreak) {\n return;\n }\n this.checkAdInsertionInManifest();\n });\n this.hls.on(import_hls.default.Events.FRAG_BUFFERED, async (_evt, data) => {\n if (this.hasInitialBufferCompleted) {\n return;\n }\n this.bufferedSegmentsCount++;\n const minSegments = this.config.minSegmentsBeforePlay ?? 2;\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Buffered segment ${this.bufferedSegmentsCount}/${minSegments}`\n );\n }\n if (this.bufferedSegmentsCount >= minSegments) {\n this.hasInitialBufferCompleted = true;\n if (this.shouldAutoplayAfterBuffering) {\n if (this.inAdBreak || this.adLayer.isAdPlaying()) {\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Initial buffer complete (${this.bufferedSegmentsCount} segments). Ad break active \\u2014 deferring play() to handleAdPodComplete().`\n );\n }\n } else {\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Initial buffer complete (${this.bufferedSegmentsCount} segments). Starting playback.`\n );\n }\n await this.video.play()?.catch((err) => {\n if (this.config.debugAdTiming) {\n console.warn(\"[StormcloudVideoPlayer] Autoplay failed:\", err);\n }\n });\n }\n }\n }\n });\n this.hls.on(import_hls.default.Events.FRAG_CHANGED, (_evt, data) => {\n const frag = data?.frag;\n if (!frag) return;\n if (this.lastAdInsertionPoint && !this.inAdBreak && this.lastAdInsertionPoint.updated_at !== this.processedAdInsertionUpdatedAt) {\n const segmentName = this.lastAdInsertionPoint.segment_ts_name;\n if (this.fragmentMatchesSegment(frag, segmentName)) {\n this.processedAdInsertionUpdatedAt = this.lastAdInsertionPoint.updated_at;\n const offsetMs = (this.lastAdInsertionPoint.offset_seconds || 0) * 1e3;\n this.pushAdInsertionDebug(\"segment_playing\", segmentName, {\n offsetSeconds: this.lastAdInsertionPoint.offset_seconds,\n detail: `sn=${frag?.sn ?? \"?\"}`\n });\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Ad insertion segment \"${segmentName}\" now playing \\u2014 scheduling ad start in ${offsetMs}ms`\n );\n }\n this.pushAdInsertionDebug(\"ad_scheduled\", segmentName, {\n offsetSeconds: this.lastAdInsertionPoint.offset_seconds,\n detail: `in ${offsetMs}ms, dur=60s`\n });\n this.clearAdInsertionOffsetTimer();\n this.adInsertionOffsetTimerId = window.setTimeout(() => {\n this.adInsertionOffsetTimerId = void 0;\n if (this.inAdBreak) return;\n this.pushAdInsertionDebug(\"ad_triggered\", segmentName, {\n detail: \"ad break started (60s)\"\n });\n void this.handleAdStart(60);\n }, offsetMs);\n }\n }\n });\n this.hls.on(import_hls.default.Events.FRAG_PARSING_USERDATA, (_evt, data) => {\n const samples = data?.samples ?? [];\n for (const sample of samples) {\n const bytes = sample?.data;\n if (!bytes || bytes.length < 5) continue;\n const isSCTE35 = bytes[0] === 252;\n if (!isSCTE35) continue;\n const segName = data?.frag?.relurl ?? data?.frag?.url ?? \"\";\n this.pushAdInsertionDebug(\"scte35_inserted\", segName, {\n detail: `len=${bytes.length}B`\n });\n }\n });\n this.hls.on(import_hls.default.Events.ERROR, (_evt, data) => {\n if (data?.fatal) {\n switch (data.type) {\n case import_hls.default.ErrorTypes.NETWORK_ERROR:\n this.hls?.startLoad();\n break;\n case import_hls.default.ErrorTypes.MEDIA_ERROR:\n this.hls?.recoverMediaError();\n break;\n default:\n this.destroy();\n break;\n }\n }\n });\n this.hls.attachMedia(this.video);\n }\n getAdSource() {\n return \"vast\";\n }\n attachAdLayerEventListeners() {\n this.adLayer.on(\"ad_impression\", () => {\n if (this.config.licenseKey) {\n sendAdImpressionTracking(this.config.licenseKey, {\n source: this.getAdSource(),\n adIndex: this.currentAdIndex,\n timestamp: (/* @__PURE__ */ new Date()).toISOString()\n });\n }\n });\n this.adLayer.on(\"ad_error\", (errorPayload) => {\n let errorMessage = \"Ad playback failed\";\n if (errorPayload) {\n const errorCode = errorPayload.code || errorPayload.errorCode || \"unknown\";\n const vastErrorCode = errorPayload.vastErrorCode;\n const message = errorPayload.message || errorPayload.errorMessage || \"Unknown error\";\n const cause = errorPayload.cause || errorPayload.innerError || errorPayload.error;\n errorMessage = `Ad error: AdError ${errorCode}: ${message}`;\n if (vastErrorCode && vastErrorCode !== \"N/A\" && vastErrorCode !== errorCode) {\n errorMessage += ` (VAST Error Code: ${vastErrorCode})`;\n }\n if (cause) {\n const causeMessage = typeof cause === \"string\" ? cause : cause.message || String(cause);\n errorMessage += `. Caused by: ${causeMessage}`;\n }\n }\n this.pushDebugLog(\"error\", \"ad\", errorMessage, {\n ...errorPayload ? { payload: errorPayload } : {}\n });\n console.error(\"[AD-ERROR]\", errorMessage, errorPayload || \"\");\n this.adLayer.stop().catch(() => {\n });\n this.handleAdFailure();\n });\n this.adLayer.on(\"content_pause\", () => {\n this.clearAdFailsafeTimer();\n this.clearAdRequestWatchdog();\n this.activeAdRequestToken = null;\n this.showAds = true;\n if (this.config.disableFiller) {\n if (this.savedMutedStateBeforeAd == null) {\n this.savedMutedStateBeforeAd = { muted: this.video.muted, volume: this.video.volume };\n this.adLayer.updateOriginalMutedState(this.video.muted, this.video.volume);\n }\n if (!this.video.muted) {\n this.video.muted = true;\n this.video.volume = 0;\n }\n this.adLayer.showPlaceholder();\n }\n if (this.inAdBreak && this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {\n this.scheduleAdStopCountdown(this.getRemainingAdMs());\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Starting ad break timer on content_pause (first ad starting)\");\n }\n }\n this.adLayer.setAdVolume(\n this.adLayer.getOriginalMutedState() ? 1 : this.adLayer.getOriginalVolume()\n );\n this.stopFillerBreakTimer();\n this.hidePlaceholderLayer();\n this.isShowingPlaceholder = false;\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Hiding placeholder - new ads starting\");\n }\n });\n this.adLayer.on(\"content_resume\", () => {\n const remaining = this.getRemainingAdMs();\n const breakMuted = this.savedMutedStateBeforeAd?.muted ?? this.adLayer.getOriginalMutedState();\n const breakVolume = this.savedMutedStateBeforeAd?.volume ?? this.adLayer.getOriginalVolume();\n if (this.config.debugAdTiming) {\n console.log(\n \"[StormcloudVideoPlayer] content_resume received, inAdBreak=%s, remaining=%s, preloadedTokens=%d, pendingNext=%s\",\n this.inAdBreak,\n remaining,\n this.preloadedTokens.length,\n !!this.pendingNextAdBids\n );\n }\n this.clearAdFailsafeTimer();\n this.clearAdRequestWatchdog();\n this.activeAdRequestToken = null;\n this.showAds = false;\n if (!this.inAdBreak) {\n this.video.style.visibility = \"visible\";\n this.video.style.opacity = \"1\";\n this.syncMainContentAudioWhenVisible();\n return;\n }\n this.consecutiveFailures = 0;\n if (!this.config.disableFiller && !this.video.muted) {\n this.video.muted = true;\n this.video.volume = 0;\n }\n if (this.preloadedTokens.length > 0) {\n const token = this.preloadedTokens.shift();\n const remainingNow = this.getRemainingAdMs();\n if (this.expectedAdBreakDurationMs != null && remainingNow < this.MIN_AD_REMAINING_MS) {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] content_resume: skip preloaded ad, only\", remainingNow, \"ms left\");\n }\n this.adLayer.cancelPreload(token);\n } else {\n if (!this.config.singlePipelineMode) {\n this.showPlaceholderLayer();\n }\n this.adLayer.showPlaceholder();\n this.isInAdTransition = true;\n setTimeout(() => {\n this.isInAdTransition = false;\n if (!this.inAdBreak) return;\n this.currentAdIndex++;\n this.adLayer.playPreloaded(token).catch((err) => {\n if (this.config.debugAdTiming) console.warn(\"[StormcloudVideoPlayer] playPreloaded failed:\", err);\n this.handleAdFailure();\n });\n }, this.adTransitionGapMs);\n return;\n }\n }\n if (this.pendingNextAdBids && this.pendingNextAdBids.length > 0) {\n const bids = [...this.pendingNextAdBids];\n this.pendingNextAdBids = null;\n const remainingNow = this.getRemainingAdMs();\n if (this.expectedAdBreakDurationMs != null && remainingNow < this.MIN_AD_REMAINING_MS) {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] content_resume: skip pending bids, only\", remainingNow, \"ms left\");\n }\n } else {\n if (!this.config.singlePipelineMode) {\n this.showPlaceholderLayer();\n }\n this.adLayer.showPlaceholder();\n this.isInAdTransition = true;\n setTimeout(() => {\n this.isInAdTransition = false;\n if (!this.inAdBreak || bids.length === 0) return;\n const freshBids = this.pendingNextAdBids ?? bids;\n this.pendingNextAdBids = null;\n this.currentAdIndex++;\n this.adLayer.playAd(freshBids).catch((err) => {\n if (this.config.debugAdTiming) console.warn(\"[StormcloudVideoPlayer] playAd(pending) failed:\", err);\n this.handleAdFailure();\n });\n }, this.adTransitionGapMs);\n return;\n }\n }\n const remainingFinal = this.getRemainingAdMs();\n if (this.inAdBreak && remainingFinal > this.MIN_AD_REMAINING_MS) {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] content_resume: ad ended/failed with time remaining, showing filler and continuing fetch for\", remainingFinal, \"ms\");\n }\n if (!this.config.disableFiller) {\n this.showPlaceholderLayer();\n this.adLayer.showPlaceholder();\n } else {\n this.adLayer.hidePlaceholder();\n if (this.video.muted !== breakMuted) {\n this.video.muted = breakMuted;\n }\n if (Math.abs(this.video.volume - breakVolume) > 0.01) {\n this.video.volume = breakVolume;\n }\n if (this.video.paused) {\n this.video.play()?.catch(() => {\n });\n }\n }\n this.continuousFetchingActive = true;\n this.startContinuousFetchLoop();\n return;\n }\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] content_resume: no more ads, ending ad pod\");\n }\n this.handleAdPodComplete();\n });\n }\n ensureFillerVideo() {\n if (this.fillerVideo) return;\n if (!this.video.parentElement) return;\n const filler = document.createElement(\"video\");\n filler.src = \"https://f000.backblazeb2.com/file/AdStormAds/384/Sonifi_Filler.mp4\";\n filler.loop = true;\n filler.muted = false;\n filler.playsInline = true;\n filler.style.position = \"absolute\";\n filler.style.left = \"0\";\n filler.style.top = \"0\";\n filler.style.width = \"100%\";\n filler.style.height = \"100%\";\n filler.style.objectFit = \"cover\";\n filler.style.zIndex = \"20\";\n filler.style.display = \"none\";\n filler.preload = \"auto\";\n this.video.parentElement.appendChild(filler);\n this.fillerVideo = filler;\n }\n showPlaceholderLayer() {\n if (this.config.disableFiller) return;\n this.ensureFillerVideo();\n if (!this.fillerVideo) return;\n if (!this.video.muted) {\n this.video.muted = true;\n this.video.volume = 0;\n }\n this.fillerVideo.style.display = \"block\";\n this.fillerVideo.play().catch(() => {\n if (this.fillerVideo) {\n this.fillerVideo.style.display = \"none\";\n }\n if (!this.adLayer.isAdPlaying()) {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Filler video failed \\u2014 restoring main video\");\n }\n this.adLayer.hidePlaceholder();\n if (this.video.paused && this.video.readyState >= 2) {\n this.video.play()?.catch(() => {\n });\n }\n }\n });\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Showing filler video layer\");\n }\n }\n hidePlaceholderLayer() {\n if (!this.fillerVideo) return;\n this.fillerVideo.style.display = \"none\";\n this.fillerVideo.pause();\n this.fillerVideo.currentTime = 0;\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Hiding filler video layer\");\n }\n }\n startFillerBreakTimer(durationMs) {\n this.stopFillerBreakTimer();\n this.showPlaceholderLayer();\n this.fillerBreakTimerId = setTimeout(() => {\n this.fillerBreakTimerId = void 0;\n this.hidePlaceholderLayer();\n if (this.inAdBreak) this.handleAdPodComplete();\n }, durationMs);\n }\n stopFillerBreakTimer() {\n if (this.fillerBreakTimerId !== void 0) {\n clearTimeout(this.fillerBreakTimerId);\n this.fillerBreakTimerId = void 0;\n }\n }\n attach() {\n if (this.attached) return;\n this.attached = true;\n this.video.autoplay = !!this.config.autoplay;\n this.video.muted = !!this.config.muted;\n if (!this.config.disableAds) {\n this.adLayer.initialize();\n if (!this.config.disableFiller) {\n this.ensureFillerVideo();\n }\n this.adLayer.updateOriginalMutedState(this.video.muted, this.video.volume);\n this.attachAdLayerEventListeners();\n }\n this.timeUpdateHandler = () => {\n this.onTimeUpdate(this.video.currentTime);\n };\n this.video.addEventListener(\"timeupdate\", this.timeUpdateHandler);\n this.emptiedHandler = () => {\n if (this.nativeHlsMode && this.videoSrcProtection && !this.adLayer.isAdPlaying()) {\n if (this.config.debugAdTiming) {\n console.log(\n \"[StormcloudVideoPlayer] Video src was cleared, restoring:\",\n this.videoSrcProtection\n );\n }\n const currentTime = this.video.currentTime;\n const wasPaused = this.video.paused;\n this.video.src = this.videoSrcProtection;\n this.video.currentTime = currentTime;\n if (!wasPaused) {\n this.video.play().catch(() => {\n });\n }\n }\n };\n this.video.addEventListener(\"emptied\", this.emptiedHandler);\n }\n shouldUseNativeHls() {\n const streamType = this.getStreamType();\n if (streamType === \"other\") {\n return true;\n }\n const canNative = this.video.canPlayType(\"application/vnd.apple.mpegurl\");\n return !!(this.config.allowNativeHls && canNative);\n }\n initializeTracking() {\n sendInitialTracking(this.config.licenseKey).then(() => {\n this.heartbeatInterval = window.setInterval(() => {\n this.sendHeartbeatIfNeeded();\n }, 5e3);\n }).catch((error) => {\n if (this.config.debugAdTiming) {\n console.warn(\n \"[StormcloudVideoPlayer] Failed to send initial tracking:\",\n error\n );\n }\n this.heartbeatInterval = window.setInterval(() => {\n this.sendHeartbeatIfNeeded();\n }, 5e3);\n });\n }\n sendHeartbeatIfNeeded() {\n const now = Date.now();\n if (!this.lastHeartbeatTime || now - this.lastHeartbeatTime > 3e4) {\n this.lastHeartbeatTime = now;\n sendHeartbeat(this.config.licenseKey).catch((error) => {\n if (this.config.debugAdTiming) {\n console.warn(\n \"[StormcloudVideoPlayer] Failed to send heartbeat:\",\n error\n );\n }\n });\n }\n }\n getCurrentAdIndex() {\n return this.currentAdIndex;\n }\n getTotalAdsInBreak() {\n return this.totalAdsInBreak;\n }\n getRemainingAdSeconds() {\n const remainingMs = this.getRemainingAdMs();\n if (!Number.isFinite(remainingMs) || remainingMs <= 0 || remainingMs === Number.MAX_SAFE_INTEGER) {\n return 0;\n }\n return Math.ceil(remainingMs / 1e3);\n }\n isAdPlaying() {\n return this.inAdBreak && this.adLayer.isAdPlaying();\n }\n isShowingAds() {\n return this.showAds;\n }\n syncMainContentAudioWhenVisible() {\n const adLayerShowing = this.showAds || this.adLayer.isAdPlaying();\n if (adLayerShowing) return;\n const muted = this.adLayer.getOriginalMutedState();\n const volume = this.adLayer.getOriginalVolume();\n if (this.video.muted !== muted) this.video.muted = muted;\n if (Math.abs(this.video.volume - volume) > 0.01) this.video.volume = volume;\n }\n getStreamType() {\n const url = this.config.src.toLowerCase();\n if (url.includes(\".m3u8\") || url.includes(\"/hls/\") || url.includes(\"application/vnd.apple.mpegurl\")) {\n return \"hls\";\n }\n return \"other\";\n }\n shouldShowNativeControls() {\n const streamType = this.getStreamType();\n if (streamType === \"other\") {\n return !(this.config.showCustomControls ?? false);\n }\n return !!(this.config.allowNativeHls && !(this.config.showCustomControls ?? false));\n }\n shouldContinueLiveStreamDuringAds() {\n if (this.config.allowNativeHls) {\n return false;\n }\n if (!this.isLiveStream) {\n return false;\n }\n if (this.config.singlePipelineMode) {\n return false;\n }\n const browser = detectBrowser();\n if (browser.isSmartTV) {\n return false;\n }\n return true;\n }\n startAdPrefetch(durationSeconds, fragmentSn) {\n if (this.config.disableAds) return;\n if (this.pendingAdBreak || this.inAdBreak) {\n return;\n }\n this.pendingAdBreak = {\n ...durationSeconds !== void 0 ? { durationSeconds } : {},\n ...fragmentSn !== void 0 ? { detectedAtFragmentSn: fragmentSn } : {},\n isFetching: false,\n fetchStartTime: Date.now()\n };\n void this.runAdPrefetch(durationSeconds);\n if (this.config.debugAdTiming) {\n console.log(\"[PREFETCH] Ad break registered, multi-ad prefetch started\");\n }\n }\n async runAdPrefetch(durationSeconds) {\n const durSec = durationSeconds ?? 60;\n const context = {\n breakDurationSec: durSec,\n remainingBreakSec: durSec\n };\n let firstBids;\n try {\n firstBids = await this.adRequest({ ...context, adIndex: 1 });\n } catch {\n firstBids = [];\n }\n if (this.inAdBreak) return;\n if (firstBids.length === 0) {\n if (this.config.debugAdTiming) {\n console.log(\"[PREFETCH] First VAST request returned no ad, aborting prefetch\");\n }\n return;\n }\n const adDurationSec = firstBids[0]?.durationSec ?? 30;\n const estimatedCount = Math.max(1, Math.ceil(durSec / adDurationSec));\n if (this.config.debugAdTiming) {\n console.log(\n `[PREFETCH] Ad duration=${adDurationSec}s, break=${durSec}s \\u2192 ${estimatedCount} ad(s) needed`\n );\n }\n const firstToken = `preload_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;\n try {\n await this.adLayer.preloadAd(firstBids, firstToken);\n if (!this.inAdBreak) {\n this.preloadedTokens.push(firstToken);\n if (this.config.debugAdTiming) {\n console.log(`[PREFETCH] First ad preloaded and queued, token=${firstToken}`);\n }\n }\n } catch {\n if (this.config.debugAdTiming) {\n console.warn(`[PREFETCH] First ad preload failed, token=${firstToken}`);\n }\n }\n if (estimatedCount > 1) {\n const remaining = Array.from(\n { length: estimatedCount - 1 },\n (_, i) => this.adRequest({ ...context, adIndex: i + 2 }).then((bids) => ({ ok: true, value: bids })).catch(() => ({ ok: false }))\n );\n const results = await Promise.all(remaining);\n for (const result of results) {\n if (this.inAdBreak) break;\n if (result.ok && result.value.length > 0) {\n const token = `preload_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;\n try {\n await this.adLayer.preloadAd(result.value, token);\n if (!this.inAdBreak) {\n this.preloadedTokens.push(token);\n if (this.config.debugAdTiming) {\n console.log(`[PREFETCH] Additional ad preloaded and queued, token=${token}`);\n }\n }\n } catch {\n if (this.config.debugAdTiming) {\n console.warn(`[PREFETCH] Additional ad preload failed, token=${token}`);\n }\n }\n }\n }\n }\n if (this.config.debugAdTiming) {\n console.log(`[PREFETCH] Pre-fetch complete: ${this.preloadedTokens.length} ad(s) queued`);\n }\n }\n clearPendingAdBreak() {\n if (this.prefetchTimerId != null) {\n clearTimeout(this.prefetchTimerId);\n this.prefetchTimerId = void 0;\n }\n this.pendingAdBreak = null;\n }\n cancelAndClearPreloadedTokens() {\n for (const token of this.preloadedTokens) {\n this.adLayer.cancelPreload(token);\n }\n this.preloadedTokens = [];\n }\n startAdInsertionPolling() {\n if (this.adInsertionPollingId != null) return;\n this.fetchAdInsertionPoint();\n this.adInsertionPollingId = window.setInterval(() => {\n this.fetchAdInsertionPoint();\n }, 1e3);\n }\n stopAdInsertionPolling() {\n if (this.adInsertionPollingId != null) {\n clearInterval(this.adInsertionPollingId);\n this.adInsertionPollingId = void 0;\n }\n }\n async fetchAdInsertionPoint() {\n if (!this.config.projectId) return;\n try {\n const resp = await fetch(\n `https://adstorm.co/api-adstorm-dev/adstorm/swirl/projects/${encodeURIComponent(this.config.projectId)}/ad-insertion-point`\n );\n if (!resp.ok) return;\n const data = await resp.json();\n const isNew = data.updated_at !== this.lastAdInsertionPoint?.updated_at;\n this.lastAdInsertionPoint = data;\n if (isNew) {\n this.pushAdInsertionDebug(\"api_response\", data.segment_ts_name, {\n offsetSeconds: data.offset_seconds,\n updatedAt: data.updated_at,\n detail: `project=${data.project_id}`\n });\n }\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Ad insertion point API response:\", data);\n }\n } catch {\n if (this.config.debugAdTiming) {\n console.warn(\"[StormcloudVideoPlayer] Ad insertion point API fetch failed\");\n }\n }\n }\n checkAdInsertionInManifest() {\n if (!this.lastAdInsertionPoint) return;\n if (this.inAdBreak || this.pendingAdBreak) return;\n if (this.lastAdInsertionPoint.updated_at === this.processedAdInsertionUpdatedAt) return;\n const segmentName = this.lastAdInsertionPoint.segment_ts_name;\n const levels = this.hls?.levels;\n if (!levels) return;\n for (const level of levels) {\n const fragments = level.details?.fragments;\n if (!Array.isArray(fragments)) continue;\n for (const frag of fragments) {\n if (this.fragmentMatchesSegment(frag, segmentName)) {\n this.pushAdInsertionDebug(\"segment_found\", segmentName, {\n detail: `sn=${frag?.sn ?? \"?\"}`\n });\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Ad insertion segment \"${segmentName}\" found in manifest \\u2014 starting pre-fetch`\n );\n }\n this.startAdPrefetch(60, frag?.sn);\n return;\n }\n }\n }\n }\n fragmentMatchesSegment(frag, segmentName) {\n const rawUrl = frag?.url || frag?.relurl || \"\";\n const url = rawUrl.split(\"?\")[0] ?? \"\";\n const name = segmentName.startsWith(\"/\") ? segmentName : \"/\" + segmentName;\n return url.endsWith(name) || url.includes(name);\n }\n clearAdInsertionOffsetTimer() {\n if (this.adInsertionOffsetTimerId != null) {\n clearTimeout(this.adInsertionOffsetTimerId);\n this.adInsertionOffsetTimerId = void 0;\n }\n }\n startContinuousFetchLoop() {\n if (this.continuousFetchLoopPromise != null) return;\n this.continuousFetchLoopPromise = this.runContinuousFetchLoop();\n }\n async runContinuousFetchLoop() {\n const backoffMs = () => {\n const mult = Math.pow(2, this.consecutiveFailures);\n return Math.min(this.backoffBaseMs * mult, this.maxBackoffMs);\n };\n while (this.inAdBreak && this.continuousFetchingActive) {\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) break;\n if (this.totalAdRequestsInBreak >= this.maxTotalAdRequestsPerBreak) break;\n if (this.adLayer.isAdPlaying() || this.isInAdTransition) {\n if (this.pendingNextAdBids == null) {\n try {\n const remaining = this.getRemainingAdMs();\n const prefetchContext = this.expectedAdBreakDurationMs != null ? {\n breakDurationSec: this.expectedAdBreakDurationMs / 1e3,\n remainingBreakSec: remaining / 1e3,\n adIndex: this.currentAdIndex + 1\n } : void 0;\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Pre-fetching next ad during playback, remaining:\", remaining, \"ms\");\n }\n const bids = await this.adRequest(prefetchContext);\n this.lastAdRequestTime = Date.now();\n if (!this.inAdBreak) break;\n if (bids.length > 0) {\n this.consecutiveFailures = 0;\n this.pendingNextAdBids = bids;\n this.totalAdsInBreak = Math.max(\n this.totalAdsInBreak,\n this.currentAdIndex + this.preloadedTokens.length + 1\n );\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Pre-fetched next ad stored as pending\");\n }\n } else {\n this.consecutiveFailures++;\n }\n } catch (err) {\n this.consecutiveFailures++;\n if (this.config.debugAdTiming) {\n console.warn(\"[CONTINUOUS-FETCH] Pre-fetch adRequest failed:\", err);\n }\n }\n } else {\n await new Promise((r) => setTimeout(r, 200));\n }\n continue;\n }\n if (this.pendingNextAdBids != null && this.pendingNextAdBids.length > 0) {\n const bids = this.pendingNextAdBids;\n this.pendingNextAdBids = null;\n const remainingNow = this.getRemainingAdMs();\n if (this.expectedAdBreakDurationMs == null || remainingNow >= this.MIN_AD_REMAINING_MS) {\n this.currentAdIndex++;\n if (this.config.licenseKey) {\n sendAdLoadedTracking(this.config.licenseKey, {\n source: this.getAdSource(),\n timestamp: (/* @__PURE__ */ new Date()).toISOString()\n });\n }\n await this.adLayer.playAd(bids);\n if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {\n this.scheduleAdStopCountdown(this.getRemainingAdMs());\n }\n this.adLayer.setAdVolume(\n this.adLayer.getOriginalMutedState() ? 1 : this.adLayer.getOriginalVolume()\n );\n } else if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Discarding pre-fetched bids: only\", remainingNow, \"ms left\");\n }\n continue;\n }\n const urgentNeedAd = this.inAdBreak && !this.adLayer.isAdPlaying();\n const delay = this.lastAdRequestTime ? this.minAdRequestIntervalMs + (!urgentNeedAd && this.consecutiveFailures > 0 ? backoffMs() : 0) : 0;\n const elapsed = Date.now() - this.lastAdRequestTime;\n if (elapsed < delay && this.lastAdRequestTime > 0) {\n await new Promise((r) => setTimeout(r, delay - elapsed));\n }\n if (!this.inAdBreak || !this.continuousFetchingActive) break;\n try {\n const remaining = this.getRemainingAdMs();\n const context = this.expectedAdBreakDurationMs != null ? {\n breakDurationSec: this.expectedAdBreakDurationMs / 1e3,\n remainingBreakSec: remaining / 1e3,\n adIndex: this.currentAdIndex + 1\n } : void 0;\n const bids = await this.adRequest(context);\n this.lastAdRequestTime = Date.now();\n if (!this.inAdBreak) break;\n if (bids.length > 0) {\n this.consecutiveFailures = 0;\n if (this.adLayer.isAdPlaying() || this.isInAdTransition) {\n this.pendingNextAdBids = bids;\n this.totalAdsInBreak = Math.max(\n this.totalAdsInBreak,\n this.currentAdIndex + this.preloadedTokens.length + 1\n );\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Next ad response stored (ad currently playing or in transition)\");\n }\n } else {\n const remainingNow = this.getRemainingAdMs();\n if (this.expectedAdBreakDurationMs != null && remainingNow < this.MIN_AD_REMAINING_MS) {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Skipping ad from loop: only\", remainingNow, \"ms left\");\n }\n } else {\n this.currentAdIndex++;\n if (this.config.licenseKey) {\n sendAdLoadedTracking(this.config.licenseKey, {\n source: this.getAdSource(),\n timestamp: (/* @__PURE__ */ new Date()).toISOString()\n });\n }\n await this.adLayer.playAd(bids);\n if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {\n this.scheduleAdStopCountdown(this.getRemainingAdMs());\n }\n this.adLayer.setAdVolume(\n this.adLayer.getOriginalMutedState() ? 1 : this.adLayer.getOriginalVolume()\n );\n }\n }\n } else {\n this.consecutiveFailures++;\n }\n } catch (err) {\n this.consecutiveFailures++;\n if (this.config.debugAdTiming) {\n console.warn(\"[CONTINUOUS-FETCH] adRequest failed:\", err);\n }\n }\n const sleepMs = this.inAdBreak && !this.adLayer.isAdPlaying() ? 0 : backoffMs();\n await new Promise((r) => setTimeout(r, sleepMs));\n }\n this.continuousFetchLoopPromise = null;\n }\n async handleAdStart(durationSeconds) {\n const adBreakDurationMs = durationSeconds != null ? durationSeconds * 1e3 : void 0;\n if (this.config.debugAdTiming) {\n const mode = this.isLiveStream ? \"LIVE\" : \"VOD\";\n console.log(\n `[CONTINUOUS-FETCH] \\u{1F4FA} ${mode} MODE: Target duration=${adBreakDurationMs}ms`\n );\n }\n this.consecutiveFailures = 0;\n this.continuousFetchingActive = true;\n this.continuousFetchLoopPromise = null;\n this.pendingNextAdBids = null;\n this.isShowingPlaceholder = false;\n this.totalAdRequestsInBreak = 0;\n if (this.savedMutedStateBeforeAd == null && !this.video.muted) {\n this.savedMutedStateBeforeAd = {\n muted: false,\n volume: this.video.volume\n };\n }\n const state = this.savedMutedStateBeforeAd ?? {\n muted: this.video.muted,\n volume: this.video.volume\n };\n this.adLayer.updateOriginalMutedState(state.muted, state.volume);\n if (!this.config.disableFiller && !this.video.muted) {\n this.video.muted = true;\n this.video.volume = 0;\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Muted video in handleAdStart\");\n }\n }\n this.inAdBreak = true;\n this.currentAdBreakStartWallClockMs = Date.now();\n this.currentAdIndex = 0;\n this.totalAdsInBreak = Math.max(1, this.preloadedTokens.length);\n this.adPodQueue = [];\n if (!this.config.disableFiller) this.showAds = true;\n if (adBreakDurationMs != null) {\n this.startFillerBreakTimer(adBreakDurationMs);\n } else if (!this.config.disableFiller && this.preloadedTokens.length === 0) {\n this.showPlaceholderLayer();\n }\n if (!this.config.disableFiller) this.adLayer.showPlaceholder();\n if (this.expectedAdBreakDurationMs == null && adBreakDurationMs != null) {\n this.expectedAdBreakDurationMs = adBreakDurationMs;\n }\n if (this.expectedAdBreakDurationMs != null) {\n this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);\n }\n this.clearPendingAdBreak();\n const adBreakToken = Date.now();\n this.activeAdRequestToken = adBreakToken;\n this.startAdFailsafeTimer(adBreakToken);\n this.startAdRequestWatchdog(adBreakToken);\n const adVolume = state.muted ? 1 : state.volume;\n if (this.preloadedTokens.length > 0) {\n const token = this.preloadedTokens.shift();\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] \\u2705 Playing pre-buffered ad, token=\", token);\n }\n const remaining = this.getRemainingAdMs();\n if (this.expectedAdBreakDurationMs == null || remaining >= this.MIN_AD_REMAINING_MS) {\n this.currentAdIndex++;\n if (this.config.licenseKey) {\n sendAdLoadedTracking(this.config.licenseKey, {\n source: this.getAdSource(),\n timestamp: (/* @__PURE__ */ new Date()).toISOString()\n });\n }\n try {\n await this.adLayer.playPreloaded(token);\n if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {\n this.scheduleAdStopCountdown(this.getRemainingAdMs());\n }\n this.adLayer.setAdVolume(adVolume);\n } catch (err) {\n if (this.config.debugAdTiming) console.warn(\"[CONTINUOUS-FETCH] playPreloaded failed:\", err);\n this.consecutiveFailures++;\n await this.showPlaceholderAndWaitForAds();\n }\n } else {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Skipping ad: only\", remaining, \"ms left in break\");\n }\n this.adLayer.cancelPreload(token);\n await this.showPlaceholderAndWaitForAds();\n }\n }\n this.startContinuousFetchLoop();\n }\n stopContinuousFetching() {\n this.continuousFetchingActive = false;\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] \\u{1F6D1} Stopping continuous ad fetching\");\n }\n }\n async tryNextAvailableAdWithRateLimit() {\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) {\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] \\u{1F6D1} Too many consecutive failures (${this.consecutiveFailures}), ending ad break gracefully`);\n }\n this.handleAdPodComplete();\n return;\n }\n const backoffMultiplier = Math.pow(2, this.consecutiveFailures);\n const backoffDelay = Math.min(this.backoffBaseMs * backoffMultiplier, this.maxBackoffMs);\n const effectiveMinInterval = this.minAdRequestIntervalMs + (this.consecutiveFailures > 0 ? backoffDelay : 0);\n const timeSinceLastRequest = Date.now() - this.lastAdRequestTime;\n if (timeSinceLastRequest < effectiveMinInterval) {\n const waitTime = effectiveMinInterval - timeSinceLastRequest;\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] \\u23F3 Rate limiting: waiting ${waitTime}ms before next request (backoff: ${this.consecutiveFailures} failures)`);\n }\n await new Promise((resolve) => setTimeout(resolve, waitTime));\n }\n return this.tryNextAvailableAd(0);\n }\n async tryNextAvailableAd(_retryCount = 0) {\n if (this.totalAdRequestsInBreak >= this.maxTotalAdRequestsPerBreak) {\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] \\u{1F6D1} Max ad requests per break (${this.maxTotalAdRequestsPerBreak}) reached`);\n }\n this.handleAdPodComplete();\n return;\n }\n const remaining = this.getRemainingAdMs();\n if (remaining <= 500 && this.expectedAdBreakDurationMs != null) {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] \\u23F9\\uFE0F No time remaining, ending ad break\");\n }\n this.handleAdPodComplete();\n return;\n }\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) {\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] \\u{1F6D1} Too many consecutive failures (${this.consecutiveFailures}), ending ad break`);\n }\n this.handleAdPodComplete();\n return;\n }\n try {\n this.lastAdRequestTime = Date.now();\n const bids = await this.adRequest();\n if (!this.inAdBreak) return;\n if (bids.length > 0) {\n this.consecutiveFailures = 0;\n this.currentAdIndex++;\n this.totalAdRequestsInBreak++;\n if (this.adLayer.isAdPlaying() || this.isInAdTransition) {\n this.pendingNextAdBids = bids;\n this.totalAdsInBreak = Math.max(\n this.totalAdsInBreak,\n this.currentAdIndex + this.preloadedTokens.length\n );\n } else {\n if (this.config.licenseKey) {\n sendAdLoadedTracking(this.config.licenseKey, {\n source: this.getAdSource(),\n timestamp: (/* @__PURE__ */ new Date()).toISOString()\n });\n }\n await this.adLayer.playAd(bids);\n if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {\n this.scheduleAdStopCountdown(this.getRemainingAdMs());\n }\n this.adLayer.setAdVolume(\n this.adLayer.getOriginalMutedState() ? 1 : this.adLayer.getOriginalVolume()\n );\n }\n } else {\n this.consecutiveFailures++;\n await this.showPlaceholderAndWaitForAds();\n }\n } catch (error) {\n this.consecutiveFailures++;\n if (this.config.debugAdTiming) {\n console.warn(\"[CONTINUOUS-FETCH] tryNextAvailableAd request failed:\", error);\n }\n await this.showPlaceholderAndWaitForAds();\n }\n }\n async showPlaceholderAndWaitForAds() {\n const remaining = this.getRemainingAdMs();\n const waitTime = Math.min(this.maxPlaceholderDurationMs, remaining);\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) {\n const stillRemaining2 = this.getRemainingAdMs();\n if (stillRemaining2 >= 1e3) {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] \\u{1F6D1} Max failures reached but break still active \\u2014 resetting and continuing filler\");\n }\n this.consecutiveFailures = 0;\n return;\n }\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] \\u{1F6D1} Skipping placeholder - too many consecutive failures\");\n }\n this.handleAdPodComplete();\n return;\n }\n if (waitTime < 1e3) {\n this.handleAdPodComplete();\n return;\n }\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] \\u2B1B Showing placeholder for ${waitTime}ms while waiting for ad response`);\n }\n if (!this.config.disableFiller) {\n this.isShowingPlaceholder = true;\n this.showPlaceholderLayer();\n this.adLayer.showPlaceholder();\n }\n const checkInterval = 300;\n const maxChecks = Math.floor(waitTime / checkInterval);\n for (let i = 0; i < maxChecks; i++) {\n await new Promise((resolve) => setTimeout(resolve, checkInterval));\n if (!this.inAdBreak) return;\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] \\u{1F6D1} Too many failures during placeholder wait \\u2014 resetting and continuing filler\");\n }\n this.consecutiveFailures = 0;\n break;\n }\n if (this.pendingNextAdBids != null && this.pendingNextAdBids.length > 0) {\n const bids = this.pendingNextAdBids;\n this.pendingNextAdBids = null;\n this.isShowingPlaceholder = false;\n this.adLayer.hidePlaceholder();\n this.currentAdIndex++;\n try {\n await this.adLayer.playAd(bids);\n this.consecutiveFailures = 0;\n } catch {\n this.consecutiveFailures++;\n await this.tryNextAvailableAdWithRateLimit();\n }\n return;\n }\n if (this.adLayer.isAdPlaying()) {\n this.isShowingPlaceholder = false;\n this.adLayer.hidePlaceholder();\n return;\n }\n }\n const stillRemaining = this.getRemainingAdMs();\n if (stillRemaining >= 1e3) {\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] \\u23F0 Placeholder slot expired, ${stillRemaining}ms still remaining \\u2014 continuing filler`);\n }\n this.isShowingPlaceholder = false;\n this.adLayer.hidePlaceholder();\n this.consecutiveFailures = 0;\n return;\n }\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] \\u23F0 Placeholder timeout, ending ad break\");\n }\n this.isShowingPlaceholder = false;\n this.adLayer.hidePlaceholder();\n this.handleAdPodComplete();\n }\n onTimeUpdate(_currentTimeSec) {\n if (this.adLayer.isAdPlaying()) return;\n }\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 if (!this.inAdBreak) return;\n this.adStopTimerId = void 0;\n const adPlaying = this.adLayer.isAdPlaying();\n const pendingAds = this.adPodQueue.length > 0;\n const checkIntervalMs = Math.max(\n 250,\n Math.floor(this.config.adBreakCheckIntervalMs ?? 1e3)\n );\n const maxExtensionMsConfig = this.config.maxAdBreakExtensionMs;\n const maxExtensionMs = typeof maxExtensionMsConfig === \"number\" && maxExtensionMsConfig > 0 ? maxExtensionMsConfig : 6e4;\n let elapsedSinceStartMs = 0;\n if (this.currentAdBreakStartWallClockMs != null) {\n elapsedSinceStartMs = Date.now() - this.currentAdBreakStartWallClockMs;\n }\n const expectedDurationMs = this.expectedAdBreakDurationMs ?? 0;\n const overrunMs = Math.max(0, elapsedSinceStartMs - expectedDurationMs);\n const shouldExtendAdBreak = (adPlaying || pendingAds || this.showAds) && overrunMs < maxExtensionMs;\n if (shouldExtendAdBreak) {\n this.scheduleAdStopCountdown(checkIntervalMs);\n return;\n }\n if (adPlaying) {\n this.adLayer.stop().catch(() => {\n });\n }\n this.handleAdPodComplete();\n }\n handleAdPodComplete() {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] \\u{1F3C1} Ad pod complete - cleaning up\");\n }\n this.clearAdRequestWatchdog();\n this.clearAdFailsafeTimer();\n this.clearAdInsertionOffsetTimer();\n this.activeAdRequestToken = null;\n this.isInAdTransition = false;\n this.stopContinuousFetching();\n this.stopFillerBreakTimer();\n this.hidePlaceholderLayer();\n this.clearPendingAdBreak();\n this.cancelAndClearPreloadedTokens();\n this.pendingNextAdBids = null;\n if (this.isShowingPlaceholder) {\n this.adLayer.hidePlaceholder();\n this.isShowingPlaceholder = false;\n }\n this.inAdBreak = false;\n this.expectedAdBreakDurationMs = void 0;\n this.currentAdBreakStartWallClockMs = void 0;\n this.clearAdStopTimer();\n this.adPodQueue = [];\n this.showAds = false;\n this.currentAdIndex = 0;\n this.totalAdsInBreak = 0;\n this.totalAdRequestsInBreak = 0;\n this.consecutiveFailures = 0;\n const restoredMuted = this.savedMutedStateBeforeAd?.muted ?? this.adLayer.getOriginalMutedState();\n const restoredVolume = this.savedMutedStateBeforeAd?.volume ?? this.adLayer.getOriginalVolume();\n this.adLayer.updateOriginalMutedState(restoredMuted, restoredVolume);\n this.adLayer.stop().catch(() => {\n });\n if (this.video.muted !== restoredMuted) {\n this.video.muted = restoredMuted;\n }\n if (Math.abs(this.video.volume - restoredVolume) > 0.01) {\n this.video.volume = restoredVolume;\n }\n const browser = detectBrowser();\n const isSmartTV = browser.tizenVersion !== void 0 || browser.webOSVersion !== void 0 || !!this.config.singlePipelineMode;\n if (isSmartTV && this.hls) {\n const hlsRef = this.hls;\n const savedMuted = restoredMuted;\n const savedVolume = restoredVolume;\n const videoRef = this.video;\n const debugEnabled = this.config.debugAdTiming;\n const tryPlay = (attempt) => {\n if (this.inAdBreak || this.adLayer.isAdPlaying()) return;\n videoRef.play()?.catch(() => {\n if (attempt < 3) {\n if (debugEnabled) {\n console.log(`[StormcloudVideoPlayer] Smart TV: play() retry ${attempt + 1}/3 in ${500 * (attempt + 1)}ms`);\n }\n setTimeout(() => tryPlay(attempt + 1), 500 * (attempt + 1));\n }\n });\n };\n const onManifestParsedRestore = () => {\n hlsRef.off(import_hls.default.Events.MANIFEST_PARSED, onManifestParsedRestore);\n if (!this.inAdBreak && !this.adLayer.isAdPlaying()) {\n if (videoRef.muted !== savedMuted) videoRef.muted = savedMuted;\n if (Math.abs(videoRef.volume - savedVolume) > 0.01) videoRef.volume = savedVolume;\n if (debugEnabled) {\n console.log(\"[StormcloudVideoPlayer] Smart TV: audio state restored on MANIFEST_PARSED after re-attach\");\n }\n hlsRef.startLoad(-1);\n if (debugEnabled) {\n console.log(\"[StormcloudVideoPlayer] Smart TV: seeking to live edge and resuming playback after re-attach\");\n }\n }\n };\n hlsRef.on(import_hls.default.Events.MANIFEST_PARSED, onManifestParsedRestore);\n const pipelineDelayMs = 300;\n if (debugEnabled) {\n console.log(`[StormcloudVideoPlayer] Smart TV: waiting ${pipelineDelayMs}ms for hardware pipeline release before re-attach`);\n }\n setTimeout(() => {\n if (this.inAdBreak || this.adLayer.isAdPlaying()) return;\n if (this.hls) {\n this.hls.attachMedia(this.video);\n if (debugEnabled) {\n console.log(\"[StormcloudVideoPlayer] Smart TV: re-attached HLS to video element after ad break to restore media pipeline\");\n }\n }\n }, pipelineDelayMs);\n } else {\n if (this.shouldContinueLiveStreamDuringAds()) {\n if (this.config.debugAdTiming) {\n if (this.video.paused) {\n console.log(\"[StormcloudVideoPlayer] Content video paused in live mode after ads, resuming playback\");\n } else {\n console.log(\"[StormcloudVideoPlayer] Content video already playing in live mode after ads\");\n }\n }\n this.video.play()?.catch(() => {\n });\n } else if (this.video.paused) {\n this.video.play()?.catch(() => {\n });\n }\n }\n this.syncMainContentAudioWhenVisible();\n if (!restoredMuted) {\n requestAnimationFrame(() => {\n this.syncMainContentAudioWhenVisible();\n });\n setTimeout(() => {\n this.syncMainContentAudioWhenVisible();\n }, 0);\n setTimeout(() => {\n this.syncMainContentAudioWhenVisible();\n }, 50);\n setTimeout(() => {\n this.syncMainContentAudioWhenVisible();\n }, 100);\n setTimeout(() => {\n this.syncMainContentAudioWhenVisible();\n }, 150);\n }\n if (isSmartTV && !restoredMuted) {\n [500, 1e3, 2e3, 3e3, 5e3].forEach((delay) => {\n setTimeout(() => {\n if (!this.inAdBreak && !this.adLayer.isAdPlaying()) {\n if (this.video.muted !== restoredMuted) this.video.muted = restoredMuted;\n if (Math.abs(this.video.volume - restoredVolume) > 0.01) this.video.volume = restoredVolume;\n }\n }, delay);\n });\n }\n this.savedMutedStateBeforeAd = null;\n }\n handleAdFailure() {\n this.consecutiveFailures++;\n if (this.config.debugAdTiming) {\n console.log(\n `[CONTINUOUS-FETCH] Ad failure: consecutiveFailures=${this.consecutiveFailures}`\n );\n }\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) {\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] \\u{1F6D1} Max consecutive failures reached (${this.consecutiveFailures}), ending ad break gracefully`);\n }\n this.handleAdPodComplete();\n return;\n }\n if (this.inAdBreak && !this.config.disableFiller) {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Ad failure in active break \\u2014 showing filler while awaiting next ad\");\n }\n this.showPlaceholderLayer();\n this.adLayer.showPlaceholder();\n } else if (this.inAdBreak) {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Ad failure with no filler \\u2014 restoring main video temporarily\");\n }\n this.adLayer.hidePlaceholder();\n if (!this.adLayer.isAdPlaying() && this.video.paused && this.video.readyState >= 2) {\n this.video.play()?.catch(() => {\n });\n }\n }\n }\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.handleAdFailure();\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 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 imaAdPlaying: this.adLayer.isAdPlaying()\n });\n this.handleAdFailure();\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.config.debugAdTiming) {\n return;\n }\n this.pushDebugLog(\"info\", \"ad-state\", event, extra);\n console.log(\"[StormcloudVideoPlayer][AdState]\", {\n event,\n timestamp: (/* @__PURE__ */ new Date()).toISOString(),\n showAds: this.showAds,\n adPlaying: this.adLayer.isAdPlaying(),\n inAdBreak: this.inAdBreak,\n activeAdRequestToken: this.activeAdRequestToken,\n ...extra\n });\n }\n getRemainingAdMs() {\n if (this.currentAdBreakStartWallClockMs == null) return 0;\n if (this.expectedAdBreakDurationMs == null) return Number.MAX_SAFE_INTEGER;\n const elapsed = Date.now() - this.currentAdBreakStartWallClockMs;\n return Math.max(0, this.expectedAdBreakDurationMs - elapsed);\n }\n pushDebugLog(level, category, message, details) {\n if (!this.config.debugAdTiming) return;\n this.debugLogEntries.push({\n timestampMs: Date.now(),\n level,\n category,\n message,\n ...details ? { details } : {}\n });\n if (this.debugLogEntries.length > DEBUG_HISTORY_LIMIT) {\n this.debugLogEntries = this.debugLogEntries.slice(-DEBUG_HISTORY_LIMIT);\n }\n }\n pushAdInsertionDebug(event, segmentName, opts) {\n if (!this.config.debugAdTiming) return;\n this.adInsertionDebugHistory.push({\n timestampMs: Date.now(),\n event,\n segmentName,\n ...opts?.offsetSeconds !== void 0 ? { offsetSeconds: opts.offsetSeconds } : {},\n ...opts?.updatedAt ? { updatedAt: opts.updatedAt } : {},\n ...opts?.detail ? { detail: opts.detail } : {}\n });\n if (this.adInsertionDebugHistory.length > DEBUG_HISTORY_LIMIT) {\n this.adInsertionDebugHistory = this.adInsertionDebugHistory.slice(-DEBUG_HISTORY_LIMIT);\n }\n }\n getAdInsertionDebugLog() {\n return this.adInsertionDebugHistory.slice();\n }\n getDebugLogs() {\n return this.debugLogEntries.slice();\n }\n toggleMute() {\n if (this.adLayer.isAdPlaying()) {\n const isAdCurrentlyMuted = this.adLayer.getAdVolume() === 0;\n if (isAdCurrentlyMuted) {\n const savedVolume = this.adLayer.getOriginalVolume() || 1;\n this.adLayer.setAdVolume(savedVolume);\n this.adLayer.updateOriginalMutedState(false, savedVolume);\n } else {\n const currentAdVolume = this.adLayer.getAdVolume();\n this.adLayer.setAdVolume(0);\n this.adLayer.updateOriginalMutedState(true, currentAdVolume);\n }\n if (this.config.debugAdTiming) {\n console.log(\n \"[StormcloudVideoPlayer] Mute toggle during ad:\",\n isAdCurrentlyMuted ? \"unmuted\" : \"muted\"\n );\n }\n } else {\n this.video.muted = !this.video.muted;\n this.adLayer.updateOriginalMutedState(this.video.muted, this.video.volume);\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Muted:\", this.video.muted);\n }\n }\n }\n toggleFullscreen() {\n return new Promise((resolve, reject) => {\n if (!document.fullscreenElement) {\n const container = this.video.parentElement;\n if (!container) {\n reject(new Error(\"No parent container found for fullscreen\"));\n return;\n }\n container.requestFullscreen().then(() => {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Entered fullscreen\");\n }\n resolve();\n }).catch((err) => {\n if (this.config.debugAdTiming) {\n console.error(\"[StormcloudVideoPlayer] Fullscreen error:\", err);\n }\n reject(err);\n });\n } else {\n document.exitFullscreen().then(() => {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Exited fullscreen\");\n }\n resolve();\n }).catch((err) => {\n if (this.config.debugAdTiming) {\n console.error(\n \"[StormcloudVideoPlayer] Exit fullscreen error:\",\n err\n );\n }\n reject(err);\n });\n }\n });\n }\n isMuted() {\n if (this.adLayer.isAdPlaying()) {\n const adMuted = this.adLayer.getAdVolume() === 0;\n if (this.config.debugAdTiming) {\n console.log(\n \"[StormcloudVideoPlayer] isMuted() during ad playback ->\",\n adMuted\n );\n }\n return adMuted;\n }\n return this.video.muted;\n }\n setMuted(muted) {\n const adPlaying = this.adLayer.isAdPlaying();\n if (adPlaying) {\n const savedVolume = this.adLayer.getOriginalVolume() || 1;\n this.adLayer.setAdVolume(muted ? 0 : savedVolume);\n this.adLayer.updateOriginalMutedState(muted, savedVolume);\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] setMuted applied to ad layer (content stays muted)\", {\n muted,\n savedVolume\n });\n }\n return;\n }\n this.video.muted = muted;\n if (!this.inAdBreak) {\n this.adLayer.updateOriginalMutedState(muted, this.video.volume);\n }\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] setMuted called:\", muted);\n }\n }\n setVolume(volume) {\n const clampedVolume = Math.max(0, Math.min(1, volume));\n const adPlaying = this.adLayer.isAdPlaying();\n if (adPlaying) {\n this.adLayer.setAdVolume(clampedVolume);\n const preservedVolume = clampedVolume > 0 ? clampedVolume : this.adLayer.getOriginalVolume();\n this.adLayer.updateOriginalMutedState(clampedVolume === 0, preservedVolume);\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] setVolume applied during ad\", {\n volume: clampedVolume\n });\n }\n } else {\n this.video.volume = clampedVolume;\n this.video.muted = clampedVolume === 0;\n if (!this.inAdBreak) {\n this.adLayer.updateOriginalMutedState(clampedVolume === 0, clampedVolume);\n }\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] setVolume called:\", clampedVolume);\n }\n }\n }\n getVolume() {\n const adPlaying = this.adLayer.isAdPlaying();\n if (adPlaying) {\n return this.adLayer.getAdVolume();\n }\n return this.video.volume;\n }\n isFullscreen() {\n return !!document.fullscreenElement;\n }\n isLive() {\n return this.isLiveStream;\n }\n getMinHlsResolution() {\n const levels = this.hls?.levels;\n if (!levels || levels.length === 0) return null;\n let min = null;\n let minPixels = Infinity;\n for (const level of levels) {\n if (level.width && level.height) {\n const pixels = level.width * level.height;\n if (pixels < minPixels) {\n minPixels = pixels;\n min = { width: level.width, height: level.height };\n }\n }\n }\n return min;\n }\n getCurrentHlsSegmentDurationMs() {\n const fallbackMs = 4e3;\n if (this.nativeHlsMode) {\n return fallbackMs;\n }\n const hls = this.hls;\n if (!hls) return null;\n const levelCandidates = [hls.currentLevel, hls.nextLoadLevel, hls.loadLevel];\n for (const levelIndex of levelCandidates) {\n if (typeof levelIndex !== \"number\" || levelIndex < 0) continue;\n const details = hls.levels?.[levelIndex]?.details;\n if (!details) continue;\n const targetDurationSec = typeof details.partTarget === \"number\" && details.partTarget > 0 ? details.partTarget : typeof details.targetduration === \"number\" && details.targetduration > 0 ? details.targetduration : void 0;\n if (targetDurationSec !== void 0) {\n return Math.max(800, Math.floor(targetDurationSec * 1e3));\n }\n }\n return fallbackMs;\n }\n get videoElement() {\n return this.video;\n }\n resize() {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Resizing player\");\n }\n if (this.adLayer && this.adLayer.isAdPlaying()) {\n const width = this.video.clientWidth || 640;\n const height = this.video.clientHeight || 480;\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Resizing ads manager to ${width}x${height}`\n );\n }\n this.adLayer.resize(width, height);\n }\n }\n destroy() {\n this.stopAdInsertionPolling();\n this.clearAdInsertionOffsetTimer();\n this.stopContinuousFetching();\n this.stopFillerBreakTimer();\n this.clearAdStopTimer();\n this.clearAdFailsafeTimer();\n this.clearAdRequestWatchdog();\n this.clearPendingAdBreak();\n if (this.fillerVideo) {\n this.fillerVideo.pause();\n if (this.fillerVideo.parentElement) {\n this.fillerVideo.parentElement.removeChild(this.fillerVideo);\n }\n this.fillerVideo = void 0;\n }\n if (this.timeUpdateHandler) {\n this.video.removeEventListener(\"timeupdate\", this.timeUpdateHandler);\n delete this.timeUpdateHandler;\n }\n if (this.emptiedHandler) {\n this.video.removeEventListener(\"emptied\", this.emptiedHandler);\n delete this.emptiedHandler;\n }\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n this.heartbeatInterval = void 0;\n }\n this.hls?.destroy();\n this.adLayer?.destroy();\n this.consecutiveFailures = 0;\n this.debugLogEntries = [];\n this.adInsertionDebugHistory = [];\n }\n};\n// Annotate the CommonJS export names for ESM import in node:\n0 && (module.exports = {\n StormcloudVideoPlayer\n});\n","import Hls from \"hls.js\";\nimport type {\n StormcloudVideoPlayerConfig,\n AdBreakContext,\n AdInsertionPointResponse,\n} from \"../types\";\nimport type { VastBidResponse } from \"../types\";\nimport { createAdStormPlayer } from \"../sdk/adstormPlayer\";\nimport type { AdStormAdLayer } from \"../sdk/adstormPlayer\";\nimport {\n sendInitialTracking,\n sendHeartbeat,\n sendAdLoadedTracking,\n sendAdImpressionTracking,\n} from \"../utils/tracking\";\nimport { initializePolyfills } from \"../utils/polyfills\";\nimport { logBrowserInfo, getBrowserConfigOverrides, detectBrowser } from \"../utils/browserCompat\";\n\nconst DEBUG_HISTORY_LIMIT = 120;\n\ntype DebugLogLevel = \"info\" | \"warn\" | \"error\";\n\ninterface DebugLogEntry {\n timestampMs: number;\n level: DebugLogLevel;\n category: string;\n message: string;\n details?: Record<string, unknown>;\n}\n\ntype AdInsertionDebugEvent =\n | \"api_response\"\n | \"scte35_inserted\"\n | \"segment_found\"\n | \"segment_playing\"\n | \"ad_scheduled\"\n | \"ad_triggered\";\n\ninterface AdInsertionDebugEntry {\n timestampMs: number;\n event: AdInsertionDebugEvent;\n segmentName: string;\n offsetSeconds?: number;\n updatedAt?: string;\n detail?: string;\n}\n\nexport class StormcloudVideoPlayer {\n private readonly video: HTMLVideoElement;\n private readonly config: StormcloudVideoPlayerConfig;\n private hls?: Hls;\n private adLayer: AdStormAdLayer;\n private pendingNextAdBids: VastBidResponse[] | null = null;\n private continuousFetchLoopPromise: Promise<void> | null = null;\n private attached = false;\n private inAdBreak = false;\n private currentAdBreakStartWallClockMs: number | undefined;\n private expectedAdBreakDurationMs: number | undefined;\n private adStopTimerId: number | undefined;\n private adFailsafeTimerId: number | undefined;\n private adPodQueue: string[] = [];\n private lastHeartbeatTime: number = 0;\n private heartbeatInterval: number | undefined;\n private currentAdIndex: number = 0;\n private totalAdsInBreak: number = 0;\n private showAds: boolean = false;\n private isLiveStream: boolean = false;\n private nativeHlsMode: boolean = false;\n private videoSrcProtection: string | null = null;\n private bufferedSegmentsCount: number = 0;\n private shouldAutoplayAfterBuffering: boolean = false;\n private hasInitialBufferCompleted: boolean = false;\n private activeAdRequestToken: number | null = null;\n private adRequestWatchdogId: number | undefined;\n private adRequestWatchdogToken: number | null = null;\n private adFailsafeToken: number | null = null;\n private continuousFetchingActive: boolean = false;\n private isInAdTransition: boolean = false;\n private maxPlaceholderDurationMs: number = 5000;\n private isShowingPlaceholder: boolean = false;\n private timeUpdateHandler?: (event: Event) => void;\n private emptiedHandler?: (event: Event) => void;\n\n private adInsertionPollingId: number | undefined;\n private lastAdInsertionPoint: AdInsertionPointResponse | null = null;\n private processedAdInsertionUpdatedAt: string | null = null;\n private adInsertionOffsetTimerId: number | undefined;\n\n private totalAdRequestsInBreak: number = 0;\n private readonly maxTotalAdRequestsPerBreak: number = 20;\n \n private pendingAdBreak: {\n durationSeconds?: number;\n detectedAtFragmentSn?: number;\n isFetching: boolean;\n fetchStartTime?: number;\n } | null = null;\n private prefetchTimerId: number | undefined;\n private savedMutedStateBeforeAd: { muted: boolean; volume: number } | null = null;\n\n private consecutiveFailures: number = 0;\n private readonly maxConsecutiveFailures: number = 5;\n private lastAdRequestTime: number = 0;\n private readonly minAdRequestIntervalMs: number = 2500;\n private readonly backoffBaseMs: number = 1000;\n private readonly maxBackoffMs: number = 15000;\n private readonly adTransitionGapMs: number;\n private readonly MIN_AD_REMAINING_MS: number = 15000;\n private readonly adRequestTimeoutMs: number = 5000;\n private readonly adRequestMaxRetries: number = 3;\n private readonly adRequestRetryBackoffMs: number = 1500;\n private preloadedTokens: string[] = [];\n private fillerVideo: HTMLVideoElement | undefined;\n private fillerBreakTimerId: ReturnType<typeof setTimeout> | undefined;\n private debugLogEntries: DebugLogEntry[] = [];\n private adInsertionDebugHistory: AdInsertionDebugEntry[] = [];\n\n constructor(config: StormcloudVideoPlayerConfig) {\n initializePolyfills();\n\n const browserOverrides = getBrowserConfigOverrides();\n \n this.config = { ...browserOverrides, ...config };\n this.video = config.videoElement;\n this.adTransitionGapMs = this.config.adTransitionGapMs ?? 100;\n\n logBrowserInfo(config.debugAdTiming);\n\n const browserForAdLayer = detectBrowser();\n const isSinglePipeline = browserForAdLayer.isSmartTV || !!this.config.singlePipelineMode;\n this.adLayer = createAdStormPlayer(this.video, {\n licenseKey: this.config.licenseKey || \"\",\n debug: !!config.debugAdTiming,\n });\n this.adLayer.updateOptions({\n continueLiveStreamDuringAds: !isSinglePipeline && this.shouldContinueLiveStreamDuringAds(),\n });\n }\n\n private async adRequest(context?: AdBreakContext): Promise<VastBidResponse[]> {\n if (this.config.disableAds) return [];\n const durationSeconds = Math.max(\n 1,\n Math.ceil(context?.remainingBreakSec ?? context?.breakDurationSec ?? 30)\n );\n await this.adLayer.requestAds(String(durationSeconds));\n return [\n {\n bidder: \"adstorm-direct\",\n cpm: 0,\n width: 0,\n height: 0,\n adId: \"adstorm\",\n impId: \"\",\n creativeId: \"adstorm\",\n currency: \"USD\",\n durationSec: durationSeconds,\n },\n ];\n }\n\n async load(): Promise<void> {\n if (!this.attached) {\n this.attach();\n }\n\n this.initializeTracking();\n\n if (this.shouldUseNativeHls()) {\n this.nativeHlsMode = true;\n this.videoSrcProtection = this.config.src;\n this.video.src = this.config.src;\n\n this.isLiveStream = this.config.lowLatencyMode ?? false;\n\n if (this.config.debugAdTiming) {\n console.log(\n \"[StormcloudVideoPlayer] Using native HLS playback - VOD mode:\",\n {\n isLive: this.isLiveStream,\n allowNativeHls: this.config.allowNativeHls,\n adBehavior: \"vod (main video pauses during ads)\",\n }\n );\n }\n\n if (!this.config.disableAds) {\n this.adLayer.updateOptions({ continueLiveStreamDuringAds: false, mainHlsInstance: null });\n }\n\n if (this.config.autoplay) {\n await this.video.play()?.catch(() => {});\n }\n return;\n }\n\n this.hls = new Hls({\n enableWorker: true,\n backBufferLength: 30,\n liveDurationInfinity: true,\n lowLatencyMode: !!this.config.lowLatencyMode,\n maxLiveSyncPlaybackRate: this.config.lowLatencyMode ? 1.5 : 1.0,\n ...(this.config.lowLatencyMode ? { liveSyncDuration: 2 } : {}),\n maxBufferLength: 30,\n maxMaxBufferLength: 600,\n maxBufferSize: 60 * 1000 * 1000,\n maxBufferHole: 0.5,\n highBufferWatchdogPeriod: 2,\n nudgeOffset: 0.1,\n nudgeMaxRetry: 3,\n startPosition: -1,\n });\n\n this.hls.on(Hls.Events.MEDIA_ATTACHED, () => {\n this.hls?.loadSource(this.config.src);\n });\n\n this.hls.on(Hls.Events.MANIFEST_PARSED, async (_, data: any) => {\n if (this.config.allowNativeHls === false) {\n this.isLiveStream = true;\n } else {\n this.isLiveStream =\n this.hls?.levels?.some(\n (level) =>\n level?.details?.live === true || level?.details?.type === \"LIVE\"\n ) ?? false;\n }\n\n if (this.config.debugAdTiming) {\n const adBehavior = this.shouldContinueLiveStreamDuringAds()\n ? \"live (main video continues muted during ads)\"\n : \"vod (main video pauses during ads)\";\n console.log(\"[StormcloudVideoPlayer] Stream type detected:\", {\n isLive: this.isLiveStream,\n allowNativeHls: this.config.allowNativeHls,\n adBehavior,\n });\n }\n\n if (!this.config.disableAds) {\n this.adLayer.updateOptions({\n continueLiveStreamDuringAds: this.shouldContinueLiveStreamDuringAds(),\n mainHlsInstance: this.hls ?? null,\n });\n }\n\n this.bufferedSegmentsCount = 0;\n this.hasInitialBufferCompleted = false;\n this.shouldAutoplayAfterBuffering = !!this.config.autoplay;\n\n const minSegments = this.config.minSegmentsBeforePlay ?? 2;\n\n if (this.config.debugAdTiming) {\n console.log(\n \"[StormcloudVideoPlayer] Waiting for\",\n minSegments,\n \"segments to buffer before playback\"\n );\n }\n\n if (minSegments === 0 || !this.config.autoplay) {\n this.hasInitialBufferCompleted = true;\n if (this.config.autoplay) {\n await this.video.play()?.catch(() => {});\n }\n }\n\n if (!this.config.disableAds && this.config.projectId) {\n this.startAdInsertionPolling();\n }\n });\n\n this.hls.on(Hls.Events.LEVEL_LOADED, () => {\n if (this.inAdBreak || this.pendingAdBreak) {\n return;\n }\n this.checkAdInsertionInManifest();\n });\n\n this.hls.on(Hls.Events.FRAG_BUFFERED, async (_evt, data: any) => {\n if (this.hasInitialBufferCompleted) {\n return;\n }\n\n this.bufferedSegmentsCount++;\n const minSegments = this.config.minSegmentsBeforePlay ?? 2;\n\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Buffered segment ${this.bufferedSegmentsCount}/${minSegments}`\n );\n }\n\n if (this.bufferedSegmentsCount >= minSegments) {\n this.hasInitialBufferCompleted = true;\n\n if (this.shouldAutoplayAfterBuffering) {\n if (this.inAdBreak || this.adLayer.isAdPlaying()) {\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Initial buffer complete (${this.bufferedSegmentsCount} segments). Ad break active — deferring play() to handleAdPodComplete().`\n );\n }\n } else {\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Initial buffer complete (${this.bufferedSegmentsCount} segments). Starting playback.`\n );\n }\n await this.video.play()?.catch((err) => {\n if (this.config.debugAdTiming) {\n console.warn(\"[StormcloudVideoPlayer] Autoplay failed:\", err);\n }\n });\n }\n }\n }\n });\n\n this.hls.on(Hls.Events.FRAG_CHANGED, (_evt, data: any) => {\n const frag = data?.frag;\n if (!frag) return;\n\n if (\n this.lastAdInsertionPoint &&\n !this.inAdBreak &&\n this.lastAdInsertionPoint.updated_at !== this.processedAdInsertionUpdatedAt\n ) {\n const segmentName = this.lastAdInsertionPoint.segment_ts_name;\n if (this.fragmentMatchesSegment(frag, segmentName)) {\n this.processedAdInsertionUpdatedAt = this.lastAdInsertionPoint.updated_at;\n const offsetMs = (this.lastAdInsertionPoint.offset_seconds || 0) * 1000;\n\n this.pushAdInsertionDebug(\"segment_playing\", segmentName, {\n offsetSeconds: this.lastAdInsertionPoint.offset_seconds,\n detail: `sn=${frag?.sn ?? \"?\"}`,\n });\n\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Ad insertion segment \"${segmentName}\" now playing — scheduling ad start in ${offsetMs}ms`\n );\n }\n\n this.pushAdInsertionDebug(\"ad_scheduled\", segmentName, {\n offsetSeconds: this.lastAdInsertionPoint.offset_seconds,\n detail: `in ${offsetMs}ms, dur=60s`,\n });\n\n this.clearAdInsertionOffsetTimer();\n this.adInsertionOffsetTimerId = window.setTimeout(() => {\n this.adInsertionOffsetTimerId = undefined;\n if (this.inAdBreak) return;\n\n this.pushAdInsertionDebug(\"ad_triggered\", segmentName, {\n detail: \"ad break started (60s)\",\n });\n\n void this.handleAdStart(60);\n }, offsetMs);\n }\n }\n });\n\n this.hls.on(Hls.Events.FRAG_PARSING_USERDATA, (_evt, data: any) => {\n const samples: Array<{ data: Uint8Array }> = data?.samples ?? [];\n for (const sample of samples) {\n const bytes = sample?.data;\n if (!bytes || bytes.length < 5) continue;\n // SCTE-35 splice_info_section starts with 0xFC (table_id)\n const isSCTE35 = bytes[0] === 0xfc;\n if (!isSCTE35) continue;\n const segName = data?.frag?.relurl ?? data?.frag?.url ?? \"\";\n this.pushAdInsertionDebug(\"scte35_inserted\", segName, {\n detail: `len=${bytes.length}B`,\n });\n }\n });\n\n this.hls.on(Hls.Events.ERROR, (_evt, data) => {\n if (data?.fatal) {\n switch (data.type) {\n case Hls.ErrorTypes.NETWORK_ERROR:\n this.hls?.startLoad();\n break;\n case Hls.ErrorTypes.MEDIA_ERROR:\n this.hls?.recoverMediaError();\n break;\n default:\n this.destroy();\n break;\n }\n }\n });\n\n this.hls.attachMedia(this.video);\n }\n\n private getAdSource(): \"vast\" {\n return \"vast\";\n }\n\n private attachAdLayerEventListeners(): void {\n this.adLayer.on(\"ad_impression\", () => {\n if (this.config.licenseKey) {\n sendAdImpressionTracking(this.config.licenseKey, {\n source: this.getAdSource(),\n adIndex: this.currentAdIndex,\n timestamp: new Date().toISOString(),\n });\n }\n });\n this.adLayer.on(\"ad_error\", (errorPayload?: any) => {\n let errorMessage = \"Ad playback failed\";\n \n if (errorPayload) {\n const errorCode = errorPayload.code || errorPayload.errorCode || \"unknown\";\n const vastErrorCode = errorPayload.vastErrorCode;\n const message = errorPayload.message || errorPayload.errorMessage || \"Unknown error\";\n const cause = errorPayload.cause || errorPayload.innerError || errorPayload.error;\n \n errorMessage = `Ad error: AdError ${errorCode}: ${message}`;\n \n if (vastErrorCode && vastErrorCode !== \"N/A\" && vastErrorCode !== errorCode) {\n errorMessage += ` (VAST Error Code: ${vastErrorCode})`;\n }\n \n if (cause) {\n const causeMessage = typeof cause === \"string\" ? cause : (cause.message || String(cause));\n errorMessage += `. Caused by: ${causeMessage}`;\n }\n }\n \n this.pushDebugLog(\"error\", \"ad\", errorMessage, {\n ...(errorPayload ? { payload: errorPayload as Record<string, unknown> } : {}),\n });\n console.error(\"[AD-ERROR]\", errorMessage, errorPayload || \"\");\n this.adLayer.stop().catch(() => {});\n this.handleAdFailure();\n });\n this.adLayer.on(\"content_pause\", () => {\n this.clearAdFailsafeTimer();\n this.clearAdRequestWatchdog();\n this.activeAdRequestToken = null;\n this.showAds = true;\n\n if (this.config.disableFiller) {\n if (this.savedMutedStateBeforeAd == null) {\n this.savedMutedStateBeforeAd = { muted: this.video.muted, volume: this.video.volume };\n this.adLayer.updateOriginalMutedState(this.video.muted, this.video.volume);\n }\n if (!this.video.muted) {\n this.video.muted = true;\n this.video.volume = 0;\n }\n this.adLayer.showPlaceholder();\n }\n \n if (this.inAdBreak && this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {\n this.scheduleAdStopCountdown(this.getRemainingAdMs());\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Starting ad break timer on content_pause (first ad starting)\");\n }\n }\n\n this.adLayer.setAdVolume(\n this.adLayer.getOriginalMutedState() ? 1 : this.adLayer.getOriginalVolume()\n );\n\n this.stopFillerBreakTimer();\n this.hidePlaceholderLayer();\n this.isShowingPlaceholder = false;\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Hiding placeholder - new ads starting\");\n }\n });\n this.adLayer.on(\"content_resume\", () => {\n const remaining = this.getRemainingAdMs();\n const breakMuted = this.savedMutedStateBeforeAd?.muted ?? this.adLayer.getOriginalMutedState();\n const breakVolume = this.savedMutedStateBeforeAd?.volume ?? this.adLayer.getOriginalVolume();\n if (this.config.debugAdTiming) {\n console.log(\n \"[StormcloudVideoPlayer] content_resume received, inAdBreak=%s, remaining=%s, preloadedTokens=%d, pendingNext=%s\",\n this.inAdBreak,\n remaining,\n this.preloadedTokens.length,\n !!this.pendingNextAdBids\n );\n }\n\n this.clearAdFailsafeTimer();\n this.clearAdRequestWatchdog();\n this.activeAdRequestToken = null;\n this.showAds = false;\n\n if (!this.inAdBreak) {\n this.video.style.visibility = \"visible\";\n this.video.style.opacity = \"1\";\n this.syncMainContentAudioWhenVisible();\n return;\n }\n\n this.consecutiveFailures = 0;\n\n if (!this.config.disableFiller && !this.video.muted) {\n this.video.muted = true;\n this.video.volume = 0;\n }\n\n if (this.preloadedTokens.length > 0) {\n const token = this.preloadedTokens.shift()!;\n const remainingNow = this.getRemainingAdMs();\n if (this.expectedAdBreakDurationMs != null && remainingNow < this.MIN_AD_REMAINING_MS) {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] content_resume: skip preloaded ad, only\", remainingNow, \"ms left\");\n }\n this.adLayer.cancelPreload(token);\n } else {\n if (!this.config.singlePipelineMode) {\n this.showPlaceholderLayer();\n }\n this.adLayer.showPlaceholder();\n this.isInAdTransition = true;\n setTimeout(() => {\n this.isInAdTransition = false;\n if (!this.inAdBreak) return;\n this.currentAdIndex++;\n this.adLayer.playPreloaded(token).catch((err) => {\n if (this.config.debugAdTiming) console.warn(\"[StormcloudVideoPlayer] playPreloaded failed:\", err);\n this.handleAdFailure();\n });\n }, this.adTransitionGapMs);\n return;\n }\n }\n\n if (this.pendingNextAdBids && this.pendingNextAdBids.length > 0) {\n const bids = [...this.pendingNextAdBids];\n this.pendingNextAdBids = null;\n const remainingNow = this.getRemainingAdMs();\n if (this.expectedAdBreakDurationMs != null && remainingNow < this.MIN_AD_REMAINING_MS) {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] content_resume: skip pending bids, only\", remainingNow, \"ms left\");\n }\n } else {\n if (!this.config.singlePipelineMode) {\n this.showPlaceholderLayer();\n }\n this.adLayer.showPlaceholder();\n this.isInAdTransition = true;\n setTimeout(() => {\n this.isInAdTransition = false;\n if (!this.inAdBreak || bids.length === 0) return;\n const freshBids = this.pendingNextAdBids ?? bids;\n this.pendingNextAdBids = null;\n this.currentAdIndex++;\n this.adLayer.playAd(freshBids).catch((err) => {\n if (this.config.debugAdTiming) console.warn(\"[StormcloudVideoPlayer] playAd(pending) failed:\", err);\n this.handleAdFailure();\n });\n }, this.adTransitionGapMs);\n return;\n }\n }\n\n const remainingFinal = this.getRemainingAdMs();\n if (this.inAdBreak && remainingFinal > this.MIN_AD_REMAINING_MS) {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] content_resume: ad ended/failed with time remaining, showing filler and continuing fetch for\", remainingFinal, \"ms\");\n }\n if (!this.config.disableFiller) {\n this.showPlaceholderLayer();\n this.adLayer.showPlaceholder();\n } else {\n this.adLayer.hidePlaceholder();\n if (this.video.muted !== breakMuted) {\n this.video.muted = breakMuted;\n }\n if (Math.abs(this.video.volume - breakVolume) > 0.01) {\n this.video.volume = breakVolume;\n }\n if (this.video.paused) {\n this.video.play()?.catch(() => {});\n }\n }\n\n this.continuousFetchingActive = true;\n this.startContinuousFetchLoop();\n return;\n }\n\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] content_resume: no more ads, ending ad pod\");\n }\n this.handleAdPodComplete();\n });\n }\n\n private ensureFillerVideo(): void {\n if (this.fillerVideo) return;\n if (!this.video.parentElement) return;\n\n const filler = document.createElement(\"video\");\n filler.src = \"https://f000.backblazeb2.com/file/AdStormAds/384/Sonifi_Filler.mp4\";\n filler.loop = true;\n filler.muted = false;\n filler.playsInline = true;\n filler.style.position = \"absolute\";\n filler.style.left = \"0\";\n filler.style.top = \"0\";\n filler.style.width = \"100%\";\n filler.style.height = \"100%\";\n filler.style.objectFit = \"cover\";\n filler.style.zIndex = \"20\";\n filler.style.display = \"none\";\n filler.preload = \"auto\";\n this.video.parentElement.appendChild(filler);\n this.fillerVideo = filler;\n }\n\n private showPlaceholderLayer(): void {\n if (this.config.disableFiller) return;\n this.ensureFillerVideo();\n if (!this.fillerVideo) return;\n\n if (!this.video.muted) {\n this.video.muted = true;\n this.video.volume = 0;\n }\n\n this.fillerVideo.style.display = \"block\";\n this.fillerVideo.play().catch(() => {\n if (this.fillerVideo) {\n this.fillerVideo.style.display = \"none\";\n }\n if (!this.adLayer.isAdPlaying()) {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Filler video failed — restoring main video\");\n }\n this.adLayer.hidePlaceholder();\n if (this.video.paused && this.video.readyState >= 2) {\n this.video.play()?.catch(() => {});\n }\n }\n });\n\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Showing filler video layer\");\n }\n }\n\n private hidePlaceholderLayer(): void {\n if (!this.fillerVideo) return;\n\n this.fillerVideo.style.display = \"none\";\n this.fillerVideo.pause();\n this.fillerVideo.currentTime = 0;\n\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Hiding filler video layer\");\n }\n }\n\n private startFillerBreakTimer(durationMs: number): void {\n this.stopFillerBreakTimer();\n this.showPlaceholderLayer();\n this.fillerBreakTimerId = setTimeout(() => {\n this.fillerBreakTimerId = undefined;\n this.hidePlaceholderLayer();\n if (this.inAdBreak) this.handleAdPodComplete();\n }, durationMs);\n }\n\n private stopFillerBreakTimer(): void {\n if (this.fillerBreakTimerId !== undefined) {\n clearTimeout(this.fillerBreakTimerId);\n this.fillerBreakTimerId = undefined;\n }\n }\n\n private attach(): void {\n if (this.attached) return;\n this.attached = true;\n this.video.autoplay = !!this.config.autoplay;\n this.video.muted = !!this.config.muted;\n\n if (!this.config.disableAds) {\n this.adLayer.initialize();\n if (!this.config.disableFiller) {\n this.ensureFillerVideo();\n }\n this.adLayer.updateOriginalMutedState(this.video.muted, this.video.volume);\n this.attachAdLayerEventListeners();\n }\n\n this.timeUpdateHandler = () => {\n this.onTimeUpdate(this.video.currentTime);\n };\n this.video.addEventListener(\"timeupdate\", this.timeUpdateHandler);\n\n this.emptiedHandler = () => {\n if (\n this.nativeHlsMode &&\n this.videoSrcProtection &&\n !this.adLayer.isAdPlaying()\n ) {\n if (this.config.debugAdTiming) {\n console.log(\n \"[StormcloudVideoPlayer] Video src was cleared, restoring:\",\n this.videoSrcProtection\n );\n }\n const currentTime = this.video.currentTime;\n const wasPaused = this.video.paused;\n this.video.src = this.videoSrcProtection;\n this.video.currentTime = currentTime;\n if (!wasPaused) {\n this.video.play().catch(() => {});\n }\n }\n };\n this.video.addEventListener(\"emptied\", this.emptiedHandler);\n }\n\n private shouldUseNativeHls(): boolean {\n const streamType = this.getStreamType();\n\n if (streamType === \"other\") {\n return true;\n }\n\n const canNative = this.video.canPlayType(\"application/vnd.apple.mpegurl\");\n return !!(this.config.allowNativeHls && canNative);\n }\n\n private initializeTracking(): void {\n sendInitialTracking(this.config.licenseKey)\n .then(() => {\n this.heartbeatInterval = window.setInterval(() => {\n this.sendHeartbeatIfNeeded();\n }, 5000);\n })\n .catch((error) => {\n if (this.config.debugAdTiming) {\n console.warn(\n \"[StormcloudVideoPlayer] Failed to send initial tracking:\",\n error\n );\n }\n this.heartbeatInterval = window.setInterval(() => {\n this.sendHeartbeatIfNeeded();\n }, 5000);\n });\n }\n\n private sendHeartbeatIfNeeded(): void {\n const now = Date.now();\n if (!this.lastHeartbeatTime || now - this.lastHeartbeatTime > 30000) {\n this.lastHeartbeatTime = now;\n sendHeartbeat(this.config.licenseKey).catch((error) => {\n if (this.config.debugAdTiming) {\n console.warn(\n \"[StormcloudVideoPlayer] Failed to send heartbeat:\",\n error\n );\n }\n });\n }\n }\n\n getCurrentAdIndex(): number {\n return this.currentAdIndex;\n }\n\n getTotalAdsInBreak(): number {\n return this.totalAdsInBreak;\n }\n\n getRemainingAdSeconds(): number {\n const remainingMs = this.getRemainingAdMs();\n if (\n !Number.isFinite(remainingMs) ||\n remainingMs <= 0 ||\n remainingMs === Number.MAX_SAFE_INTEGER\n ) {\n return 0;\n }\n return Math.ceil(remainingMs / 1000);\n }\n\n isAdPlaying(): boolean {\n return this.inAdBreak && this.adLayer.isAdPlaying();\n }\n\n isShowingAds(): boolean {\n return this.showAds;\n }\n\n private syncMainContentAudioWhenVisible(): void {\n const adLayerShowing = this.showAds || this.adLayer.isAdPlaying();\n if (adLayerShowing) return;\n const muted = this.adLayer.getOriginalMutedState();\n const volume = this.adLayer.getOriginalVolume();\n if (this.video.muted !== muted) this.video.muted = muted;\n if (Math.abs(this.video.volume - volume) > 0.01) this.video.volume = volume;\n }\n\n getStreamType(): \"hls\" | \"other\" {\n const url = this.config.src.toLowerCase();\n if (\n url.includes(\".m3u8\") ||\n url.includes(\"/hls/\") ||\n url.includes(\"application/vnd.apple.mpegurl\")\n ) {\n return \"hls\";\n }\n return \"other\";\n }\n\n shouldShowNativeControls(): boolean {\n const streamType = this.getStreamType();\n if (streamType === \"other\") {\n return !(this.config.showCustomControls ?? false);\n }\n return !!(\n this.config.allowNativeHls && !(this.config.showCustomControls ?? false)\n );\n }\n\n private shouldContinueLiveStreamDuringAds(): boolean {\n if (this.config.allowNativeHls) {\n return false;\n }\n\n if (!this.isLiveStream) {\n return false;\n }\n\n if (this.config.singlePipelineMode) {\n return false;\n }\n\n const browser = detectBrowser();\n if (browser.isSmartTV) {\n return false;\n }\n\n return true;\n }\n\n private startAdPrefetch(durationSeconds?: number, fragmentSn?: number): void {\n if (this.config.disableAds) return;\n if (this.pendingAdBreak || this.inAdBreak) {\n return;\n }\n\n this.pendingAdBreak = {\n ...(durationSeconds !== undefined ? { durationSeconds } : {}),\n ...(fragmentSn !== undefined ? { detectedAtFragmentSn: fragmentSn } : {}),\n isFetching: false,\n fetchStartTime: Date.now(),\n };\n\n void this.runAdPrefetch(durationSeconds);\n\n if (this.config.debugAdTiming) {\n console.log(\"[PREFETCH] Ad break registered, multi-ad prefetch started\");\n }\n }\n\n private async runAdPrefetch(durationSeconds?: number): Promise<void> {\n const durSec = durationSeconds ?? 60;\n\n const context: AdBreakContext = {\n breakDurationSec: durSec,\n remainingBreakSec: durSec,\n };\n\n let firstBids: VastBidResponse[];\n try {\n firstBids = await this.adRequest({ ...context, adIndex: 1 });\n } catch {\n firstBids = [];\n }\n\n if (this.inAdBreak) return;\n\n if (firstBids.length === 0) {\n if (this.config.debugAdTiming) {\n console.log(\"[PREFETCH] First VAST request returned no ad, aborting prefetch\");\n }\n return;\n }\n\n const adDurationSec = firstBids[0]?.durationSec ?? 30;\n const estimatedCount = Math.max(1, Math.ceil(durSec / adDurationSec));\n\n if (this.config.debugAdTiming) {\n console.log(\n `[PREFETCH] Ad duration=${adDurationSec}s, break=${durSec}s → ${estimatedCount} ad(s) needed`\n );\n }\n\n const firstToken = `preload_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;\n try {\n await this.adLayer.preloadAd(firstBids, firstToken);\n if (!this.inAdBreak) {\n this.preloadedTokens.push(firstToken);\n if (this.config.debugAdTiming) {\n console.log(`[PREFETCH] First ad preloaded and queued, token=${firstToken}`);\n }\n }\n } catch {\n if (this.config.debugAdTiming) {\n console.warn(`[PREFETCH] First ad preload failed, token=${firstToken}`);\n }\n }\n\n if (estimatedCount > 1) {\n type SettledResult = { ok: true; value: VastBidResponse[] } | { ok: false };\n const remaining: Promise<SettledResult>[] = Array.from(\n { length: estimatedCount - 1 },\n (_, i) =>\n this.adRequest({ ...context, adIndex: i + 2 })\n .then((bids): SettledResult => ({ ok: true, value: bids }))\n .catch((): SettledResult => ({ ok: false }))\n );\n\n const results = await Promise.all(remaining);\n\n for (const result of results) {\n if (this.inAdBreak) break;\n if (result.ok && result.value.length > 0) {\n const token = `preload_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;\n try {\n await this.adLayer.preloadAd(result.value, token);\n if (!this.inAdBreak) {\n this.preloadedTokens.push(token);\n if (this.config.debugAdTiming) {\n console.log(`[PREFETCH] Additional ad preloaded and queued, token=${token}`);\n }\n }\n } catch {\n if (this.config.debugAdTiming) {\n console.warn(`[PREFETCH] Additional ad preload failed, token=${token}`);\n }\n }\n }\n }\n }\n\n if (this.config.debugAdTiming) {\n console.log(`[PREFETCH] Pre-fetch complete: ${this.preloadedTokens.length} ad(s) queued`);\n }\n }\n\n private clearPendingAdBreak(): void {\n if (this.prefetchTimerId != null) {\n clearTimeout(this.prefetchTimerId);\n this.prefetchTimerId = undefined;\n }\n this.pendingAdBreak = null;\n }\n\n private cancelAndClearPreloadedTokens(): void {\n for (const token of this.preloadedTokens) {\n this.adLayer.cancelPreload(token);\n }\n this.preloadedTokens = [];\n }\n\n private startAdInsertionPolling(): void {\n if (this.adInsertionPollingId != null) return;\n this.fetchAdInsertionPoint();\n this.adInsertionPollingId = window.setInterval(() => {\n this.fetchAdInsertionPoint();\n }, 1000);\n }\n\n private stopAdInsertionPolling(): void {\n if (this.adInsertionPollingId != null) {\n clearInterval(this.adInsertionPollingId);\n this.adInsertionPollingId = undefined;\n }\n }\n\n private async fetchAdInsertionPoint(): Promise<void> {\n if (!this.config.projectId) return;\n try {\n const resp = await fetch(\n `https://adstorm.co/api-adstorm-dev/adstorm/swirl/projects/${encodeURIComponent(this.config.projectId)}/ad-insertion-point`\n );\n if (!resp.ok) return;\n const data: AdInsertionPointResponse = await resp.json();\n const isNew = data.updated_at !== this.lastAdInsertionPoint?.updated_at;\n this.lastAdInsertionPoint = data;\n\n if (isNew) {\n this.pushAdInsertionDebug(\"api_response\", data.segment_ts_name, {\n offsetSeconds: data.offset_seconds,\n updatedAt: data.updated_at,\n detail: `project=${data.project_id}`,\n });\n }\n\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Ad insertion point API response:\", data);\n }\n } catch {\n if (this.config.debugAdTiming) {\n console.warn(\"[StormcloudVideoPlayer] Ad insertion point API fetch failed\");\n }\n }\n }\n\n private checkAdInsertionInManifest(): void {\n if (!this.lastAdInsertionPoint) return;\n if (this.inAdBreak || this.pendingAdBreak) return;\n if (this.lastAdInsertionPoint.updated_at === this.processedAdInsertionUpdatedAt) return;\n\n const segmentName = this.lastAdInsertionPoint.segment_ts_name;\n const levels = this.hls?.levels;\n if (!levels) return;\n\n for (const level of levels) {\n const fragments = (level as any).details?.fragments;\n if (!Array.isArray(fragments)) continue;\n\n for (const frag of fragments) {\n if (this.fragmentMatchesSegment(frag, segmentName)) {\n this.pushAdInsertionDebug(\"segment_found\", segmentName, {\n detail: `sn=${frag?.sn ?? \"?\"}`,\n });\n\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Ad insertion segment \"${segmentName}\" found in manifest — starting pre-fetch`\n );\n }\n\n this.startAdPrefetch(60, frag?.sn);\n return;\n }\n }\n }\n }\n\n private fragmentMatchesSegment(frag: any, segmentName: string): boolean {\n const rawUrl: string = frag?.url || frag?.relurl || \"\";\n const url = rawUrl.split(\"?\")[0] ?? \"\";\n const name = segmentName.startsWith(\"/\") ? segmentName : \"/\" + segmentName;\n return url.endsWith(name) || url.includes(name);\n }\n\n private clearAdInsertionOffsetTimer(): void {\n if (this.adInsertionOffsetTimerId != null) {\n clearTimeout(this.adInsertionOffsetTimerId);\n this.adInsertionOffsetTimerId = undefined;\n }\n }\n\n private startContinuousFetchLoop(): void {\n if (this.continuousFetchLoopPromise != null) return;\n this.continuousFetchLoopPromise = this.runContinuousFetchLoop();\n }\n\n private async runContinuousFetchLoop(): Promise<void> {\n const backoffMs = () => {\n const mult = Math.pow(2, this.consecutiveFailures);\n return Math.min(this.backoffBaseMs * mult, this.maxBackoffMs);\n };\n while (this.inAdBreak && this.continuousFetchingActive) {\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) break;\n if (this.totalAdRequestsInBreak >= this.maxTotalAdRequestsPerBreak) break;\n\n if (this.adLayer.isAdPlaying() || this.isInAdTransition) {\n if (this.pendingNextAdBids == null) {\n try {\n const remaining = this.getRemainingAdMs();\n const prefetchContext: AdBreakContext | undefined = this.expectedAdBreakDurationMs != null\n ? {\n breakDurationSec: this.expectedAdBreakDurationMs / 1000,\n remainingBreakSec: remaining / 1000,\n adIndex: this.currentAdIndex + 1,\n }\n : undefined;\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Pre-fetching next ad during playback, remaining:\", remaining, \"ms\");\n }\n const bids = await this.adRequest(prefetchContext);\n this.lastAdRequestTime = Date.now();\n if (!this.inAdBreak) break;\n if (bids.length > 0) {\n this.consecutiveFailures = 0;\n this.pendingNextAdBids = bids;\n this.totalAdsInBreak = Math.max(\n this.totalAdsInBreak,\n this.currentAdIndex + this.preloadedTokens.length + 1\n );\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Pre-fetched next ad stored as pending\");\n }\n } else {\n this.consecutiveFailures++;\n }\n } catch (err) {\n this.consecutiveFailures++;\n if (this.config.debugAdTiming) {\n console.warn(\"[CONTINUOUS-FETCH] Pre-fetch adRequest failed:\", err);\n }\n }\n } else {\n await new Promise((r) => setTimeout(r, 200));\n }\n continue;\n }\n\n if (this.pendingNextAdBids != null && this.pendingNextAdBids.length > 0) {\n const bids = this.pendingNextAdBids;\n this.pendingNextAdBids = null;\n const remainingNow = this.getRemainingAdMs();\n if (this.expectedAdBreakDurationMs == null || remainingNow >= this.MIN_AD_REMAINING_MS) {\n this.currentAdIndex++;\n if (this.config.licenseKey) {\n sendAdLoadedTracking(this.config.licenseKey, {\n source: this.getAdSource(),\n timestamp: new Date().toISOString(),\n });\n }\n await this.adLayer.playAd(bids);\n if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {\n this.scheduleAdStopCountdown(this.getRemainingAdMs());\n }\n this.adLayer.setAdVolume(\n this.adLayer.getOriginalMutedState() ? 1 : this.adLayer.getOriginalVolume()\n );\n } else if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Discarding pre-fetched bids: only\", remainingNow, \"ms left\");\n }\n continue;\n }\n\n const urgentNeedAd = this.inAdBreak && !this.adLayer.isAdPlaying();\n const delay = this.lastAdRequestTime\n ? this.minAdRequestIntervalMs + (!urgentNeedAd && this.consecutiveFailures > 0 ? backoffMs() : 0)\n : 0;\n const elapsed = Date.now() - this.lastAdRequestTime;\n if (elapsed < delay && this.lastAdRequestTime > 0) {\n await new Promise((r) => setTimeout(r, delay - elapsed));\n }\n if (!this.inAdBreak || !this.continuousFetchingActive) break;\n try {\n const remaining = this.getRemainingAdMs();\n const context: AdBreakContext | undefined = this.expectedAdBreakDurationMs != null\n ? {\n breakDurationSec: this.expectedAdBreakDurationMs / 1000,\n remainingBreakSec: remaining / 1000,\n adIndex: this.currentAdIndex + 1,\n }\n : undefined;\n const bids = await this.adRequest(context);\n this.lastAdRequestTime = Date.now();\n if (!this.inAdBreak) break;\n if (bids.length > 0) {\n this.consecutiveFailures = 0;\n if (this.adLayer.isAdPlaying() || this.isInAdTransition) {\n this.pendingNextAdBids = bids;\n this.totalAdsInBreak = Math.max(\n this.totalAdsInBreak,\n this.currentAdIndex + this.preloadedTokens.length + 1\n );\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Next ad response stored (ad currently playing or in transition)\");\n }\n } else {\n const remainingNow = this.getRemainingAdMs();\n if (this.expectedAdBreakDurationMs != null && remainingNow < this.MIN_AD_REMAINING_MS) {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Skipping ad from loop: only\", remainingNow, \"ms left\");\n }\n } else {\n this.currentAdIndex++;\n if (this.config.licenseKey) {\n sendAdLoadedTracking(this.config.licenseKey, {\n source: this.getAdSource(),\n timestamp: new Date().toISOString(),\n });\n }\n await this.adLayer.playAd(bids);\n if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {\n this.scheduleAdStopCountdown(this.getRemainingAdMs());\n }\n this.adLayer.setAdVolume(\n this.adLayer.getOriginalMutedState() ? 1 : this.adLayer.getOriginalVolume()\n );\n }\n }\n } else {\n this.consecutiveFailures++;\n }\n } catch (err) {\n this.consecutiveFailures++;\n if (this.config.debugAdTiming) {\n console.warn(\"[CONTINUOUS-FETCH] adRequest failed:\", err);\n }\n }\n const sleepMs = (this.inAdBreak && !this.adLayer.isAdPlaying())\n ? 0\n : backoffMs();\n await new Promise((r) => setTimeout(r, sleepMs));\n }\n this.continuousFetchLoopPromise = null;\n }\n\n private async handleAdStart(durationSeconds?: number): Promise<void> {\n const adBreakDurationMs = durationSeconds != null ? durationSeconds * 1000 : undefined;\n\n if (this.config.debugAdTiming) {\n const mode = this.isLiveStream ? \"LIVE\" : \"VOD\";\n console.log(\n `[CONTINUOUS-FETCH] 📺 ${mode} MODE: Target duration=${adBreakDurationMs}ms`\n );\n }\n\n this.consecutiveFailures = 0;\n this.continuousFetchingActive = true;\n this.continuousFetchLoopPromise = null;\n this.pendingNextAdBids = null;\n this.isShowingPlaceholder = false;\n this.totalAdRequestsInBreak = 0;\n\n if (this.savedMutedStateBeforeAd == null && !this.video.muted) {\n this.savedMutedStateBeforeAd = {\n muted: false,\n volume: this.video.volume,\n };\n }\n\n const state = this.savedMutedStateBeforeAd ?? {\n muted: this.video.muted,\n volume: this.video.volume,\n };\n this.adLayer.updateOriginalMutedState(state.muted, state.volume);\n\n if (!this.config.disableFiller && !this.video.muted) {\n this.video.muted = true;\n this.video.volume = 0;\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Muted video in handleAdStart\");\n }\n }\n\n this.inAdBreak = true;\n this.currentAdBreakStartWallClockMs = Date.now();\n this.currentAdIndex = 0;\n this.totalAdsInBreak = Math.max(1, this.preloadedTokens.length);\n this.adPodQueue = [];\n\n if (!this.config.disableFiller) this.showAds = true;\n\n if (adBreakDurationMs != null) {\n this.startFillerBreakTimer(adBreakDurationMs);\n } else if (!this.config.disableFiller && this.preloadedTokens.length === 0) {\n this.showPlaceholderLayer();\n }\n if (!this.config.disableFiller) this.adLayer.showPlaceholder();\n\n if (this.expectedAdBreakDurationMs == null && adBreakDurationMs != null) {\n this.expectedAdBreakDurationMs = adBreakDurationMs;\n }\n\n if (this.expectedAdBreakDurationMs != null) {\n this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);\n }\n\n this.clearPendingAdBreak();\n\n const adBreakToken = Date.now();\n this.activeAdRequestToken = adBreakToken;\n this.startAdFailsafeTimer(adBreakToken);\n this.startAdRequestWatchdog(adBreakToken);\n\n const adVolume = state.muted ? 1 : state.volume;\n\n if (this.preloadedTokens.length > 0) {\n const token = this.preloadedTokens.shift()!;\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] ✅ Playing pre-buffered ad, token=\", token);\n }\n const remaining = this.getRemainingAdMs();\n if (this.expectedAdBreakDurationMs == null || remaining >= this.MIN_AD_REMAINING_MS) {\n this.currentAdIndex++;\n if (this.config.licenseKey) {\n sendAdLoadedTracking(this.config.licenseKey, {\n source: this.getAdSource(),\n timestamp: new Date().toISOString(),\n });\n }\n try {\n await this.adLayer.playPreloaded(token);\n if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {\n this.scheduleAdStopCountdown(this.getRemainingAdMs());\n }\n this.adLayer.setAdVolume(adVolume);\n } catch (err) {\n if (this.config.debugAdTiming) console.warn(\"[CONTINUOUS-FETCH] playPreloaded failed:\", err);\n this.consecutiveFailures++;\n await this.showPlaceholderAndWaitForAds();\n }\n } else {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Skipping ad: only\", remaining, \"ms left in break\");\n }\n this.adLayer.cancelPreload(token);\n await this.showPlaceholderAndWaitForAds();\n }\n }\n\n this.startContinuousFetchLoop();\n }\n\n private stopContinuousFetching(): void {\n this.continuousFetchingActive = false;\n\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] 🛑 Stopping continuous ad fetching\");\n }\n }\n\n private async tryNextAvailableAdWithRateLimit(): Promise<void> {\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) {\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] 🛑 Too many consecutive failures (${this.consecutiveFailures}), ending ad break gracefully`);\n }\n this.handleAdPodComplete();\n return;\n }\n\n const backoffMultiplier = Math.pow(2, this.consecutiveFailures);\n const backoffDelay = Math.min(this.backoffBaseMs * backoffMultiplier, this.maxBackoffMs);\n const effectiveMinInterval = this.minAdRequestIntervalMs + (this.consecutiveFailures > 0 ? backoffDelay : 0);\n \n const timeSinceLastRequest = Date.now() - this.lastAdRequestTime;\n if (timeSinceLastRequest < effectiveMinInterval) {\n const waitTime = effectiveMinInterval - timeSinceLastRequest;\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] ⏳ Rate limiting: waiting ${waitTime}ms before next request (backoff: ${this.consecutiveFailures} failures)`);\n }\n await new Promise(resolve => setTimeout(resolve, waitTime));\n }\n\n return this.tryNextAvailableAd(0);\n }\n\n private async tryNextAvailableAd(_retryCount: number = 0): Promise<void> {\n if (this.totalAdRequestsInBreak >= this.maxTotalAdRequestsPerBreak) {\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] 🛑 Max ad requests per break (${this.maxTotalAdRequestsPerBreak}) reached`);\n }\n this.handleAdPodComplete();\n return;\n }\n const remaining = this.getRemainingAdMs();\n if (remaining <= 500 && this.expectedAdBreakDurationMs != null) {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] ⏹️ No time remaining, ending ad break\");\n }\n this.handleAdPodComplete();\n return;\n }\n\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) {\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] 🛑 Too many consecutive failures (${this.consecutiveFailures}), ending ad break`);\n }\n this.handleAdPodComplete();\n return;\n }\n\n try {\n this.lastAdRequestTime = Date.now();\n const bids = await this.adRequest();\n if (!this.inAdBreak) return;\n if (bids.length > 0) {\n this.consecutiveFailures = 0;\n this.currentAdIndex++;\n this.totalAdRequestsInBreak++;\n if (this.adLayer.isAdPlaying() || this.isInAdTransition) {\n this.pendingNextAdBids = bids;\n this.totalAdsInBreak = Math.max(\n this.totalAdsInBreak,\n this.currentAdIndex + this.preloadedTokens.length\n );\n } else {\n if (this.config.licenseKey) {\n sendAdLoadedTracking(this.config.licenseKey, {\n source: this.getAdSource(),\n timestamp: new Date().toISOString(),\n });\n }\n await this.adLayer.playAd(bids);\n if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {\n this.scheduleAdStopCountdown(this.getRemainingAdMs());\n }\n this.adLayer.setAdVolume(\n this.adLayer.getOriginalMutedState() ? 1 : this.adLayer.getOriginalVolume()\n );\n }\n } else {\n this.consecutiveFailures++;\n await this.showPlaceholderAndWaitForAds();\n }\n } catch (error) {\n this.consecutiveFailures++;\n if (this.config.debugAdTiming) {\n console.warn(\"[CONTINUOUS-FETCH] tryNextAvailableAd request failed:\", error);\n }\n await this.showPlaceholderAndWaitForAds();\n }\n }\n\n private async showPlaceholderAndWaitForAds(): Promise<void> {\n const remaining = this.getRemainingAdMs();\n const waitTime = Math.min(this.maxPlaceholderDurationMs, remaining);\n\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) {\n const stillRemaining = this.getRemainingAdMs();\n if (stillRemaining >= 1000) {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] 🛑 Max failures reached but break still active — resetting and continuing filler\");\n }\n this.consecutiveFailures = 0;\n return;\n }\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] 🛑 Skipping placeholder - too many consecutive failures\");\n }\n this.handleAdPodComplete();\n return;\n }\n\n if (waitTime < 1000) {\n this.handleAdPodComplete();\n return;\n }\n\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] ⬛ Showing placeholder for ${waitTime}ms while waiting for ad response`);\n }\n\n if (!this.config.disableFiller) {\n this.isShowingPlaceholder = true;\n this.showPlaceholderLayer();\n this.adLayer.showPlaceholder();\n }\n\n const checkInterval = 300;\n const maxChecks = Math.floor(waitTime / checkInterval);\n\n for (let i = 0; i < maxChecks; i++) {\n await new Promise((resolve) => setTimeout(resolve, checkInterval));\n\n if (!this.inAdBreak) return;\n\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] 🛑 Too many failures during placeholder wait — resetting and continuing filler\");\n }\n this.consecutiveFailures = 0;\n break;\n }\n\n if (this.pendingNextAdBids != null && this.pendingNextAdBids.length > 0) {\n const bids = this.pendingNextAdBids;\n this.pendingNextAdBids = null;\n this.isShowingPlaceholder = false;\n this.adLayer.hidePlaceholder();\n this.currentAdIndex++;\n try {\n await this.adLayer.playAd(bids);\n this.consecutiveFailures = 0;\n } catch {\n this.consecutiveFailures++;\n await this.tryNextAvailableAdWithRateLimit();\n }\n return;\n }\n\n if (this.adLayer.isAdPlaying()) {\n this.isShowingPlaceholder = false;\n this.adLayer.hidePlaceholder();\n return;\n }\n }\n\n const stillRemaining = this.getRemainingAdMs();\n if (stillRemaining >= 1000) {\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] ⏰ Placeholder slot expired, ${stillRemaining}ms still remaining — continuing filler`);\n }\n this.isShowingPlaceholder = false;\n this.adLayer.hidePlaceholder();\n this.consecutiveFailures = 0;\n return;\n }\n\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] ⏰ Placeholder timeout, ending ad break\");\n }\n\n this.isShowingPlaceholder = false;\n this.adLayer.hidePlaceholder();\n this.handleAdPodComplete();\n }\n\n private onTimeUpdate(_currentTimeSec: number): void {\n if (this.adLayer.isAdPlaying()) return;\n }\n\n private 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 private clearAdStopTimer(): void {\n if (this.adStopTimerId != null) {\n clearTimeout(this.adStopTimerId);\n this.adStopTimerId = undefined;\n }\n }\n\n private ensureAdStoppedByTimer(): void {\n if (!this.inAdBreak) return;\n\n this.adStopTimerId = undefined;\n\n const adPlaying = this.adLayer.isAdPlaying();\n const pendingAds = this.adPodQueue.length > 0;\n const checkIntervalMs = Math.max(\n 250,\n Math.floor(this.config.adBreakCheckIntervalMs ?? 1000)\n );\n const maxExtensionMsConfig = this.config.maxAdBreakExtensionMs;\n const maxExtensionMs =\n typeof maxExtensionMsConfig === \"number\" && maxExtensionMsConfig > 0\n ? maxExtensionMsConfig\n : 60000;\n\n let elapsedSinceStartMs = 0;\n if (this.currentAdBreakStartWallClockMs != null) {\n elapsedSinceStartMs = Date.now() - this.currentAdBreakStartWallClockMs;\n }\n const expectedDurationMs = this.expectedAdBreakDurationMs ?? 0;\n const overrunMs = Math.max(0, elapsedSinceStartMs - expectedDurationMs);\n\n const shouldExtendAdBreak =\n (adPlaying || pendingAds || this.showAds) && overrunMs < maxExtensionMs;\n\n if (shouldExtendAdBreak) {\n this.scheduleAdStopCountdown(checkIntervalMs);\n return;\n }\n\n if (adPlaying) {\n this.adLayer.stop().catch(() => {});\n }\n\n this.handleAdPodComplete();\n }\n\n private handleAdPodComplete(): void {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] 🏁 Ad pod complete - cleaning up\");\n }\n\n this.clearAdRequestWatchdog();\n this.clearAdFailsafeTimer();\n this.clearAdInsertionOffsetTimer();\n this.activeAdRequestToken = null;\n\n this.isInAdTransition = false;\n this.stopContinuousFetching();\n this.stopFillerBreakTimer();\n this.hidePlaceholderLayer();\n this.clearPendingAdBreak();\n this.cancelAndClearPreloadedTokens();\n this.pendingNextAdBids = null;\n\n if (this.isShowingPlaceholder) {\n this.adLayer.hidePlaceholder();\n this.isShowingPlaceholder = false;\n }\n\n this.inAdBreak = false;\n this.expectedAdBreakDurationMs = undefined;\n this.currentAdBreakStartWallClockMs = undefined;\n this.clearAdStopTimer();\n this.adPodQueue = [];\n this.showAds = false;\n this.currentAdIndex = 0;\n this.totalAdsInBreak = 0;\n this.totalAdRequestsInBreak = 0;\n this.consecutiveFailures = 0;\n\n const restoredMuted = this.savedMutedStateBeforeAd?.muted ?? this.adLayer.getOriginalMutedState();\n const restoredVolume = this.savedMutedStateBeforeAd?.volume ?? this.adLayer.getOriginalVolume();\n this.adLayer.updateOriginalMutedState(restoredMuted, restoredVolume);\n\n this.adLayer.stop().catch(() => {});\n\n if (this.video.muted !== restoredMuted) {\n this.video.muted = restoredMuted;\n }\n if (Math.abs(this.video.volume - restoredVolume) > 0.01) {\n this.video.volume = restoredVolume;\n }\n\n const browser = detectBrowser();\n const isSmartTV = browser.tizenVersion !== undefined || browser.webOSVersion !== undefined || !!this.config.singlePipelineMode;\n if (isSmartTV && this.hls) {\n const hlsRef = this.hls;\n const savedMuted = restoredMuted;\n const savedVolume = restoredVolume;\n const videoRef = this.video;\n const debugEnabled = this.config.debugAdTiming;\n\n const tryPlay = (attempt: number) => {\n if (this.inAdBreak || this.adLayer.isAdPlaying()) return;\n videoRef.play()?.catch(() => {\n if (attempt < 3) {\n if (debugEnabled) {\n console.log(`[StormcloudVideoPlayer] Smart TV: play() retry ${attempt + 1}/3 in ${500 * (attempt + 1)}ms`);\n }\n setTimeout(() => tryPlay(attempt + 1), 500 * (attempt + 1));\n }\n });\n };\n\n const onManifestParsedRestore = () => {\n hlsRef.off(Hls.Events.MANIFEST_PARSED, onManifestParsedRestore);\n if (!this.inAdBreak && !this.adLayer.isAdPlaying()) {\n if (videoRef.muted !== savedMuted) videoRef.muted = savedMuted;\n if (Math.abs(videoRef.volume - savedVolume) > 0.01) videoRef.volume = savedVolume;\n if (debugEnabled) {\n console.log(\"[StormcloudVideoPlayer] Smart TV: audio state restored on MANIFEST_PARSED after re-attach\");\n }\n hlsRef.startLoad(-1);\n if (debugEnabled) {\n console.log(\"[StormcloudVideoPlayer] Smart TV: seeking to live edge and resuming playback after re-attach\");\n }\n }\n };\n hlsRef.on(Hls.Events.MANIFEST_PARSED, onManifestParsedRestore);\n\n const pipelineDelayMs = 300;\n if (debugEnabled) {\n console.log(`[StormcloudVideoPlayer] Smart TV: waiting ${pipelineDelayMs}ms for hardware pipeline release before re-attach`);\n }\n setTimeout(() => {\n if (this.inAdBreak || this.adLayer.isAdPlaying()) return;\n if (this.hls) {\n this.hls.attachMedia(this.video);\n if (debugEnabled) {\n console.log(\"[StormcloudVideoPlayer] Smart TV: re-attached HLS to video element after ad break to restore media pipeline\");\n }\n }\n }, pipelineDelayMs);\n } else {\n if (this.shouldContinueLiveStreamDuringAds()) {\n if (this.config.debugAdTiming) {\n if (this.video.paused) {\n console.log(\"[StormcloudVideoPlayer] Content video paused in live mode after ads, resuming playback\");\n } else {\n console.log(\"[StormcloudVideoPlayer] Content video already playing in live mode after ads\");\n }\n }\n this.video.play()?.catch(() => {});\n } else if (this.video.paused) {\n this.video.play()?.catch(() => {});\n }\n }\n\n this.syncMainContentAudioWhenVisible();\n\n if (!restoredMuted) {\n requestAnimationFrame(() => {\n this.syncMainContentAudioWhenVisible();\n });\n setTimeout(() => {\n this.syncMainContentAudioWhenVisible();\n }, 0);\n setTimeout(() => {\n this.syncMainContentAudioWhenVisible();\n }, 50);\n setTimeout(() => {\n this.syncMainContentAudioWhenVisible();\n }, 100);\n setTimeout(() => {\n this.syncMainContentAudioWhenVisible();\n }, 150);\n }\n\n if (isSmartTV && !restoredMuted) {\n [500, 1000, 2000, 3000, 5000].forEach(delay => {\n setTimeout(() => {\n if (!this.inAdBreak && !this.adLayer.isAdPlaying()) {\n if (this.video.muted !== restoredMuted) this.video.muted = restoredMuted;\n if (Math.abs(this.video.volume - restoredVolume) > 0.01) this.video.volume = restoredVolume;\n }\n }, delay);\n });\n }\n\n this.savedMutedStateBeforeAd = null;\n }\n\n private handleAdFailure(): void {\n this.consecutiveFailures++;\n if (this.config.debugAdTiming) {\n console.log(\n `[CONTINUOUS-FETCH] Ad failure: consecutiveFailures=${this.consecutiveFailures}`\n );\n }\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) {\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] 🛑 Max consecutive failures reached (${this.consecutiveFailures}), ending ad break gracefully`);\n }\n this.handleAdPodComplete();\n return;\n }\n\n if (this.inAdBreak && !this.config.disableFiller) {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Ad failure in active break — showing filler while awaiting next ad\");\n }\n this.showPlaceholderLayer();\n this.adLayer.showPlaceholder();\n } else if (this.inAdBreak) {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Ad failure with no filler — restoring main video temporarily\");\n }\n this.adLayer.hidePlaceholder();\n if (!this.adLayer.isAdPlaying() && this.video.paused && this.video.readyState >= 2) {\n this.video.play()?.catch(() => {});\n }\n }\n }\n\n private 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.handleAdFailure();\n }, timeoutMs) as unknown as number;\n\n this.logAdState(\"ad_request_watchdog_started\", { token, timeoutMs });\n }\n\n private 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 private 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 imaAdPlaying: this.adLayer.isAdPlaying(),\n });\n\n this.handleAdFailure();\n }, failsafeMs) as unknown as number;\n\n this.logAdState(\"ad_failsafe_started\", { token, failsafeMs });\n }\n\n private 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 private logAdState(event: string, extra: Record<string, unknown> = {}): void {\n if (!this.config.debugAdTiming) {\n return;\n }\n this.pushDebugLog(\"info\", \"ad-state\", event, extra);\n\n console.log(\"[StormcloudVideoPlayer][AdState]\", {\n event,\n timestamp: new Date().toISOString(),\n showAds: this.showAds,\n adPlaying: this.adLayer.isAdPlaying(),\n inAdBreak: this.inAdBreak,\n activeAdRequestToken: this.activeAdRequestToken,\n ...extra,\n });\n }\n\n private getRemainingAdMs(): number {\n if (this.currentAdBreakStartWallClockMs == null) return 0;\n if (this.expectedAdBreakDurationMs == null) return Number.MAX_SAFE_INTEGER;\n const elapsed = Date.now() - this.currentAdBreakStartWallClockMs;\n return Math.max(0, this.expectedAdBreakDurationMs - elapsed);\n }\n\n private pushDebugLog(\n level: DebugLogLevel,\n category: string,\n message: string,\n details?: Record<string, unknown>\n ): void {\n if (!this.config.debugAdTiming) return;\n this.debugLogEntries.push({\n timestampMs: Date.now(),\n level,\n category,\n message,\n ...(details ? { details } : {}),\n });\n if (this.debugLogEntries.length > DEBUG_HISTORY_LIMIT) {\n this.debugLogEntries = this.debugLogEntries.slice(-DEBUG_HISTORY_LIMIT);\n }\n }\n\n private pushAdInsertionDebug(\n event: AdInsertionDebugEvent,\n segmentName: string,\n opts?: { offsetSeconds?: number; updatedAt?: string; detail?: string }\n ): void {\n if (!this.config.debugAdTiming) return;\n this.adInsertionDebugHistory.push({\n timestampMs: Date.now(),\n event,\n segmentName,\n ...(opts?.offsetSeconds !== undefined ? { offsetSeconds: opts.offsetSeconds } : {}),\n ...(opts?.updatedAt ? { updatedAt: opts.updatedAt } : {}),\n ...(opts?.detail ? { detail: opts.detail } : {}),\n });\n if (this.adInsertionDebugHistory.length > DEBUG_HISTORY_LIMIT) {\n this.adInsertionDebugHistory = this.adInsertionDebugHistory.slice(-DEBUG_HISTORY_LIMIT);\n }\n }\n\n getAdInsertionDebugLog(): ReadonlyArray<{\n timestampMs: number;\n event: string;\n segmentName: string;\n offsetSeconds?: number;\n updatedAt?: string;\n detail?: string;\n }> {\n return this.adInsertionDebugHistory.slice();\n }\n\n getDebugLogs(): ReadonlyArray<{\n timestampMs: number;\n level: DebugLogLevel;\n category: string;\n message: string;\n details?: Record<string, unknown>;\n }> {\n return this.debugLogEntries.slice();\n }\n\n toggleMute(): void {\n if (this.adLayer.isAdPlaying()) {\n const isAdCurrentlyMuted = this.adLayer.getAdVolume() === 0;\n if (isAdCurrentlyMuted) {\n const savedVolume = this.adLayer.getOriginalVolume() || 1;\n this.adLayer.setAdVolume(savedVolume);\n this.adLayer.updateOriginalMutedState(false, savedVolume);\n } else {\n const currentAdVolume = this.adLayer.getAdVolume();\n this.adLayer.setAdVolume(0);\n this.adLayer.updateOriginalMutedState(true, currentAdVolume);\n }\n\n if (this.config.debugAdTiming) {\n console.log(\n \"[StormcloudVideoPlayer] Mute toggle during ad:\", isAdCurrentlyMuted ? \"unmuted\" : \"muted\"\n );\n }\n } else {\n this.video.muted = !this.video.muted;\n this.adLayer.updateOriginalMutedState(this.video.muted, this.video.volume);\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Muted:\", this.video.muted);\n }\n }\n }\n\n toggleFullscreen(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!document.fullscreenElement) {\n const container = this.video.parentElement;\n if (!container) {\n reject(new Error(\"No parent container found for fullscreen\"));\n return;\n }\n container\n .requestFullscreen()\n .then(() => {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Entered fullscreen\");\n }\n resolve();\n })\n .catch((err) => {\n if (this.config.debugAdTiming) {\n console.error(\"[StormcloudVideoPlayer] Fullscreen error:\", err);\n }\n reject(err);\n });\n } else {\n document\n .exitFullscreen()\n .then(() => {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Exited fullscreen\");\n }\n resolve();\n })\n .catch((err) => {\n if (this.config.debugAdTiming) {\n console.error(\n \"[StormcloudVideoPlayer] Exit fullscreen error:\",\n err\n );\n }\n reject(err);\n });\n }\n });\n }\n\n isMuted(): boolean {\n if (this.adLayer.isAdPlaying()) {\n const adMuted = this.adLayer.getAdVolume() === 0;\n if (this.config.debugAdTiming) {\n console.log(\n \"[StormcloudVideoPlayer] isMuted() during ad playback ->\", adMuted\n );\n }\n return adMuted;\n }\n return this.video.muted;\n }\n\n setMuted(muted: boolean): void {\n const adPlaying = this.adLayer.isAdPlaying();\n\n if (adPlaying) {\n const savedVolume = this.adLayer.getOriginalVolume() || 1;\n this.adLayer.setAdVolume(muted ? 0 : savedVolume);\n this.adLayer.updateOriginalMutedState(muted, savedVolume);\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] setMuted applied to ad layer (content stays muted)\", {\n muted, savedVolume,\n });\n }\n return;\n }\n\n this.video.muted = muted;\n\n if (!this.inAdBreak) {\n this.adLayer.updateOriginalMutedState(muted, this.video.volume);\n }\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] setMuted called:\", muted);\n }\n }\n\n setVolume(volume: number): void {\n const clampedVolume = Math.max(0, Math.min(1, volume));\n const adPlaying = this.adLayer.isAdPlaying();\n\n if (adPlaying) {\n this.adLayer.setAdVolume(clampedVolume);\n const preservedVolume = clampedVolume > 0 ? clampedVolume : this.adLayer.getOriginalVolume();\n this.adLayer.updateOriginalMutedState(clampedVolume === 0, preservedVolume);\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] setVolume applied during ad\", {\n volume: clampedVolume,\n });\n }\n } else {\n this.video.volume = clampedVolume;\n this.video.muted = clampedVolume === 0;\n if (!this.inAdBreak) {\n this.adLayer.updateOriginalMutedState(clampedVolume === 0, clampedVolume);\n }\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] setVolume called:\", clampedVolume);\n }\n }\n }\n\n getVolume(): number {\n const adPlaying = this.adLayer.isAdPlaying();\n if (adPlaying) {\n return this.adLayer.getAdVolume();\n }\n return this.video.volume;\n }\n\n isFullscreen(): boolean {\n return !!document.fullscreenElement;\n }\n\n isLive(): boolean {\n return this.isLiveStream;\n }\n\n getMinHlsResolution(): { width: number; height: number } | null {\n const levels = this.hls?.levels;\n if (!levels || levels.length === 0) return null;\n\n let min: { width: number; height: number } | null = null;\n let minPixels = Infinity;\n\n for (const level of levels) {\n if (level.width && level.height) {\n const pixels = level.width * level.height;\n if (pixels < minPixels) {\n minPixels = pixels;\n min = { width: level.width, height: level.height };\n }\n }\n }\n return min;\n }\n\n getCurrentHlsSegmentDurationMs(): number | null {\n const fallbackMs = 4000;\n\n if (this.nativeHlsMode) {\n return fallbackMs;\n }\n\n const hls = this.hls;\n if (!hls) return null;\n\n const levelCandidates = [hls.currentLevel, hls.nextLoadLevel, hls.loadLevel];\n for (const levelIndex of levelCandidates) {\n if (typeof levelIndex !== \"number\" || levelIndex < 0) continue;\n const details = hls.levels?.[levelIndex]?.details as\n | { targetduration?: number; partTarget?: number }\n | undefined;\n if (!details) continue;\n\n const targetDurationSec =\n typeof details.partTarget === \"number\" && details.partTarget > 0\n ? details.partTarget\n : typeof details.targetduration === \"number\" && details.targetduration > 0\n ? details.targetduration\n : undefined;\n\n if (targetDurationSec !== undefined) {\n return Math.max(800, Math.floor(targetDurationSec * 1000));\n }\n }\n\n return fallbackMs;\n }\n\n get videoElement(): HTMLVideoElement {\n return this.video;\n }\n\n resize(): void {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Resizing player\");\n }\n\n if (this.adLayer && this.adLayer.isAdPlaying()) {\n const width = this.video.clientWidth || 640;\n const height = this.video.clientHeight || 480;\n\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Resizing ads manager to ${width}x${height}`\n );\n }\n\n this.adLayer.resize(width, height);\n }\n }\n\n destroy(): void {\n this.stopAdInsertionPolling();\n this.clearAdInsertionOffsetTimer();\n this.stopContinuousFetching();\n this.stopFillerBreakTimer();\n this.clearAdStopTimer();\n this.clearAdFailsafeTimer();\n this.clearAdRequestWatchdog();\n this.clearPendingAdBreak();\n \n if (this.fillerVideo) {\n this.fillerVideo.pause();\n if (this.fillerVideo.parentElement) {\n this.fillerVideo.parentElement.removeChild(this.fillerVideo);\n }\n this.fillerVideo = undefined;\n }\n \n if (this.timeUpdateHandler) {\n this.video.removeEventListener(\"timeupdate\", this.timeUpdateHandler);\n delete this.timeUpdateHandler;\n }\n if (this.emptiedHandler) {\n this.video.removeEventListener(\"emptied\", this.emptiedHandler);\n delete this.emptiedHandler;\n }\n \n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n this.heartbeatInterval = undefined;\n }\n this.hls?.destroy();\n this.adLayer?.destroy();\n this.consecutiveFailures = 0;\n this.debugLogEntries = [];\n this.adInsertionDebugHistory = [];\n }\n}\n","export interface VastMediaFile {\n url: string;\n type: string;\n width: number;\n height: number;\n bitrate?: number | undefined;\n}\n\nexport interface VastTrackingUrls {\n impression: string[];\n start: string[];\n firstQuartile: string[];\n midpoint: string[];\n thirdQuartile: string[];\n complete: string[];\n mute: string[];\n unmute: string[];\n pause: string[];\n resume: string[];\n fullscreen: string[];\n exitFullscreen: string[];\n skip: string[];\n error: string[];\n}\n\nexport interface VastAd {\n id: string;\n title: string;\n duration: number;\n mediaFiles: VastMediaFile[];\n trackingUrls: VastTrackingUrls;\n clickThrough?: string | undefined;\n}\n\nexport type MediaFileFilter = \"hls-only\" | \"mp4-first\" | \"all\";\n\nfunction isHlsType(type: string): boolean {\n return type === \"application/x-mpegURL\" || type.includes(\"m3u8\");\n}\n\nfunction isMp4Type(type: string): boolean {\n return type === \"video/mp4\" || type.includes(\"mp4\");\n}\n\nexport function parseVastXml(\n xmlString: string,\n filter: MediaFileFilter = \"all\",\n logPrefix = \"[VastParser]\"\n): VastAd | null {\n try {\n const parser = new DOMParser();\n const xmlDoc = parser.parseFromString(xmlString, \"text/xml\");\n\n const parserError = xmlDoc.querySelector(\"parsererror\");\n if (parserError) {\n console.error(\n `${logPrefix} XML parsing error (malformed VAST XML):`,\n parserError.textContent\n );\n return null;\n }\n\n const adElement = xmlDoc.querySelector(\"Ad\");\n if (!adElement) {\n console.warn(`${logPrefix} No Ad element found in VAST XML`);\n return null;\n }\n\n const adId = adElement.getAttribute(\"id\") || \"unknown\";\n const title = xmlDoc.querySelector(\"AdTitle\")?.textContent || \"Ad\";\n\n const isNoAdAvailable =\n adId === \"empty\" ||\n title.toLowerCase().includes(\"no ad available\") ||\n title.toLowerCase() === \"no ad available\";\n\n const durationText =\n xmlDoc.querySelector(\"Duration\")?.textContent || \"00:00:30\";\n const durationParts = durationText.split(\":\");\n const duration =\n parseInt(durationParts[0] || \"0\", 10) * 3600 +\n parseInt(durationParts[1] || \"0\", 10) * 60 +\n Math.round(parseFloat(durationParts[2] || \"0\"));\n\n const mediaFileElements = xmlDoc.querySelectorAll(\"MediaFile\");\n const mediaFiles: VastMediaFile[] = [];\n\n console.log(\n `${logPrefix} Found ${mediaFileElements.length} MediaFile element(s) in VAST XML`\n );\n\n mediaFileElements.forEach((mf, index) => {\n const type = mf.getAttribute(\"type\") || \"\";\n const url = mf.textContent?.trim() || \"\";\n const width = mf.getAttribute(\"width\") || \"\";\n const height = mf.getAttribute(\"height\") || \"\";\n\n console.log(\n `${logPrefix} MediaFile ${index}: type=\"${type}\", url=\"${url.substring(0, 80)}...\", width=\"${width}\", height=\"${height}\"`\n );\n\n if (!url) {\n console.warn(`${logPrefix} MediaFile ${index} has empty URL`);\n return;\n }\n\n const isHls = isHlsType(type);\n const isMp4 = isMp4Type(type);\n\n let accepted = false;\n if (filter === \"hls-only\") {\n accepted = isHls;\n } else if (filter === \"mp4-first\") {\n accepted = isMp4 || isHls;\n } else {\n accepted = true;\n }\n\n if (!accepted) {\n console.log(\n `${logPrefix} MediaFile ${index} ignored (type=\"${type}\" not accepted by filter \"${filter}\")`\n );\n return;\n }\n\n const bitrateAttr = mf.getAttribute(\"bitrate\");\n const bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : undefined;\n\n mediaFiles.push({\n url,\n type,\n width: parseInt(width || \"1920\", 10),\n height: parseInt(height || \"1080\", 10),\n bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : undefined,\n });\n\n console.log(`${logPrefix} Added MediaFile: type=\"${type}\" url=\"${url.substring(0, 80)}...\"`);\n });\n\n if (filter === \"mp4-first\" && mediaFiles.length > 1) {\n mediaFiles.sort((a, b) => {\n const aIsMp4 = isMp4Type(a.type) ? 0 : 1;\n const bIsMp4 = isMp4Type(b.type) ? 0 : 1;\n return aIsMp4 - bIsMp4;\n });\n }\n\n if (mediaFiles.length === 0) {\n if (isNoAdAvailable) {\n console.warn(\n `${logPrefix} No ads available (VAST response indicates no ads)`\n );\n } else {\n console.warn(`${logPrefix} No compatible media files found in VAST XML`);\n }\n return null;\n }\n\n const trackingUrls: VastTrackingUrls = {\n impression: [],\n start: [],\n firstQuartile: [],\n midpoint: [],\n thirdQuartile: [],\n complete: [],\n mute: [],\n unmute: [],\n pause: [],\n resume: [],\n fullscreen: [],\n exitFullscreen: [],\n skip: [],\n error: [],\n };\n\n xmlDoc.querySelectorAll(\"Impression\").forEach((el) => {\n const url = el.textContent?.trim();\n if (url) trackingUrls.impression.push(url);\n });\n\n xmlDoc.querySelectorAll(\"Tracking\").forEach((el) => {\n const event = el.getAttribute(\"event\");\n const url = el.textContent?.trim();\n if (event && url) {\n const eventKey = event as keyof VastTrackingUrls;\n if (trackingUrls[eventKey]) {\n trackingUrls[eventKey].push(url);\n }\n }\n });\n\n const clickThrough = xmlDoc\n .querySelector(\"ClickThrough\")\n ?.textContent?.trim();\n\n return {\n id: adId,\n title,\n duration,\n mediaFiles,\n trackingUrls,\n clickThrough,\n };\n } catch (error) {\n console.error(`${logPrefix} Error parsing VAST XML:`, error);\n return null;\n }\n}\n\nexport async function fetchAndParseVastAd(\n vastTagUrl: string,\n filter: MediaFileFilter = \"all\",\n logPrefix = \"[VastParser]\"\n): Promise<VastAd | null> {\n const response = await fetch(vastTagUrl, {\n mode: \"cors\",\n credentials: \"include\",\n headers: {\n Accept: \"application/xml, text/xml, */*\",\n },\n referrerPolicy: \"no-referrer-when-downgrade\",\n });\n if (!response.ok) {\n throw new Error(`Failed to fetch VAST: ${response.statusText}`);\n }\n\n const vastXml = await response.text();\n console.log(`${logPrefix} VAST XML received`);\n console.log(\n `${logPrefix} VAST XML content (first 2000 chars):`,\n vastXml.substring(0, 2000)\n );\n\n return parseVastXml(vastXml, filter, logPrefix);\n}\n\nexport function createEmptyTrackingState() {\n return {\n impression: false,\n start: false,\n firstQuartile: false,\n midpoint: false,\n thirdQuartile: false,\n complete: false,\n };\n}\n\nasync function firePixelWithRetry(\n url: string,\n retries = 2,\n delayMs = 500,\n logPrefix = \"[VastParser]\"\n): Promise<void> {\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n await fetch(url, {\n method: \"GET\",\n mode: \"no-cors\",\n cache: \"no-cache\",\n keepalive: true,\n });\n return;\n } catch {\n if (attempt < retries) {\n await new Promise((r) => setTimeout(r, delayMs * Math.pow(2, attempt)));\n } else {\n console.warn(`${logPrefix} Tracking pixel failed after ${retries + 1} attempts: ${url}`);\n }\n }\n }\n}\n\nexport function fireTrackingPixels(\n urls: string[],\n sessionId?: string,\n logPrefix = \"[VastParser]\"\n): void {\n if (!urls || urls.length === 0) return;\n\n urls.forEach((url) => {\n try {\n let trackingUrl = url;\n\n if (sessionId) {\n trackingUrl = `${trackingUrl}${\n trackingUrl.includes(\"?\") ? \"&\" : \"?\"\n }session_id=${sessionId}`;\n }\n\n if (typeof fetch !== \"undefined\") {\n firePixelWithRetry(trackingUrl, 2, 500, logPrefix).catch(() => {});\n } else {\n const img = new Image(1, 1);\n img.onerror = () => {};\n img.src = trackingUrl;\n }\n\n console.log(`${logPrefix} Fired tracking pixel: ${trackingUrl}`);\n } catch (error) {\n console.warn(`${logPrefix} Error firing tracking pixel:`, error);\n }\n });\n}\n","import type { AdController, AdBreakContext } from \"../types\";\nimport { fireTrackingPixels as fireTrackingPixelsShared } from \"./vastParser\";\n\ninterface VastMediaFile {\n url: string;\n type: string;\n width: number;\n height: number;\n bitrate?: number | undefined;\n}\n\nconst SUPPORTED_VIDEO_EXTENSIONS = ['.mp4', '.webm', '.ogg', '.m3u8', '.ts'];\nconst UNSUPPORTED_VIDEO_EXTENSIONS = ['.flv', '.f4v', '.swf', '.wmv', '.avi', '.mov', '.mkv'];\nconst REQUEST_TIMEOUT_MS = 5000;\nconst REQUEST_MAX_RETRIES = 3;\nconst REQUEST_RETRY_BACKOFF_MS = 1500;\nconst AD_LAYER_Z_INDEX = \"30\";\nconst COUNTDOWN_Z_INDEX = \"31\";\nconst STALL_TIMEOUT_MS = 8000;\n\nfunction getFileExtension(url: string): string {\n try {\n const pathname = new URL(url, 'http://dummy').pathname;\n const lastDot = pathname.lastIndexOf('.');\n if (lastDot === -1) return '';\n return pathname.slice(lastDot).toLowerCase();\n } catch {\n const lastDot = url.lastIndexOf('.');\n if (lastDot === -1) return '';\n const ext = url.slice(lastDot).split(/[?#]/)[0];\n return (ext || '').toLowerCase();\n }\n}\n\nfunction isUnsupportedFormat(url: string): boolean {\n const ext = getFileExtension(url);\n return UNSUPPORTED_VIDEO_EXTENSIONS.indexOf(ext) !== -1;\n}\n\nfunction replaceFlvExtension(url: string): string {\n const ext = getFileExtension(url);\n if (ext === '.flv') {\n return url.replace(/\\.flv(\\?|$)/i, '.mp4$1');\n }\n return url;\n}\n\nfunction isSupportedFormat(url: string, mimeType: string): boolean {\n if (isUnsupportedFormat(url)) {\n return false;\n }\n \n const ext = getFileExtension(url);\n \n if (SUPPORTED_VIDEO_EXTENSIONS.indexOf(ext) !== -1) {\n return true;\n }\n \n if (ext === '' || ext === '.') {\n return mimeType.includes('video/mp4') || \n mimeType.includes('video/webm') || \n mimeType.includes('m3u8') ||\n mimeType.includes('application/x-mpegurl');\n }\n \n return false;\n}\n\ninterface VastTrackingUrls {\n impression: string[];\n start: string[];\n firstQuartile: string[];\n midpoint: string[];\n thirdQuartile: string[];\n complete: string[];\n mute: string[];\n unmute: string[];\n pause: string[];\n resume: string[];\n error: string[];\n}\n\ninterface VastAd {\n id: string;\n title: string;\n duration: number;\n mediaFiles: VastMediaFile[];\n trackingUrls: VastTrackingUrls;\n clickThrough?: string | undefined;\n}\n\nexport interface AdStormPlayerOptions {\n licenseKey: string;\n debug?: boolean;\n}\n\nexport interface AdStormLayerOptionsUpdate {\n continueLiveStreamDuringAds?: boolean;\n mainHlsInstance?: unknown;\n}\n\nexport interface AdStormAdLayer extends AdController {\n requestAds: (duration?: string) => Promise<void>;\n updateOptions: (opts: AdStormLayerOptionsUpdate) => void;\n playAd: (requestContext?: unknown) => Promise<void>;\n preloadAd: (arg1: unknown, arg2?: unknown) => Promise<void>;\n playPreloaded: (token: string) => Promise<void>;\n hasPreloaded: (token: string) => boolean;\n cancelPreload: (token: string) => void;\n}\n\nexport function createAdStormPlayer(\n contentVideo: HTMLVideoElement,\n options: AdStormPlayerOptions\n): AdStormAdLayer {\n const { licenseKey, debug = false } = options;\n \n let adPlaying = false;\n let originalMutedState = false;\n let originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));\n const listeners = new Map<string, Set<(payload?: any) => void>>();\n \n let adVideoElement: HTMLVideoElement | undefined;\n let adContainerEl: HTMLDivElement | undefined;\n let adCountdownEl: HTMLDivElement | undefined;\n let currentAd: VastAd | undefined;\n let destroyed = false;\n let tornDown = false;\n let continueLiveStreamDuringAds = false;\n let sessionId: string | undefined;\n let adStallTimerId: ReturnType<typeof setTimeout> | undefined;\n let adCountdownTimerId: ReturnType<typeof setInterval> | undefined;\n let adHideTimerId: ReturnType<typeof setTimeout> | undefined;\n let lastCountdownSecond = -1;\n let adListenersBound = false;\n let parentPositionOverridden = false;\n\n const adHandlers = {\n timeupdate: () => {\n if (!currentAd || !adVideoElement || destroyed || tornDown) return;\n const progress = adVideoElement.currentTime / currentAd.duration;\n\n if (progress >= 0.25 && !trackingFired.firstQuartile) {\n trackingFired.firstQuartile = true;\n fireTrackingPixels(currentAd.trackingUrls.firstQuartile);\n }\n if (progress >= 0.5 && !trackingFired.midpoint) {\n trackingFired.midpoint = true;\n fireTrackingPixels(currentAd.trackingUrls.midpoint);\n }\n if (progress >= 0.75 && !trackingFired.thirdQuartile) {\n trackingFired.thirdQuartile = true;\n fireTrackingPixels(currentAd.trackingUrls.thirdQuartile);\n }\n updateAdCountdown();\n },\n playing: () => {\n clearAdStallTimer();\n if (!currentAd || trackingFired.start || destroyed || tornDown) return;\n trackingFired.start = true;\n fireTrackingPixels(currentAd.trackingUrls.start);\n startAdCountdown();\n log(\"Ad started playing\");\n },\n ended: () => {\n if (!currentAd || trackingFired.complete || destroyed || tornDown) return;\n trackingFired.complete = true;\n fireTrackingPixels(currentAd.trackingUrls.complete);\n log(\"Ad completed\");\n handleAdComplete();\n },\n error: (e: Event) => {\n if (destroyed || tornDown) return;\n console.error(\"[AdStormPlayer] Ad video error:\", e);\n if (currentAd) fireTrackingPixels(currentAd.trackingUrls.error);\n handleAdError();\n },\n waiting: () => {\n clearAdStallTimer();\n adStallTimerId = setTimeout(() => {\n adStallTimerId = undefined;\n if (!adPlaying || destroyed || tornDown) return;\n console.warn(\"[AdStormPlayer] Ad playback stalled too long\");\n handleAdError();\n }, STALL_TIMEOUT_MS);\n },\n volumechange: () => {\n if (!currentAd || !adVideoElement || destroyed || tornDown) return;\n if (adVideoElement.muted || adVideoElement.volume <= 0) {\n fireTrackingPixels(currentAd.trackingUrls.mute);\n } else {\n fireTrackingPixels(currentAd.trackingUrls.unmute);\n }\n },\n pause: () => {\n if (!currentAd || !adVideoElement || destroyed || tornDown) return;\n if (!adVideoElement.ended) {\n fireTrackingPixels(currentAd.trackingUrls.pause);\n }\n },\n play: () => {\n if (!currentAd || !adVideoElement || destroyed || tornDown) return;\n if (adVideoElement.currentTime > 0) {\n fireTrackingPixels(currentAd.trackingUrls.resume);\n }\n },\n };\n \n let trackingFired = {\n impression: false,\n start: false,\n firstQuartile: false,\n midpoint: false,\n thirdQuartile: false,\n complete: false,\n };\n const preloadSlots = new Map<string, { ad: VastAd }>();\n\n function log(...args: any[]): void {\n if (debug) {\n console.log(\"[AdStormPlayer]\", ...args);\n }\n }\n\n function emit(event: string, payload?: any): void {\n const set = listeners.get(event);\n if (!set) return;\n for (const fn of Array.from(set)) {\n try {\n fn(payload);\n } catch (error) {\n console.warn(`[AdStormPlayer] Error in event listener for ${event}:`, error);\n }\n }\n }\n\n function fireTrackingPixels(urls: string[]): void {\n fireTrackingPixelsShared(urls, sessionId, \"[AdStormPlayer]\");\n }\n\n function clearAdStallTimer(): void {\n if (adStallTimerId) {\n clearTimeout(adStallTimerId);\n adStallTimerId = undefined;\n }\n }\n\n function clearAdCountdownTimer(): void {\n if (adCountdownTimerId) {\n clearInterval(adCountdownTimerId);\n adCountdownTimerId = undefined;\n }\n lastCountdownSecond = -1;\n }\n\n function updateAdCountdown(): void {\n if (!adCountdownEl || !adVideoElement || !currentAd || !adPlaying) return;\n const remainingSec = Math.max(\n 0,\n Math.ceil((currentAd.duration || 0) - adVideoElement.currentTime)\n );\n if (remainingSec === lastCountdownSecond) return;\n lastCountdownSecond = remainingSec;\n adCountdownEl.textContent = `Ad ${remainingSec}s`;\n emit(\"ad_countdown\", {\n remainingSec,\n durationSec: currentAd.duration,\n currentTimeSec: adVideoElement.currentTime,\n });\n }\n\n function startAdCountdown(): void {\n clearAdCountdownTimer();\n updateAdCountdown();\n adCountdownTimerId = setInterval(updateAdCountdown, 250);\n }\n\n function generateSessionId(): string {\n return `adstorm-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;\n }\n\n function bindAdEventListeners(): void {\n if (!adVideoElement || adListenersBound) return;\n adVideoElement.addEventListener(\"timeupdate\", adHandlers.timeupdate);\n adVideoElement.addEventListener(\"playing\", adHandlers.playing);\n adVideoElement.addEventListener(\"ended\", adHandlers.ended);\n adVideoElement.addEventListener(\"error\", adHandlers.error);\n adVideoElement.addEventListener(\"waiting\", adHandlers.waiting);\n adVideoElement.addEventListener(\"volumechange\", adHandlers.volumechange);\n adVideoElement.addEventListener(\"pause\", adHandlers.pause);\n adVideoElement.addEventListener(\"play\", adHandlers.play);\n adListenersBound = true;\n }\n\n function unbindAdEventListeners(): void {\n if (!adVideoElement || !adListenersBound) return;\n adVideoElement.removeEventListener(\"timeupdate\", adHandlers.timeupdate);\n adVideoElement.removeEventListener(\"playing\", adHandlers.playing);\n adVideoElement.removeEventListener(\"ended\", adHandlers.ended);\n adVideoElement.removeEventListener(\"error\", adHandlers.error);\n adVideoElement.removeEventListener(\"waiting\", adHandlers.waiting);\n adVideoElement.removeEventListener(\"volumechange\", adHandlers.volumechange);\n adVideoElement.removeEventListener(\"pause\", adHandlers.pause);\n adVideoElement.removeEventListener(\"play\", adHandlers.play);\n adListenersBound = false;\n }\n\n function teardownCurrentPlayback(): void {\n unbindAdEventListeners();\n clearAdStallTimer();\n clearAdCountdownTimer();\n if (!adVideoElement) return;\n adVideoElement.pause();\n adVideoElement.removeAttribute(\"src\");\n adVideoElement.load();\n }\n\n function buildVastUrl(durationSeconds: number): string {\n const baseUrl = `https://adstorm.co/api-adstorm-dev/adstorm/nab/vast/pod`;\n\n return `${baseUrl}?duration=${Math.ceil(durationSeconds)}`;\n }\n\n function parseVastXml(xmlString: string): VastAd[] {\n const ads: VastAd[] = [];\n \n try {\n const parser = new DOMParser();\n const xmlDoc = parser.parseFromString(xmlString, \"text/xml\");\n \n const parserError = xmlDoc.querySelector(\"parsererror\");\n if (parserError) {\n console.error(\"[AdStormPlayer] XML parsing error:\", parserError.textContent);\n return [];\n }\n \n const adElements = xmlDoc.querySelectorAll(\"Ad\");\n \n adElements.forEach((adElement) => {\n const adId = adElement.getAttribute(\"id\") || \"unknown\";\n const title = adElement.querySelector(\"AdTitle\")?.textContent || \"Ad\";\n \n const durationText = adElement.querySelector(\"Duration\")?.textContent || \"00:00:30\";\n const durationParts = durationText.split(\":\");\n const duration =\n parseInt(durationParts[0] || \"0\", 10) * 3600 +\n parseInt(durationParts[1] || \"0\", 10) * 60 +\n parseFloat(durationParts[2] || \"0\");\n \n const mediaFileElements = adElement.querySelectorAll(\"MediaFile\");\n const mediaFiles: VastMediaFile[] = [];\n \n mediaFileElements.forEach((mf) => {\n const type = mf.getAttribute(\"type\") || \"\";\n let url = mf.textContent?.trim() || \"\";\n const width = parseInt(mf.getAttribute(\"width\") || \"1920\", 10);\n const height = parseInt(mf.getAttribute(\"height\") || \"1080\", 10);\n const bitrate = mf.getAttribute(\"bitrate\") \n ? parseInt(mf.getAttribute(\"bitrate\")!, 10) \n : undefined;\n \n if (!url) {\n log(`Skipping empty MediaFile URL`);\n return;\n }\n \n const originalUrl = url;\n url = replaceFlvExtension(url);\n if (url !== originalUrl) {\n log(`Converted FLV to MP4: ${originalUrl} -> ${url}`);\n }\n \n if (isUnsupportedFormat(url)) {\n const ext = getFileExtension(url);\n log(`Skipping unsupported format: ${url} (extension: ${ext}, declared type: ${type})`);\n return;\n }\n \n if (isSupportedFormat(url, type)) {\n mediaFiles.push({ url, type, width, height, bitrate });\n log(`Found media file: ${url} (${type}, ${width}x${height})`);\n } else {\n log(`Skipping incompatible media file: ${url} (type: ${type})`);\n }\n });\n \n if (mediaFiles.length === 0) {\n log(\"No valid media files found in ad:\", adId);\n return;\n }\n \n const trackingUrls: VastTrackingUrls = {\n impression: [],\n start: [],\n firstQuartile: [],\n midpoint: [],\n thirdQuartile: [],\n complete: [],\n mute: [],\n unmute: [],\n pause: [],\n resume: [],\n error: [],\n };\n \n adElement.querySelectorAll(\"Impression\").forEach((el) => {\n const url = el.textContent?.trim();\n if (url) trackingUrls.impression.push(url);\n });\n \n adElement.querySelectorAll(\"Tracking\").forEach((el) => {\n const event = el.getAttribute(\"event\");\n const url = el.textContent?.trim();\n if (event && url) {\n const eventKey = event as keyof VastTrackingUrls;\n if (trackingUrls[eventKey]) {\n trackingUrls[eventKey].push(url);\n }\n }\n });\n \n const clickThrough = adElement.querySelector(\"ClickThrough\")?.textContent?.trim();\n \n ads.push({\n id: adId,\n title,\n duration,\n mediaFiles,\n trackingUrls,\n clickThrough,\n });\n \n log(`Parsed ad: ${title}, duration: ${duration}s, media files: ${mediaFiles.length}`);\n });\n \n } catch (error) {\n console.error(\"[AdStormPlayer] Error parsing VAST XML:\", error);\n }\n \n return ads;\n }\n\n function selectBestMediaFile(mediaFiles: VastMediaFile[]): VastMediaFile | null {\n if (mediaFiles.length === 0) return null;\n if (mediaFiles.length === 1) return mediaFiles[0]!;\n \n const mp4Files = mediaFiles.filter(mf => mf.type.includes(\"video/mp4\"));\n const candidates = mp4Files.length > 0 ? mp4Files : mediaFiles;\n \n const targetWidth = contentVideo.videoWidth || 1280;\n const targetHeight = contentVideo.videoHeight || 720;\n \n candidates.sort((a, b) => {\n const diffA = Math.abs(a.width - targetWidth) + Math.abs(a.height - targetHeight);\n const diffB = Math.abs(b.width - targetWidth) + Math.abs(b.height - targetHeight);\n return diffA - diffB;\n });\n \n return candidates[0] || null;\n }\n\n function createAdVideoElement(): HTMLVideoElement {\n const video = document.createElement(\"video\");\n video.style.position = \"absolute\";\n video.style.left = \"0\";\n video.style.top = \"0\";\n video.style.width = \"100%\";\n video.style.height = \"100%\";\n video.style.objectFit = \"contain\";\n video.style.backgroundColor = \"#000\";\n video.style.zIndex = \"1\";\n video.playsInline = true;\n video.preload = \"auto\";\n video.muted = originalMutedState;\n video.volume = originalMutedState ? 0 : originalVolume;\n \n return video;\n }\n\n function setAdPlayingFlag(isPlaying: boolean): void {\n if (isPlaying) {\n contentVideo.dataset.stormcloudAdPlaying = \"true\";\n } else {\n delete contentVideo.dataset.stormcloudAdPlaying;\n }\n }\n\n function setupAdEventListeners(): void {\n bindAdEventListeners();\n }\n\n function handleAdComplete(): void {\n if (destroyed || tornDown) return;\n log(\"Handling ad completion\");\n adPlaying = false;\n setAdPlayingFlag(false);\n clearAdStallTimer();\n clearAdCountdownTimer();\n \n if (adContainerEl) {\n adContainerEl.style.opacity = \"0\";\n adHideTimerId = setTimeout(() => {\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n }, 300);\n }\n \n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n contentVideo.muted = originalMutedState;\n contentVideo.volume = originalVolume;\n currentAd = undefined;\n \n emit(\"content_resume\");\n emit(\"all_ads_completed\");\n }\n\n function handleAdError(): void {\n if (destroyed || tornDown) return;\n log(\"Handling ad error\");\n if (!adPlaying) return;\n adPlaying = false;\n setAdPlayingFlag(false);\n clearAdStallTimer();\n clearAdCountdownTimer();\n \n contentVideo.muted = originalMutedState;\n contentVideo.volume = originalVolume;\n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n \n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n \n currentAd = undefined;\n emit(\"ad_error\");\n emit(\"content_resume\");\n }\n\n async function fetchVastOnce(durationSeconds: number): Promise<VastAd[]> {\n const vastUrl = buildVastUrl(durationSeconds);\n log(\"Fetching VAST from:\", vastUrl);\n\n const controller =\n typeof AbortController !== \"undefined\" ? new AbortController() : null;\n const timeoutId = setTimeout(() => controller?.abort(), REQUEST_TIMEOUT_MS);\n\n try {\n const requestInit: RequestInit = {\n method: \"GET\",\n mode: \"cors\",\n credentials: \"omit\",\n headers: {\n Accept: \"application/xml, text/xml, */*\",\n },\n referrerPolicy: \"no-referrer-when-downgrade\",\n };\n if (controller) {\n requestInit.signal = controller.signal;\n }\n\n const response = await fetch(vastUrl, requestInit);\n\n if (!response.ok) {\n throw new Error(`Failed to fetch VAST: ${response.status} ${response.statusText}`);\n }\n\n const xmlText = await response.text();\n log(\"VAST response received, length:\", xmlText.length);\n return parseVastXml(xmlText);\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n async function fetchVast(durationSeconds: number): Promise<VastAd[]> {\n let lastError: unknown;\n for (let attempt = 1; attempt <= REQUEST_MAX_RETRIES; attempt++) {\n try {\n const ads = await fetchVastOnce(durationSeconds);\n if (ads.length > 0) return ads;\n log(`No ad returned from VAST on attempt ${attempt}/${REQUEST_MAX_RETRIES}`);\n } catch (error: any) {\n lastError = error;\n if (error?.name === \"AbortError\") {\n console.warn(\n `[AdStormPlayer] VAST request timed out (${REQUEST_TIMEOUT_MS}ms), attempt ${attempt}/${REQUEST_MAX_RETRIES}`\n );\n } else {\n console.warn(`[AdStormPlayer] VAST request failed on attempt ${attempt}/${REQUEST_MAX_RETRIES}:`, error);\n }\n }\n\n if (attempt < REQUEST_MAX_RETRIES) {\n const delay = REQUEST_RETRY_BACKOFF_MS * attempt;\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n if (lastError instanceof Error) {\n throw lastError;\n }\n return [];\n }\n\n function getDurationSecondsFromContext(requestContext?: unknown): number {\n if (!requestContext || typeof requestContext !== \"object\") {\n return 30;\n }\n const ctx = requestContext as AdBreakContext;\n const value = ctx.remainingBreakSec ?? ctx.breakDurationSec;\n if (typeof value !== \"number\" || Number.isNaN(value)) {\n return 30;\n }\n return Math.max(1, Math.ceil(value));\n }\n\n async function requestAdFromApi(requestContext?: unknown): Promise<VastAd | null> {\n const durationSeconds = getDurationSecondsFromContext(requestContext);\n const ads = await fetchVast(durationSeconds);\n return ads[0] || null;\n }\n\n function assignCurrentAd(ad: VastAd): void {\n currentAd = ad;\n sessionId = generateSessionId();\n trackingFired = {\n impression: false,\n start: false,\n firstQuartile: false,\n midpoint: false,\n thirdQuartile: false,\n complete: false,\n };\n fireTrackingPixels(currentAd.trackingUrls.impression);\n trackingFired.impression = true;\n emit(\"ad_impression\");\n }\n\n return {\n initialize() {\n log(\"Initializing\");\n \n if (!adContainerEl) {\n const parent = contentVideo.parentElement;\n if (parent) {\n const computed = window.getComputedStyle(parent).position;\n if (computed === \"static\") {\n parent.style.position = \"relative\";\n parentPositionOverridden = true;\n }\n }\n\n const container = document.createElement(\"div\");\n container.style.position = \"absolute\";\n container.style.left = \"0\";\n container.style.top = \"0\";\n container.style.right = \"0\";\n container.style.bottom = \"0\";\n container.style.display = \"none\";\n container.style.alignItems = \"center\";\n container.style.justifyContent = \"center\";\n container.style.pointerEvents = \"none\";\n container.style.zIndex = AD_LAYER_Z_INDEX;\n container.style.backgroundColor = \"#000\";\n container.style.transition = \"opacity 0.3s ease-in-out\";\n container.style.opacity = \"0\";\n container.style.isolation = \"isolate\";\n \n const countdown = document.createElement(\"div\");\n countdown.style.position = \"absolute\";\n countdown.style.left = \"12px\";\n countdown.style.top = \"12px\";\n countdown.style.padding = \"4px 8px\";\n countdown.style.borderRadius = \"4px\";\n countdown.style.background = \"rgba(0,0,0,0.75)\";\n countdown.style.color = \"#fff\";\n countdown.style.fontFamily = \"sans-serif\";\n countdown.style.fontSize = \"12px\";\n countdown.style.lineHeight = \"1.2\";\n countdown.style.pointerEvents = \"none\";\n countdown.style.zIndex = COUNTDOWN_Z_INDEX;\n countdown.textContent = \"Ad\";\n container.appendChild(countdown);\n\n contentVideo.parentElement?.appendChild(container);\n adContainerEl = container;\n adCountdownEl = countdown;\n }\n },\n\n async requestAds(duration?: string) {\n log(\"Requesting ads for duration:\", duration);\n \n if (adPlaying) {\n return Promise.reject(new Error(\"Ad already playing\"));\n }\n if (destroyed) {\n return Promise.reject(new Error(\"Player has been destroyed\"));\n }\n \n try {\n tornDown = false;\n let durationSeconds = 30;\n const parsed = parseInt(duration || \"\", 10);\n if (!isNaN(parsed) && parsed > 0) {\n durationSeconds = parsed;\n }\n \n const ads = await fetchVast(durationSeconds);\n \n if (ads.length === 0) {\n log(\"No ads available from VAST response\");\n emit(\"ad_error\");\n return Promise.resolve();\n }\n \n assignCurrentAd(ads[0]!);\n log(`Ad loaded: ${currentAd!.title}, duration: ${currentAd!.duration}s`);\n \n return Promise.resolve();\n } catch (error) {\n console.error(\"[AdStormPlayer] Error requesting ads:\", error);\n emit(\"ad_error\");\n return Promise.reject(error);\n }\n },\n\n async play() {\n if (!currentAd) {\n return Promise.reject(new Error(\"No ad loaded\"));\n }\n if (destroyed) {\n return Promise.reject(new Error(\"Player has been destroyed\"));\n }\n \n log(\"Starting ad playback\");\n \n try {\n tornDown = false;\n if (adHideTimerId) {\n clearTimeout(adHideTimerId);\n adHideTimerId = undefined;\n }\n\n if (!adVideoElement) {\n adVideoElement = createAdVideoElement();\n adContainerEl?.appendChild(adVideoElement);\n } else {\n teardownCurrentPlayback();\n }\n setupAdEventListeners();\n \n trackingFired = {\n impression: trackingFired.impression,\n start: false,\n firstQuartile: false,\n midpoint: false,\n thirdQuartile: false,\n complete: false,\n };\n \n contentVideo.style.transition = \"opacity 0.3s ease-in-out\";\n contentVideo.style.opacity = \"0\";\n setTimeout(() => {\n contentVideo.style.visibility = \"hidden\";\n }, 300);\n contentVideo.muted = true;\n contentVideo.volume = 0;\n \n if (!continueLiveStreamDuringAds) {\n contentVideo.pause();\n }\n \n adPlaying = true;\n setAdPlayingFlag(true);\n \n if (adVideoElement) {\n adVideoElement.volume = originalMutedState ? 0 : originalVolume;\n adVideoElement.muted = originalMutedState;\n }\n \n if (adContainerEl) {\n adContainerEl.style.display = \"flex\";\n adContainerEl.style.pointerEvents = \"auto\";\n adContainerEl.offsetHeight;\n adContainerEl.style.opacity = \"1\";\n }\n \n emit(\"content_pause\");\n \n const mediaFile = selectBestMediaFile(currentAd.mediaFiles);\n if (!mediaFile) {\n throw new Error(\"No media file available\");\n }\n \n log(\"Playing media file:\", mediaFile.url);\n adVideoElement!.src = mediaFile.url;\n adVideoElement!.load();\n \n await adVideoElement!.play();\n \n return Promise.resolve();\n } catch (error) {\n console.error(\"[AdStormPlayer] Error playing ad:\", error);\n handleAdError();\n return Promise.reject(error);\n }\n },\n\n async stop() {\n log(\"Stopping ad\");\n tornDown = true;\n adPlaying = false;\n setAdPlayingFlag(false);\n clearAdStallTimer();\n clearAdCountdownTimer();\n \n if (adContainerEl) {\n adContainerEl.style.opacity = \"0\";\n adHideTimerId = setTimeout(() => {\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n }, 300);\n }\n \n teardownCurrentPlayback();\n \n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n contentVideo.muted = originalMutedState;\n contentVideo.volume = originalVolume;\n \n currentAd = undefined;\n return Promise.resolve();\n },\n\n pause() {\n if (!adPlaying || !adVideoElement) return;\n try {\n if (!adVideoElement.paused) adVideoElement.pause();\n } catch (error) {\n console.warn(\"[AdStormPlayer] Error pausing ad:\", error);\n }\n },\n\n resume() {\n if (!adPlaying || !adVideoElement) return;\n try {\n if (adVideoElement.paused) adVideoElement.play().catch(() => {});\n } catch (error) {\n console.warn(\"[AdStormPlayer] Error resuming ad:\", error);\n }\n },\n\n destroy() {\n log(\"Destroying\");\n destroyed = true;\n tornDown = true;\n adPlaying = false;\n setAdPlayingFlag(false);\n clearAdStallTimer();\n clearAdCountdownTimer();\n if (adHideTimerId) {\n clearTimeout(adHideTimerId);\n adHideTimerId = undefined;\n }\n \n contentVideo.muted = originalMutedState;\n contentVideo.volume = originalVolume;\n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n \n teardownCurrentPlayback();\n adVideoElement?.remove();\n adVideoElement = undefined;\n \n if (adContainerEl?.parentElement) {\n adContainerEl.parentElement.removeChild(adContainerEl);\n }\n \n adContainerEl = undefined;\n adCountdownEl = undefined;\n currentAd = undefined;\n sessionId = undefined;\n preloadSlots.clear();\n listeners.clear();\n if (parentPositionOverridden && contentVideo.parentElement) {\n contentVideo.parentElement.style.position = \"\";\n parentPositionOverridden = false;\n }\n },\n\n updateOptions(opts: AdStormLayerOptionsUpdate) {\n if (opts.continueLiveStreamDuringAds !== undefined) {\n continueLiveStreamDuringAds = opts.continueLiveStreamDuringAds;\n }\n },\n\n async playAd(requestContext?: unknown) {\n if (destroyed) return Promise.reject(new Error(\"Player has been destroyed\"));\n if (!currentAd) {\n const ad = await requestAdFromApi(requestContext);\n if (!ad) {\n emit(\"ad_error\", { message: \"No valid ad from AdStorm API\" });\n return Promise.reject(new Error(\"No valid ad from AdStorm API\"));\n }\n assignCurrentAd(ad);\n }\n return this.play();\n },\n\n async preloadAd(arg1: unknown, arg2?: unknown) {\n if (destroyed) return;\n const token =\n typeof arg1 === \"string\"\n ? arg1\n : typeof arg2 === \"string\"\n ? arg2\n : undefined;\n if (!token) return;\n\n if (currentAd) {\n preloadSlots.set(token, { ad: currentAd });\n currentAd = undefined;\n return;\n }\n\n const requestContext = typeof arg1 === \"string\" ? arg2 : arg1;\n const ad = await requestAdFromApi(requestContext);\n if (!ad) return;\n preloadSlots.set(token, { ad });\n },\n\n async playPreloaded(token: string) {\n if (destroyed) return Promise.reject(new Error(\"Player has been destroyed\"));\n const slot = preloadSlots.get(token);\n if (!slot) {\n return Promise.reject(new Error(`No preloaded ad for token ${token}`));\n }\n preloadSlots.delete(token);\n assignCurrentAd(slot.ad);\n return this.play();\n },\n\n hasPreloaded(token: string): boolean {\n return preloadSlots.has(token);\n },\n\n cancelPreload(token: string) {\n preloadSlots.delete(token);\n },\n\n isAdPlaying() {\n return adPlaying;\n },\n\n resize(width: number, height: number) {\n log(`Resizing to ${width}x${height}`);\n \n if (adContainerEl) {\n adContainerEl.style.width = `${width}px`;\n adContainerEl.style.height = `${height}px`;\n }\n \n if (adVideoElement) {\n adVideoElement.style.width = `${width}px`;\n adVideoElement.style.height = `${height}px`;\n }\n },\n\n on(event: string, listener: (payload?: any) => void) {\n if (!listeners.has(event)) listeners.set(event, new Set());\n listeners.get(event)!.add(listener);\n },\n\n off(event: string, listener: (payload?: any) => void) {\n listeners.get(event)?.delete(listener);\n },\n\n updateOriginalMutedState(muted: boolean, volume?: number) {\n const nextVolume =\n typeof volume === \"number\" && !Number.isNaN(volume)\n ? Math.max(0, Math.min(1, volume))\n : originalVolume;\n log(`updateOriginalMutedState: muted=${muted}, volume=${nextVolume}`);\n originalMutedState = muted;\n originalVolume = nextVolume;\n },\n\n getOriginalMutedState() {\n return originalMutedState;\n },\n\n getOriginalVolume() {\n return originalVolume;\n },\n\n setAdVolume(volume: number) {\n if (adVideoElement && adPlaying) {\n adVideoElement.volume = Math.max(0, Math.min(1, volume));\n adVideoElement.muted = volume === 0;\n }\n },\n\n getAdVolume(): number {\n if (adVideoElement && adPlaying) {\n return adVideoElement.volume;\n }\n return 1;\n },\n\n showPlaceholder() {\n if (!adContainerEl) {\n const parent = contentVideo.parentElement;\n if (parent) {\n const computed = window.getComputedStyle(parent).position;\n if (computed === \"static\") {\n parent.style.position = \"relative\";\n parentPositionOverridden = true;\n }\n }\n\n const container = document.createElement(\"div\");\n container.style.position = \"absolute\";\n container.style.left = \"0\";\n container.style.top = \"0\";\n container.style.right = \"0\";\n container.style.bottom = \"0\";\n container.style.display = \"none\";\n container.style.alignItems = \"center\";\n container.style.justifyContent = \"center\";\n container.style.pointerEvents = \"none\";\n container.style.zIndex = AD_LAYER_Z_INDEX;\n container.style.backgroundColor = \"#000\";\n container.style.isolation = \"isolate\";\n\n const countdown = document.createElement(\"div\");\n countdown.style.position = \"absolute\";\n countdown.style.left = \"12px\";\n countdown.style.top = \"12px\";\n countdown.style.padding = \"4px 8px\";\n countdown.style.borderRadius = \"4px\";\n countdown.style.background = \"rgba(0,0,0,0.75)\";\n countdown.style.color = \"#fff\";\n countdown.style.fontFamily = \"sans-serif\";\n countdown.style.fontSize = \"12px\";\n countdown.style.lineHeight = \"1.2\";\n countdown.style.pointerEvents = \"none\";\n countdown.style.zIndex = COUNTDOWN_Z_INDEX;\n countdown.textContent = \"Ad\";\n container.appendChild(countdown);\n \n contentVideo.parentElement?.appendChild(container);\n adContainerEl = container;\n adCountdownEl = countdown;\n }\n \n if (adContainerEl) {\n adContainerEl.style.display = \"flex\";\n adContainerEl.style.opacity = \"1\";\n adContainerEl.style.pointerEvents = \"auto\";\n }\n },\n\n hidePlaceholder() {\n if (adContainerEl) {\n adContainerEl.style.opacity = \"0\";\n setTimeout(() => {\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n }, 300);\n }\n },\n };\n}\n\n","import type {\n ClientInfo,\n TrackingData,\n HeartbeatData,\n AdDetectInfo,\n AdLoadedInfo,\n AdImpressionInfo,\n} from \"../types\";\n\nlet cachedBrowserId: string | null = null;\n\nexport function getClientInfo(): ClientInfo {\n const ua = navigator.userAgent;\n const platform = navigator.platform;\n const vendor = navigator.vendor || \"\";\n const maxTouchPoints = navigator.maxTouchPoints || 0;\n const memory = (navigator as any).deviceMemory || null;\n const hardwareConcurrency = navigator.hardwareConcurrency || 1;\n\n const screenInfo = {\n width: screen?.width,\n height: screen?.height,\n availWidth: screen?.availWidth,\n availHeight: screen?.availHeight,\n orientation: (screen?.orientation as any)?.type || \"\",\n pixelDepth: screen?.pixelDepth,\n };\n\n let deviceType: \"tv\" | \"mobile\" | \"tablet\" | \"desktop\" = \"desktop\";\n let brand = \"Unknown\";\n let os = \"Unknown\";\n let model = \"\";\n let isSmartTV = false;\n let isAndroid = false;\n let isWebView = false;\n let isWebApp = false;\n\n if (ua.includes(\"Web0S\")) {\n brand = \"LG\";\n os = \"webOS\";\n isSmartTV = true;\n deviceType = \"tv\";\n const webosMatch = ua.match(/Web0S\\/([^\\s]+)/);\n model = webosMatch ? `webOS ${webosMatch[1]}` : \"webOS TV\";\n } else if (ua.includes(\"Tizen\")) {\n brand = \"Samsung\";\n os = \"Tizen\";\n isSmartTV = true;\n deviceType = \"tv\";\n const tizenMatch = ua.match(/Tizen\\/([^\\s]+)/);\n const tvMatch = ua.match(/(?:Smart-TV|SMART-TV|TV)/i) ? \"Smart TV\" : \"\";\n model = tizenMatch\n ? `Tizen ${tizenMatch[1]} ${tvMatch}`.trim()\n : \"Tizen TV\";\n } else if (ua.includes(\"Philips\")) {\n brand = \"Philips\";\n os = \"Saphi\";\n isSmartTV = true;\n deviceType = \"tv\";\n } else if (ua.includes(\"Sharp\") || ua.includes(\"AQUOS\")) {\n brand = \"Sharp\";\n os = \"Android TV\";\n isSmartTV = true;\n deviceType = \"tv\";\n } else if (\n ua.includes(\"Android\") &&\n (ua.includes(\"Sony\") || vendor.includes(\"Sony\"))\n ) {\n brand = \"Sony\";\n os = \"Android TV\";\n isSmartTV = true;\n deviceType = \"tv\";\n } else if (\n ua.includes(\"Android\") &&\n (ua.includes(\"NetCast\") || ua.includes(\"LG\"))\n ) {\n brand = \"LG\";\n os = \"Android TV\";\n isSmartTV = true;\n deviceType = \"tv\";\n } else if (ua.includes(\" Roku\") || ua.includes(\"Roku/\")) {\n brand = \"Roku\";\n os = \"Roku OS\";\n isSmartTV = true;\n deviceType = \"tv\";\n } else if (ua.includes(\"AppleTV\")) {\n brand = \"Apple\";\n os = \"tvOS\";\n isSmartTV = true;\n deviceType = \"tv\";\n }\n\n if (ua.includes(\"Android\")) {\n isAndroid = true;\n os = \"Android\";\n deviceType = /Mobile/.test(ua) ? \"mobile\" : \"tablet\";\n\n if (\n ua.includes(\"Android\") &&\n (maxTouchPoints === 0 ||\n ua.includes(\"Google TV\") ||\n ua.includes(\"XiaoMi\"))\n ) {\n deviceType = \"tv\";\n isSmartTV = true;\n brand = brand === \"Unknown\" ? \"Android TV\" : brand;\n }\n\n const androidModelMatch = ua.match(/\\(([^)]*Android[^)]*)\\)/);\n if (androidModelMatch && androidModelMatch[1]) {\n model = androidModelMatch[1];\n }\n }\n\n if (/iPad|iPhone|iPod/.test(ua)) {\n os = \"iOS\";\n deviceType = \"mobile\";\n brand = \"Apple\";\n if (navigator.maxTouchPoints > 1 && /iPad/.test(ua)) {\n deviceType = \"tablet\";\n }\n }\n\n if (!isAndroid && !isSmartTV && !/Mobile/.test(ua)) {\n if (ua.includes(\"Windows\")) {\n os = \"Windows\";\n deviceType = \"desktop\";\n } else if (ua.includes(\"Mac\") && !/iPhone/.test(ua)) {\n os = \"macOS\";\n deviceType = \"desktop\";\n if (maxTouchPoints > 1) deviceType = \"tablet\";\n } else if (ua.includes(\"Linux\")) {\n os = \"Linux\";\n deviceType = \"desktop\";\n }\n }\n\n if (brand === \"Unknown\") {\n if (vendor.includes(\"Google\") || ua.includes(\"Chrome\")) brand = \"Google\";\n if (vendor.includes(\"Apple\")) brand = \"Apple\";\n if (vendor.includes(\"Samsung\") || ua.includes(\"SM-\")) brand = \"Samsung\";\n }\n\n isWebView = /wv|WebView|Linux; U;/.test(ua);\n\n if (window?.outerHeight === 0 && window?.outerWidth === 0) {\n isWebView = true;\n }\n\n isWebApp =\n window.matchMedia(\"(display-mode: standalone)\").matches ||\n (window.navigator as any).standalone === true ||\n window.screen?.orientation?.angle !== undefined;\n\n return {\n brand,\n os,\n model: model || ua.substring(0, 50) + \"...\",\n deviceType,\n isSmartTV,\n isAndroid,\n isWebView,\n isWebApp,\n domain: window.location.hostname,\n origin: window.location.origin,\n path: window.location.pathname,\n userAgent: ua,\n vendor,\n platform,\n screen: screenInfo,\n hardwareConcurrency,\n deviceMemory: memory,\n maxTouchPoints,\n language: navigator.language,\n languages: navigator.languages?.join(\",\") || \"\",\n cookieEnabled: navigator.cookieEnabled,\n doNotTrack: navigator.doNotTrack || \"\",\n referrer: document.referrer,\n visibilityState: document.visibilityState,\n };\n}\n\nexport async function getBrowserID(clientInfo: ClientInfo): Promise<string> {\n if (cachedBrowserId) {\n return cachedBrowserId;\n }\n\n const fingerprintString = JSON.stringify(clientInfo);\n\n if (typeof crypto !== \"undefined\" && crypto.subtle && crypto.subtle.digest) {\n try {\n await crypto.subtle.digest(\"SHA-256\", new Uint8Array([1, 2, 3]));\n\n let encodedData: BufferSource;\n if (typeof TextEncoder !== \"undefined\") {\n encodedData = new TextEncoder().encode(fingerprintString);\n } else {\n const utf8 = unescape(encodeURIComponent(fingerprintString));\n const buffer = new Uint8Array(utf8.length);\n for (let i = 0; i < utf8.length; i++) {\n buffer[i] = utf8.charCodeAt(i);\n }\n encodedData = buffer;\n }\n\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", encodedData);\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n const hashHex = hashArray\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n cachedBrowserId = hashHex;\n return hashHex;\n } catch (error) {\n console.warn(\n \"[StormcloudVideoPlayer] crypto.subtle.digest not supported, using fallback hash\"\n );\n }\n }\n\n let hash = 0;\n for (let i = 0; i < fingerprintString.length; i++) {\n const char = fingerprintString.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash;\n }\n\n const fallbackHash = Math.abs(hash).toString(16).padStart(8, \"0\");\n const timestamp = Date.now().toString(16).padStart(12, \"0\");\n const random = Math.random().toString(16).substring(2, 14).padStart(12, \"0\");\n\n cachedBrowserId = (fallbackHash + timestamp + random).padEnd(64, \"0\");\n return cachedBrowserId;\n}\n\nconst TRACK_URL =\n \"https://adstorm.co/api-adstorm-dev/adstorm/player-tracking/track\";\n\nasync function sendTrackRequest(\n licenseKey: string | undefined,\n body: Record<string, unknown>\n): Promise<void> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (licenseKey) {\n headers[\"Authorization\"] = `Bearer ${licenseKey}`;\n }\n const response = await fetch(TRACK_URL, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n await response.json();\n}\n\nexport async function sendInitialTracking(licenseKey?: string): Promise<void> {\n try {\n const clientInfo = getClientInfo();\n const browserId = await getBrowserID(clientInfo);\n\n const trackingData: TrackingData = {\n browserId,\n ...clientInfo,\n };\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (licenseKey) {\n headers[\"Authorization\"] = `Bearer ${licenseKey}`;\n }\n\n const response = await fetch(TRACK_URL, {\n method: \"POST\",\n headers,\n body: JSON.stringify(trackingData),\n });\n\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n\n await response.json();\n } catch (error) {\n console.error(\n \"[StormcloudVideoPlayer] Error sending initial tracking data:\",\n error\n );\n }\n}\n\nexport async function sendAdDetectTracking(\n licenseKey: string | undefined,\n adDetectInfo: AdDetectInfo\n): Promise<void> {\n try {\n const clientInfo = getClientInfo();\n const browserId = await getBrowserID(clientInfo);\n const trackingData: TrackingData = { browserId, ...clientInfo };\n await sendTrackRequest(licenseKey, {\n ...trackingData,\n licenseKey,\n adDetectInfo,\n });\n } catch (error) {\n console.error(\n \"[StormcloudVideoPlayer] Error sending ad detect tracking:\",\n error\n );\n }\n}\n\nexport async function sendAdLoadedTracking(\n licenseKey: string | undefined,\n adLoadedInfo: AdLoadedInfo\n): Promise<void> {\n try {\n const clientInfo = getClientInfo();\n const browserId = await getBrowserID(clientInfo);\n const trackingData: TrackingData = { browserId, ...clientInfo };\n await sendTrackRequest(licenseKey, {\n ...trackingData,\n licenseKey,\n adLoadedInfo,\n });\n } catch (error) {\n console.error(\n \"[StormcloudVideoPlayer] Error sending ad loaded tracking:\",\n error\n );\n }\n}\n\nexport async function sendAdImpressionTracking(\n licenseKey: string | undefined,\n adImpressionInfo: AdImpressionInfo\n): Promise<void> {\n try {\n const clientInfo = getClientInfo();\n const browserId = await getBrowserID(clientInfo);\n const trackingData: TrackingData = { browserId, ...clientInfo };\n await sendTrackRequest(licenseKey, {\n ...trackingData,\n licenseKey,\n adImpressionInfo,\n });\n } catch (error) {\n console.error(\n \"[StormcloudVideoPlayer] Error sending ad impression tracking:\",\n error\n );\n }\n}\n\nexport async function sendHeartbeat(licenseKey?: string): Promise<void> {\n try {\n const clientInfo = getClientInfo();\n const browserId = await getBrowserID(clientInfo);\n\n const heartbeatData: HeartbeatData = {\n browserId,\n timestamp: new Date().toISOString(),\n };\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (licenseKey) {\n headers[\"Authorization\"] = `Bearer ${licenseKey}`;\n }\n\n const response = await fetch(\n \"https://adstorm.co/api-adstorm-dev/adstorm/player-tracking/heartbeat\",\n {\n method: \"POST\",\n headers,\n body: JSON.stringify(heartbeatData),\n }\n );\n\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n\n await response.json();\n } catch (error) {\n console.error(\"[StormcloudVideoPlayer] Error sending heartbeat:\", error);\n }\n}\n","export function polyfillURLSearchParams(): void {\n if (typeof URLSearchParams !== 'undefined') {\n return;\n }\n\n class URLSearchParamsPolyfill {\n private params: Map<string, string[]>;\n\n constructor(init?: string | URLSearchParamsPolyfill) {\n this.params = new Map();\n\n if (typeof init === 'string') {\n this.parseQueryString(init);\n } else if (init instanceof URLSearchParamsPolyfill) {\n init.forEach((value, key) => {\n this.append(key, value);\n });\n }\n }\n\n private parseQueryString(query: string): void {\n const cleanQuery = query.startsWith('?') ? query.slice(1) : query;\n if (!cleanQuery) return;\n\n cleanQuery.split('&').forEach((param) => {\n const [key, value] = param.split('=');\n if (key) {\n const decodedKey = this.safeDecodeURIComponent(key);\n const decodedValue = value ? this.safeDecodeURIComponent(value) : '';\n this.append(decodedKey, decodedValue);\n }\n });\n }\n\n private safeDecodeURIComponent(str: string): string {\n try {\n return decodeURIComponent(str.replace(/\\+/g, ' '));\n } catch (e) {\n return str;\n }\n }\n\n append(name: string, value: string): void {\n const values = this.params.get(name) || [];\n values.push(String(value));\n this.params.set(name, values);\n }\n\n delete(name: string): void {\n this.params.delete(name);\n }\n\n get(name: string): string | null {\n const values = this.params.get(name);\n return values && values.length > 0 && values[0] !== undefined ? values[0] : null;\n }\n\n getAll(name: string): string[] {\n return this.params.get(name) || [];\n }\n\n has(name: string): boolean {\n return this.params.has(name);\n }\n\n set(name: string, value: string): void {\n this.params.set(name, [String(value)]);\n }\n\n forEach(callback: (value: string, key: string, parent: URLSearchParamsPolyfill) => void): void {\n this.params.forEach((values, key) => {\n values.forEach((value) => {\n callback(value, key, this);\n });\n });\n }\n\n toString(): string {\n const parts: string[] = [];\n this.params.forEach((values, key) => {\n values.forEach((value) => {\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);\n });\n });\n return parts.join('&');\n }\n }\n\n // @ts-ignore\n window.URLSearchParams = URLSearchParamsPolyfill;\n}\n\nexport function polyfillTextEncoder(): void {\n if (typeof TextEncoder !== 'undefined') {\n return;\n }\n\n class TextEncoderPolyfill {\n encoding = 'utf-8';\n\n encode(str: string): Uint8Array {\n const utf8: number[] = [];\n for (let i = 0; i < str.length; i++) {\n let charcode = str.charCodeAt(i);\n if (charcode < 0x80) {\n utf8.push(charcode);\n } else if (charcode < 0x800) {\n utf8.push(0xc0 | (charcode >> 6), 0x80 | (charcode & 0x3f));\n } else if (charcode < 0xd800 || charcode >= 0xe000) {\n utf8.push(\n 0xe0 | (charcode >> 12),\n 0x80 | ((charcode >> 6) & 0x3f),\n 0x80 | (charcode & 0x3f)\n );\n } else {\n i++;\n charcode = 0x10000 + (((charcode & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff));\n utf8.push(\n 0xf0 | (charcode >> 18),\n 0x80 | ((charcode >> 12) & 0x3f),\n 0x80 | ((charcode >> 6) & 0x3f),\n 0x80 | (charcode & 0x3f)\n );\n }\n }\n return new Uint8Array(utf8);\n }\n }\n\n // @ts-ignore\n window.TextEncoder = TextEncoderPolyfill;\n}\n\nexport function polyfillPromiseFinally(): void {\n if (typeof Promise !== 'undefined' && !Promise.prototype.finally) {\n Promise.prototype.finally = function (callback: () => void) {\n const constructor = this.constructor as PromiseConstructor;\n return this.then(\n (value) => constructor.resolve(callback()).then(() => value),\n (reason) =>\n constructor.resolve(callback()).then(() => {\n throw reason;\n })\n );\n };\n }\n}\n\nexport function polyfillObjectAssign(): void {\n if (typeof Object.assign !== 'function') {\n Object.assign = function (target: any, ...sources: any[]) {\n if (target == null) {\n throw new TypeError('Cannot convert undefined or null to object');\n }\n\n const to = Object(target);\n\n for (let i = 0; i < sources.length; i++) {\n const nextSource = sources[i];\n\n if (nextSource != null) {\n for (const nextKey in nextSource) {\n if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {\n to[nextKey] = nextSource[nextKey];\n }\n }\n }\n }\n\n return to;\n };\n }\n}\n\nexport function polyfillArrayFrom(): void {\n if (!Array.from) {\n Array.from = function (arrayLike: any, mapFn?: any, thisArg?: any) {\n const items = Object(arrayLike);\n if (arrayLike == null) {\n throw new TypeError('Array.from requires an array-like object');\n }\n\n const len = items.length >>> 0;\n const result = new Array(len);\n\n for (let i = 0; i < len; i++) {\n if (mapFn) {\n result[i] = mapFn.call(thisArg, items[i], i);\n } else {\n result[i] = items[i];\n }\n }\n\n return result;\n };\n }\n}\n\nexport function polyfillStringStartsWith(): void {\n if (!String.prototype.startsWith) {\n String.prototype.startsWith = function (search: string, pos?: number) {\n pos = !pos || pos < 0 ? 0 : +pos;\n return this.substring(pos, pos + search.length) === search;\n };\n }\n}\n\nexport function polyfillStringEndsWith(): void {\n if (!String.prototype.endsWith) {\n String.prototype.endsWith = function (search: string, length?: number) {\n if (length === undefined || length > this.length) {\n length = this.length;\n }\n return this.substring(length - search.length, length) === search;\n };\n }\n}\n\nexport function polyfillStringIncludes(): void {\n if (!String.prototype.includes) {\n String.prototype.includes = function (search: string, start?: number) {\n if (typeof start !== 'number') {\n start = 0;\n }\n if (start + search.length > this.length) {\n return false;\n }\n return this.indexOf(search, start) !== -1;\n };\n }\n}\n\nexport function initializePolyfills(): void {\n polyfillObjectAssign();\n polyfillArrayFrom();\n polyfillStringStartsWith();\n polyfillStringEndsWith();\n polyfillStringIncludes();\n polyfillURLSearchParams();\n polyfillTextEncoder();\n polyfillPromiseFinally();\n}\n\n","interface NavigatorUAData {\n platform?: string;\n brands?: Array<{ brand: string; version: string }>;\n mobile?: boolean;\n}\n\ndeclare global {\n interface Navigator {\n userAgentData?: NavigatorUAData;\n }\n}\n\nexport interface BrowserInfo {\n name: string;\n version: string;\n majorVersion: number;\n isSmartTV: boolean;\n isLegacyTV: boolean;\n platform: string;\n supportsIMA: boolean;\n supportsModernJS: boolean;\n recommendedAdPlayer: 'ima' | 'hls';\n webOSVersion?: number | undefined;\n tizenVersion?: number | undefined;\n chromeVersion?: number | undefined;\n}\n\nfunction getChromeVersion(ua: string): number {\n const match = ua.match(/Chrome\\/(\\d+)/);\n return match && match[1] ? parseInt(match[1], 10) : 0;\n}\n\nfunction getWebKitVersion(ua: string): number {\n const match = ua.match(/AppleWebKit\\/(\\d+)/);\n return match && match[1] ? parseInt(match[1], 10) : 0;\n}\n\nfunction getPlatform(): string {\n if ('userAgentData' in navigator && navigator.userAgentData?.platform) {\n return navigator.userAgentData.platform;\n }\n\n const ua = navigator.userAgent;\n if (/Mac|iPhone|iPad|iPod/i.test(ua)) {\n return /iPhone|iPad|iPod/i.test(ua) ? 'iPhone' : 'MacIntel';\n }\n if (/Win/i.test(ua)) {\n return 'Win32';\n }\n if (/Linux/i.test(ua)) {\n return /Android/i.test(ua) ? 'Linux armv8l' : 'Linux x86_64';\n }\n if (/CrOS/i.test(ua)) {\n return 'CrOS';\n }\n\n // eslint-disable-next-line deprecation/deprecation\n return (navigator as any).platform || 'Unknown';\n}\n\nexport function detectBrowser(): BrowserInfo {\n const ua = navigator.userAgent;\n const platform = getPlatform();\n\n let name = 'Unknown';\n let version = '0';\n let majorVersion = 0;\n let isSmartTV = false;\n let isLegacyTV = false;\n let supportsIMA = true;\n let supportsModernJS = true;\n let recommendedAdPlayer: 'ima' | 'hls' = 'ima';\n let webOSVersion: number | undefined;\n let tizenVersion: number | undefined;\n let chromeVersionNum: number | undefined;\n\n const chromeVersion = getChromeVersion(ua);\n const webkitVersion = getWebKitVersion(ua);\n chromeVersionNum = chromeVersion > 0 ? chromeVersion : undefined;\n\n if (/Web0S|webOS|LG Browser|LGSTB/i.test(ua)) {\n name = 'LG WebOS';\n isSmartTV = true;\n \n let match = ua.match(/Web0S[/\\s]*([\\d.]+)/i) || ua.match(/webOS[/\\s]*([\\d.]+)/i);\n \n if (!match || !match[1]) {\n match = ua.match(/webOSTV[/\\s-]*([\\d.]+)/i) || ua.match(/webOS\\.TV[/\\s-]*([\\d.]+)/i);\n }\n \n if (match && match[1]) {\n version = match[1];\n const parts = version.split('.');\n majorVersion = parts[0] ? parseInt(parts[0], 10) : 0;\n webOSVersion = majorVersion;\n } else if (chromeVersion > 0) {\n if (chromeVersion >= 79) {\n webOSVersion = 6;\n version = '6.0';\n majorVersion = 6;\n } else if (chromeVersion >= 68) {\n webOSVersion = 5;\n version = '5.0';\n majorVersion = 5;\n } else if (chromeVersion >= 53) {\n webOSVersion = 4;\n version = '4.0';\n majorVersion = 4;\n } else if (chromeVersion >= 38) {\n webOSVersion = 3;\n version = '3.0';\n majorVersion = 3;\n } else {\n webOSVersion = 2;\n version = '2.0';\n majorVersion = 2;\n }\n } else {\n version = 'Unknown';\n webOSVersion = undefined;\n }\n\n if (webOSVersion !== undefined && webOSVersion >= 4) {\n supportsIMA = true;\n recommendedAdPlayer = 'ima';\n isLegacyTV = false;\n } else if (webOSVersion !== undefined && webOSVersion >= 3) {\n if (chromeVersion >= 53) {\n supportsIMA = true;\n recommendedAdPlayer = 'ima';\n isLegacyTV = false;\n } else {\n supportsIMA = false;\n recommendedAdPlayer = 'hls';\n isLegacyTV = true;\n }\n } else if (chromeVersion >= 53) {\n supportsIMA = true;\n recommendedAdPlayer = 'ima';\n isLegacyTV = false;\n } else {\n supportsIMA = false;\n recommendedAdPlayer = 'hls';\n isLegacyTV = true;\n }\n } else if (/Tizen/i.test(ua)) {\n name = 'Samsung Tizen';\n isSmartTV = true;\n const match = ua.match(/Tizen[/\\s]*([\\d.]+)/i);\n version = match && match[1] ? match[1] : 'Unknown';\n if (version !== 'Unknown') {\n const parts = version.split('.');\n majorVersion = parts[0] ? parseInt(parts[0], 10) : 0;\n tizenVersion = majorVersion;\n }\n \n if (tizenVersion !== undefined && tizenVersion >= 4) {\n supportsIMA = true;\n recommendedAdPlayer = 'ima';\n isLegacyTV = false;\n } else if (tizenVersion !== undefined && tizenVersion >= 3 && chromeVersion >= 47) {\n supportsIMA = true;\n recommendedAdPlayer = 'ima';\n isLegacyTV = false;\n } else if (chromeVersion >= 53) {\n supportsIMA = true;\n recommendedAdPlayer = 'ima';\n isLegacyTV = false;\n } else {\n supportsIMA = false;\n recommendedAdPlayer = 'hls';\n isLegacyTV = true;\n }\n } else if (/SMART-TV|SmartTV/i.test(ua)) {\n name = 'Smart TV';\n isSmartTV = true;\n if (chromeVersion >= 53) {\n supportsIMA = true;\n recommendedAdPlayer = 'ima';\n } else {\n supportsIMA = false;\n recommendedAdPlayer = 'hls';\n isLegacyTV = true;\n }\n } else if (/NetCast/i.test(ua)) {\n name = 'LG NetCast';\n isSmartTV = true;\n isLegacyTV = true;\n supportsIMA = false;\n recommendedAdPlayer = 'hls';\n } else if (/BRAVIA/i.test(ua)) {\n name = 'Sony BRAVIA';\n isSmartTV = true;\n if (chromeVersion >= 53) {\n supportsIMA = true;\n recommendedAdPlayer = 'ima';\n } else {\n supportsIMA = false;\n recommendedAdPlayer = 'hls';\n isLegacyTV = true;\n }\n } else {\n if (chromeVersion > 0) {\n name = 'Chrome';\n version = chromeVersion.toString();\n majorVersion = chromeVersion;\n\n if (chromeVersion < 50) {\n supportsIMA = false;\n supportsModernJS = false;\n recommendedAdPlayer = 'hls';\n }\n }\n\n if (webkitVersion > 0 && webkitVersion < 600) {\n supportsModernJS = false;\n if (chromeVersion < 50) {\n supportsIMA = false;\n recommendedAdPlayer = 'hls';\n }\n }\n }\n\n if (typeof Promise === 'undefined' ||\n typeof Map === 'undefined' ||\n typeof Set === 'undefined') {\n supportsModernJS = false;\n supportsIMA = false;\n recommendedAdPlayer = 'hls';\n }\n\n if (typeof URLSearchParams === 'undefined') {\n supportsModernJS = false;\n }\n\n return {\n name,\n version,\n majorVersion,\n isSmartTV,\n isLegacyTV,\n platform,\n supportsIMA,\n supportsModernJS,\n recommendedAdPlayer,\n webOSVersion,\n tizenVersion,\n chromeVersion: chromeVersionNum,\n };\n}\n\nexport function supportsGoogleIMA(): boolean {\n const browser = detectBrowser();\n\n if (browser.isLegacyTV) {\n return false;\n }\n\n if (typeof document === 'undefined' ||\n typeof document.createElement !== 'function') {\n return false;\n }\n\n try {\n const video = document.createElement('video');\n if (!video) {\n return false;\n }\n } catch (e) {\n return false;\n }\n\n if (typeof Promise === 'undefined') {\n return false;\n }\n\n return browser.supportsIMA;\n}\n\nexport function getRecommendedAdPlayer(): 'ima' | 'hls' {\n const browser = detectBrowser();\n return browser.recommendedAdPlayer;\n}\n\nexport function supportsModernJS(): boolean {\n try {\n return (\n typeof Promise !== 'undefined' &&\n typeof Map !== 'undefined' &&\n typeof Set !== 'undefined' &&\n typeof Array.from !== 'undefined' &&\n typeof Object.assign !== 'undefined' &&\n typeof Array.prototype.forEach !== 'undefined' &&\n typeof String.prototype.includes !== 'undefined'\n );\n } catch (e) {\n return false;\n }\n}\n\nexport function logBrowserInfo(debug: boolean = false): void {\n if (!debug) return;\n\n const browser = detectBrowser();\n const imaSupport = supportsGoogleIMA();\n\n console.log('[StormcloudVideoPlayer] Browser Compatibility Info:', {\n browser: `${browser.name} ${browser.version}`,\n platform: browser.platform,\n isSmartTV: browser.isSmartTV,\n isLegacyTV: browser.isLegacyTV,\n supportsIMA: imaSupport,\n supportsModernJS: browser.supportsModernJS,\n recommendedAdPlayer: browser.recommendedAdPlayer,\n ...(browser.webOSVersion !== undefined ? { webOSVersion: browser.webOSVersion } : {}),\n ...(browser.tizenVersion !== undefined ? { tizenVersion: browser.tizenVersion } : {}),\n ...(browser.chromeVersion !== undefined ? { chromeVersion: browser.chromeVersion } : {}),\n userAgent: navigator.userAgent,\n });\n}\n\nexport function getBrowserConfigOverrides(): {\n allowNativeHls?: boolean;\n} {\n const browser = detectBrowser();\n const overrides: { allowNativeHls?: boolean } = {};\n\n if (browser.isSmartTV) {\n overrides.allowNativeHls = true;\n }\n\n return overrides;\n}\n\nexport function supportsFeature(feature: string): boolean {\n switch (feature) {\n case 'ima':\n return supportsGoogleIMA();\n case 'urlsearchparams':\n return typeof URLSearchParams !== 'undefined';\n case 'textencoder':\n return typeof TextEncoder !== 'undefined';\n case 'promises':\n return typeof Promise !== 'undefined';\n case 'fetch':\n return typeof fetch !== 'undefined';\n case 'crypto':\n return typeof crypto !== 'undefined' && typeof crypto.subtle !== 'undefined';\n default:\n return false;\n }\n}\n\n"]}
1
+ {"version":3,"sources":["/home/ubuntu24-new/Dev/stormcloud-vp/lib/player/StormcloudVideoPlayer.cjs","../../src/player/StormcloudVideoPlayer.ts","../../src/sdk/vastParser.ts","../../src/sdk/adstormPlayer.ts","../../src/utils/tracking.ts","../../src/utils/polyfills.ts","../../src/utils/browserCompat.ts"],"names":["__create","Object","create","__defProp","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","getOwnPropertyNames","__getProtoOf","getPrototypeOf","__hasOwnProp","prototype","hasOwnProperty","__export","target","all","name","get","enumerable","__copyProps","to","from","except","desc","key","call","__toESM","mod","isNodeMode","__esModule","value","__toCommonJS","StormcloudVideoPlayer_exports","StormcloudVideoPlayer","exports","import_hls","require","firePixelWithRetry","url","retries","delayMs","logPrefix","attempt","fetch","method","mode","cache","keepalive","Promise","r","setTimeout","Math","pow","console","warn","fireTrackingPixels","urls","sessionId","length","forEach","trackingUrl","includes","catch","img","Image","onerror","src","log","error","SUPPORTED_VIDEO_EXTENSIONS","UNSUPPORTED_VIDEO_EXTENSIONS","REQUEST_TIMEOUT_MS","REQUEST_MAX_RETRIES","REQUEST_RETRY_BACKOFF_MS","AD_LAYER_Z_INDEX","COUNTDOWN_Z_INDEX","STALL_TIMEOUT_MS","pathname","replace","getFileExtension","URL","lastDot","slice","toLowerCase","lastIndexOf","ext","split","isUnsupportedFormat","indexOf","replaceFlvExtension","isSupportedFormat","mimeType","adCountdownEl","createAdStormPlayer","licenseKey","contentVideo","options","debug","originalMutedState","originalVolume","max","min","volume","listeners","Map","adContainerEl","currentAd","tornDown","continueLiveStreamDuringAds","adStallTimerId","adCountdownTimerId","adHideTimerId","lastCountdownSecond","adListenersBound","parentPositionOverridden","adHandlers","timeupdate","adVideoElement","destroyed","progress","currentTime","duration","trackingFired","firstQuartile","trackingUrls","midpoint","thirdQuartile","updateAdCountdown","playing","clearAdStallTimer","start","startAdCountdown","ended","complete","handleAdComplete","impression","e","handleAdError","waiting","adPlaying","volumechange","muted","mute","unmute","pause","play","resume","set","event","preloadSlots","args","emit","payload","Array","fn","addEventListener","clearTimeout","clearAdCountdownTimer","clearInterval","remainingSec","ceil","textContent","durationSec","currentTimeSec","setInterval","generateSessionId","Date","now","random","toString","bindAdEventListeners","unbindAdEventListeners","removeEventListener","teardownCurrentPlayback","removeAttribute","load","buildVastUrl","durationSeconds","baseUrl","parseVastXml","xmlString","ads","parser","DOMParser","xmlDoc","parseFromString","parserError","querySelector","adElements","querySelectorAll","adElement","adId","getAttribute","title","durationText","durationParts","parseInt","mediaFileElements","parseFloat","mediaFiles","mf","type","trim","width","height","bitrate","originalUrl","push","el","eventKey","clickThrough","id","selectBestMediaFile","mp4Files","filter","candidates","targetWidth","videoWidth","targetHeight","videoHeight","sort","a","b","diffA","abs","diffB","createAdVideoElement","video","document","createElement","style","position","left","top","objectFit","backgroundColor","zIndex","playsInline","preload","setAdPlayingFlag","isPlaying","dataset","stormcloudAdPlaying","setupAdEventListeners","opacity","display","pointerEvents","visibility","fetchVastOnce","vastUrl","controller","timeoutId","requestInit","response","xmlText","AbortController","abort","credentials","headers","Accept","referrerPolicy","signal","ok","Error","status","statusText","text","fetchVast","lastError","delay","resolve","assignCurrentAd","getDurationSecondsFromContext","requestContext","ctx","remainingBreakSec","breakDurationSec","Number","isNaN","requestAdFromApi","ad","initialize","parent","parentElement","computed","window","getComputedStyle","container","countdown","right","bottom","alignItems","justifyContent","transition","isolation","padding","borderRadius","fontFamily","fontSize","appendChild","requestAds","parsed","reject","mediaFile","offsetHeight","stop","paused","destroy","remove","removeChild","clear","updateOptions","opts","playAd","message","preloadAd","arg1","arg2","token","playPreloaded","slot","delete","hasPreloaded","has","cancelPreload","isAdPlaying","resize","on","listener","Set","add","off","updateOriginalMutedState","nextVolume","getOriginalMutedState","getOriginalVolume","setAdVolume","getAdVolume","showPlaceholder","background","color","lineHeight","hidePlaceholder","cachedBrowserId","getClientInfo","screen","navigator","ua","userAgent","platform","vendor","maxTouchPoints","memory","deviceMemory","hardwareConcurrency","screenInfo","availWidth","availHeight","orientation","pixelDepth","deviceType","brand","os","model","isSmartTV","isAndroid","isWebView","isWebApp","webosMatch","match","tizenMatch","tvMatch","test","androidModelMatch","outerHeight","outerWidth","matchMedia","matches","standalone","angle","location","substring","domain","hostname","origin","path","language","cookieEnabled","doNotTrack","referrer","visibilityState","getBrowserID","clientInfo","fingerprintString","encodedData","utf8","buffer","i","hashBuffer","hashArray","hashHex","hash","char","fallbackHash","timestamp","JSON","stringify","crypto","subtle","digest","Uint8Array","TextEncoder","encode","unescape","encodeURIComponent","charCodeAt","map","padStart","padEnd","TRACK_URL","sendTrackRequest","body","json","sendInitialTracking","browserId","trackingData","sendAdLoadedTracking","adLoadedInfo","sendAdImpressionTracking","adImpressionInfo","sendHeartbeat","heartbeatData","toISOString","polyfillURLSearchParams","URLSearchParams","URLSearchParamsPolyfill","init","params","parseQueryString","append","query","cleanQuery","startsWith","param","decodedKey","safeDecodeURIComponent","decodedValue","str","decodeURIComponent","values","String","getAll","callback","parts","join","polyfillTextEncoder","TextEncoderPolyfill","encoding","charcode","polyfillPromiseFinally","finally","constructor","then","reason","polyfillObjectAssign","assign","sources","TypeError","nextSource","nextKey","polyfillArrayFrom","arrayLike","mapFn","thisArg","items","len","result","search","pos","polyfillStringEndsWith","userAgentData","endsWith","polyfillStringIncludes","getPlatform","version","majorVersion","isLegacyTV","supportsIMA","supportsModernJS","recommendedAdPlayer","webOSVersion","tizenVersion","chromeVersionNum","chromeVersion","getChromeVersion","webkitVersion","getWebKitVersion","browser","overrides","showAds","maxBackoffMs","supportsGoogleIMA","detectBrowser","logBrowserInfo","imaSupport","allowNativeHls","DEBUG_HISTORY_LIMIT","config","pendingNextAdBids","continuousFetchLoopPromise","attached","adPodQueue","lastHeartbeatTime","currentAdIndex","isLiveStream","nativeHlsMode","videoSrcProtection","bufferedSegmentsCount","hasInitialBufferCompleted","activeAdRequestToken","adRequestWatchdogToken","adFailsafeToken","continuousFetchingActive","isInAdTransition","maxPlaceholderDurationMs","isShowingPlaceholder","lastAdInsertionPoint","processedAdInsertionUpdatedAt","totalAdRequestsInBreak","maxTotalAdRequestsPerBreak","pendingAdBreak","minAdRequestIntervalMs","MIN_AD_REMAINING_MS","adRequestTimeoutMs","adRequestMaxRetries","adRequestRetryBackoffMs","debugLogEntries","adInsertionDebugHistory","initializePolyfills","browserOverrides","getBrowserConfigOverrides","videoElement","adTransitionGapMs","debugAdTiming","browserForAdLayer","isSinglePipeline","adLayer","singlePipelineMode","shouldContinueLiveStreamDuringAds","adRequest","context","disableAds","bidder","cpm","impId","creativeId","currency","attach","initializeTracking","shouldUseNativeHls","lowLatencyMode","isLive","adBehavior","mainHlsInstance","hls","Hls","enableWorker","backBufferLength","liveDurationInfinity","maxLiveSyncPlaybackRate","liveSyncDuration","maxBufferLength","maxMaxBufferLength","maxBufferHole","highBufferWatchdogPeriod","nudgeOffset","nudgeMaxRetry","startPosition","Events","MEDIA_ATTACHED","loadSource","MANIFEST_PARSED","_","data","minSegments","levels","some","level","details","live","shouldAutoplayAfterBuffering","autoplay","minSegmentsBeforePlay","projectId","startAdInsertionPolling","LEVEL_LOADED","inAdBreak","checkAdInsertionInManifest","FRAG_BUFFERED","_evt","err","FRAG_CHANGED","frag","updated_at","segmentName","segment_ts_name","fragmentMatchesSegment","offsetMs","offset_seconds","pushAdInsertionDebug","offsetSeconds","detail","sn","clearAdInsertionOffsetTimer","adInsertionOffsetTimerId","handleAdStart","FRAG_PARSING_USERDATA","samples","sample","bytes","isSCTE35","segName","relurl","ERROR","fatal","ErrorTypes","NETWORK_ERROR","startLoad","MEDIA_ERROR","recoverMediaError","attachMedia","getAdSource","attachAdLayerEventListeners","source","adIndex","errorPayload","errorMessage","errorCode","code","vastErrorCode","cause","innerError","causeMessage","pushDebugLog","handleAdFailure","clearAdFailsafeTimer","clearAdRequestWatchdog","disableFiller","savedMutedStateBeforeAd","expectedAdBreakDurationMs","scheduleAdStopCountdown","adStopTimerId","getRemainingAdMs","stopFillerBreakTimer","hidePlaceholderLayer","remaining","breakMuted","breakVolume","preloadedTokens","syncMainContentAudioWhenVisible","consecutiveFailures","remainingNow","showPlaceholderLayer","bids","freshBids","remainingFinal","startContinuousFetchLoop","handleAdPodComplete","ensureFillerVideo","fillerVideo","filler","loop","startFillerBreakTimer","durationMs","fillerBreakTimerId","timeUpdateHandler","onTimeUpdate","emptiedHandler","wasPaused","streamType","getStreamType","canNative","canPlayType","heartbeatInterval","sendHeartbeatIfNeeded","getCurrentAdIndex","getTotalAdsInBreak","totalAdsInBreak","getRemainingAdSeconds","remainingMs","isFinite","MAX_SAFE_INTEGER","isShowingAds","adLayerShowing","shouldShowNativeControls","showCustomControls","startAdPrefetch","fragmentSn","detectedAtFragmentSn","isFetching","fetchStartTime","runAdPrefetch"],"mappings":"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","sourcesContent":["\"use strict\";\nvar __create = Object.create;\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __getProtoOf = Object.getPrototypeOf;\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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(\n // If the importer is in node compatibility mode or this is not an ESM\n // file that has been converted to a CommonJS file using a Babel-\n // compatible transform (i.e. \"__esModule\" has not been set), then set\n // \"default\" to the CommonJS \"module.exports\" for node compatibility.\n isNodeMode || !mod || !mod.__esModule ? __defProp(target, \"default\", { value: mod, enumerable: true }) : target,\n mod\n));\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/player/StormcloudVideoPlayer.ts\nvar StormcloudVideoPlayer_exports = {};\n__export(StormcloudVideoPlayer_exports, {\n StormcloudVideoPlayer: () => StormcloudVideoPlayer\n});\nmodule.exports = __toCommonJS(StormcloudVideoPlayer_exports);\nvar import_hls = __toESM(require(\"hls.js\"), 1);\n\n// src/sdk/vastParser.ts\nasync function firePixelWithRetry(url, retries = 2, delayMs = 500, logPrefix = \"[VastParser]\") {\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n await fetch(url, {\n method: \"GET\",\n mode: \"no-cors\",\n cache: \"no-cache\",\n keepalive: true\n });\n return;\n } catch {\n if (attempt < retries) {\n await new Promise((r) => setTimeout(r, delayMs * Math.pow(2, attempt)));\n } else {\n console.warn(`${logPrefix} Tracking pixel failed after ${retries + 1} attempts: ${url}`);\n }\n }\n }\n}\nfunction fireTrackingPixels(urls, sessionId, logPrefix = \"[VastParser]\") {\n if (!urls || urls.length === 0) return;\n urls.forEach((url) => {\n try {\n let trackingUrl = url;\n if (sessionId) {\n trackingUrl = `${trackingUrl}${trackingUrl.includes(\"?\") ? \"&\" : \"?\"}session_id=${sessionId}`;\n }\n if (typeof fetch !== \"undefined\") {\n firePixelWithRetry(trackingUrl, 2, 500, logPrefix).catch(() => {\n });\n } else {\n const img = new Image(1, 1);\n img.onerror = () => {\n };\n img.src = trackingUrl;\n }\n console.log(`${logPrefix} Fired tracking pixel: ${trackingUrl}`);\n } catch (error) {\n console.warn(`${logPrefix} Error firing tracking pixel:`, error);\n }\n });\n}\n\n// src/sdk/adstormPlayer.ts\nvar SUPPORTED_VIDEO_EXTENSIONS = [\".mp4\", \".webm\", \".ogg\", \".m3u8\", \".ts\"];\nvar UNSUPPORTED_VIDEO_EXTENSIONS = [\".flv\", \".f4v\", \".swf\", \".wmv\", \".avi\", \".mov\", \".mkv\"];\nvar REQUEST_TIMEOUT_MS = 5e3;\nvar REQUEST_MAX_RETRIES = 3;\nvar REQUEST_RETRY_BACKOFF_MS = 1500;\nvar AD_LAYER_Z_INDEX = \"30\";\nvar COUNTDOWN_Z_INDEX = \"31\";\nvar STALL_TIMEOUT_MS = 8e3;\nfunction getFileExtension(url) {\n try {\n const pathname = new URL(url, \"http://dummy\").pathname;\n const lastDot = pathname.lastIndexOf(\".\");\n if (lastDot === -1) return \"\";\n return pathname.slice(lastDot).toLowerCase();\n } catch {\n const lastDot = url.lastIndexOf(\".\");\n if (lastDot === -1) return \"\";\n const ext = url.slice(lastDot).split(/[?#]/)[0];\n return (ext || \"\").toLowerCase();\n }\n}\nfunction isUnsupportedFormat(url) {\n const ext = getFileExtension(url);\n return UNSUPPORTED_VIDEO_EXTENSIONS.indexOf(ext) !== -1;\n}\nfunction replaceFlvExtension(url) {\n const ext = getFileExtension(url);\n if (ext === \".flv\") {\n return url.replace(/\\.flv(\\?|$)/i, \".mp4$1\");\n }\n return url;\n}\nfunction isSupportedFormat(url, mimeType) {\n if (isUnsupportedFormat(url)) {\n return false;\n }\n const ext = getFileExtension(url);\n if (SUPPORTED_VIDEO_EXTENSIONS.indexOf(ext) !== -1) {\n return true;\n }\n if (ext === \"\" || ext === \".\") {\n return mimeType.includes(\"video/mp4\") || mimeType.includes(\"video/webm\") || mimeType.includes(\"m3u8\") || mimeType.includes(\"application/x-mpegurl\");\n }\n return false;\n}\nfunction createAdStormPlayer(contentVideo, options) {\n const { licenseKey, debug = false } = options;\n let adPlaying = false;\n let originalMutedState = false;\n let originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));\n const listeners = /* @__PURE__ */ new Map();\n let adVideoElement;\n let adContainerEl;\n let adCountdownEl;\n let currentAd;\n let destroyed = false;\n let tornDown = false;\n let continueLiveStreamDuringAds = false;\n let sessionId;\n let adStallTimerId;\n let adCountdownTimerId;\n let adHideTimerId;\n let lastCountdownSecond = -1;\n let adListenersBound = false;\n let parentPositionOverridden = false;\n const adHandlers = {\n timeupdate: () => {\n if (!currentAd || !adVideoElement || destroyed || tornDown) return;\n const progress = adVideoElement.currentTime / currentAd.duration;\n if (progress >= 0.25 && !trackingFired.firstQuartile) {\n trackingFired.firstQuartile = true;\n fireTrackingPixels2(currentAd.trackingUrls.firstQuartile);\n }\n if (progress >= 0.5 && !trackingFired.midpoint) {\n trackingFired.midpoint = true;\n fireTrackingPixels2(currentAd.trackingUrls.midpoint);\n }\n if (progress >= 0.75 && !trackingFired.thirdQuartile) {\n trackingFired.thirdQuartile = true;\n fireTrackingPixels2(currentAd.trackingUrls.thirdQuartile);\n }\n updateAdCountdown();\n },\n playing: () => {\n clearAdStallTimer();\n if (!currentAd || trackingFired.start || destroyed || tornDown) return;\n trackingFired.start = true;\n fireTrackingPixels2(currentAd.trackingUrls.start);\n startAdCountdown();\n log(\"Ad started playing\");\n },\n ended: () => {\n if (!currentAd || trackingFired.complete || destroyed || tornDown) return;\n trackingFired.complete = true;\n fireTrackingPixels2(currentAd.trackingUrls.complete);\n log(\"Ad completed\");\n handleAdComplete();\n },\n error: (e) => {\n if (destroyed || tornDown) return;\n console.error(\"[AdStormPlayer] Ad video error:\", e);\n if (currentAd) fireTrackingPixels2(currentAd.trackingUrls.error);\n handleAdError();\n },\n waiting: () => {\n clearAdStallTimer();\n adStallTimerId = setTimeout(() => {\n adStallTimerId = void 0;\n if (!adPlaying || destroyed || tornDown) return;\n console.warn(\"[AdStormPlayer] Ad playback stalled too long\");\n handleAdError();\n }, STALL_TIMEOUT_MS);\n },\n volumechange: () => {\n if (!currentAd || !adVideoElement || destroyed || tornDown) return;\n if (adVideoElement.muted || adVideoElement.volume <= 0) {\n fireTrackingPixels2(currentAd.trackingUrls.mute);\n } else {\n fireTrackingPixels2(currentAd.trackingUrls.unmute);\n }\n },\n pause: () => {\n if (!currentAd || !adVideoElement || destroyed || tornDown) return;\n if (!adVideoElement.ended) {\n fireTrackingPixels2(currentAd.trackingUrls.pause);\n }\n },\n play: () => {\n if (!currentAd || !adVideoElement || destroyed || tornDown) return;\n if (adVideoElement.currentTime > 0) {\n fireTrackingPixels2(currentAd.trackingUrls.resume);\n }\n }\n };\n let trackingFired = {\n impression: false,\n start: false,\n firstQuartile: false,\n midpoint: false,\n thirdQuartile: false,\n complete: false\n };\n const preloadSlots = /* @__PURE__ */ new Map();\n function log(...args) {\n if (debug) {\n console.log(\"[AdStormPlayer]\", ...args);\n }\n }\n function emit(event, payload) {\n const set = listeners.get(event);\n if (!set) return;\n for (const fn of Array.from(set)) {\n try {\n fn(payload);\n } catch (error) {\n console.warn(`[AdStormPlayer] Error in event listener for ${event}:`, error);\n }\n }\n }\n function fireTrackingPixels2(urls) {\n fireTrackingPixels(urls, sessionId, \"[AdStormPlayer]\");\n }\n function clearAdStallTimer() {\n if (adStallTimerId) {\n clearTimeout(adStallTimerId);\n adStallTimerId = void 0;\n }\n }\n function clearAdCountdownTimer() {\n if (adCountdownTimerId) {\n clearInterval(adCountdownTimerId);\n adCountdownTimerId = void 0;\n }\n lastCountdownSecond = -1;\n }\n function updateAdCountdown() {\n if (!adCountdownEl || !adVideoElement || !currentAd || !adPlaying) return;\n const remainingSec = Math.max(\n 0,\n Math.ceil((currentAd.duration || 0) - adVideoElement.currentTime)\n );\n if (remainingSec === lastCountdownSecond) return;\n lastCountdownSecond = remainingSec;\n adCountdownEl.textContent = `Ad ${remainingSec}s`;\n emit(\"ad_countdown\", {\n remainingSec,\n durationSec: currentAd.duration,\n currentTimeSec: adVideoElement.currentTime\n });\n }\n function startAdCountdown() {\n clearAdCountdownTimer();\n updateAdCountdown();\n adCountdownTimerId = setInterval(updateAdCountdown, 250);\n }\n function generateSessionId() {\n return `adstorm-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;\n }\n function bindAdEventListeners() {\n if (!adVideoElement || adListenersBound) return;\n adVideoElement.addEventListener(\"timeupdate\", adHandlers.timeupdate);\n adVideoElement.addEventListener(\"playing\", adHandlers.playing);\n adVideoElement.addEventListener(\"ended\", adHandlers.ended);\n adVideoElement.addEventListener(\"error\", adHandlers.error);\n adVideoElement.addEventListener(\"waiting\", adHandlers.waiting);\n adVideoElement.addEventListener(\"volumechange\", adHandlers.volumechange);\n adVideoElement.addEventListener(\"pause\", adHandlers.pause);\n adVideoElement.addEventListener(\"play\", adHandlers.play);\n adListenersBound = true;\n }\n function unbindAdEventListeners() {\n if (!adVideoElement || !adListenersBound) return;\n adVideoElement.removeEventListener(\"timeupdate\", adHandlers.timeupdate);\n adVideoElement.removeEventListener(\"playing\", adHandlers.playing);\n adVideoElement.removeEventListener(\"ended\", adHandlers.ended);\n adVideoElement.removeEventListener(\"error\", adHandlers.error);\n adVideoElement.removeEventListener(\"waiting\", adHandlers.waiting);\n adVideoElement.removeEventListener(\"volumechange\", adHandlers.volumechange);\n adVideoElement.removeEventListener(\"pause\", adHandlers.pause);\n adVideoElement.removeEventListener(\"play\", adHandlers.play);\n adListenersBound = false;\n }\n function teardownCurrentPlayback() {\n unbindAdEventListeners();\n clearAdStallTimer();\n clearAdCountdownTimer();\n if (!adVideoElement) return;\n adVideoElement.pause();\n adVideoElement.removeAttribute(\"src\");\n adVideoElement.load();\n }\n function buildVastUrl(durationSeconds) {\n const baseUrl = `https://adstorm.co/api-adstorm-dev/adstorm/nab/vast/pod`;\n return `${baseUrl}?duration=${Math.ceil(durationSeconds)}`;\n }\n function parseVastXml(xmlString) {\n const ads = [];\n try {\n const parser = new DOMParser();\n const xmlDoc = parser.parseFromString(xmlString, \"text/xml\");\n const parserError = xmlDoc.querySelector(\"parsererror\");\n if (parserError) {\n console.error(\"[AdStormPlayer] XML parsing error:\", parserError.textContent);\n return [];\n }\n const adElements = xmlDoc.querySelectorAll(\"Ad\");\n adElements.forEach((adElement) => {\n const adId = adElement.getAttribute(\"id\") || \"unknown\";\n const title = adElement.querySelector(\"AdTitle\")?.textContent || \"Ad\";\n const durationText = adElement.querySelector(\"Duration\")?.textContent || \"00:00:30\";\n const durationParts = durationText.split(\":\");\n const duration = parseInt(durationParts[0] || \"0\", 10) * 3600 + parseInt(durationParts[1] || \"0\", 10) * 60 + parseFloat(durationParts[2] || \"0\");\n const mediaFileElements = adElement.querySelectorAll(\"MediaFile\");\n const mediaFiles = [];\n mediaFileElements.forEach((mf) => {\n const type = mf.getAttribute(\"type\") || \"\";\n let url = mf.textContent?.trim() || \"\";\n const width = parseInt(mf.getAttribute(\"width\") || \"1920\", 10);\n const height = parseInt(mf.getAttribute(\"height\") || \"1080\", 10);\n const bitrate = mf.getAttribute(\"bitrate\") ? parseInt(mf.getAttribute(\"bitrate\"), 10) : void 0;\n if (!url) {\n log(`Skipping empty MediaFile URL`);\n return;\n }\n const originalUrl = url;\n url = replaceFlvExtension(url);\n if (url !== originalUrl) {\n log(`Converted FLV to MP4: ${originalUrl} -> ${url}`);\n }\n if (isUnsupportedFormat(url)) {\n const ext = getFileExtension(url);\n log(`Skipping unsupported format: ${url} (extension: ${ext}, declared type: ${type})`);\n return;\n }\n if (isSupportedFormat(url, type)) {\n mediaFiles.push({ url, type, width, height, bitrate });\n log(`Found media file: ${url} (${type}, ${width}x${height})`);\n } else {\n log(`Skipping incompatible media file: ${url} (type: ${type})`);\n }\n });\n if (mediaFiles.length === 0) {\n log(\"No valid media files found in ad:\", adId);\n return;\n }\n const trackingUrls = {\n impression: [],\n start: [],\n firstQuartile: [],\n midpoint: [],\n thirdQuartile: [],\n complete: [],\n mute: [],\n unmute: [],\n pause: [],\n resume: [],\n error: []\n };\n adElement.querySelectorAll(\"Impression\").forEach((el) => {\n const url = el.textContent?.trim();\n if (url) trackingUrls.impression.push(url);\n });\n adElement.querySelectorAll(\"Tracking\").forEach((el) => {\n const event = el.getAttribute(\"event\");\n const url = el.textContent?.trim();\n if (event && url) {\n const eventKey = event;\n if (trackingUrls[eventKey]) {\n trackingUrls[eventKey].push(url);\n }\n }\n });\n const clickThrough = adElement.querySelector(\"ClickThrough\")?.textContent?.trim();\n ads.push({\n id: adId,\n title,\n duration,\n mediaFiles,\n trackingUrls,\n clickThrough\n });\n log(`Parsed ad: ${title}, duration: ${duration}s, media files: ${mediaFiles.length}`);\n });\n } catch (error) {\n console.error(\"[AdStormPlayer] Error parsing VAST XML:\", error);\n }\n return ads;\n }\n function selectBestMediaFile(mediaFiles) {\n if (mediaFiles.length === 0) return null;\n if (mediaFiles.length === 1) return mediaFiles[0];\n const mp4Files = mediaFiles.filter((mf) => mf.type.includes(\"video/mp4\"));\n const candidates = mp4Files.length > 0 ? mp4Files : mediaFiles;\n const targetWidth = contentVideo.videoWidth || 1280;\n const targetHeight = contentVideo.videoHeight || 720;\n candidates.sort((a, b) => {\n const diffA = Math.abs(a.width - targetWidth) + Math.abs(a.height - targetHeight);\n const diffB = Math.abs(b.width - targetWidth) + Math.abs(b.height - targetHeight);\n return diffA - diffB;\n });\n return candidates[0] || null;\n }\n function createAdVideoElement() {\n const video = document.createElement(\"video\");\n video.style.position = \"absolute\";\n video.style.left = \"0\";\n video.style.top = \"0\";\n video.style.width = \"100%\";\n video.style.height = \"100%\";\n video.style.objectFit = \"contain\";\n video.style.backgroundColor = \"#000\";\n video.style.zIndex = \"1\";\n video.playsInline = true;\n video.preload = \"auto\";\n video.muted = originalMutedState;\n video.volume = originalMutedState ? 0 : originalVolume;\n return video;\n }\n function setAdPlayingFlag(isPlaying) {\n if (isPlaying) {\n contentVideo.dataset.stormcloudAdPlaying = \"true\";\n } else {\n delete contentVideo.dataset.stormcloudAdPlaying;\n }\n }\n function setupAdEventListeners() {\n bindAdEventListeners();\n }\n function handleAdComplete() {\n if (destroyed || tornDown) return;\n log(\"Handling ad completion\");\n adPlaying = false;\n setAdPlayingFlag(false);\n clearAdStallTimer();\n clearAdCountdownTimer();\n if (adContainerEl) {\n adContainerEl.style.opacity = \"0\";\n adHideTimerId = setTimeout(() => {\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n }, 300);\n }\n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n contentVideo.muted = originalMutedState;\n contentVideo.volume = originalVolume;\n currentAd = void 0;\n emit(\"content_resume\");\n emit(\"all_ads_completed\");\n }\n function handleAdError() {\n if (destroyed || tornDown) return;\n log(\"Handling ad error\");\n if (!adPlaying) return;\n adPlaying = false;\n setAdPlayingFlag(false);\n clearAdStallTimer();\n clearAdCountdownTimer();\n contentVideo.muted = originalMutedState;\n contentVideo.volume = originalVolume;\n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n currentAd = void 0;\n emit(\"ad_error\");\n emit(\"content_resume\");\n }\n async function fetchVastOnce(durationSeconds) {\n const vastUrl = buildVastUrl(durationSeconds);\n log(\"Fetching VAST from:\", vastUrl);\n const controller = typeof AbortController !== \"undefined\" ? new AbortController() : null;\n const timeoutId = setTimeout(() => controller?.abort(), REQUEST_TIMEOUT_MS);\n try {\n const requestInit = {\n method: \"GET\",\n mode: \"cors\",\n credentials: \"omit\",\n headers: {\n Accept: \"application/xml, text/xml, */*\"\n },\n referrerPolicy: \"no-referrer-when-downgrade\"\n };\n if (controller) {\n requestInit.signal = controller.signal;\n }\n const response = await fetch(vastUrl, requestInit);\n if (!response.ok) {\n throw new Error(`Failed to fetch VAST: ${response.status} ${response.statusText}`);\n }\n const xmlText = await response.text();\n log(\"VAST response received, length:\", xmlText.length);\n return parseVastXml(xmlText);\n } finally {\n clearTimeout(timeoutId);\n }\n }\n async function fetchVast(durationSeconds) {\n let lastError;\n for (let attempt = 1; attempt <= REQUEST_MAX_RETRIES; attempt++) {\n try {\n const ads = await fetchVastOnce(durationSeconds);\n if (ads.length > 0) return ads;\n log(`No ad returned from VAST on attempt ${attempt}/${REQUEST_MAX_RETRIES}`);\n } catch (error) {\n lastError = error;\n if (error?.name === \"AbortError\") {\n console.warn(\n `[AdStormPlayer] VAST request timed out (${REQUEST_TIMEOUT_MS}ms), attempt ${attempt}/${REQUEST_MAX_RETRIES}`\n );\n } else {\n console.warn(`[AdStormPlayer] VAST request failed on attempt ${attempt}/${REQUEST_MAX_RETRIES}:`, error);\n }\n }\n if (attempt < REQUEST_MAX_RETRIES) {\n const delay = REQUEST_RETRY_BACKOFF_MS * attempt;\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n if (lastError instanceof Error) {\n throw lastError;\n }\n return [];\n }\n function getDurationSecondsFromContext(requestContext) {\n if (!requestContext || typeof requestContext !== \"object\") {\n return 30;\n }\n const ctx = requestContext;\n const value = ctx.remainingBreakSec ?? ctx.breakDurationSec;\n if (typeof value !== \"number\" || Number.isNaN(value)) {\n return 30;\n }\n return Math.max(1, Math.ceil(value));\n }\n async function requestAdFromApi(requestContext) {\n const durationSeconds = getDurationSecondsFromContext(requestContext);\n const ads = await fetchVast(durationSeconds);\n return ads[0] || null;\n }\n function assignCurrentAd(ad) {\n currentAd = ad;\n sessionId = generateSessionId();\n trackingFired = {\n impression: false,\n start: false,\n firstQuartile: false,\n midpoint: false,\n thirdQuartile: false,\n complete: false\n };\n fireTrackingPixels2(currentAd.trackingUrls.impression);\n trackingFired.impression = true;\n emit(\"ad_impression\");\n }\n return {\n initialize() {\n log(\"Initializing\");\n if (!adContainerEl) {\n const parent = contentVideo.parentElement;\n if (parent) {\n const computed = window.getComputedStyle(parent).position;\n if (computed === \"static\") {\n parent.style.position = \"relative\";\n parentPositionOverridden = true;\n }\n }\n const container = document.createElement(\"div\");\n container.style.position = \"absolute\";\n container.style.left = \"0\";\n container.style.top = \"0\";\n container.style.right = \"0\";\n container.style.bottom = \"0\";\n container.style.display = \"none\";\n container.style.alignItems = \"center\";\n container.style.justifyContent = \"center\";\n container.style.pointerEvents = \"none\";\n container.style.zIndex = AD_LAYER_Z_INDEX;\n container.style.backgroundColor = \"#000\";\n container.style.transition = \"opacity 0.3s ease-in-out\";\n container.style.opacity = \"0\";\n container.style.isolation = \"isolate\";\n const countdown = document.createElement(\"div\");\n countdown.style.position = \"absolute\";\n countdown.style.left = \"12px\";\n countdown.style.top = \"12px\";\n countdown.style.padding = \"4px 8px\";\n countdown.style.borderRadius = \"4px\";\n countdown.style.background = \"rgba(0,0,0,0.75)\";\n countdown.style.color = \"#fff\";\n countdown.style.fontFamily = \"sans-serif\";\n countdown.style.fontSize = \"12px\";\n countdown.style.lineHeight = \"1.2\";\n countdown.style.pointerEvents = \"none\";\n countdown.style.zIndex = COUNTDOWN_Z_INDEX;\n countdown.textContent = \"Ad\";\n container.appendChild(countdown);\n contentVideo.parentElement?.appendChild(container);\n adContainerEl = container;\n adCountdownEl = countdown;\n }\n },\n async requestAds(duration) {\n log(\"Requesting ads for duration:\", duration);\n if (adPlaying) {\n return Promise.reject(new Error(\"Ad already playing\"));\n }\n if (destroyed) {\n return Promise.reject(new Error(\"Player has been destroyed\"));\n }\n try {\n tornDown = false;\n let durationSeconds = 30;\n const parsed = parseInt(duration || \"\", 10);\n if (!isNaN(parsed) && parsed > 0) {\n durationSeconds = parsed;\n }\n const ads = await fetchVast(durationSeconds);\n if (ads.length === 0) {\n log(\"No ads available from VAST response\");\n emit(\"ad_error\");\n return Promise.resolve();\n }\n assignCurrentAd(ads[0]);\n log(`Ad loaded: ${currentAd.title}, duration: ${currentAd.duration}s`);\n return Promise.resolve();\n } catch (error) {\n console.error(\"[AdStormPlayer] Error requesting ads:\", error);\n emit(\"ad_error\");\n return Promise.reject(error);\n }\n },\n async play() {\n if (!currentAd) {\n return Promise.reject(new Error(\"No ad loaded\"));\n }\n if (destroyed) {\n return Promise.reject(new Error(\"Player has been destroyed\"));\n }\n log(\"Starting ad playback\");\n try {\n tornDown = false;\n if (adHideTimerId) {\n clearTimeout(adHideTimerId);\n adHideTimerId = void 0;\n }\n if (!adVideoElement) {\n adVideoElement = createAdVideoElement();\n adContainerEl?.appendChild(adVideoElement);\n } else {\n teardownCurrentPlayback();\n }\n setupAdEventListeners();\n trackingFired = {\n impression: trackingFired.impression,\n start: false,\n firstQuartile: false,\n midpoint: false,\n thirdQuartile: false,\n complete: false\n };\n contentVideo.style.transition = \"opacity 0.3s ease-in-out\";\n contentVideo.style.opacity = \"0\";\n setTimeout(() => {\n contentVideo.style.visibility = \"hidden\";\n }, 300);\n contentVideo.muted = true;\n contentVideo.volume = 0;\n if (!continueLiveStreamDuringAds) {\n contentVideo.pause();\n }\n adPlaying = true;\n setAdPlayingFlag(true);\n if (adVideoElement) {\n adVideoElement.volume = originalMutedState ? 0 : originalVolume;\n adVideoElement.muted = originalMutedState;\n }\n if (adContainerEl) {\n adContainerEl.style.display = \"flex\";\n adContainerEl.style.pointerEvents = \"auto\";\n adContainerEl.offsetHeight;\n adContainerEl.style.opacity = \"1\";\n }\n emit(\"content_pause\");\n const mediaFile = selectBestMediaFile(currentAd.mediaFiles);\n if (!mediaFile) {\n throw new Error(\"No media file available\");\n }\n log(\"Playing media file:\", mediaFile.url);\n adVideoElement.src = mediaFile.url;\n adVideoElement.load();\n await adVideoElement.play();\n return Promise.resolve();\n } catch (error) {\n console.error(\"[AdStormPlayer] Error playing ad:\", error);\n handleAdError();\n return Promise.reject(error);\n }\n },\n async stop() {\n log(\"Stopping ad\");\n tornDown = true;\n adPlaying = false;\n setAdPlayingFlag(false);\n clearAdStallTimer();\n clearAdCountdownTimer();\n if (adContainerEl) {\n adContainerEl.style.opacity = \"0\";\n adHideTimerId = setTimeout(() => {\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n }, 300);\n }\n teardownCurrentPlayback();\n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n contentVideo.muted = originalMutedState;\n contentVideo.volume = originalVolume;\n currentAd = void 0;\n return Promise.resolve();\n },\n pause() {\n if (!adPlaying || !adVideoElement) return;\n try {\n if (!adVideoElement.paused) adVideoElement.pause();\n } catch (error) {\n console.warn(\"[AdStormPlayer] Error pausing ad:\", error);\n }\n },\n resume() {\n if (!adPlaying || !adVideoElement) return;\n try {\n if (adVideoElement.paused) adVideoElement.play().catch(() => {\n });\n } catch (error) {\n console.warn(\"[AdStormPlayer] Error resuming ad:\", error);\n }\n },\n destroy() {\n log(\"Destroying\");\n destroyed = true;\n tornDown = true;\n adPlaying = false;\n setAdPlayingFlag(false);\n clearAdStallTimer();\n clearAdCountdownTimer();\n if (adHideTimerId) {\n clearTimeout(adHideTimerId);\n adHideTimerId = void 0;\n }\n contentVideo.muted = originalMutedState;\n contentVideo.volume = originalVolume;\n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n teardownCurrentPlayback();\n adVideoElement?.remove();\n adVideoElement = void 0;\n if (adContainerEl?.parentElement) {\n adContainerEl.parentElement.removeChild(adContainerEl);\n }\n adContainerEl = void 0;\n adCountdownEl = void 0;\n currentAd = void 0;\n sessionId = void 0;\n preloadSlots.clear();\n listeners.clear();\n if (parentPositionOverridden && contentVideo.parentElement) {\n contentVideo.parentElement.style.position = \"\";\n parentPositionOverridden = false;\n }\n },\n updateOptions(opts) {\n if (opts.continueLiveStreamDuringAds !== void 0) {\n continueLiveStreamDuringAds = opts.continueLiveStreamDuringAds;\n }\n },\n async playAd(requestContext) {\n if (destroyed) return Promise.reject(new Error(\"Player has been destroyed\"));\n if (!currentAd) {\n const ad = await requestAdFromApi(requestContext);\n if (!ad) {\n emit(\"ad_error\", { message: \"No valid ad from AdStorm API\" });\n return Promise.reject(new Error(\"No valid ad from AdStorm API\"));\n }\n assignCurrentAd(ad);\n }\n return this.play();\n },\n async preloadAd(arg1, arg2) {\n if (destroyed) return;\n const token = typeof arg1 === \"string\" ? arg1 : typeof arg2 === \"string\" ? arg2 : void 0;\n if (!token) return;\n if (currentAd) {\n preloadSlots.set(token, { ad: currentAd });\n currentAd = void 0;\n return;\n }\n const requestContext = typeof arg1 === \"string\" ? arg2 : arg1;\n const ad = await requestAdFromApi(requestContext);\n if (!ad) return;\n preloadSlots.set(token, { ad });\n },\n async playPreloaded(token) {\n if (destroyed) return Promise.reject(new Error(\"Player has been destroyed\"));\n const slot = preloadSlots.get(token);\n if (!slot) {\n return Promise.reject(new Error(`No preloaded ad for token ${token}`));\n }\n preloadSlots.delete(token);\n assignCurrentAd(slot.ad);\n return this.play();\n },\n hasPreloaded(token) {\n return preloadSlots.has(token);\n },\n cancelPreload(token) {\n preloadSlots.delete(token);\n },\n isAdPlaying() {\n return adPlaying;\n },\n resize(width, height) {\n log(`Resizing to ${width}x${height}`);\n if (adContainerEl) {\n adContainerEl.style.width = `${width}px`;\n adContainerEl.style.height = `${height}px`;\n }\n if (adVideoElement) {\n adVideoElement.style.width = `${width}px`;\n adVideoElement.style.height = `${height}px`;\n }\n },\n on(event, listener) {\n if (!listeners.has(event)) listeners.set(event, /* @__PURE__ */ new Set());\n listeners.get(event).add(listener);\n },\n off(event, listener) {\n listeners.get(event)?.delete(listener);\n },\n updateOriginalMutedState(muted, volume) {\n const nextVolume = typeof volume === \"number\" && !Number.isNaN(volume) ? Math.max(0, Math.min(1, volume)) : originalVolume;\n log(`updateOriginalMutedState: muted=${muted}, volume=${nextVolume}`);\n originalMutedState = muted;\n originalVolume = nextVolume;\n },\n getOriginalMutedState() {\n return originalMutedState;\n },\n getOriginalVolume() {\n return originalVolume;\n },\n setAdVolume(volume) {\n if (adVideoElement && adPlaying) {\n adVideoElement.volume = Math.max(0, Math.min(1, volume));\n adVideoElement.muted = volume === 0;\n }\n },\n getAdVolume() {\n if (adVideoElement && adPlaying) {\n return adVideoElement.volume;\n }\n return 1;\n },\n showPlaceholder() {\n if (!adContainerEl) {\n const parent = contentVideo.parentElement;\n if (parent) {\n const computed = window.getComputedStyle(parent).position;\n if (computed === \"static\") {\n parent.style.position = \"relative\";\n parentPositionOverridden = true;\n }\n }\n const container = document.createElement(\"div\");\n container.style.position = \"absolute\";\n container.style.left = \"0\";\n container.style.top = \"0\";\n container.style.right = \"0\";\n container.style.bottom = \"0\";\n container.style.display = \"none\";\n container.style.alignItems = \"center\";\n container.style.justifyContent = \"center\";\n container.style.pointerEvents = \"none\";\n container.style.zIndex = AD_LAYER_Z_INDEX;\n container.style.backgroundColor = \"#000\";\n container.style.isolation = \"isolate\";\n const countdown = document.createElement(\"div\");\n countdown.style.position = \"absolute\";\n countdown.style.left = \"12px\";\n countdown.style.top = \"12px\";\n countdown.style.padding = \"4px 8px\";\n countdown.style.borderRadius = \"4px\";\n countdown.style.background = \"rgba(0,0,0,0.75)\";\n countdown.style.color = \"#fff\";\n countdown.style.fontFamily = \"sans-serif\";\n countdown.style.fontSize = \"12px\";\n countdown.style.lineHeight = \"1.2\";\n countdown.style.pointerEvents = \"none\";\n countdown.style.zIndex = COUNTDOWN_Z_INDEX;\n countdown.textContent = \"Ad\";\n container.appendChild(countdown);\n contentVideo.parentElement?.appendChild(container);\n adContainerEl = container;\n adCountdownEl = countdown;\n }\n if (adContainerEl) {\n adContainerEl.style.display = \"flex\";\n adContainerEl.style.opacity = \"1\";\n adContainerEl.style.pointerEvents = \"auto\";\n }\n },\n hidePlaceholder() {\n if (adContainerEl) {\n adContainerEl.style.opacity = \"0\";\n setTimeout(() => {\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n }, 300);\n }\n }\n };\n}\n\n// src/utils/tracking.ts\nvar cachedBrowserId = null;\nfunction getClientInfo() {\n const ua = navigator.userAgent;\n const platform = navigator.platform;\n const vendor = navigator.vendor || \"\";\n const maxTouchPoints = navigator.maxTouchPoints || 0;\n const memory = navigator.deviceMemory || null;\n const hardwareConcurrency = navigator.hardwareConcurrency || 1;\n const screenInfo = {\n width: screen?.width,\n height: screen?.height,\n availWidth: screen?.availWidth,\n availHeight: screen?.availHeight,\n orientation: screen?.orientation?.type || \"\",\n pixelDepth: screen?.pixelDepth\n };\n let deviceType = \"desktop\";\n let brand = \"Unknown\";\n let os = \"Unknown\";\n let model = \"\";\n let isSmartTV = false;\n let isAndroid = false;\n let isWebView = false;\n let isWebApp = false;\n if (ua.includes(\"Web0S\")) {\n brand = \"LG\";\n os = \"webOS\";\n isSmartTV = true;\n deviceType = \"tv\";\n const webosMatch = ua.match(/Web0S\\/([^\\s]+)/);\n model = webosMatch ? `webOS ${webosMatch[1]}` : \"webOS TV\";\n } else if (ua.includes(\"Tizen\")) {\n brand = \"Samsung\";\n os = \"Tizen\";\n isSmartTV = true;\n deviceType = \"tv\";\n const tizenMatch = ua.match(/Tizen\\/([^\\s]+)/);\n const tvMatch = ua.match(/(?:Smart-TV|SMART-TV|TV)/i) ? \"Smart TV\" : \"\";\n model = tizenMatch ? `Tizen ${tizenMatch[1]} ${tvMatch}`.trim() : \"Tizen TV\";\n } else if (ua.includes(\"Philips\")) {\n brand = \"Philips\";\n os = \"Saphi\";\n isSmartTV = true;\n deviceType = \"tv\";\n } else if (ua.includes(\"Sharp\") || ua.includes(\"AQUOS\")) {\n brand = \"Sharp\";\n os = \"Android TV\";\n isSmartTV = true;\n deviceType = \"tv\";\n } else if (ua.includes(\"Android\") && (ua.includes(\"Sony\") || vendor.includes(\"Sony\"))) {\n brand = \"Sony\";\n os = \"Android TV\";\n isSmartTV = true;\n deviceType = \"tv\";\n } else if (ua.includes(\"Android\") && (ua.includes(\"NetCast\") || ua.includes(\"LG\"))) {\n brand = \"LG\";\n os = \"Android TV\";\n isSmartTV = true;\n deviceType = \"tv\";\n } else if (ua.includes(\" Roku\") || ua.includes(\"Roku/\")) {\n brand = \"Roku\";\n os = \"Roku OS\";\n isSmartTV = true;\n deviceType = \"tv\";\n } else if (ua.includes(\"AppleTV\")) {\n brand = \"Apple\";\n os = \"tvOS\";\n isSmartTV = true;\n deviceType = \"tv\";\n }\n if (ua.includes(\"Android\")) {\n isAndroid = true;\n os = \"Android\";\n deviceType = /Mobile/.test(ua) ? \"mobile\" : \"tablet\";\n if (ua.includes(\"Android\") && (maxTouchPoints === 0 || ua.includes(\"Google TV\") || ua.includes(\"XiaoMi\"))) {\n deviceType = \"tv\";\n isSmartTV = true;\n brand = brand === \"Unknown\" ? \"Android TV\" : brand;\n }\n const androidModelMatch = ua.match(/\\(([^)]*Android[^)]*)\\)/);\n if (androidModelMatch && androidModelMatch[1]) {\n model = androidModelMatch[1];\n }\n }\n if (/iPad|iPhone|iPod/.test(ua)) {\n os = \"iOS\";\n deviceType = \"mobile\";\n brand = \"Apple\";\n if (navigator.maxTouchPoints > 1 && /iPad/.test(ua)) {\n deviceType = \"tablet\";\n }\n }\n if (!isAndroid && !isSmartTV && !/Mobile/.test(ua)) {\n if (ua.includes(\"Windows\")) {\n os = \"Windows\";\n deviceType = \"desktop\";\n } else if (ua.includes(\"Mac\") && !/iPhone/.test(ua)) {\n os = \"macOS\";\n deviceType = \"desktop\";\n if (maxTouchPoints > 1) deviceType = \"tablet\";\n } else if (ua.includes(\"Linux\")) {\n os = \"Linux\";\n deviceType = \"desktop\";\n }\n }\n if (brand === \"Unknown\") {\n if (vendor.includes(\"Google\") || ua.includes(\"Chrome\")) brand = \"Google\";\n if (vendor.includes(\"Apple\")) brand = \"Apple\";\n if (vendor.includes(\"Samsung\") || ua.includes(\"SM-\")) brand = \"Samsung\";\n }\n isWebView = /wv|WebView|Linux; U;/.test(ua);\n if (window?.outerHeight === 0 && window?.outerWidth === 0) {\n isWebView = true;\n }\n isWebApp = window.matchMedia(\"(display-mode: standalone)\").matches || window.navigator.standalone === true || window.screen?.orientation?.angle !== void 0;\n return {\n brand,\n os,\n model: model || ua.substring(0, 50) + \"...\",\n deviceType,\n isSmartTV,\n isAndroid,\n isWebView,\n isWebApp,\n domain: window.location.hostname,\n origin: window.location.origin,\n path: window.location.pathname,\n userAgent: ua,\n vendor,\n platform,\n screen: screenInfo,\n hardwareConcurrency,\n deviceMemory: memory,\n maxTouchPoints,\n language: navigator.language,\n languages: navigator.languages?.join(\",\") || \"\",\n cookieEnabled: navigator.cookieEnabled,\n doNotTrack: navigator.doNotTrack || \"\",\n referrer: document.referrer,\n visibilityState: document.visibilityState\n };\n}\nasync function getBrowserID(clientInfo) {\n if (cachedBrowserId) {\n return cachedBrowserId;\n }\n const fingerprintString = JSON.stringify(clientInfo);\n if (typeof crypto !== \"undefined\" && crypto.subtle && crypto.subtle.digest) {\n try {\n await crypto.subtle.digest(\"SHA-256\", new Uint8Array([1, 2, 3]));\n let encodedData;\n if (typeof TextEncoder !== \"undefined\") {\n encodedData = new TextEncoder().encode(fingerprintString);\n } else {\n const utf8 = unescape(encodeURIComponent(fingerprintString));\n const buffer = new Uint8Array(utf8.length);\n for (let i = 0; i < utf8.length; i++) {\n buffer[i] = utf8.charCodeAt(i);\n }\n encodedData = buffer;\n }\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", encodedData);\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n const hashHex = hashArray.map((b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n cachedBrowserId = hashHex;\n return hashHex;\n } catch (error) {\n console.warn(\n \"[StormcloudVideoPlayer] crypto.subtle.digest not supported, using fallback hash\"\n );\n }\n }\n let hash = 0;\n for (let i = 0; i < fingerprintString.length; i++) {\n const char = fingerprintString.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash;\n }\n const fallbackHash = Math.abs(hash).toString(16).padStart(8, \"0\");\n const timestamp = Date.now().toString(16).padStart(12, \"0\");\n const random = Math.random().toString(16).substring(2, 14).padStart(12, \"0\");\n cachedBrowserId = (fallbackHash + timestamp + random).padEnd(64, \"0\");\n return cachedBrowserId;\n}\nvar TRACK_URL = \"https://adstorm.co/api-adstorm-dev/adstorm/player-tracking/track\";\nasync function sendTrackRequest(licenseKey, body) {\n const headers = {\n \"Content-Type\": \"application/json\"\n };\n if (licenseKey) {\n headers[\"Authorization\"] = `Bearer ${licenseKey}`;\n }\n const response = await fetch(TRACK_URL, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body)\n });\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n await response.json();\n}\nasync function sendInitialTracking(licenseKey) {\n try {\n const clientInfo = getClientInfo();\n const browserId = await getBrowserID(clientInfo);\n const trackingData = {\n browserId,\n ...clientInfo\n };\n const headers = {\n \"Content-Type\": \"application/json\"\n };\n if (licenseKey) {\n headers[\"Authorization\"] = `Bearer ${licenseKey}`;\n }\n const response = await fetch(TRACK_URL, {\n method: \"POST\",\n headers,\n body: JSON.stringify(trackingData)\n });\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n await response.json();\n } catch (error) {\n console.error(\n \"[StormcloudVideoPlayer] Error sending initial tracking data:\",\n error\n );\n }\n}\nasync function sendAdLoadedTracking(licenseKey, adLoadedInfo) {\n try {\n const clientInfo = getClientInfo();\n const browserId = await getBrowserID(clientInfo);\n const trackingData = { browserId, ...clientInfo };\n await sendTrackRequest(licenseKey, {\n ...trackingData,\n licenseKey,\n adLoadedInfo\n });\n } catch (error) {\n console.error(\n \"[StormcloudVideoPlayer] Error sending ad loaded tracking:\",\n error\n );\n }\n}\nasync function sendAdImpressionTracking(licenseKey, adImpressionInfo) {\n try {\n const clientInfo = getClientInfo();\n const browserId = await getBrowserID(clientInfo);\n const trackingData = { browserId, ...clientInfo };\n await sendTrackRequest(licenseKey, {\n ...trackingData,\n licenseKey,\n adImpressionInfo\n });\n } catch (error) {\n console.error(\n \"[StormcloudVideoPlayer] Error sending ad impression tracking:\",\n error\n );\n }\n}\nasync function sendHeartbeat(licenseKey) {\n try {\n const clientInfo = getClientInfo();\n const browserId = await getBrowserID(clientInfo);\n const heartbeatData = {\n browserId,\n timestamp: (/* @__PURE__ */ new Date()).toISOString()\n };\n const headers = {\n \"Content-Type\": \"application/json\"\n };\n if (licenseKey) {\n headers[\"Authorization\"] = `Bearer ${licenseKey}`;\n }\n const response = await fetch(\n \"https://adstorm.co/api-adstorm-dev/adstorm/player-tracking/heartbeat\",\n {\n method: \"POST\",\n headers,\n body: JSON.stringify(heartbeatData)\n }\n );\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n await response.json();\n } catch (error) {\n console.error(\"[StormcloudVideoPlayer] Error sending heartbeat:\", error);\n }\n}\n\n// src/utils/polyfills.ts\nfunction polyfillURLSearchParams() {\n if (typeof URLSearchParams !== \"undefined\") {\n return;\n }\n class URLSearchParamsPolyfill {\n constructor(init) {\n this.params = /* @__PURE__ */ new Map();\n if (typeof init === \"string\") {\n this.parseQueryString(init);\n } else if (init instanceof URLSearchParamsPolyfill) {\n init.forEach((value, key) => {\n this.append(key, value);\n });\n }\n }\n parseQueryString(query) {\n const cleanQuery = query.startsWith(\"?\") ? query.slice(1) : query;\n if (!cleanQuery) return;\n cleanQuery.split(\"&\").forEach((param) => {\n const [key, value] = param.split(\"=\");\n if (key) {\n const decodedKey = this.safeDecodeURIComponent(key);\n const decodedValue = value ? this.safeDecodeURIComponent(value) : \"\";\n this.append(decodedKey, decodedValue);\n }\n });\n }\n safeDecodeURIComponent(str) {\n try {\n return decodeURIComponent(str.replace(/\\+/g, \" \"));\n } catch (e) {\n return str;\n }\n }\n append(name, value) {\n const values = this.params.get(name) || [];\n values.push(String(value));\n this.params.set(name, values);\n }\n delete(name) {\n this.params.delete(name);\n }\n get(name) {\n const values = this.params.get(name);\n return values && values.length > 0 && values[0] !== void 0 ? values[0] : null;\n }\n getAll(name) {\n return this.params.get(name) || [];\n }\n has(name) {\n return this.params.has(name);\n }\n set(name, value) {\n this.params.set(name, [String(value)]);\n }\n forEach(callback) {\n this.params.forEach((values, key) => {\n values.forEach((value) => {\n callback(value, key, this);\n });\n });\n }\n toString() {\n const parts = [];\n this.params.forEach((values, key) => {\n values.forEach((value) => {\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);\n });\n });\n return parts.join(\"&\");\n }\n }\n window.URLSearchParams = URLSearchParamsPolyfill;\n}\nfunction polyfillTextEncoder() {\n if (typeof TextEncoder !== \"undefined\") {\n return;\n }\n class TextEncoderPolyfill {\n constructor() {\n this.encoding = \"utf-8\";\n }\n encode(str) {\n const utf8 = [];\n for (let i = 0; i < str.length; i++) {\n let charcode = str.charCodeAt(i);\n if (charcode < 128) {\n utf8.push(charcode);\n } else if (charcode < 2048) {\n utf8.push(192 | charcode >> 6, 128 | charcode & 63);\n } else if (charcode < 55296 || charcode >= 57344) {\n utf8.push(\n 224 | charcode >> 12,\n 128 | charcode >> 6 & 63,\n 128 | charcode & 63\n );\n } else {\n i++;\n charcode = 65536 + ((charcode & 1023) << 10 | str.charCodeAt(i) & 1023);\n utf8.push(\n 240 | charcode >> 18,\n 128 | charcode >> 12 & 63,\n 128 | charcode >> 6 & 63,\n 128 | charcode & 63\n );\n }\n }\n return new Uint8Array(utf8);\n }\n }\n window.TextEncoder = TextEncoderPolyfill;\n}\nfunction polyfillPromiseFinally() {\n if (typeof Promise !== \"undefined\" && !Promise.prototype.finally) {\n Promise.prototype.finally = function(callback) {\n const constructor = this.constructor;\n return this.then(\n (value) => constructor.resolve(callback()).then(() => value),\n (reason) => constructor.resolve(callback()).then(() => {\n throw reason;\n })\n );\n };\n }\n}\nfunction polyfillObjectAssign() {\n if (typeof Object.assign !== \"function\") {\n Object.assign = function(target, ...sources) {\n if (target == null) {\n throw new TypeError(\"Cannot convert undefined or null to object\");\n }\n const to = Object(target);\n for (let i = 0; i < sources.length; i++) {\n const nextSource = sources[i];\n if (nextSource != null) {\n for (const nextKey in nextSource) {\n if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {\n to[nextKey] = nextSource[nextKey];\n }\n }\n }\n }\n return to;\n };\n }\n}\nfunction polyfillArrayFrom() {\n if (!Array.from) {\n Array.from = function(arrayLike, mapFn, thisArg) {\n const items = Object(arrayLike);\n if (arrayLike == null) {\n throw new TypeError(\"Array.from requires an array-like object\");\n }\n const len = items.length >>> 0;\n const result = new Array(len);\n for (let i = 0; i < len; i++) {\n if (mapFn) {\n result[i] = mapFn.call(thisArg, items[i], i);\n } else {\n result[i] = items[i];\n }\n }\n return result;\n };\n }\n}\nfunction polyfillStringStartsWith() {\n if (!String.prototype.startsWith) {\n String.prototype.startsWith = function(search, pos) {\n pos = !pos || pos < 0 ? 0 : +pos;\n return this.substring(pos, pos + search.length) === search;\n };\n }\n}\nfunction polyfillStringEndsWith() {\n if (!String.prototype.endsWith) {\n String.prototype.endsWith = function(search, length) {\n if (length === void 0 || length > this.length) {\n length = this.length;\n }\n return this.substring(length - search.length, length) === search;\n };\n }\n}\nfunction polyfillStringIncludes() {\n if (!String.prototype.includes) {\n String.prototype.includes = function(search, start) {\n if (typeof start !== \"number\") {\n start = 0;\n }\n if (start + search.length > this.length) {\n return false;\n }\n return this.indexOf(search, start) !== -1;\n };\n }\n}\nfunction initializePolyfills() {\n polyfillObjectAssign();\n polyfillArrayFrom();\n polyfillStringStartsWith();\n polyfillStringEndsWith();\n polyfillStringIncludes();\n polyfillURLSearchParams();\n polyfillTextEncoder();\n polyfillPromiseFinally();\n}\n\n// src/utils/browserCompat.ts\nfunction getChromeVersion(ua) {\n const match = ua.match(/Chrome\\/(\\d+)/);\n return match && match[1] ? parseInt(match[1], 10) : 0;\n}\nfunction getWebKitVersion(ua) {\n const match = ua.match(/AppleWebKit\\/(\\d+)/);\n return match && match[1] ? parseInt(match[1], 10) : 0;\n}\nfunction getPlatform() {\n if (\"userAgentData\" in navigator && navigator.userAgentData?.platform) {\n return navigator.userAgentData.platform;\n }\n const ua = navigator.userAgent;\n if (/Mac|iPhone|iPad|iPod/i.test(ua)) {\n return /iPhone|iPad|iPod/i.test(ua) ? \"iPhone\" : \"MacIntel\";\n }\n if (/Win/i.test(ua)) {\n return \"Win32\";\n }\n if (/Linux/i.test(ua)) {\n return /Android/i.test(ua) ? \"Linux armv8l\" : \"Linux x86_64\";\n }\n if (/CrOS/i.test(ua)) {\n return \"CrOS\";\n }\n return navigator.platform || \"Unknown\";\n}\nfunction detectBrowser() {\n const ua = navigator.userAgent;\n const platform = getPlatform();\n let name = \"Unknown\";\n let version = \"0\";\n let majorVersion = 0;\n let isSmartTV = false;\n let isLegacyTV = false;\n let supportsIMA = true;\n let supportsModernJS = true;\n let recommendedAdPlayer = \"ima\";\n let webOSVersion;\n let tizenVersion;\n let chromeVersionNum;\n const chromeVersion = getChromeVersion(ua);\n const webkitVersion = getWebKitVersion(ua);\n chromeVersionNum = chromeVersion > 0 ? chromeVersion : void 0;\n if (/Web0S|webOS|LG Browser|LGSTB/i.test(ua)) {\n name = \"LG WebOS\";\n isSmartTV = true;\n let match = ua.match(/Web0S[/\\s]*([\\d.]+)/i) || ua.match(/webOS[/\\s]*([\\d.]+)/i);\n if (!match || !match[1]) {\n match = ua.match(/webOSTV[/\\s-]*([\\d.]+)/i) || ua.match(/webOS\\.TV[/\\s-]*([\\d.]+)/i);\n }\n if (match && match[1]) {\n version = match[1];\n const parts = version.split(\".\");\n majorVersion = parts[0] ? parseInt(parts[0], 10) : 0;\n webOSVersion = majorVersion;\n } else if (chromeVersion > 0) {\n if (chromeVersion >= 79) {\n webOSVersion = 6;\n version = \"6.0\";\n majorVersion = 6;\n } else if (chromeVersion >= 68) {\n webOSVersion = 5;\n version = \"5.0\";\n majorVersion = 5;\n } else if (chromeVersion >= 53) {\n webOSVersion = 4;\n version = \"4.0\";\n majorVersion = 4;\n } else if (chromeVersion >= 38) {\n webOSVersion = 3;\n version = \"3.0\";\n majorVersion = 3;\n } else {\n webOSVersion = 2;\n version = \"2.0\";\n majorVersion = 2;\n }\n } else {\n version = \"Unknown\";\n webOSVersion = void 0;\n }\n if (webOSVersion !== void 0 && webOSVersion >= 4) {\n supportsIMA = true;\n recommendedAdPlayer = \"ima\";\n isLegacyTV = false;\n } else if (webOSVersion !== void 0 && webOSVersion >= 3) {\n if (chromeVersion >= 53) {\n supportsIMA = true;\n recommendedAdPlayer = \"ima\";\n isLegacyTV = false;\n } else {\n supportsIMA = false;\n recommendedAdPlayer = \"hls\";\n isLegacyTV = true;\n }\n } else if (chromeVersion >= 53) {\n supportsIMA = true;\n recommendedAdPlayer = \"ima\";\n isLegacyTV = false;\n } else {\n supportsIMA = false;\n recommendedAdPlayer = \"hls\";\n isLegacyTV = true;\n }\n } else if (/Tizen/i.test(ua)) {\n name = \"Samsung Tizen\";\n isSmartTV = true;\n const match = ua.match(/Tizen[/\\s]*([\\d.]+)/i);\n version = match && match[1] ? match[1] : \"Unknown\";\n if (version !== \"Unknown\") {\n const parts = version.split(\".\");\n majorVersion = parts[0] ? parseInt(parts[0], 10) : 0;\n tizenVersion = majorVersion;\n }\n if (tizenVersion !== void 0 && tizenVersion >= 4) {\n supportsIMA = true;\n recommendedAdPlayer = \"ima\";\n isLegacyTV = false;\n } else if (tizenVersion !== void 0 && tizenVersion >= 3 && chromeVersion >= 47) {\n supportsIMA = true;\n recommendedAdPlayer = \"ima\";\n isLegacyTV = false;\n } else if (chromeVersion >= 53) {\n supportsIMA = true;\n recommendedAdPlayer = \"ima\";\n isLegacyTV = false;\n } else {\n supportsIMA = false;\n recommendedAdPlayer = \"hls\";\n isLegacyTV = true;\n }\n } else if (/SMART-TV|SmartTV/i.test(ua)) {\n name = \"Smart TV\";\n isSmartTV = true;\n if (chromeVersion >= 53) {\n supportsIMA = true;\n recommendedAdPlayer = \"ima\";\n } else {\n supportsIMA = false;\n recommendedAdPlayer = \"hls\";\n isLegacyTV = true;\n }\n } else if (/NetCast/i.test(ua)) {\n name = \"LG NetCast\";\n isSmartTV = true;\n isLegacyTV = true;\n supportsIMA = false;\n recommendedAdPlayer = \"hls\";\n } else if (/BRAVIA/i.test(ua)) {\n name = \"Sony BRAVIA\";\n isSmartTV = true;\n if (chromeVersion >= 53) {\n supportsIMA = true;\n recommendedAdPlayer = \"ima\";\n } else {\n supportsIMA = false;\n recommendedAdPlayer = \"hls\";\n isLegacyTV = true;\n }\n } else {\n if (chromeVersion > 0) {\n name = \"Chrome\";\n version = chromeVersion.toString();\n majorVersion = chromeVersion;\n if (chromeVersion < 50) {\n supportsIMA = false;\n supportsModernJS = false;\n recommendedAdPlayer = \"hls\";\n }\n }\n if (webkitVersion > 0 && webkitVersion < 600) {\n supportsModernJS = false;\n if (chromeVersion < 50) {\n supportsIMA = false;\n recommendedAdPlayer = \"hls\";\n }\n }\n }\n if (typeof Promise === \"undefined\" || typeof Map === \"undefined\" || typeof Set === \"undefined\") {\n supportsModernJS = false;\n supportsIMA = false;\n recommendedAdPlayer = \"hls\";\n }\n if (typeof URLSearchParams === \"undefined\") {\n supportsModernJS = false;\n }\n return {\n name,\n version,\n majorVersion,\n isSmartTV,\n isLegacyTV,\n platform,\n supportsIMA,\n supportsModernJS,\n recommendedAdPlayer,\n webOSVersion,\n tizenVersion,\n chromeVersion: chromeVersionNum\n };\n}\nfunction supportsGoogleIMA() {\n const browser = detectBrowser();\n if (browser.isLegacyTV) {\n return false;\n }\n if (typeof document === \"undefined\" || typeof document.createElement !== \"function\") {\n return false;\n }\n try {\n const video = document.createElement(\"video\");\n if (!video) {\n return false;\n }\n } catch (e) {\n return false;\n }\n if (typeof Promise === \"undefined\") {\n return false;\n }\n return browser.supportsIMA;\n}\nfunction logBrowserInfo(debug = false) {\n if (!debug) return;\n const browser = detectBrowser();\n const imaSupport = supportsGoogleIMA();\n console.log(\"[StormcloudVideoPlayer] Browser Compatibility Info:\", {\n browser: `${browser.name} ${browser.version}`,\n platform: browser.platform,\n isSmartTV: browser.isSmartTV,\n isLegacyTV: browser.isLegacyTV,\n supportsIMA: imaSupport,\n supportsModernJS: browser.supportsModernJS,\n recommendedAdPlayer: browser.recommendedAdPlayer,\n ...browser.webOSVersion !== void 0 ? { webOSVersion: browser.webOSVersion } : {},\n ...browser.tizenVersion !== void 0 ? { tizenVersion: browser.tizenVersion } : {},\n ...browser.chromeVersion !== void 0 ? { chromeVersion: browser.chromeVersion } : {},\n userAgent: navigator.userAgent\n });\n}\nfunction getBrowserConfigOverrides() {\n const browser = detectBrowser();\n const overrides = {};\n if (browser.isSmartTV) {\n overrides.allowNativeHls = true;\n }\n return overrides;\n}\n\n// src/player/StormcloudVideoPlayer.ts\nvar DEBUG_HISTORY_LIMIT = 120;\nvar StormcloudVideoPlayer = class {\n constructor(config) {\n this.pendingNextAdBids = null;\n this.continuousFetchLoopPromise = null;\n this.attached = false;\n this.inAdBreak = false;\n this.adPodQueue = [];\n this.lastHeartbeatTime = 0;\n this.currentAdIndex = 0;\n this.totalAdsInBreak = 0;\n this.showAds = false;\n this.isLiveStream = false;\n this.nativeHlsMode = false;\n this.videoSrcProtection = null;\n this.bufferedSegmentsCount = 0;\n this.shouldAutoplayAfterBuffering = false;\n this.hasInitialBufferCompleted = false;\n this.activeAdRequestToken = null;\n this.adRequestWatchdogToken = null;\n this.adFailsafeToken = null;\n this.continuousFetchingActive = false;\n this.isInAdTransition = false;\n this.maxPlaceholderDurationMs = 5e3;\n this.isShowingPlaceholder = false;\n this.lastAdInsertionPoint = null;\n this.processedAdInsertionUpdatedAt = null;\n this.totalAdRequestsInBreak = 0;\n this.maxTotalAdRequestsPerBreak = 20;\n this.pendingAdBreak = null;\n this.savedMutedStateBeforeAd = null;\n this.consecutiveFailures = 0;\n this.maxConsecutiveFailures = 5;\n this.lastAdRequestTime = 0;\n this.minAdRequestIntervalMs = 2500;\n this.backoffBaseMs = 1e3;\n this.maxBackoffMs = 15e3;\n this.MIN_AD_REMAINING_MS = 15e3;\n this.adRequestTimeoutMs = 5e3;\n this.adRequestMaxRetries = 3;\n this.adRequestRetryBackoffMs = 1500;\n this.preloadedTokens = [];\n this.debugLogEntries = [];\n this.adInsertionDebugHistory = [];\n initializePolyfills();\n const browserOverrides = getBrowserConfigOverrides();\n this.config = { ...browserOverrides, ...config };\n this.video = config.videoElement;\n this.adTransitionGapMs = this.config.adTransitionGapMs ?? 100;\n logBrowserInfo(config.debugAdTiming);\n const browserForAdLayer = detectBrowser();\n const isSinglePipeline = browserForAdLayer.isSmartTV || !!this.config.singlePipelineMode;\n this.adLayer = createAdStormPlayer(this.video, {\n licenseKey: this.config.licenseKey || \"\",\n debug: !!config.debugAdTiming\n });\n this.adLayer.updateOptions({\n continueLiveStreamDuringAds: !isSinglePipeline && this.shouldContinueLiveStreamDuringAds()\n });\n }\n async adRequest(context) {\n if (this.config.disableAds) return [];\n const durationSeconds = Math.max(\n 1,\n Math.ceil(context?.remainingBreakSec ?? context?.breakDurationSec ?? 30)\n );\n await this.adLayer.requestAds(String(durationSeconds));\n return [\n {\n bidder: \"adstorm-direct\",\n cpm: 0,\n width: 0,\n height: 0,\n adId: \"adstorm\",\n impId: \"\",\n creativeId: \"adstorm\",\n currency: \"USD\",\n durationSec: durationSeconds\n }\n ];\n }\n async load() {\n if (!this.attached) {\n this.attach();\n }\n this.initializeTracking();\n if (this.shouldUseNativeHls()) {\n this.nativeHlsMode = true;\n this.videoSrcProtection = this.config.src;\n this.video.src = this.config.src;\n this.isLiveStream = this.config.lowLatencyMode ?? false;\n if (this.config.debugAdTiming) {\n console.log(\n \"[StormcloudVideoPlayer] Using native HLS playback - VOD mode:\",\n {\n isLive: this.isLiveStream,\n allowNativeHls: this.config.allowNativeHls,\n adBehavior: \"vod (main video pauses during ads)\"\n }\n );\n }\n if (!this.config.disableAds) {\n this.adLayer.updateOptions({ continueLiveStreamDuringAds: false, mainHlsInstance: null });\n }\n if (this.config.autoplay) {\n await this.video.play()?.catch(() => {\n });\n }\n return;\n }\n this.hls = new import_hls.default({\n enableWorker: true,\n backBufferLength: 30,\n liveDurationInfinity: true,\n lowLatencyMode: !!this.config.lowLatencyMode,\n maxLiveSyncPlaybackRate: this.config.lowLatencyMode ? 1.5 : 1,\n ...this.config.lowLatencyMode ? { liveSyncDuration: 2 } : {},\n maxBufferLength: 30,\n maxMaxBufferLength: 600,\n maxBufferSize: 60 * 1e3 * 1e3,\n maxBufferHole: 0.5,\n highBufferWatchdogPeriod: 2,\n nudgeOffset: 0.1,\n nudgeMaxRetry: 3,\n startPosition: -1\n });\n this.hls.on(import_hls.default.Events.MEDIA_ATTACHED, () => {\n this.hls?.loadSource(this.config.src);\n });\n this.hls.on(import_hls.default.Events.MANIFEST_PARSED, async (_, data) => {\n if (this.config.allowNativeHls === false) {\n this.isLiveStream = true;\n } else {\n this.isLiveStream = this.hls?.levels?.some(\n (level) => level?.details?.live === true || level?.details?.type === \"LIVE\"\n ) ?? false;\n }\n if (this.config.debugAdTiming) {\n const adBehavior = this.shouldContinueLiveStreamDuringAds() ? \"live (main video continues muted during ads)\" : \"vod (main video pauses during ads)\";\n console.log(\"[StormcloudVideoPlayer] Stream type detected:\", {\n isLive: this.isLiveStream,\n allowNativeHls: this.config.allowNativeHls,\n adBehavior\n });\n }\n if (!this.config.disableAds) {\n this.adLayer.updateOptions({\n continueLiveStreamDuringAds: this.shouldContinueLiveStreamDuringAds(),\n mainHlsInstance: this.hls ?? null\n });\n }\n this.bufferedSegmentsCount = 0;\n this.hasInitialBufferCompleted = false;\n this.shouldAutoplayAfterBuffering = !!this.config.autoplay;\n const minSegments = this.config.minSegmentsBeforePlay ?? 2;\n if (this.config.debugAdTiming) {\n console.log(\n \"[StormcloudVideoPlayer] Waiting for\",\n minSegments,\n \"segments to buffer before playback\"\n );\n }\n if (minSegments === 0 || !this.config.autoplay) {\n this.hasInitialBufferCompleted = true;\n if (this.config.autoplay) {\n await this.video.play()?.catch(() => {\n });\n }\n }\n if (!this.config.disableAds && this.config.projectId) {\n this.startAdInsertionPolling();\n }\n });\n this.hls.on(import_hls.default.Events.LEVEL_LOADED, () => {\n if (this.inAdBreak || this.pendingAdBreak) {\n return;\n }\n this.checkAdInsertionInManifest();\n });\n this.hls.on(import_hls.default.Events.FRAG_BUFFERED, async (_evt, data) => {\n if (this.hasInitialBufferCompleted) {\n return;\n }\n this.bufferedSegmentsCount++;\n const minSegments = this.config.minSegmentsBeforePlay ?? 2;\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Buffered segment ${this.bufferedSegmentsCount}/${minSegments}`\n );\n }\n if (this.bufferedSegmentsCount >= minSegments) {\n this.hasInitialBufferCompleted = true;\n if (this.shouldAutoplayAfterBuffering) {\n if (this.inAdBreak || this.adLayer.isAdPlaying()) {\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Initial buffer complete (${this.bufferedSegmentsCount} segments). Ad break active \\u2014 deferring play() to handleAdPodComplete().`\n );\n }\n } else {\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Initial buffer complete (${this.bufferedSegmentsCount} segments). Starting playback.`\n );\n }\n await this.video.play()?.catch((err) => {\n if (this.config.debugAdTiming) {\n console.warn(\"[StormcloudVideoPlayer] Autoplay failed:\", err);\n }\n });\n }\n }\n }\n });\n this.hls.on(import_hls.default.Events.FRAG_CHANGED, (_evt, data) => {\n const frag = data?.frag;\n if (!frag) return;\n if (this.lastAdInsertionPoint && !this.inAdBreak && this.lastAdInsertionPoint.updated_at !== this.processedAdInsertionUpdatedAt) {\n const segmentName = this.lastAdInsertionPoint.segment_ts_name;\n if (this.fragmentMatchesSegment(frag, segmentName)) {\n this.processedAdInsertionUpdatedAt = this.lastAdInsertionPoint.updated_at;\n const offsetMs = (this.lastAdInsertionPoint.offset_seconds || 0) * 1e3;\n this.pushAdInsertionDebug(\"segment_playing\", segmentName, {\n offsetSeconds: this.lastAdInsertionPoint.offset_seconds,\n detail: `sn=${frag?.sn ?? \"?\"}`\n });\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Ad insertion segment \"${segmentName}\" now playing \\u2014 scheduling ad start in ${offsetMs}ms`\n );\n }\n this.pushAdInsertionDebug(\"ad_scheduled\", segmentName, {\n offsetSeconds: this.lastAdInsertionPoint.offset_seconds,\n detail: `in ${offsetMs}ms, dur=60s`\n });\n this.clearAdInsertionOffsetTimer();\n this.adInsertionOffsetTimerId = window.setTimeout(() => {\n this.adInsertionOffsetTimerId = void 0;\n if (this.inAdBreak) return;\n this.pushAdInsertionDebug(\"ad_triggered\", segmentName, {\n detail: \"ad break started (60s)\"\n });\n void this.handleAdStart(60);\n }, offsetMs);\n }\n }\n });\n this.hls.on(import_hls.default.Events.FRAG_PARSING_USERDATA, (_evt, data) => {\n const samples = data?.samples ?? [];\n for (const sample of samples) {\n const bytes = sample?.data;\n if (!bytes || bytes.length < 5) continue;\n const isSCTE35 = bytes[0] === 252;\n if (!isSCTE35) continue;\n const segName = data?.frag?.relurl ?? data?.frag?.url ?? \"\";\n this.pushAdInsertionDebug(\"scte35_inserted\", segName, {\n detail: `len=${bytes.length}B`\n });\n }\n });\n this.hls.on(import_hls.default.Events.ERROR, (_evt, data) => {\n if (data?.fatal) {\n switch (data.type) {\n case import_hls.default.ErrorTypes.NETWORK_ERROR:\n this.hls?.startLoad();\n break;\n case import_hls.default.ErrorTypes.MEDIA_ERROR:\n this.hls?.recoverMediaError();\n break;\n default:\n this.destroy();\n break;\n }\n }\n });\n this.hls.attachMedia(this.video);\n }\n getAdSource() {\n return \"vast\";\n }\n attachAdLayerEventListeners() {\n this.adLayer.on(\"ad_impression\", () => {\n if (this.config.licenseKey) {\n sendAdImpressionTracking(this.config.licenseKey, {\n source: this.getAdSource(),\n adIndex: this.currentAdIndex,\n timestamp: (/* @__PURE__ */ new Date()).toISOString()\n });\n }\n });\n this.adLayer.on(\"ad_error\", (errorPayload) => {\n let errorMessage = \"Ad playback failed\";\n if (errorPayload) {\n const errorCode = errorPayload.code || errorPayload.errorCode || \"unknown\";\n const vastErrorCode = errorPayload.vastErrorCode;\n const message = errorPayload.message || errorPayload.errorMessage || \"Unknown error\";\n const cause = errorPayload.cause || errorPayload.innerError || errorPayload.error;\n errorMessage = `Ad error: AdError ${errorCode}: ${message}`;\n if (vastErrorCode && vastErrorCode !== \"N/A\" && vastErrorCode !== errorCode) {\n errorMessage += ` (VAST Error Code: ${vastErrorCode})`;\n }\n if (cause) {\n const causeMessage = typeof cause === \"string\" ? cause : cause.message || String(cause);\n errorMessage += `. Caused by: ${causeMessage}`;\n }\n }\n this.pushDebugLog(\"error\", \"ad\", errorMessage, {\n ...errorPayload ? { payload: errorPayload } : {}\n });\n console.error(\"[AD-ERROR]\", errorMessage, errorPayload || \"\");\n this.adLayer.stop().catch(() => {\n });\n this.handleAdFailure();\n });\n this.adLayer.on(\"content_pause\", () => {\n this.clearAdFailsafeTimer();\n this.clearAdRequestWatchdog();\n this.activeAdRequestToken = null;\n this.showAds = true;\n if (this.config.disableFiller) {\n if (this.savedMutedStateBeforeAd == null) {\n this.savedMutedStateBeforeAd = { muted: this.video.muted, volume: this.video.volume };\n this.adLayer.updateOriginalMutedState(this.video.muted, this.video.volume);\n }\n if (!this.video.muted) {\n this.video.muted = true;\n this.video.volume = 0;\n }\n this.adLayer.showPlaceholder();\n }\n if (this.inAdBreak && this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {\n this.scheduleAdStopCountdown(this.getRemainingAdMs());\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Starting ad break timer on content_pause (first ad starting)\");\n }\n }\n this.adLayer.setAdVolume(\n this.adLayer.getOriginalMutedState() ? 1 : this.adLayer.getOriginalVolume()\n );\n this.stopFillerBreakTimer();\n this.hidePlaceholderLayer();\n this.isShowingPlaceholder = false;\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Hiding placeholder - new ads starting\");\n }\n });\n this.adLayer.on(\"content_resume\", () => {\n const remaining = this.getRemainingAdMs();\n const breakMuted = this.savedMutedStateBeforeAd?.muted ?? this.adLayer.getOriginalMutedState();\n const breakVolume = this.savedMutedStateBeforeAd?.volume ?? this.adLayer.getOriginalVolume();\n if (this.config.debugAdTiming) {\n console.log(\n \"[StormcloudVideoPlayer] content_resume received, inAdBreak=%s, remaining=%s, preloadedTokens=%d, pendingNext=%s\",\n this.inAdBreak,\n remaining,\n this.preloadedTokens.length,\n !!this.pendingNextAdBids\n );\n }\n this.clearAdFailsafeTimer();\n this.clearAdRequestWatchdog();\n this.activeAdRequestToken = null;\n this.showAds = false;\n if (!this.inAdBreak) {\n this.video.style.visibility = \"visible\";\n this.video.style.opacity = \"1\";\n this.syncMainContentAudioWhenVisible();\n return;\n }\n this.consecutiveFailures = 0;\n if (!this.config.disableFiller && !this.video.muted) {\n this.video.muted = true;\n this.video.volume = 0;\n }\n if (this.preloadedTokens.length > 0) {\n const token = this.preloadedTokens.shift();\n const remainingNow = this.getRemainingAdMs();\n if (this.expectedAdBreakDurationMs != null && remainingNow < this.MIN_AD_REMAINING_MS) {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] content_resume: skip preloaded ad, only\", remainingNow, \"ms left\");\n }\n this.adLayer.cancelPreload(token);\n } else {\n if (!this.config.singlePipelineMode) {\n this.showPlaceholderLayer();\n }\n this.adLayer.showPlaceholder();\n this.isInAdTransition = true;\n setTimeout(() => {\n this.isInAdTransition = false;\n if (!this.inAdBreak) return;\n this.currentAdIndex++;\n this.adLayer.playPreloaded(token).catch((err) => {\n if (this.config.debugAdTiming) console.warn(\"[StormcloudVideoPlayer] playPreloaded failed:\", err);\n this.handleAdFailure();\n });\n }, this.adTransitionGapMs);\n return;\n }\n }\n if (this.pendingNextAdBids && this.pendingNextAdBids.length > 0) {\n const bids = [...this.pendingNextAdBids];\n this.pendingNextAdBids = null;\n const remainingNow = this.getRemainingAdMs();\n if (this.expectedAdBreakDurationMs != null && remainingNow < this.MIN_AD_REMAINING_MS) {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] content_resume: skip pending bids, only\", remainingNow, \"ms left\");\n }\n } else {\n if (!this.config.singlePipelineMode) {\n this.showPlaceholderLayer();\n }\n this.adLayer.showPlaceholder();\n this.isInAdTransition = true;\n setTimeout(() => {\n this.isInAdTransition = false;\n if (!this.inAdBreak || bids.length === 0) return;\n const freshBids = this.pendingNextAdBids ?? bids;\n this.pendingNextAdBids = null;\n this.currentAdIndex++;\n this.adLayer.playAd(freshBids).catch((err) => {\n if (this.config.debugAdTiming) console.warn(\"[StormcloudVideoPlayer] playAd(pending) failed:\", err);\n this.handleAdFailure();\n });\n }, this.adTransitionGapMs);\n return;\n }\n }\n const remainingFinal = this.getRemainingAdMs();\n if (this.inAdBreak && remainingFinal > this.MIN_AD_REMAINING_MS) {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] content_resume: ad ended/failed with time remaining, showing filler and continuing fetch for\", remainingFinal, \"ms\");\n }\n if (!this.config.disableFiller) {\n this.showPlaceholderLayer();\n this.adLayer.showPlaceholder();\n } else {\n this.adLayer.hidePlaceholder();\n if (this.video.muted !== breakMuted) {\n this.video.muted = breakMuted;\n }\n if (Math.abs(this.video.volume - breakVolume) > 0.01) {\n this.video.volume = breakVolume;\n }\n if (this.video.paused) {\n this.video.play()?.catch(() => {\n });\n }\n }\n this.continuousFetchingActive = true;\n this.startContinuousFetchLoop();\n return;\n }\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] content_resume: no more ads, ending ad pod\");\n }\n this.handleAdPodComplete();\n });\n }\n ensureFillerVideo() {\n if (this.fillerVideo) return;\n if (!this.video.parentElement) return;\n const filler = document.createElement(\"video\");\n filler.src = \"https://f000.backblazeb2.com/file/AdStormAds/384/Sonifi_Filler.mp4\";\n filler.loop = true;\n filler.muted = false;\n filler.playsInline = true;\n filler.style.position = \"absolute\";\n filler.style.left = \"0\";\n filler.style.top = \"0\";\n filler.style.width = \"100%\";\n filler.style.height = \"100%\";\n filler.style.objectFit = \"cover\";\n filler.style.zIndex = \"20\";\n filler.style.display = \"none\";\n filler.preload = \"auto\";\n this.video.parentElement.appendChild(filler);\n this.fillerVideo = filler;\n }\n showPlaceholderLayer() {\n if (this.config.disableFiller) return;\n this.ensureFillerVideo();\n if (!this.fillerVideo) return;\n if (!this.video.muted) {\n this.video.muted = true;\n this.video.volume = 0;\n }\n this.fillerVideo.style.display = \"block\";\n this.fillerVideo.play().catch(() => {\n if (this.fillerVideo) {\n this.fillerVideo.style.display = \"none\";\n }\n if (!this.adLayer.isAdPlaying()) {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Filler video failed \\u2014 restoring main video\");\n }\n this.adLayer.hidePlaceholder();\n if (this.video.paused && this.video.readyState >= 2) {\n this.video.play()?.catch(() => {\n });\n }\n }\n });\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Showing filler video layer\");\n }\n }\n hidePlaceholderLayer() {\n if (!this.fillerVideo) return;\n this.fillerVideo.style.display = \"none\";\n this.fillerVideo.pause();\n this.fillerVideo.currentTime = 0;\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Hiding filler video layer\");\n }\n }\n startFillerBreakTimer(durationMs) {\n this.stopFillerBreakTimer();\n this.showPlaceholderLayer();\n this.fillerBreakTimerId = setTimeout(() => {\n this.fillerBreakTimerId = void 0;\n this.hidePlaceholderLayer();\n if (this.inAdBreak) this.handleAdPodComplete();\n }, durationMs);\n }\n stopFillerBreakTimer() {\n if (this.fillerBreakTimerId !== void 0) {\n clearTimeout(this.fillerBreakTimerId);\n this.fillerBreakTimerId = void 0;\n }\n }\n attach() {\n if (this.attached) return;\n this.attached = true;\n this.video.autoplay = !!this.config.autoplay;\n this.video.muted = !!this.config.muted;\n if (!this.config.disableAds) {\n this.adLayer.initialize();\n if (!this.config.disableFiller) {\n this.ensureFillerVideo();\n }\n this.adLayer.updateOriginalMutedState(this.video.muted, this.video.volume);\n this.attachAdLayerEventListeners();\n }\n this.timeUpdateHandler = () => {\n this.onTimeUpdate(this.video.currentTime);\n };\n this.video.addEventListener(\"timeupdate\", this.timeUpdateHandler);\n this.emptiedHandler = () => {\n if (this.nativeHlsMode && this.videoSrcProtection && !this.adLayer.isAdPlaying()) {\n if (this.config.debugAdTiming) {\n console.log(\n \"[StormcloudVideoPlayer] Video src was cleared, restoring:\",\n this.videoSrcProtection\n );\n }\n const currentTime = this.video.currentTime;\n const wasPaused = this.video.paused;\n this.video.src = this.videoSrcProtection;\n this.video.currentTime = currentTime;\n if (!wasPaused) {\n this.video.play().catch(() => {\n });\n }\n }\n };\n this.video.addEventListener(\"emptied\", this.emptiedHandler);\n }\n shouldUseNativeHls() {\n const streamType = this.getStreamType();\n if (streamType === \"other\") {\n return true;\n }\n const canNative = this.video.canPlayType(\"application/vnd.apple.mpegurl\");\n return !!(this.config.allowNativeHls && canNative);\n }\n initializeTracking() {\n sendInitialTracking(this.config.licenseKey).then(() => {\n this.heartbeatInterval = window.setInterval(() => {\n this.sendHeartbeatIfNeeded();\n }, 5e3);\n }).catch((error) => {\n if (this.config.debugAdTiming) {\n console.warn(\n \"[StormcloudVideoPlayer] Failed to send initial tracking:\",\n error\n );\n }\n this.heartbeatInterval = window.setInterval(() => {\n this.sendHeartbeatIfNeeded();\n }, 5e3);\n });\n }\n sendHeartbeatIfNeeded() {\n const now = Date.now();\n if (!this.lastHeartbeatTime || now - this.lastHeartbeatTime > 3e4) {\n this.lastHeartbeatTime = now;\n sendHeartbeat(this.config.licenseKey).catch((error) => {\n if (this.config.debugAdTiming) {\n console.warn(\n \"[StormcloudVideoPlayer] Failed to send heartbeat:\",\n error\n );\n }\n });\n }\n }\n getCurrentAdIndex() {\n return this.currentAdIndex;\n }\n getTotalAdsInBreak() {\n return this.totalAdsInBreak;\n }\n getRemainingAdSeconds() {\n const remainingMs = this.getRemainingAdMs();\n if (!Number.isFinite(remainingMs) || remainingMs <= 0 || remainingMs === Number.MAX_SAFE_INTEGER) {\n return 0;\n }\n return Math.ceil(remainingMs / 1e3);\n }\n isAdPlaying() {\n return this.inAdBreak && this.adLayer.isAdPlaying();\n }\n isShowingAds() {\n return this.showAds;\n }\n syncMainContentAudioWhenVisible() {\n const adLayerShowing = this.showAds || this.adLayer.isAdPlaying();\n if (adLayerShowing) return;\n const muted = this.adLayer.getOriginalMutedState();\n const volume = this.adLayer.getOriginalVolume();\n if (this.video.muted !== muted) this.video.muted = muted;\n if (Math.abs(this.video.volume - volume) > 0.01) this.video.volume = volume;\n }\n getStreamType() {\n const url = this.config.src.toLowerCase();\n if (url.includes(\".m3u8\") || url.includes(\"/hls/\") || url.includes(\"application/vnd.apple.mpegurl\")) {\n return \"hls\";\n }\n return \"other\";\n }\n shouldShowNativeControls() {\n const streamType = this.getStreamType();\n if (streamType === \"other\") {\n return !(this.config.showCustomControls ?? false);\n }\n return !!(this.config.allowNativeHls && !(this.config.showCustomControls ?? false));\n }\n shouldContinueLiveStreamDuringAds() {\n if (this.config.allowNativeHls) {\n return false;\n }\n if (!this.isLiveStream) {\n return false;\n }\n if (this.config.singlePipelineMode) {\n return false;\n }\n const browser = detectBrowser();\n if (browser.isSmartTV) {\n return false;\n }\n return true;\n }\n startAdPrefetch(durationSeconds, fragmentSn) {\n if (this.config.disableAds) return;\n if (this.pendingAdBreak || this.inAdBreak) {\n return;\n }\n this.pendingAdBreak = {\n ...durationSeconds !== void 0 ? { durationSeconds } : {},\n ...fragmentSn !== void 0 ? { detectedAtFragmentSn: fragmentSn } : {},\n isFetching: false,\n fetchStartTime: Date.now()\n };\n void this.runAdPrefetch(durationSeconds);\n if (this.config.debugAdTiming) {\n console.log(\"[PREFETCH] Ad break registered, multi-ad prefetch started\");\n }\n }\n async runAdPrefetch(durationSeconds) {\n const durSec = durationSeconds ?? 60;\n const context = {\n breakDurationSec: durSec,\n remainingBreakSec: durSec\n };\n let firstBids;\n try {\n firstBids = await this.adRequest({ ...context, adIndex: 1 });\n } catch {\n firstBids = [];\n }\n if (this.inAdBreak) return;\n if (firstBids.length === 0) {\n if (this.config.debugAdTiming) {\n console.log(\"[PREFETCH] First VAST request returned no ad, aborting prefetch\");\n }\n this.clearPendingAdBreak();\n return;\n }\n const adDurationSec = firstBids[0]?.durationSec ?? 30;\n const estimatedCount = Math.max(1, Math.ceil(durSec / adDurationSec));\n if (this.config.debugAdTiming) {\n console.log(\n `[PREFETCH] Ad duration=${adDurationSec}s, break=${durSec}s \\u2192 ${estimatedCount} ad(s) needed`\n );\n }\n const firstToken = `preload_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;\n try {\n await this.adLayer.preloadAd(firstBids, firstToken);\n if (!this.inAdBreak) {\n this.preloadedTokens.push(firstToken);\n if (this.config.debugAdTiming) {\n console.log(`[PREFETCH] First ad preloaded and queued, token=${firstToken}`);\n }\n }\n } catch {\n if (this.config.debugAdTiming) {\n console.warn(`[PREFETCH] First ad preload failed, token=${firstToken}`);\n }\n }\n if (estimatedCount > 1) {\n const remaining = Array.from(\n { length: estimatedCount - 1 },\n (_, i) => this.adRequest({ ...context, adIndex: i + 2 }).then((bids) => ({ ok: true, value: bids })).catch(() => ({ ok: false }))\n );\n const results = await Promise.all(remaining);\n for (const result of results) {\n if (this.inAdBreak) break;\n if (result.ok && result.value.length > 0) {\n const token = `preload_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;\n try {\n await this.adLayer.preloadAd(result.value, token);\n if (!this.inAdBreak) {\n this.preloadedTokens.push(token);\n if (this.config.debugAdTiming) {\n console.log(`[PREFETCH] Additional ad preloaded and queued, token=${token}`);\n }\n }\n } catch {\n if (this.config.debugAdTiming) {\n console.warn(`[PREFETCH] Additional ad preload failed, token=${token}`);\n }\n }\n }\n }\n }\n if (this.config.debugAdTiming) {\n console.log(`[PREFETCH] Pre-fetch complete: ${this.preloadedTokens.length} ad(s) queued`);\n }\n }\n clearPendingAdBreak() {\n if (this.prefetchTimerId != null) {\n clearTimeout(this.prefetchTimerId);\n this.prefetchTimerId = void 0;\n }\n this.pendingAdBreak = null;\n }\n cancelAndClearPreloadedTokens() {\n for (const token of this.preloadedTokens) {\n this.adLayer.cancelPreload(token);\n }\n this.preloadedTokens = [];\n }\n startAdInsertionPolling() {\n if (this.adInsertionPollingId != null) return;\n this.fetchAdInsertionPoint();\n this.adInsertionPollingId = window.setInterval(() => {\n this.fetchAdInsertionPoint();\n }, 1e3);\n }\n stopAdInsertionPolling() {\n if (this.adInsertionPollingId != null) {\n clearInterval(this.adInsertionPollingId);\n this.adInsertionPollingId = void 0;\n }\n }\n async fetchAdInsertionPoint() {\n if (!this.config.projectId) return;\n try {\n const resp = await fetch(\n `https://adstorm.co/api-adstorm-dev/adstorm/swirl/projects/${encodeURIComponent(this.config.projectId)}/ad-insertion-point`\n );\n if (!resp.ok) return;\n const data = await resp.json();\n const prevSegment = this.lastAdInsertionPoint?.segment_ts_name;\n const isNew = data.updated_at !== this.lastAdInsertionPoint?.updated_at;\n const segmentChanged = prevSegment !== data.segment_ts_name;\n this.lastAdInsertionPoint = data;\n if (isNew) {\n this.pushAdInsertionDebug(\"api_response\", data.segment_ts_name, {\n offsetSeconds: data.offset_seconds,\n updatedAt: data.updated_at,\n detail: `project=${data.project_id}`\n });\n if (segmentChanged && (this.pendingAdBreak || this.adInsertionOffsetTimerId != null)) {\n this.clearAdInsertionOffsetTimer();\n this.clearPendingAdBreak();\n this.cancelAndClearPreloadedTokens();\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Insertion segment changed (${prevSegment} \\u2192 ${data.segment_ts_name}), stale pending state cleared`\n );\n }\n }\n this.checkAdInsertionInManifest();\n }\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Ad insertion point API response:\", data);\n }\n } catch {\n if (this.config.debugAdTiming) {\n console.warn(\"[StormcloudVideoPlayer] Ad insertion point API fetch failed\");\n }\n }\n }\n checkAdInsertionInManifest() {\n if (!this.lastAdInsertionPoint) return;\n if (this.inAdBreak || this.pendingAdBreak) return;\n if (this.lastAdInsertionPoint.updated_at === this.processedAdInsertionUpdatedAt) return;\n const segmentName = this.lastAdInsertionPoint.segment_ts_name;\n const levels = this.hls?.levels;\n if (!levels) return;\n for (const level of levels) {\n const fragments = level.details?.fragments;\n if (!Array.isArray(fragments)) continue;\n for (const frag of fragments) {\n if (this.fragmentMatchesSegment(frag, segmentName)) {\n const currentTime = this.video.currentTime;\n const fragStart = frag.start ?? 0;\n const fragDuration = frag.duration ?? 0;\n const isCurrentlyPlaying = fragDuration > 0 && currentTime >= fragStart && currentTime < fragStart + fragDuration;\n this.pushAdInsertionDebug(\"segment_found\", segmentName, {\n detail: `sn=${frag?.sn ?? \"?\"} ${isCurrentlyPlaying ? \"(playing)\" : \"(future)\"}`\n });\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Ad insertion segment \"${segmentName}\" found in manifest \\u2014 ` + (isCurrentlyPlaying ? \"currently playing, scheduling directly\" : \"starting pre-fetch\")\n );\n }\n this.startAdPrefetch(60, frag?.sn);\n if (isCurrentlyPlaying && !this.inAdBreak) {\n this.processedAdInsertionUpdatedAt = this.lastAdInsertionPoint.updated_at;\n const rawOffsetMs = (this.lastAdInsertionPoint.offset_seconds ?? 0) * 1e3;\n const elapsedInFragMs = (currentTime - fragStart) * 1e3;\n const remainingOffsetMs = Math.max(0, rawOffsetMs - elapsedInFragMs);\n this.pushAdInsertionDebug(\"segment_playing\", segmentName, {\n offsetSeconds: this.lastAdInsertionPoint.offset_seconds,\n detail: `sn=${frag?.sn ?? \"?\"} (caught in manifest check)`\n });\n this.pushAdInsertionDebug(\"ad_scheduled\", segmentName, {\n offsetSeconds: this.lastAdInsertionPoint.offset_seconds,\n detail: `in ${remainingOffsetMs}ms (adjusted for elapsed ${Math.round(elapsedInFragMs)}ms)`\n });\n this.clearAdInsertionOffsetTimer();\n this.adInsertionOffsetTimerId = window.setTimeout(() => {\n this.adInsertionOffsetTimerId = void 0;\n if (this.inAdBreak) return;\n this.pushAdInsertionDebug(\"ad_triggered\", segmentName, {\n detail: \"ad break started (60s, via manifest-check path)\"\n });\n void this.handleAdStart(60);\n }, remainingOffsetMs);\n }\n return;\n }\n }\n }\n }\n fragmentMatchesSegment(frag, segmentName) {\n const rawUrl = frag?.url || frag?.relurl || \"\";\n const url = rawUrl.split(\"?\")[0] ?? \"\";\n const name = segmentName.startsWith(\"/\") ? segmentName : \"/\" + segmentName;\n return url.endsWith(name) || url.includes(name);\n }\n clearAdInsertionOffsetTimer() {\n if (this.adInsertionOffsetTimerId != null) {\n clearTimeout(this.adInsertionOffsetTimerId);\n this.adInsertionOffsetTimerId = void 0;\n }\n }\n startContinuousFetchLoop() {\n if (this.continuousFetchLoopPromise != null) return;\n this.continuousFetchLoopPromise = this.runContinuousFetchLoop();\n }\n async runContinuousFetchLoop() {\n const backoffMs = () => {\n const mult = Math.pow(2, this.consecutiveFailures);\n return Math.min(this.backoffBaseMs * mult, this.maxBackoffMs);\n };\n while (this.inAdBreak && this.continuousFetchingActive) {\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) break;\n if (this.totalAdRequestsInBreak >= this.maxTotalAdRequestsPerBreak) break;\n if (this.adLayer.isAdPlaying() || this.isInAdTransition) {\n if (this.pendingNextAdBids == null) {\n try {\n const remaining = this.getRemainingAdMs();\n const prefetchContext = this.expectedAdBreakDurationMs != null ? {\n breakDurationSec: this.expectedAdBreakDurationMs / 1e3,\n remainingBreakSec: remaining / 1e3,\n adIndex: this.currentAdIndex + 1\n } : void 0;\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Pre-fetching next ad during playback, remaining:\", remaining, \"ms\");\n }\n const bids = await this.adRequest(prefetchContext);\n this.lastAdRequestTime = Date.now();\n if (!this.inAdBreak) break;\n if (bids.length > 0) {\n this.consecutiveFailures = 0;\n this.pendingNextAdBids = bids;\n this.totalAdsInBreak = Math.max(\n this.totalAdsInBreak,\n this.currentAdIndex + this.preloadedTokens.length + 1\n );\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Pre-fetched next ad stored as pending\");\n }\n } else {\n this.consecutiveFailures++;\n }\n } catch (err) {\n this.consecutiveFailures++;\n if (this.config.debugAdTiming) {\n console.warn(\"[CONTINUOUS-FETCH] Pre-fetch adRequest failed:\", err);\n }\n }\n } else {\n await new Promise((r) => setTimeout(r, 200));\n }\n continue;\n }\n if (this.pendingNextAdBids != null && this.pendingNextAdBids.length > 0) {\n const bids = this.pendingNextAdBids;\n this.pendingNextAdBids = null;\n const remainingNow = this.getRemainingAdMs();\n if (this.expectedAdBreakDurationMs == null || remainingNow >= this.MIN_AD_REMAINING_MS) {\n this.currentAdIndex++;\n if (this.config.licenseKey) {\n sendAdLoadedTracking(this.config.licenseKey, {\n source: this.getAdSource(),\n timestamp: (/* @__PURE__ */ new Date()).toISOString()\n });\n }\n await this.adLayer.playAd(bids);\n if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {\n this.scheduleAdStopCountdown(this.getRemainingAdMs());\n }\n this.adLayer.setAdVolume(\n this.adLayer.getOriginalMutedState() ? 1 : this.adLayer.getOriginalVolume()\n );\n } else if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Discarding pre-fetched bids: only\", remainingNow, \"ms left\");\n }\n continue;\n }\n const urgentNeedAd = this.inAdBreak && !this.adLayer.isAdPlaying();\n const delay = this.lastAdRequestTime ? this.minAdRequestIntervalMs + (!urgentNeedAd && this.consecutiveFailures > 0 ? backoffMs() : 0) : 0;\n const elapsed = Date.now() - this.lastAdRequestTime;\n if (elapsed < delay && this.lastAdRequestTime > 0) {\n await new Promise((r) => setTimeout(r, delay - elapsed));\n }\n if (!this.inAdBreak || !this.continuousFetchingActive) break;\n try {\n const remaining = this.getRemainingAdMs();\n const context = this.expectedAdBreakDurationMs != null ? {\n breakDurationSec: this.expectedAdBreakDurationMs / 1e3,\n remainingBreakSec: remaining / 1e3,\n adIndex: this.currentAdIndex + 1\n } : void 0;\n const bids = await this.adRequest(context);\n this.lastAdRequestTime = Date.now();\n if (!this.inAdBreak) break;\n if (bids.length > 0) {\n this.consecutiveFailures = 0;\n if (this.adLayer.isAdPlaying() || this.isInAdTransition) {\n this.pendingNextAdBids = bids;\n this.totalAdsInBreak = Math.max(\n this.totalAdsInBreak,\n this.currentAdIndex + this.preloadedTokens.length + 1\n );\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Next ad response stored (ad currently playing or in transition)\");\n }\n } else {\n const remainingNow = this.getRemainingAdMs();\n if (this.expectedAdBreakDurationMs != null && remainingNow < this.MIN_AD_REMAINING_MS) {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Skipping ad from loop: only\", remainingNow, \"ms left\");\n }\n } else {\n this.currentAdIndex++;\n if (this.config.licenseKey) {\n sendAdLoadedTracking(this.config.licenseKey, {\n source: this.getAdSource(),\n timestamp: (/* @__PURE__ */ new Date()).toISOString()\n });\n }\n await this.adLayer.playAd(bids);\n if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {\n this.scheduleAdStopCountdown(this.getRemainingAdMs());\n }\n this.adLayer.setAdVolume(\n this.adLayer.getOriginalMutedState() ? 1 : this.adLayer.getOriginalVolume()\n );\n }\n }\n } else {\n this.consecutiveFailures++;\n }\n } catch (err) {\n this.consecutiveFailures++;\n if (this.config.debugAdTiming) {\n console.warn(\"[CONTINUOUS-FETCH] adRequest failed:\", err);\n }\n }\n const sleepMs = this.inAdBreak && !this.adLayer.isAdPlaying() ? 0 : backoffMs();\n await new Promise((r) => setTimeout(r, sleepMs));\n }\n this.continuousFetchLoopPromise = null;\n }\n async handleAdStart(durationSeconds) {\n const adBreakDurationMs = durationSeconds != null ? durationSeconds * 1e3 : void 0;\n if (this.config.debugAdTiming) {\n const mode = this.isLiveStream ? \"LIVE\" : \"VOD\";\n console.log(\n `[CONTINUOUS-FETCH] \\u{1F4FA} ${mode} MODE: Target duration=${adBreakDurationMs}ms`\n );\n }\n this.consecutiveFailures = 0;\n this.continuousFetchingActive = true;\n this.continuousFetchLoopPromise = null;\n this.pendingNextAdBids = null;\n this.isShowingPlaceholder = false;\n this.totalAdRequestsInBreak = 0;\n if (this.savedMutedStateBeforeAd == null && !this.video.muted) {\n this.savedMutedStateBeforeAd = {\n muted: false,\n volume: this.video.volume\n };\n }\n const state = this.savedMutedStateBeforeAd ?? {\n muted: this.video.muted,\n volume: this.video.volume\n };\n this.adLayer.updateOriginalMutedState(state.muted, state.volume);\n if (!this.config.disableFiller && !this.video.muted) {\n this.video.muted = true;\n this.video.volume = 0;\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Muted video in handleAdStart\");\n }\n }\n this.inAdBreak = true;\n this.currentAdBreakStartWallClockMs = Date.now();\n this.currentAdIndex = 0;\n this.totalAdsInBreak = Math.max(1, this.preloadedTokens.length);\n this.adPodQueue = [];\n if (!this.config.disableFiller) this.showAds = true;\n if (adBreakDurationMs != null) {\n this.startFillerBreakTimer(adBreakDurationMs);\n } else if (!this.config.disableFiller && this.preloadedTokens.length === 0) {\n this.showPlaceholderLayer();\n }\n if (!this.config.disableFiller) this.adLayer.showPlaceholder();\n if (this.expectedAdBreakDurationMs == null && adBreakDurationMs != null) {\n this.expectedAdBreakDurationMs = adBreakDurationMs;\n }\n if (this.expectedAdBreakDurationMs != null) {\n this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);\n }\n this.clearPendingAdBreak();\n const adBreakToken = Date.now();\n this.activeAdRequestToken = adBreakToken;\n this.startAdFailsafeTimer(adBreakToken);\n this.startAdRequestWatchdog(adBreakToken);\n const adVolume = state.muted ? 1 : state.volume;\n if (this.preloadedTokens.length > 0) {\n const token = this.preloadedTokens.shift();\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] \\u2705 Playing pre-buffered ad, token=\", token);\n }\n const remaining = this.getRemainingAdMs();\n if (this.expectedAdBreakDurationMs == null || remaining >= this.MIN_AD_REMAINING_MS) {\n this.currentAdIndex++;\n if (this.config.licenseKey) {\n sendAdLoadedTracking(this.config.licenseKey, {\n source: this.getAdSource(),\n timestamp: (/* @__PURE__ */ new Date()).toISOString()\n });\n }\n try {\n await this.adLayer.playPreloaded(token);\n if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {\n this.scheduleAdStopCountdown(this.getRemainingAdMs());\n }\n this.adLayer.setAdVolume(adVolume);\n } catch (err) {\n if (this.config.debugAdTiming) console.warn(\"[CONTINUOUS-FETCH] playPreloaded failed:\", err);\n this.consecutiveFailures++;\n await this.showPlaceholderAndWaitForAds();\n }\n } else {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Skipping ad: only\", remaining, \"ms left in break\");\n }\n this.adLayer.cancelPreload(token);\n await this.showPlaceholderAndWaitForAds();\n }\n }\n this.startContinuousFetchLoop();\n }\n stopContinuousFetching() {\n this.continuousFetchingActive = false;\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] \\u{1F6D1} Stopping continuous ad fetching\");\n }\n }\n async tryNextAvailableAdWithRateLimit() {\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) {\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] \\u{1F6D1} Too many consecutive failures (${this.consecutiveFailures}), ending ad break gracefully`);\n }\n this.handleAdPodComplete();\n return;\n }\n const backoffMultiplier = Math.pow(2, this.consecutiveFailures);\n const backoffDelay = Math.min(this.backoffBaseMs * backoffMultiplier, this.maxBackoffMs);\n const effectiveMinInterval = this.minAdRequestIntervalMs + (this.consecutiveFailures > 0 ? backoffDelay : 0);\n const timeSinceLastRequest = Date.now() - this.lastAdRequestTime;\n if (timeSinceLastRequest < effectiveMinInterval) {\n const waitTime = effectiveMinInterval - timeSinceLastRequest;\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] \\u23F3 Rate limiting: waiting ${waitTime}ms before next request (backoff: ${this.consecutiveFailures} failures)`);\n }\n await new Promise((resolve) => setTimeout(resolve, waitTime));\n }\n return this.tryNextAvailableAd(0);\n }\n async tryNextAvailableAd(_retryCount = 0) {\n if (this.totalAdRequestsInBreak >= this.maxTotalAdRequestsPerBreak) {\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] \\u{1F6D1} Max ad requests per break (${this.maxTotalAdRequestsPerBreak}) reached`);\n }\n this.handleAdPodComplete();\n return;\n }\n const remaining = this.getRemainingAdMs();\n if (remaining <= 500 && this.expectedAdBreakDurationMs != null) {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] \\u23F9\\uFE0F No time remaining, ending ad break\");\n }\n this.handleAdPodComplete();\n return;\n }\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) {\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] \\u{1F6D1} Too many consecutive failures (${this.consecutiveFailures}), ending ad break`);\n }\n this.handleAdPodComplete();\n return;\n }\n try {\n this.lastAdRequestTime = Date.now();\n const bids = await this.adRequest();\n if (!this.inAdBreak) return;\n if (bids.length > 0) {\n this.consecutiveFailures = 0;\n this.currentAdIndex++;\n this.totalAdRequestsInBreak++;\n if (this.adLayer.isAdPlaying() || this.isInAdTransition) {\n this.pendingNextAdBids = bids;\n this.totalAdsInBreak = Math.max(\n this.totalAdsInBreak,\n this.currentAdIndex + this.preloadedTokens.length\n );\n } else {\n if (this.config.licenseKey) {\n sendAdLoadedTracking(this.config.licenseKey, {\n source: this.getAdSource(),\n timestamp: (/* @__PURE__ */ new Date()).toISOString()\n });\n }\n await this.adLayer.playAd(bids);\n if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {\n this.scheduleAdStopCountdown(this.getRemainingAdMs());\n }\n this.adLayer.setAdVolume(\n this.adLayer.getOriginalMutedState() ? 1 : this.adLayer.getOriginalVolume()\n );\n }\n } else {\n this.consecutiveFailures++;\n await this.showPlaceholderAndWaitForAds();\n }\n } catch (error) {\n this.consecutiveFailures++;\n if (this.config.debugAdTiming) {\n console.warn(\"[CONTINUOUS-FETCH] tryNextAvailableAd request failed:\", error);\n }\n await this.showPlaceholderAndWaitForAds();\n }\n }\n async showPlaceholderAndWaitForAds() {\n const remaining = this.getRemainingAdMs();\n const waitTime = Math.min(this.maxPlaceholderDurationMs, remaining);\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) {\n const stillRemaining2 = this.getRemainingAdMs();\n if (stillRemaining2 >= 1e3) {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] \\u{1F6D1} Max failures reached but break still active \\u2014 resetting and continuing filler\");\n }\n this.consecutiveFailures = 0;\n return;\n }\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] \\u{1F6D1} Skipping placeholder - too many consecutive failures\");\n }\n this.handleAdPodComplete();\n return;\n }\n if (waitTime < 1e3) {\n this.handleAdPodComplete();\n return;\n }\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] \\u2B1B Showing placeholder for ${waitTime}ms while waiting for ad response`);\n }\n if (!this.config.disableFiller) {\n this.isShowingPlaceholder = true;\n this.showPlaceholderLayer();\n this.adLayer.showPlaceholder();\n }\n const checkInterval = 300;\n const maxChecks = Math.floor(waitTime / checkInterval);\n for (let i = 0; i < maxChecks; i++) {\n await new Promise((resolve) => setTimeout(resolve, checkInterval));\n if (!this.inAdBreak) return;\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] \\u{1F6D1} Too many failures during placeholder wait \\u2014 resetting and continuing filler\");\n }\n this.consecutiveFailures = 0;\n break;\n }\n if (this.pendingNextAdBids != null && this.pendingNextAdBids.length > 0) {\n const bids = this.pendingNextAdBids;\n this.pendingNextAdBids = null;\n this.isShowingPlaceholder = false;\n this.adLayer.hidePlaceholder();\n this.currentAdIndex++;\n try {\n await this.adLayer.playAd(bids);\n this.consecutiveFailures = 0;\n } catch {\n this.consecutiveFailures++;\n await this.tryNextAvailableAdWithRateLimit();\n }\n return;\n }\n if (this.adLayer.isAdPlaying()) {\n this.isShowingPlaceholder = false;\n this.adLayer.hidePlaceholder();\n return;\n }\n }\n const stillRemaining = this.getRemainingAdMs();\n if (stillRemaining >= 1e3) {\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] \\u23F0 Placeholder slot expired, ${stillRemaining}ms still remaining \\u2014 continuing filler`);\n }\n this.isShowingPlaceholder = false;\n this.adLayer.hidePlaceholder();\n this.consecutiveFailures = 0;\n return;\n }\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] \\u23F0 Placeholder timeout, ending ad break\");\n }\n this.isShowingPlaceholder = false;\n this.adLayer.hidePlaceholder();\n this.handleAdPodComplete();\n }\n onTimeUpdate(_currentTimeSec) {\n if (this.adLayer.isAdPlaying()) return;\n }\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 if (!this.inAdBreak) return;\n this.adStopTimerId = void 0;\n const adPlaying = this.adLayer.isAdPlaying();\n const pendingAds = this.adPodQueue.length > 0;\n const checkIntervalMs = Math.max(\n 250,\n Math.floor(this.config.adBreakCheckIntervalMs ?? 1e3)\n );\n const maxExtensionMsConfig = this.config.maxAdBreakExtensionMs;\n const maxExtensionMs = typeof maxExtensionMsConfig === \"number\" && maxExtensionMsConfig > 0 ? maxExtensionMsConfig : 6e4;\n let elapsedSinceStartMs = 0;\n if (this.currentAdBreakStartWallClockMs != null) {\n elapsedSinceStartMs = Date.now() - this.currentAdBreakStartWallClockMs;\n }\n const expectedDurationMs = this.expectedAdBreakDurationMs ?? 0;\n const overrunMs = Math.max(0, elapsedSinceStartMs - expectedDurationMs);\n const shouldExtendAdBreak = (adPlaying || pendingAds || this.showAds) && overrunMs < maxExtensionMs;\n if (shouldExtendAdBreak) {\n this.scheduleAdStopCountdown(checkIntervalMs);\n return;\n }\n if (adPlaying) {\n this.adLayer.stop().catch(() => {\n });\n }\n this.handleAdPodComplete();\n }\n handleAdPodComplete() {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] \\u{1F3C1} Ad pod complete - cleaning up\");\n }\n this.clearAdRequestWatchdog();\n this.clearAdFailsafeTimer();\n this.clearAdInsertionOffsetTimer();\n this.activeAdRequestToken = null;\n this.isInAdTransition = false;\n this.stopContinuousFetching();\n this.stopFillerBreakTimer();\n this.hidePlaceholderLayer();\n this.clearPendingAdBreak();\n this.cancelAndClearPreloadedTokens();\n this.pendingNextAdBids = null;\n if (this.isShowingPlaceholder) {\n this.adLayer.hidePlaceholder();\n this.isShowingPlaceholder = false;\n }\n this.inAdBreak = false;\n this.expectedAdBreakDurationMs = void 0;\n this.currentAdBreakStartWallClockMs = void 0;\n this.clearAdStopTimer();\n this.adPodQueue = [];\n this.showAds = false;\n this.currentAdIndex = 0;\n this.totalAdsInBreak = 0;\n this.totalAdRequestsInBreak = 0;\n this.consecutiveFailures = 0;\n const restoredMuted = this.savedMutedStateBeforeAd?.muted ?? this.adLayer.getOriginalMutedState();\n const restoredVolume = this.savedMutedStateBeforeAd?.volume ?? this.adLayer.getOriginalVolume();\n this.adLayer.updateOriginalMutedState(restoredMuted, restoredVolume);\n this.adLayer.stop().catch(() => {\n });\n if (this.video.muted !== restoredMuted) {\n this.video.muted = restoredMuted;\n }\n if (Math.abs(this.video.volume - restoredVolume) > 0.01) {\n this.video.volume = restoredVolume;\n }\n const browser = detectBrowser();\n const isSmartTV = browser.tizenVersion !== void 0 || browser.webOSVersion !== void 0 || !!this.config.singlePipelineMode;\n if (isSmartTV && this.hls) {\n const hlsRef = this.hls;\n const savedMuted = restoredMuted;\n const savedVolume = restoredVolume;\n const videoRef = this.video;\n const debugEnabled = this.config.debugAdTiming;\n const tryPlay = (attempt) => {\n if (this.inAdBreak || this.adLayer.isAdPlaying()) return;\n videoRef.play()?.catch(() => {\n if (attempt < 3) {\n if (debugEnabled) {\n console.log(`[StormcloudVideoPlayer] Smart TV: play() retry ${attempt + 1}/3 in ${500 * (attempt + 1)}ms`);\n }\n setTimeout(() => tryPlay(attempt + 1), 500 * (attempt + 1));\n }\n });\n };\n const onManifestParsedRestore = () => {\n hlsRef.off(import_hls.default.Events.MANIFEST_PARSED, onManifestParsedRestore);\n if (!this.inAdBreak && !this.adLayer.isAdPlaying()) {\n if (videoRef.muted !== savedMuted) videoRef.muted = savedMuted;\n if (Math.abs(videoRef.volume - savedVolume) > 0.01) videoRef.volume = savedVolume;\n if (debugEnabled) {\n console.log(\"[StormcloudVideoPlayer] Smart TV: audio state restored on MANIFEST_PARSED after re-attach\");\n }\n hlsRef.startLoad(-1);\n if (debugEnabled) {\n console.log(\"[StormcloudVideoPlayer] Smart TV: seeking to live edge and resuming playback after re-attach\");\n }\n }\n };\n hlsRef.on(import_hls.default.Events.MANIFEST_PARSED, onManifestParsedRestore);\n const pipelineDelayMs = 300;\n if (debugEnabled) {\n console.log(`[StormcloudVideoPlayer] Smart TV: waiting ${pipelineDelayMs}ms for hardware pipeline release before re-attach`);\n }\n setTimeout(() => {\n if (this.inAdBreak || this.adLayer.isAdPlaying()) return;\n if (this.hls) {\n this.hls.attachMedia(this.video);\n if (debugEnabled) {\n console.log(\"[StormcloudVideoPlayer] Smart TV: re-attached HLS to video element after ad break to restore media pipeline\");\n }\n }\n }, pipelineDelayMs);\n } else {\n if (this.shouldContinueLiveStreamDuringAds()) {\n if (this.config.debugAdTiming) {\n if (this.video.paused) {\n console.log(\"[StormcloudVideoPlayer] Content video paused in live mode after ads, resuming playback\");\n } else {\n console.log(\"[StormcloudVideoPlayer] Content video already playing in live mode after ads\");\n }\n }\n this.video.play()?.catch(() => {\n });\n } else if (this.video.paused) {\n this.video.play()?.catch(() => {\n });\n }\n }\n this.syncMainContentAudioWhenVisible();\n if (!restoredMuted) {\n requestAnimationFrame(() => {\n this.syncMainContentAudioWhenVisible();\n });\n setTimeout(() => {\n this.syncMainContentAudioWhenVisible();\n }, 0);\n setTimeout(() => {\n this.syncMainContentAudioWhenVisible();\n }, 50);\n setTimeout(() => {\n this.syncMainContentAudioWhenVisible();\n }, 100);\n setTimeout(() => {\n this.syncMainContentAudioWhenVisible();\n }, 150);\n }\n if (isSmartTV && !restoredMuted) {\n [500, 1e3, 2e3, 3e3, 5e3].forEach((delay) => {\n setTimeout(() => {\n if (!this.inAdBreak && !this.adLayer.isAdPlaying()) {\n if (this.video.muted !== restoredMuted) this.video.muted = restoredMuted;\n if (Math.abs(this.video.volume - restoredVolume) > 0.01) this.video.volume = restoredVolume;\n }\n }, delay);\n });\n }\n this.savedMutedStateBeforeAd = null;\n }\n handleAdFailure() {\n this.consecutiveFailures++;\n if (this.config.debugAdTiming) {\n console.log(\n `[CONTINUOUS-FETCH] Ad failure: consecutiveFailures=${this.consecutiveFailures}`\n );\n }\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) {\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] \\u{1F6D1} Max consecutive failures reached (${this.consecutiveFailures}), ending ad break gracefully`);\n }\n this.handleAdPodComplete();\n return;\n }\n if (this.inAdBreak && !this.config.disableFiller) {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Ad failure in active break \\u2014 showing filler while awaiting next ad\");\n }\n this.showPlaceholderLayer();\n this.adLayer.showPlaceholder();\n } else if (this.inAdBreak) {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Ad failure with no filler \\u2014 restoring main video temporarily\");\n }\n this.adLayer.hidePlaceholder();\n if (!this.adLayer.isAdPlaying() && this.video.paused && this.video.readyState >= 2) {\n this.video.play()?.catch(() => {\n });\n }\n }\n }\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.handleAdFailure();\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 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 imaAdPlaying: this.adLayer.isAdPlaying()\n });\n this.handleAdFailure();\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.config.debugAdTiming) {\n return;\n }\n this.pushDebugLog(\"info\", \"ad-state\", event, extra);\n console.log(\"[StormcloudVideoPlayer][AdState]\", {\n event,\n timestamp: (/* @__PURE__ */ new Date()).toISOString(),\n showAds: this.showAds,\n adPlaying: this.adLayer.isAdPlaying(),\n inAdBreak: this.inAdBreak,\n activeAdRequestToken: this.activeAdRequestToken,\n ...extra\n });\n }\n getRemainingAdMs() {\n if (this.currentAdBreakStartWallClockMs == null) return 0;\n if (this.expectedAdBreakDurationMs == null) return Number.MAX_SAFE_INTEGER;\n const elapsed = Date.now() - this.currentAdBreakStartWallClockMs;\n return Math.max(0, this.expectedAdBreakDurationMs - elapsed);\n }\n pushDebugLog(level, category, message, details) {\n if (!this.config.debugAdTiming) return;\n this.debugLogEntries.push({\n timestampMs: Date.now(),\n level,\n category,\n message,\n ...details ? { details } : {}\n });\n if (this.debugLogEntries.length > DEBUG_HISTORY_LIMIT) {\n this.debugLogEntries = this.debugLogEntries.slice(-DEBUG_HISTORY_LIMIT);\n }\n }\n pushAdInsertionDebug(event, segmentName, opts) {\n if (!this.config.debugAdTiming) return;\n this.adInsertionDebugHistory.push({\n timestampMs: Date.now(),\n event,\n segmentName,\n ...opts?.offsetSeconds !== void 0 ? { offsetSeconds: opts.offsetSeconds } : {},\n ...opts?.updatedAt ? { updatedAt: opts.updatedAt } : {},\n ...opts?.detail ? { detail: opts.detail } : {}\n });\n if (this.adInsertionDebugHistory.length > DEBUG_HISTORY_LIMIT) {\n this.adInsertionDebugHistory = this.adInsertionDebugHistory.slice(-DEBUG_HISTORY_LIMIT);\n }\n }\n getAdInsertionDebugLog() {\n return this.adInsertionDebugHistory.slice();\n }\n getDebugLogs() {\n return this.debugLogEntries.slice();\n }\n toggleMute() {\n if (this.adLayer.isAdPlaying()) {\n const isAdCurrentlyMuted = this.adLayer.getAdVolume() === 0;\n if (isAdCurrentlyMuted) {\n const savedVolume = this.adLayer.getOriginalVolume() || 1;\n this.adLayer.setAdVolume(savedVolume);\n this.adLayer.updateOriginalMutedState(false, savedVolume);\n } else {\n const currentAdVolume = this.adLayer.getAdVolume();\n this.adLayer.setAdVolume(0);\n this.adLayer.updateOriginalMutedState(true, currentAdVolume);\n }\n if (this.config.debugAdTiming) {\n console.log(\n \"[StormcloudVideoPlayer] Mute toggle during ad:\",\n isAdCurrentlyMuted ? \"unmuted\" : \"muted\"\n );\n }\n } else {\n this.video.muted = !this.video.muted;\n this.adLayer.updateOriginalMutedState(this.video.muted, this.video.volume);\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Muted:\", this.video.muted);\n }\n }\n }\n toggleFullscreen() {\n return new Promise((resolve, reject) => {\n if (!document.fullscreenElement) {\n const container = this.video.parentElement;\n if (!container) {\n reject(new Error(\"No parent container found for fullscreen\"));\n return;\n }\n container.requestFullscreen().then(() => {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Entered fullscreen\");\n }\n resolve();\n }).catch((err) => {\n if (this.config.debugAdTiming) {\n console.error(\"[StormcloudVideoPlayer] Fullscreen error:\", err);\n }\n reject(err);\n });\n } else {\n document.exitFullscreen().then(() => {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Exited fullscreen\");\n }\n resolve();\n }).catch((err) => {\n if (this.config.debugAdTiming) {\n console.error(\n \"[StormcloudVideoPlayer] Exit fullscreen error:\",\n err\n );\n }\n reject(err);\n });\n }\n });\n }\n isMuted() {\n if (this.adLayer.isAdPlaying()) {\n const adMuted = this.adLayer.getAdVolume() === 0;\n if (this.config.debugAdTiming) {\n console.log(\n \"[StormcloudVideoPlayer] isMuted() during ad playback ->\",\n adMuted\n );\n }\n return adMuted;\n }\n return this.video.muted;\n }\n setMuted(muted) {\n const adPlaying = this.adLayer.isAdPlaying();\n if (adPlaying) {\n const savedVolume = this.adLayer.getOriginalVolume() || 1;\n this.adLayer.setAdVolume(muted ? 0 : savedVolume);\n this.adLayer.updateOriginalMutedState(muted, savedVolume);\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] setMuted applied to ad layer (content stays muted)\", {\n muted,\n savedVolume\n });\n }\n return;\n }\n this.video.muted = muted;\n if (!this.inAdBreak) {\n this.adLayer.updateOriginalMutedState(muted, this.video.volume);\n }\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] setMuted called:\", muted);\n }\n }\n setVolume(volume) {\n const clampedVolume = Math.max(0, Math.min(1, volume));\n const adPlaying = this.adLayer.isAdPlaying();\n if (adPlaying) {\n this.adLayer.setAdVolume(clampedVolume);\n const preservedVolume = clampedVolume > 0 ? clampedVolume : this.adLayer.getOriginalVolume();\n this.adLayer.updateOriginalMutedState(clampedVolume === 0, preservedVolume);\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] setVolume applied during ad\", {\n volume: clampedVolume\n });\n }\n } else {\n this.video.volume = clampedVolume;\n this.video.muted = clampedVolume === 0;\n if (!this.inAdBreak) {\n this.adLayer.updateOriginalMutedState(clampedVolume === 0, clampedVolume);\n }\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] setVolume called:\", clampedVolume);\n }\n }\n }\n getVolume() {\n const adPlaying = this.adLayer.isAdPlaying();\n if (adPlaying) {\n return this.adLayer.getAdVolume();\n }\n return this.video.volume;\n }\n isFullscreen() {\n return !!document.fullscreenElement;\n }\n isLive() {\n return this.isLiveStream;\n }\n getMinHlsResolution() {\n const levels = this.hls?.levels;\n if (!levels || levels.length === 0) return null;\n let min = null;\n let minPixels = Infinity;\n for (const level of levels) {\n if (level.width && level.height) {\n const pixels = level.width * level.height;\n if (pixels < minPixels) {\n minPixels = pixels;\n min = { width: level.width, height: level.height };\n }\n }\n }\n return min;\n }\n getCurrentHlsSegmentDurationMs() {\n const fallbackMs = 4e3;\n if (this.nativeHlsMode) {\n return fallbackMs;\n }\n const hls = this.hls;\n if (!hls) return null;\n const levelCandidates = [hls.currentLevel, hls.nextLoadLevel, hls.loadLevel];\n for (const levelIndex of levelCandidates) {\n if (typeof levelIndex !== \"number\" || levelIndex < 0) continue;\n const details = hls.levels?.[levelIndex]?.details;\n if (!details) continue;\n const targetDurationSec = typeof details.partTarget === \"number\" && details.partTarget > 0 ? details.partTarget : typeof details.targetduration === \"number\" && details.targetduration > 0 ? details.targetduration : void 0;\n if (targetDurationSec !== void 0) {\n return Math.max(800, Math.floor(targetDurationSec * 1e3));\n }\n }\n return fallbackMs;\n }\n get videoElement() {\n return this.video;\n }\n resize() {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Resizing player\");\n }\n if (this.adLayer && this.adLayer.isAdPlaying()) {\n const width = this.video.clientWidth || 640;\n const height = this.video.clientHeight || 480;\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Resizing ads manager to ${width}x${height}`\n );\n }\n this.adLayer.resize(width, height);\n }\n }\n destroy() {\n this.stopAdInsertionPolling();\n this.clearAdInsertionOffsetTimer();\n this.stopContinuousFetching();\n this.stopFillerBreakTimer();\n this.clearAdStopTimer();\n this.clearAdFailsafeTimer();\n this.clearAdRequestWatchdog();\n this.clearPendingAdBreak();\n if (this.fillerVideo) {\n this.fillerVideo.pause();\n if (this.fillerVideo.parentElement) {\n this.fillerVideo.parentElement.removeChild(this.fillerVideo);\n }\n this.fillerVideo = void 0;\n }\n if (this.timeUpdateHandler) {\n this.video.removeEventListener(\"timeupdate\", this.timeUpdateHandler);\n delete this.timeUpdateHandler;\n }\n if (this.emptiedHandler) {\n this.video.removeEventListener(\"emptied\", this.emptiedHandler);\n delete this.emptiedHandler;\n }\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n this.heartbeatInterval = void 0;\n }\n this.hls?.destroy();\n this.adLayer?.destroy();\n this.consecutiveFailures = 0;\n this.debugLogEntries = [];\n this.adInsertionDebugHistory = [];\n }\n};\n// Annotate the CommonJS export names for ESM import in node:\n0 && (module.exports = {\n StormcloudVideoPlayer\n});\n","import Hls from \"hls.js\";\nimport type {\n StormcloudVideoPlayerConfig,\n AdBreakContext,\n AdInsertionPointResponse,\n} from \"../types\";\nimport type { VastBidResponse } from \"../types\";\nimport { createAdStormPlayer } from \"../sdk/adstormPlayer\";\nimport type { AdStormAdLayer } from \"../sdk/adstormPlayer\";\nimport {\n sendInitialTracking,\n sendHeartbeat,\n sendAdLoadedTracking,\n sendAdImpressionTracking,\n} from \"../utils/tracking\";\nimport { initializePolyfills } from \"../utils/polyfills\";\nimport { logBrowserInfo, getBrowserConfigOverrides, detectBrowser } from \"../utils/browserCompat\";\n\nconst DEBUG_HISTORY_LIMIT = 120;\n\ntype DebugLogLevel = \"info\" | \"warn\" | \"error\";\n\ninterface DebugLogEntry {\n timestampMs: number;\n level: DebugLogLevel;\n category: string;\n message: string;\n details?: Record<string, unknown>;\n}\n\ntype AdInsertionDebugEvent =\n | \"api_response\"\n | \"scte35_inserted\"\n | \"segment_found\"\n | \"segment_playing\"\n | \"ad_scheduled\"\n | \"ad_triggered\";\n\ninterface AdInsertionDebugEntry {\n timestampMs: number;\n event: AdInsertionDebugEvent;\n segmentName: string;\n offsetSeconds?: number;\n updatedAt?: string;\n detail?: string;\n}\n\nexport class StormcloudVideoPlayer {\n private readonly video: HTMLVideoElement;\n private readonly config: StormcloudVideoPlayerConfig;\n private hls?: Hls;\n private adLayer: AdStormAdLayer;\n private pendingNextAdBids: VastBidResponse[] | null = null;\n private continuousFetchLoopPromise: Promise<void> | null = null;\n private attached = false;\n private inAdBreak = false;\n private currentAdBreakStartWallClockMs: number | undefined;\n private expectedAdBreakDurationMs: number | undefined;\n private adStopTimerId: number | undefined;\n private adFailsafeTimerId: number | undefined;\n private adPodQueue: string[] = [];\n private lastHeartbeatTime: number = 0;\n private heartbeatInterval: number | undefined;\n private currentAdIndex: number = 0;\n private totalAdsInBreak: number = 0;\n private showAds: boolean = false;\n private isLiveStream: boolean = false;\n private nativeHlsMode: boolean = false;\n private videoSrcProtection: string | null = null;\n private bufferedSegmentsCount: number = 0;\n private shouldAutoplayAfterBuffering: boolean = false;\n private hasInitialBufferCompleted: boolean = false;\n private activeAdRequestToken: number | null = null;\n private adRequestWatchdogId: number | undefined;\n private adRequestWatchdogToken: number | null = null;\n private adFailsafeToken: number | null = null;\n private continuousFetchingActive: boolean = false;\n private isInAdTransition: boolean = false;\n private maxPlaceholderDurationMs: number = 5000;\n private isShowingPlaceholder: boolean = false;\n private timeUpdateHandler?: (event: Event) => void;\n private emptiedHandler?: (event: Event) => void;\n\n private adInsertionPollingId: number | undefined;\n private lastAdInsertionPoint: AdInsertionPointResponse | null = null;\n private processedAdInsertionUpdatedAt: string | null = null;\n private adInsertionOffsetTimerId: number | undefined;\n\n private totalAdRequestsInBreak: number = 0;\n private readonly maxTotalAdRequestsPerBreak: number = 20;\n \n private pendingAdBreak: {\n durationSeconds?: number;\n detectedAtFragmentSn?: number;\n isFetching: boolean;\n fetchStartTime?: number;\n } | null = null;\n private prefetchTimerId: number | undefined;\n private savedMutedStateBeforeAd: { muted: boolean; volume: number } | null = null;\n\n private consecutiveFailures: number = 0;\n private readonly maxConsecutiveFailures: number = 5;\n private lastAdRequestTime: number = 0;\n private readonly minAdRequestIntervalMs: number = 2500;\n private readonly backoffBaseMs: number = 1000;\n private readonly maxBackoffMs: number = 15000;\n private readonly adTransitionGapMs: number;\n private readonly MIN_AD_REMAINING_MS: number = 15000;\n private readonly adRequestTimeoutMs: number = 5000;\n private readonly adRequestMaxRetries: number = 3;\n private readonly adRequestRetryBackoffMs: number = 1500;\n private preloadedTokens: string[] = [];\n private fillerVideo: HTMLVideoElement | undefined;\n private fillerBreakTimerId: ReturnType<typeof setTimeout> | undefined;\n private debugLogEntries: DebugLogEntry[] = [];\n private adInsertionDebugHistory: AdInsertionDebugEntry[] = [];\n\n constructor(config: StormcloudVideoPlayerConfig) {\n initializePolyfills();\n\n const browserOverrides = getBrowserConfigOverrides();\n \n this.config = { ...browserOverrides, ...config };\n this.video = config.videoElement;\n this.adTransitionGapMs = this.config.adTransitionGapMs ?? 100;\n\n logBrowserInfo(config.debugAdTiming);\n\n const browserForAdLayer = detectBrowser();\n const isSinglePipeline = browserForAdLayer.isSmartTV || !!this.config.singlePipelineMode;\n this.adLayer = createAdStormPlayer(this.video, {\n licenseKey: this.config.licenseKey || \"\",\n debug: !!config.debugAdTiming,\n });\n this.adLayer.updateOptions({\n continueLiveStreamDuringAds: !isSinglePipeline && this.shouldContinueLiveStreamDuringAds(),\n });\n }\n\n private async adRequest(context?: AdBreakContext): Promise<VastBidResponse[]> {\n if (this.config.disableAds) return [];\n const durationSeconds = Math.max(\n 1,\n Math.ceil(context?.remainingBreakSec ?? context?.breakDurationSec ?? 30)\n );\n await this.adLayer.requestAds(String(durationSeconds));\n return [\n {\n bidder: \"adstorm-direct\",\n cpm: 0,\n width: 0,\n height: 0,\n adId: \"adstorm\",\n impId: \"\",\n creativeId: \"adstorm\",\n currency: \"USD\",\n durationSec: durationSeconds,\n },\n ];\n }\n\n async load(): Promise<void> {\n if (!this.attached) {\n this.attach();\n }\n\n this.initializeTracking();\n\n if (this.shouldUseNativeHls()) {\n this.nativeHlsMode = true;\n this.videoSrcProtection = this.config.src;\n this.video.src = this.config.src;\n\n this.isLiveStream = this.config.lowLatencyMode ?? false;\n\n if (this.config.debugAdTiming) {\n console.log(\n \"[StormcloudVideoPlayer] Using native HLS playback - VOD mode:\",\n {\n isLive: this.isLiveStream,\n allowNativeHls: this.config.allowNativeHls,\n adBehavior: \"vod (main video pauses during ads)\",\n }\n );\n }\n\n if (!this.config.disableAds) {\n this.adLayer.updateOptions({ continueLiveStreamDuringAds: false, mainHlsInstance: null });\n }\n\n if (this.config.autoplay) {\n await this.video.play()?.catch(() => {});\n }\n return;\n }\n\n this.hls = new Hls({\n enableWorker: true,\n backBufferLength: 30,\n liveDurationInfinity: true,\n lowLatencyMode: !!this.config.lowLatencyMode,\n maxLiveSyncPlaybackRate: this.config.lowLatencyMode ? 1.5 : 1.0,\n ...(this.config.lowLatencyMode ? { liveSyncDuration: 2 } : {}),\n maxBufferLength: 30,\n maxMaxBufferLength: 600,\n maxBufferSize: 60 * 1000 * 1000,\n maxBufferHole: 0.5,\n highBufferWatchdogPeriod: 2,\n nudgeOffset: 0.1,\n nudgeMaxRetry: 3,\n startPosition: -1,\n });\n\n this.hls.on(Hls.Events.MEDIA_ATTACHED, () => {\n this.hls?.loadSource(this.config.src);\n });\n\n this.hls.on(Hls.Events.MANIFEST_PARSED, async (_, data: any) => {\n if (this.config.allowNativeHls === false) {\n this.isLiveStream = true;\n } else {\n this.isLiveStream =\n this.hls?.levels?.some(\n (level) =>\n level?.details?.live === true || level?.details?.type === \"LIVE\"\n ) ?? false;\n }\n\n if (this.config.debugAdTiming) {\n const adBehavior = this.shouldContinueLiveStreamDuringAds()\n ? \"live (main video continues muted during ads)\"\n : \"vod (main video pauses during ads)\";\n console.log(\"[StormcloudVideoPlayer] Stream type detected:\", {\n isLive: this.isLiveStream,\n allowNativeHls: this.config.allowNativeHls,\n adBehavior,\n });\n }\n\n if (!this.config.disableAds) {\n this.adLayer.updateOptions({\n continueLiveStreamDuringAds: this.shouldContinueLiveStreamDuringAds(),\n mainHlsInstance: this.hls ?? null,\n });\n }\n\n this.bufferedSegmentsCount = 0;\n this.hasInitialBufferCompleted = false;\n this.shouldAutoplayAfterBuffering = !!this.config.autoplay;\n\n const minSegments = this.config.minSegmentsBeforePlay ?? 2;\n\n if (this.config.debugAdTiming) {\n console.log(\n \"[StormcloudVideoPlayer] Waiting for\",\n minSegments,\n \"segments to buffer before playback\"\n );\n }\n\n if (minSegments === 0 || !this.config.autoplay) {\n this.hasInitialBufferCompleted = true;\n if (this.config.autoplay) {\n await this.video.play()?.catch(() => {});\n }\n }\n\n if (!this.config.disableAds && this.config.projectId) {\n this.startAdInsertionPolling();\n }\n });\n\n this.hls.on(Hls.Events.LEVEL_LOADED, () => {\n if (this.inAdBreak || this.pendingAdBreak) {\n return;\n }\n this.checkAdInsertionInManifest();\n });\n\n this.hls.on(Hls.Events.FRAG_BUFFERED, async (_evt, data: any) => {\n if (this.hasInitialBufferCompleted) {\n return;\n }\n\n this.bufferedSegmentsCount++;\n const minSegments = this.config.minSegmentsBeforePlay ?? 2;\n\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Buffered segment ${this.bufferedSegmentsCount}/${minSegments}`\n );\n }\n\n if (this.bufferedSegmentsCount >= minSegments) {\n this.hasInitialBufferCompleted = true;\n\n if (this.shouldAutoplayAfterBuffering) {\n if (this.inAdBreak || this.adLayer.isAdPlaying()) {\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Initial buffer complete (${this.bufferedSegmentsCount} segments). Ad break active — deferring play() to handleAdPodComplete().`\n );\n }\n } else {\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Initial buffer complete (${this.bufferedSegmentsCount} segments). Starting playback.`\n );\n }\n await this.video.play()?.catch((err) => {\n if (this.config.debugAdTiming) {\n console.warn(\"[StormcloudVideoPlayer] Autoplay failed:\", err);\n }\n });\n }\n }\n }\n });\n\n this.hls.on(Hls.Events.FRAG_CHANGED, (_evt, data: any) => {\n const frag = data?.frag;\n if (!frag) return;\n\n if (\n this.lastAdInsertionPoint &&\n !this.inAdBreak &&\n this.lastAdInsertionPoint.updated_at !== this.processedAdInsertionUpdatedAt\n ) {\n const segmentName = this.lastAdInsertionPoint.segment_ts_name;\n if (this.fragmentMatchesSegment(frag, segmentName)) {\n this.processedAdInsertionUpdatedAt = this.lastAdInsertionPoint.updated_at;\n const offsetMs = (this.lastAdInsertionPoint.offset_seconds || 0) * 1000;\n\n this.pushAdInsertionDebug(\"segment_playing\", segmentName, {\n offsetSeconds: this.lastAdInsertionPoint.offset_seconds,\n detail: `sn=${frag?.sn ?? \"?\"}`,\n });\n\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Ad insertion segment \"${segmentName}\" now playing — scheduling ad start in ${offsetMs}ms`\n );\n }\n\n this.pushAdInsertionDebug(\"ad_scheduled\", segmentName, {\n offsetSeconds: this.lastAdInsertionPoint.offset_seconds,\n detail: `in ${offsetMs}ms, dur=60s`,\n });\n\n this.clearAdInsertionOffsetTimer();\n this.adInsertionOffsetTimerId = window.setTimeout(() => {\n this.adInsertionOffsetTimerId = undefined;\n if (this.inAdBreak) return;\n\n this.pushAdInsertionDebug(\"ad_triggered\", segmentName, {\n detail: \"ad break started (60s)\",\n });\n\n void this.handleAdStart(60);\n }, offsetMs);\n }\n }\n });\n\n this.hls.on(Hls.Events.FRAG_PARSING_USERDATA, (_evt, data: any) => {\n const samples: Array<{ data: Uint8Array }> = data?.samples ?? [];\n for (const sample of samples) {\n const bytes = sample?.data;\n if (!bytes || bytes.length < 5) continue;\n // SCTE-35 splice_info_section starts with 0xFC (table_id)\n const isSCTE35 = bytes[0] === 0xfc;\n if (!isSCTE35) continue;\n const segName = data?.frag?.relurl ?? data?.frag?.url ?? \"\";\n this.pushAdInsertionDebug(\"scte35_inserted\", segName, {\n detail: `len=${bytes.length}B`,\n });\n }\n });\n\n this.hls.on(Hls.Events.ERROR, (_evt, data) => {\n if (data?.fatal) {\n switch (data.type) {\n case Hls.ErrorTypes.NETWORK_ERROR:\n this.hls?.startLoad();\n break;\n case Hls.ErrorTypes.MEDIA_ERROR:\n this.hls?.recoverMediaError();\n break;\n default:\n this.destroy();\n break;\n }\n }\n });\n\n this.hls.attachMedia(this.video);\n }\n\n private getAdSource(): \"vast\" {\n return \"vast\";\n }\n\n private attachAdLayerEventListeners(): void {\n this.adLayer.on(\"ad_impression\", () => {\n if (this.config.licenseKey) {\n sendAdImpressionTracking(this.config.licenseKey, {\n source: this.getAdSource(),\n adIndex: this.currentAdIndex,\n timestamp: new Date().toISOString(),\n });\n }\n });\n this.adLayer.on(\"ad_error\", (errorPayload?: any) => {\n let errorMessage = \"Ad playback failed\";\n \n if (errorPayload) {\n const errorCode = errorPayload.code || errorPayload.errorCode || \"unknown\";\n const vastErrorCode = errorPayload.vastErrorCode;\n const message = errorPayload.message || errorPayload.errorMessage || \"Unknown error\";\n const cause = errorPayload.cause || errorPayload.innerError || errorPayload.error;\n \n errorMessage = `Ad error: AdError ${errorCode}: ${message}`;\n \n if (vastErrorCode && vastErrorCode !== \"N/A\" && vastErrorCode !== errorCode) {\n errorMessage += ` (VAST Error Code: ${vastErrorCode})`;\n }\n \n if (cause) {\n const causeMessage = typeof cause === \"string\" ? cause : (cause.message || String(cause));\n errorMessage += `. Caused by: ${causeMessage}`;\n }\n }\n \n this.pushDebugLog(\"error\", \"ad\", errorMessage, {\n ...(errorPayload ? { payload: errorPayload as Record<string, unknown> } : {}),\n });\n console.error(\"[AD-ERROR]\", errorMessage, errorPayload || \"\");\n this.adLayer.stop().catch(() => {});\n this.handleAdFailure();\n });\n this.adLayer.on(\"content_pause\", () => {\n this.clearAdFailsafeTimer();\n this.clearAdRequestWatchdog();\n this.activeAdRequestToken = null;\n this.showAds = true;\n\n if (this.config.disableFiller) {\n if (this.savedMutedStateBeforeAd == null) {\n this.savedMutedStateBeforeAd = { muted: this.video.muted, volume: this.video.volume };\n this.adLayer.updateOriginalMutedState(this.video.muted, this.video.volume);\n }\n if (!this.video.muted) {\n this.video.muted = true;\n this.video.volume = 0;\n }\n this.adLayer.showPlaceholder();\n }\n \n if (this.inAdBreak && this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {\n this.scheduleAdStopCountdown(this.getRemainingAdMs());\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Starting ad break timer on content_pause (first ad starting)\");\n }\n }\n\n this.adLayer.setAdVolume(\n this.adLayer.getOriginalMutedState() ? 1 : this.adLayer.getOriginalVolume()\n );\n\n this.stopFillerBreakTimer();\n this.hidePlaceholderLayer();\n this.isShowingPlaceholder = false;\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Hiding placeholder - new ads starting\");\n }\n });\n this.adLayer.on(\"content_resume\", () => {\n const remaining = this.getRemainingAdMs();\n const breakMuted = this.savedMutedStateBeforeAd?.muted ?? this.adLayer.getOriginalMutedState();\n const breakVolume = this.savedMutedStateBeforeAd?.volume ?? this.adLayer.getOriginalVolume();\n if (this.config.debugAdTiming) {\n console.log(\n \"[StormcloudVideoPlayer] content_resume received, inAdBreak=%s, remaining=%s, preloadedTokens=%d, pendingNext=%s\",\n this.inAdBreak,\n remaining,\n this.preloadedTokens.length,\n !!this.pendingNextAdBids\n );\n }\n\n this.clearAdFailsafeTimer();\n this.clearAdRequestWatchdog();\n this.activeAdRequestToken = null;\n this.showAds = false;\n\n if (!this.inAdBreak) {\n this.video.style.visibility = \"visible\";\n this.video.style.opacity = \"1\";\n this.syncMainContentAudioWhenVisible();\n return;\n }\n\n this.consecutiveFailures = 0;\n\n if (!this.config.disableFiller && !this.video.muted) {\n this.video.muted = true;\n this.video.volume = 0;\n }\n\n if (this.preloadedTokens.length > 0) {\n const token = this.preloadedTokens.shift()!;\n const remainingNow = this.getRemainingAdMs();\n if (this.expectedAdBreakDurationMs != null && remainingNow < this.MIN_AD_REMAINING_MS) {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] content_resume: skip preloaded ad, only\", remainingNow, \"ms left\");\n }\n this.adLayer.cancelPreload(token);\n } else {\n if (!this.config.singlePipelineMode) {\n this.showPlaceholderLayer();\n }\n this.adLayer.showPlaceholder();\n this.isInAdTransition = true;\n setTimeout(() => {\n this.isInAdTransition = false;\n if (!this.inAdBreak) return;\n this.currentAdIndex++;\n this.adLayer.playPreloaded(token).catch((err) => {\n if (this.config.debugAdTiming) console.warn(\"[StormcloudVideoPlayer] playPreloaded failed:\", err);\n this.handleAdFailure();\n });\n }, this.adTransitionGapMs);\n return;\n }\n }\n\n if (this.pendingNextAdBids && this.pendingNextAdBids.length > 0) {\n const bids = [...this.pendingNextAdBids];\n this.pendingNextAdBids = null;\n const remainingNow = this.getRemainingAdMs();\n if (this.expectedAdBreakDurationMs != null && remainingNow < this.MIN_AD_REMAINING_MS) {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] content_resume: skip pending bids, only\", remainingNow, \"ms left\");\n }\n } else {\n if (!this.config.singlePipelineMode) {\n this.showPlaceholderLayer();\n }\n this.adLayer.showPlaceholder();\n this.isInAdTransition = true;\n setTimeout(() => {\n this.isInAdTransition = false;\n if (!this.inAdBreak || bids.length === 0) return;\n const freshBids = this.pendingNextAdBids ?? bids;\n this.pendingNextAdBids = null;\n this.currentAdIndex++;\n this.adLayer.playAd(freshBids).catch((err) => {\n if (this.config.debugAdTiming) console.warn(\"[StormcloudVideoPlayer] playAd(pending) failed:\", err);\n this.handleAdFailure();\n });\n }, this.adTransitionGapMs);\n return;\n }\n }\n\n const remainingFinal = this.getRemainingAdMs();\n if (this.inAdBreak && remainingFinal > this.MIN_AD_REMAINING_MS) {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] content_resume: ad ended/failed with time remaining, showing filler and continuing fetch for\", remainingFinal, \"ms\");\n }\n if (!this.config.disableFiller) {\n this.showPlaceholderLayer();\n this.adLayer.showPlaceholder();\n } else {\n this.adLayer.hidePlaceholder();\n if (this.video.muted !== breakMuted) {\n this.video.muted = breakMuted;\n }\n if (Math.abs(this.video.volume - breakVolume) > 0.01) {\n this.video.volume = breakVolume;\n }\n if (this.video.paused) {\n this.video.play()?.catch(() => {});\n }\n }\n\n this.continuousFetchingActive = true;\n this.startContinuousFetchLoop();\n return;\n }\n\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] content_resume: no more ads, ending ad pod\");\n }\n this.handleAdPodComplete();\n });\n }\n\n private ensureFillerVideo(): void {\n if (this.fillerVideo) return;\n if (!this.video.parentElement) return;\n\n const filler = document.createElement(\"video\");\n filler.src = \"https://f000.backblazeb2.com/file/AdStormAds/384/Sonifi_Filler.mp4\";\n filler.loop = true;\n filler.muted = false;\n filler.playsInline = true;\n filler.style.position = \"absolute\";\n filler.style.left = \"0\";\n filler.style.top = \"0\";\n filler.style.width = \"100%\";\n filler.style.height = \"100%\";\n filler.style.objectFit = \"cover\";\n filler.style.zIndex = \"20\";\n filler.style.display = \"none\";\n filler.preload = \"auto\";\n this.video.parentElement.appendChild(filler);\n this.fillerVideo = filler;\n }\n\n private showPlaceholderLayer(): void {\n if (this.config.disableFiller) return;\n this.ensureFillerVideo();\n if (!this.fillerVideo) return;\n\n if (!this.video.muted) {\n this.video.muted = true;\n this.video.volume = 0;\n }\n\n this.fillerVideo.style.display = \"block\";\n this.fillerVideo.play().catch(() => {\n if (this.fillerVideo) {\n this.fillerVideo.style.display = \"none\";\n }\n if (!this.adLayer.isAdPlaying()) {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Filler video failed — restoring main video\");\n }\n this.adLayer.hidePlaceholder();\n if (this.video.paused && this.video.readyState >= 2) {\n this.video.play()?.catch(() => {});\n }\n }\n });\n\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Showing filler video layer\");\n }\n }\n\n private hidePlaceholderLayer(): void {\n if (!this.fillerVideo) return;\n\n this.fillerVideo.style.display = \"none\";\n this.fillerVideo.pause();\n this.fillerVideo.currentTime = 0;\n\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Hiding filler video layer\");\n }\n }\n\n private startFillerBreakTimer(durationMs: number): void {\n this.stopFillerBreakTimer();\n this.showPlaceholderLayer();\n this.fillerBreakTimerId = setTimeout(() => {\n this.fillerBreakTimerId = undefined;\n this.hidePlaceholderLayer();\n if (this.inAdBreak) this.handleAdPodComplete();\n }, durationMs);\n }\n\n private stopFillerBreakTimer(): void {\n if (this.fillerBreakTimerId !== undefined) {\n clearTimeout(this.fillerBreakTimerId);\n this.fillerBreakTimerId = undefined;\n }\n }\n\n private attach(): void {\n if (this.attached) return;\n this.attached = true;\n this.video.autoplay = !!this.config.autoplay;\n this.video.muted = !!this.config.muted;\n\n if (!this.config.disableAds) {\n this.adLayer.initialize();\n if (!this.config.disableFiller) {\n this.ensureFillerVideo();\n }\n this.adLayer.updateOriginalMutedState(this.video.muted, this.video.volume);\n this.attachAdLayerEventListeners();\n }\n\n this.timeUpdateHandler = () => {\n this.onTimeUpdate(this.video.currentTime);\n };\n this.video.addEventListener(\"timeupdate\", this.timeUpdateHandler);\n\n this.emptiedHandler = () => {\n if (\n this.nativeHlsMode &&\n this.videoSrcProtection &&\n !this.adLayer.isAdPlaying()\n ) {\n if (this.config.debugAdTiming) {\n console.log(\n \"[StormcloudVideoPlayer] Video src was cleared, restoring:\",\n this.videoSrcProtection\n );\n }\n const currentTime = this.video.currentTime;\n const wasPaused = this.video.paused;\n this.video.src = this.videoSrcProtection;\n this.video.currentTime = currentTime;\n if (!wasPaused) {\n this.video.play().catch(() => {});\n }\n }\n };\n this.video.addEventListener(\"emptied\", this.emptiedHandler);\n }\n\n private shouldUseNativeHls(): boolean {\n const streamType = this.getStreamType();\n\n if (streamType === \"other\") {\n return true;\n }\n\n const canNative = this.video.canPlayType(\"application/vnd.apple.mpegurl\");\n return !!(this.config.allowNativeHls && canNative);\n }\n\n private initializeTracking(): void {\n sendInitialTracking(this.config.licenseKey)\n .then(() => {\n this.heartbeatInterval = window.setInterval(() => {\n this.sendHeartbeatIfNeeded();\n }, 5000);\n })\n .catch((error) => {\n if (this.config.debugAdTiming) {\n console.warn(\n \"[StormcloudVideoPlayer] Failed to send initial tracking:\",\n error\n );\n }\n this.heartbeatInterval = window.setInterval(() => {\n this.sendHeartbeatIfNeeded();\n }, 5000);\n });\n }\n\n private sendHeartbeatIfNeeded(): void {\n const now = Date.now();\n if (!this.lastHeartbeatTime || now - this.lastHeartbeatTime > 30000) {\n this.lastHeartbeatTime = now;\n sendHeartbeat(this.config.licenseKey).catch((error) => {\n if (this.config.debugAdTiming) {\n console.warn(\n \"[StormcloudVideoPlayer] Failed to send heartbeat:\",\n error\n );\n }\n });\n }\n }\n\n getCurrentAdIndex(): number {\n return this.currentAdIndex;\n }\n\n getTotalAdsInBreak(): number {\n return this.totalAdsInBreak;\n }\n\n getRemainingAdSeconds(): number {\n const remainingMs = this.getRemainingAdMs();\n if (\n !Number.isFinite(remainingMs) ||\n remainingMs <= 0 ||\n remainingMs === Number.MAX_SAFE_INTEGER\n ) {\n return 0;\n }\n return Math.ceil(remainingMs / 1000);\n }\n\n isAdPlaying(): boolean {\n return this.inAdBreak && this.adLayer.isAdPlaying();\n }\n\n isShowingAds(): boolean {\n return this.showAds;\n }\n\n private syncMainContentAudioWhenVisible(): void {\n const adLayerShowing = this.showAds || this.adLayer.isAdPlaying();\n if (adLayerShowing) return;\n const muted = this.adLayer.getOriginalMutedState();\n const volume = this.adLayer.getOriginalVolume();\n if (this.video.muted !== muted) this.video.muted = muted;\n if (Math.abs(this.video.volume - volume) > 0.01) this.video.volume = volume;\n }\n\n getStreamType(): \"hls\" | \"other\" {\n const url = this.config.src.toLowerCase();\n if (\n url.includes(\".m3u8\") ||\n url.includes(\"/hls/\") ||\n url.includes(\"application/vnd.apple.mpegurl\")\n ) {\n return \"hls\";\n }\n return \"other\";\n }\n\n shouldShowNativeControls(): boolean {\n const streamType = this.getStreamType();\n if (streamType === \"other\") {\n return !(this.config.showCustomControls ?? false);\n }\n return !!(\n this.config.allowNativeHls && !(this.config.showCustomControls ?? false)\n );\n }\n\n private shouldContinueLiveStreamDuringAds(): boolean {\n if (this.config.allowNativeHls) {\n return false;\n }\n\n if (!this.isLiveStream) {\n return false;\n }\n\n if (this.config.singlePipelineMode) {\n return false;\n }\n\n const browser = detectBrowser();\n if (browser.isSmartTV) {\n return false;\n }\n\n return true;\n }\n\n private startAdPrefetch(durationSeconds?: number, fragmentSn?: number): void {\n if (this.config.disableAds) return;\n if (this.pendingAdBreak || this.inAdBreak) {\n return;\n }\n\n this.pendingAdBreak = {\n ...(durationSeconds !== undefined ? { durationSeconds } : {}),\n ...(fragmentSn !== undefined ? { detectedAtFragmentSn: fragmentSn } : {}),\n isFetching: false,\n fetchStartTime: Date.now(),\n };\n\n void this.runAdPrefetch(durationSeconds);\n\n if (this.config.debugAdTiming) {\n console.log(\"[PREFETCH] Ad break registered, multi-ad prefetch started\");\n }\n }\n\n private async runAdPrefetch(durationSeconds?: number): Promise<void> {\n const durSec = durationSeconds ?? 60;\n\n const context: AdBreakContext = {\n breakDurationSec: durSec,\n remainingBreakSec: durSec,\n };\n\n let firstBids: VastBidResponse[];\n try {\n firstBids = await this.adRequest({ ...context, adIndex: 1 });\n } catch {\n firstBids = [];\n }\n\n if (this.inAdBreak) return;\n\n if (firstBids.length === 0) {\n if (this.config.debugAdTiming) {\n console.log(\"[PREFETCH] First VAST request returned no ad, aborting prefetch\");\n }\n this.clearPendingAdBreak();\n return;\n }\n\n const adDurationSec = firstBids[0]?.durationSec ?? 30;\n const estimatedCount = Math.max(1, Math.ceil(durSec / adDurationSec));\n\n if (this.config.debugAdTiming) {\n console.log(\n `[PREFETCH] Ad duration=${adDurationSec}s, break=${durSec}s → ${estimatedCount} ad(s) needed`\n );\n }\n\n const firstToken = `preload_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;\n try {\n await this.adLayer.preloadAd(firstBids, firstToken);\n if (!this.inAdBreak) {\n this.preloadedTokens.push(firstToken);\n if (this.config.debugAdTiming) {\n console.log(`[PREFETCH] First ad preloaded and queued, token=${firstToken}`);\n }\n }\n } catch {\n if (this.config.debugAdTiming) {\n console.warn(`[PREFETCH] First ad preload failed, token=${firstToken}`);\n }\n }\n\n if (estimatedCount > 1) {\n type SettledResult = { ok: true; value: VastBidResponse[] } | { ok: false };\n const remaining: Promise<SettledResult>[] = Array.from(\n { length: estimatedCount - 1 },\n (_, i) =>\n this.adRequest({ ...context, adIndex: i + 2 })\n .then((bids): SettledResult => ({ ok: true, value: bids }))\n .catch((): SettledResult => ({ ok: false }))\n );\n\n const results = await Promise.all(remaining);\n\n for (const result of results) {\n if (this.inAdBreak) break;\n if (result.ok && result.value.length > 0) {\n const token = `preload_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;\n try {\n await this.adLayer.preloadAd(result.value, token);\n if (!this.inAdBreak) {\n this.preloadedTokens.push(token);\n if (this.config.debugAdTiming) {\n console.log(`[PREFETCH] Additional ad preloaded and queued, token=${token}`);\n }\n }\n } catch {\n if (this.config.debugAdTiming) {\n console.warn(`[PREFETCH] Additional ad preload failed, token=${token}`);\n }\n }\n }\n }\n }\n\n if (this.config.debugAdTiming) {\n console.log(`[PREFETCH] Pre-fetch complete: ${this.preloadedTokens.length} ad(s) queued`);\n }\n }\n\n private clearPendingAdBreak(): void {\n if (this.prefetchTimerId != null) {\n clearTimeout(this.prefetchTimerId);\n this.prefetchTimerId = undefined;\n }\n this.pendingAdBreak = null;\n }\n\n private cancelAndClearPreloadedTokens(): void {\n for (const token of this.preloadedTokens) {\n this.adLayer.cancelPreload(token);\n }\n this.preloadedTokens = [];\n }\n\n private startAdInsertionPolling(): void {\n if (this.adInsertionPollingId != null) return;\n this.fetchAdInsertionPoint();\n this.adInsertionPollingId = window.setInterval(() => {\n this.fetchAdInsertionPoint();\n }, 1000);\n }\n\n private stopAdInsertionPolling(): void {\n if (this.adInsertionPollingId != null) {\n clearInterval(this.adInsertionPollingId);\n this.adInsertionPollingId = undefined;\n }\n }\n\n private async fetchAdInsertionPoint(): Promise<void> {\n if (!this.config.projectId) return;\n try {\n const resp = await fetch(\n `https://adstorm.co/api-adstorm-dev/adstorm/swirl/projects/${encodeURIComponent(this.config.projectId)}/ad-insertion-point`\n );\n if (!resp.ok) return;\n const data: AdInsertionPointResponse = await resp.json();\n const prevSegment = this.lastAdInsertionPoint?.segment_ts_name;\n const isNew = data.updated_at !== this.lastAdInsertionPoint?.updated_at;\n const segmentChanged = prevSegment !== data.segment_ts_name;\n this.lastAdInsertionPoint = data;\n\n if (isNew) {\n this.pushAdInsertionDebug(\"api_response\", data.segment_ts_name, {\n offsetSeconds: data.offset_seconds,\n updatedAt: data.updated_at,\n detail: `project=${data.project_id}`,\n });\n\n if (segmentChanged && (this.pendingAdBreak || this.adInsertionOffsetTimerId != null)) {\n this.clearAdInsertionOffsetTimer();\n this.clearPendingAdBreak();\n this.cancelAndClearPreloadedTokens();\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Insertion segment changed (${prevSegment} → ${data.segment_ts_name}), stale pending state cleared`\n );\n }\n }\n\n this.checkAdInsertionInManifest();\n }\n\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Ad insertion point API response:\", data);\n }\n } catch {\n if (this.config.debugAdTiming) {\n console.warn(\"[StormcloudVideoPlayer] Ad insertion point API fetch failed\");\n }\n }\n }\n\n private checkAdInsertionInManifest(): void {\n if (!this.lastAdInsertionPoint) return;\n if (this.inAdBreak || this.pendingAdBreak) return;\n if (this.lastAdInsertionPoint.updated_at === this.processedAdInsertionUpdatedAt) return;\n\n const segmentName = this.lastAdInsertionPoint.segment_ts_name;\n const levels = this.hls?.levels;\n if (!levels) return;\n\n for (const level of levels) {\n const fragments = (level as any).details?.fragments;\n if (!Array.isArray(fragments)) continue;\n\n for (const frag of fragments) {\n if (this.fragmentMatchesSegment(frag, segmentName)) {\n const currentTime = this.video.currentTime;\n const fragStart: number = frag.start ?? 0;\n const fragDuration: number = frag.duration ?? 0;\n const isCurrentlyPlaying =\n fragDuration > 0 &&\n currentTime >= fragStart &&\n currentTime < fragStart + fragDuration;\n\n this.pushAdInsertionDebug(\"segment_found\", segmentName, {\n detail: `sn=${frag?.sn ?? \"?\"} ${isCurrentlyPlaying ? \"(playing)\" : \"(future)\"}`,\n });\n\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Ad insertion segment \"${segmentName}\" found in manifest — ` +\n (isCurrentlyPlaying ? \"currently playing, scheduling directly\" : \"starting pre-fetch\")\n );\n }\n\n this.startAdPrefetch(60, frag?.sn);\n\n if (isCurrentlyPlaying && !this.inAdBreak) {\n this.processedAdInsertionUpdatedAt = this.lastAdInsertionPoint.updated_at;\n\n const rawOffsetMs = (this.lastAdInsertionPoint.offset_seconds ?? 0) * 1000;\n const elapsedInFragMs = (currentTime - fragStart) * 1000;\n const remainingOffsetMs = Math.max(0, rawOffsetMs - elapsedInFragMs);\n\n this.pushAdInsertionDebug(\"segment_playing\", segmentName, {\n offsetSeconds: this.lastAdInsertionPoint.offset_seconds,\n detail: `sn=${frag?.sn ?? \"?\"} (caught in manifest check)`,\n });\n\n this.pushAdInsertionDebug(\"ad_scheduled\", segmentName, {\n offsetSeconds: this.lastAdInsertionPoint.offset_seconds,\n detail: `in ${remainingOffsetMs}ms (adjusted for elapsed ${Math.round(elapsedInFragMs)}ms)`,\n });\n\n this.clearAdInsertionOffsetTimer();\n this.adInsertionOffsetTimerId = window.setTimeout(() => {\n this.adInsertionOffsetTimerId = undefined;\n if (this.inAdBreak) return;\n\n this.pushAdInsertionDebug(\"ad_triggered\", segmentName, {\n detail: \"ad break started (60s, via manifest-check path)\",\n });\n\n void this.handleAdStart(60);\n }, remainingOffsetMs);\n }\n\n return;\n }\n }\n }\n }\n\n private fragmentMatchesSegment(frag: any, segmentName: string): boolean {\n const rawUrl: string = frag?.url || frag?.relurl || \"\";\n const url = rawUrl.split(\"?\")[0] ?? \"\";\n const name = segmentName.startsWith(\"/\") ? segmentName : \"/\" + segmentName;\n return url.endsWith(name) || url.includes(name);\n }\n\n private clearAdInsertionOffsetTimer(): void {\n if (this.adInsertionOffsetTimerId != null) {\n clearTimeout(this.adInsertionOffsetTimerId);\n this.adInsertionOffsetTimerId = undefined;\n }\n }\n\n private startContinuousFetchLoop(): void {\n if (this.continuousFetchLoopPromise != null) return;\n this.continuousFetchLoopPromise = this.runContinuousFetchLoop();\n }\n\n private async runContinuousFetchLoop(): Promise<void> {\n const backoffMs = () => {\n const mult = Math.pow(2, this.consecutiveFailures);\n return Math.min(this.backoffBaseMs * mult, this.maxBackoffMs);\n };\n while (this.inAdBreak && this.continuousFetchingActive) {\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) break;\n if (this.totalAdRequestsInBreak >= this.maxTotalAdRequestsPerBreak) break;\n\n if (this.adLayer.isAdPlaying() || this.isInAdTransition) {\n if (this.pendingNextAdBids == null) {\n try {\n const remaining = this.getRemainingAdMs();\n const prefetchContext: AdBreakContext | undefined = this.expectedAdBreakDurationMs != null\n ? {\n breakDurationSec: this.expectedAdBreakDurationMs / 1000,\n remainingBreakSec: remaining / 1000,\n adIndex: this.currentAdIndex + 1,\n }\n : undefined;\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Pre-fetching next ad during playback, remaining:\", remaining, \"ms\");\n }\n const bids = await this.adRequest(prefetchContext);\n this.lastAdRequestTime = Date.now();\n if (!this.inAdBreak) break;\n if (bids.length > 0) {\n this.consecutiveFailures = 0;\n this.pendingNextAdBids = bids;\n this.totalAdsInBreak = Math.max(\n this.totalAdsInBreak,\n this.currentAdIndex + this.preloadedTokens.length + 1\n );\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Pre-fetched next ad stored as pending\");\n }\n } else {\n this.consecutiveFailures++;\n }\n } catch (err) {\n this.consecutiveFailures++;\n if (this.config.debugAdTiming) {\n console.warn(\"[CONTINUOUS-FETCH] Pre-fetch adRequest failed:\", err);\n }\n }\n } else {\n await new Promise((r) => setTimeout(r, 200));\n }\n continue;\n }\n\n if (this.pendingNextAdBids != null && this.pendingNextAdBids.length > 0) {\n const bids = this.pendingNextAdBids;\n this.pendingNextAdBids = null;\n const remainingNow = this.getRemainingAdMs();\n if (this.expectedAdBreakDurationMs == null || remainingNow >= this.MIN_AD_REMAINING_MS) {\n this.currentAdIndex++;\n if (this.config.licenseKey) {\n sendAdLoadedTracking(this.config.licenseKey, {\n source: this.getAdSource(),\n timestamp: new Date().toISOString(),\n });\n }\n await this.adLayer.playAd(bids);\n if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {\n this.scheduleAdStopCountdown(this.getRemainingAdMs());\n }\n this.adLayer.setAdVolume(\n this.adLayer.getOriginalMutedState() ? 1 : this.adLayer.getOriginalVolume()\n );\n } else if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Discarding pre-fetched bids: only\", remainingNow, \"ms left\");\n }\n continue;\n }\n\n const urgentNeedAd = this.inAdBreak && !this.adLayer.isAdPlaying();\n const delay = this.lastAdRequestTime\n ? this.minAdRequestIntervalMs + (!urgentNeedAd && this.consecutiveFailures > 0 ? backoffMs() : 0)\n : 0;\n const elapsed = Date.now() - this.lastAdRequestTime;\n if (elapsed < delay && this.lastAdRequestTime > 0) {\n await new Promise((r) => setTimeout(r, delay - elapsed));\n }\n if (!this.inAdBreak || !this.continuousFetchingActive) break;\n try {\n const remaining = this.getRemainingAdMs();\n const context: AdBreakContext | undefined = this.expectedAdBreakDurationMs != null\n ? {\n breakDurationSec: this.expectedAdBreakDurationMs / 1000,\n remainingBreakSec: remaining / 1000,\n adIndex: this.currentAdIndex + 1,\n }\n : undefined;\n const bids = await this.adRequest(context);\n this.lastAdRequestTime = Date.now();\n if (!this.inAdBreak) break;\n if (bids.length > 0) {\n this.consecutiveFailures = 0;\n if (this.adLayer.isAdPlaying() || this.isInAdTransition) {\n this.pendingNextAdBids = bids;\n this.totalAdsInBreak = Math.max(\n this.totalAdsInBreak,\n this.currentAdIndex + this.preloadedTokens.length + 1\n );\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Next ad response stored (ad currently playing or in transition)\");\n }\n } else {\n const remainingNow = this.getRemainingAdMs();\n if (this.expectedAdBreakDurationMs != null && remainingNow < this.MIN_AD_REMAINING_MS) {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Skipping ad from loop: only\", remainingNow, \"ms left\");\n }\n } else {\n this.currentAdIndex++;\n if (this.config.licenseKey) {\n sendAdLoadedTracking(this.config.licenseKey, {\n source: this.getAdSource(),\n timestamp: new Date().toISOString(),\n });\n }\n await this.adLayer.playAd(bids);\n if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {\n this.scheduleAdStopCountdown(this.getRemainingAdMs());\n }\n this.adLayer.setAdVolume(\n this.adLayer.getOriginalMutedState() ? 1 : this.adLayer.getOriginalVolume()\n );\n }\n }\n } else {\n this.consecutiveFailures++;\n }\n } catch (err) {\n this.consecutiveFailures++;\n if (this.config.debugAdTiming) {\n console.warn(\"[CONTINUOUS-FETCH] adRequest failed:\", err);\n }\n }\n const sleepMs = (this.inAdBreak && !this.adLayer.isAdPlaying())\n ? 0\n : backoffMs();\n await new Promise((r) => setTimeout(r, sleepMs));\n }\n this.continuousFetchLoopPromise = null;\n }\n\n private async handleAdStart(durationSeconds?: number): Promise<void> {\n const adBreakDurationMs = durationSeconds != null ? durationSeconds * 1000 : undefined;\n\n if (this.config.debugAdTiming) {\n const mode = this.isLiveStream ? \"LIVE\" : \"VOD\";\n console.log(\n `[CONTINUOUS-FETCH] 📺 ${mode} MODE: Target duration=${adBreakDurationMs}ms`\n );\n }\n\n this.consecutiveFailures = 0;\n this.continuousFetchingActive = true;\n this.continuousFetchLoopPromise = null;\n this.pendingNextAdBids = null;\n this.isShowingPlaceholder = false;\n this.totalAdRequestsInBreak = 0;\n\n if (this.savedMutedStateBeforeAd == null && !this.video.muted) {\n this.savedMutedStateBeforeAd = {\n muted: false,\n volume: this.video.volume,\n };\n }\n\n const state = this.savedMutedStateBeforeAd ?? {\n muted: this.video.muted,\n volume: this.video.volume,\n };\n this.adLayer.updateOriginalMutedState(state.muted, state.volume);\n\n if (!this.config.disableFiller && !this.video.muted) {\n this.video.muted = true;\n this.video.volume = 0;\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Muted video in handleAdStart\");\n }\n }\n\n this.inAdBreak = true;\n this.currentAdBreakStartWallClockMs = Date.now();\n this.currentAdIndex = 0;\n this.totalAdsInBreak = Math.max(1, this.preloadedTokens.length);\n this.adPodQueue = [];\n\n if (!this.config.disableFiller) this.showAds = true;\n\n if (adBreakDurationMs != null) {\n this.startFillerBreakTimer(adBreakDurationMs);\n } else if (!this.config.disableFiller && this.preloadedTokens.length === 0) {\n this.showPlaceholderLayer();\n }\n if (!this.config.disableFiller) this.adLayer.showPlaceholder();\n\n if (this.expectedAdBreakDurationMs == null && adBreakDurationMs != null) {\n this.expectedAdBreakDurationMs = adBreakDurationMs;\n }\n\n if (this.expectedAdBreakDurationMs != null) {\n this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);\n }\n\n this.clearPendingAdBreak();\n\n const adBreakToken = Date.now();\n this.activeAdRequestToken = adBreakToken;\n this.startAdFailsafeTimer(adBreakToken);\n this.startAdRequestWatchdog(adBreakToken);\n\n const adVolume = state.muted ? 1 : state.volume;\n\n if (this.preloadedTokens.length > 0) {\n const token = this.preloadedTokens.shift()!;\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] ✅ Playing pre-buffered ad, token=\", token);\n }\n const remaining = this.getRemainingAdMs();\n if (this.expectedAdBreakDurationMs == null || remaining >= this.MIN_AD_REMAINING_MS) {\n this.currentAdIndex++;\n if (this.config.licenseKey) {\n sendAdLoadedTracking(this.config.licenseKey, {\n source: this.getAdSource(),\n timestamp: new Date().toISOString(),\n });\n }\n try {\n await this.adLayer.playPreloaded(token);\n if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {\n this.scheduleAdStopCountdown(this.getRemainingAdMs());\n }\n this.adLayer.setAdVolume(adVolume);\n } catch (err) {\n if (this.config.debugAdTiming) console.warn(\"[CONTINUOUS-FETCH] playPreloaded failed:\", err);\n this.consecutiveFailures++;\n await this.showPlaceholderAndWaitForAds();\n }\n } else {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Skipping ad: only\", remaining, \"ms left in break\");\n }\n this.adLayer.cancelPreload(token);\n await this.showPlaceholderAndWaitForAds();\n }\n }\n\n this.startContinuousFetchLoop();\n }\n\n private stopContinuousFetching(): void {\n this.continuousFetchingActive = false;\n\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] 🛑 Stopping continuous ad fetching\");\n }\n }\n\n private async tryNextAvailableAdWithRateLimit(): Promise<void> {\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) {\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] 🛑 Too many consecutive failures (${this.consecutiveFailures}), ending ad break gracefully`);\n }\n this.handleAdPodComplete();\n return;\n }\n\n const backoffMultiplier = Math.pow(2, this.consecutiveFailures);\n const backoffDelay = Math.min(this.backoffBaseMs * backoffMultiplier, this.maxBackoffMs);\n const effectiveMinInterval = this.minAdRequestIntervalMs + (this.consecutiveFailures > 0 ? backoffDelay : 0);\n \n const timeSinceLastRequest = Date.now() - this.lastAdRequestTime;\n if (timeSinceLastRequest < effectiveMinInterval) {\n const waitTime = effectiveMinInterval - timeSinceLastRequest;\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] ⏳ Rate limiting: waiting ${waitTime}ms before next request (backoff: ${this.consecutiveFailures} failures)`);\n }\n await new Promise(resolve => setTimeout(resolve, waitTime));\n }\n\n return this.tryNextAvailableAd(0);\n }\n\n private async tryNextAvailableAd(_retryCount: number = 0): Promise<void> {\n if (this.totalAdRequestsInBreak >= this.maxTotalAdRequestsPerBreak) {\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] 🛑 Max ad requests per break (${this.maxTotalAdRequestsPerBreak}) reached`);\n }\n this.handleAdPodComplete();\n return;\n }\n const remaining = this.getRemainingAdMs();\n if (remaining <= 500 && this.expectedAdBreakDurationMs != null) {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] ⏹️ No time remaining, ending ad break\");\n }\n this.handleAdPodComplete();\n return;\n }\n\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) {\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] 🛑 Too many consecutive failures (${this.consecutiveFailures}), ending ad break`);\n }\n this.handleAdPodComplete();\n return;\n }\n\n try {\n this.lastAdRequestTime = Date.now();\n const bids = await this.adRequest();\n if (!this.inAdBreak) return;\n if (bids.length > 0) {\n this.consecutiveFailures = 0;\n this.currentAdIndex++;\n this.totalAdRequestsInBreak++;\n if (this.adLayer.isAdPlaying() || this.isInAdTransition) {\n this.pendingNextAdBids = bids;\n this.totalAdsInBreak = Math.max(\n this.totalAdsInBreak,\n this.currentAdIndex + this.preloadedTokens.length\n );\n } else {\n if (this.config.licenseKey) {\n sendAdLoadedTracking(this.config.licenseKey, {\n source: this.getAdSource(),\n timestamp: new Date().toISOString(),\n });\n }\n await this.adLayer.playAd(bids);\n if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {\n this.scheduleAdStopCountdown(this.getRemainingAdMs());\n }\n this.adLayer.setAdVolume(\n this.adLayer.getOriginalMutedState() ? 1 : this.adLayer.getOriginalVolume()\n );\n }\n } else {\n this.consecutiveFailures++;\n await this.showPlaceholderAndWaitForAds();\n }\n } catch (error) {\n this.consecutiveFailures++;\n if (this.config.debugAdTiming) {\n console.warn(\"[CONTINUOUS-FETCH] tryNextAvailableAd request failed:\", error);\n }\n await this.showPlaceholderAndWaitForAds();\n }\n }\n\n private async showPlaceholderAndWaitForAds(): Promise<void> {\n const remaining = this.getRemainingAdMs();\n const waitTime = Math.min(this.maxPlaceholderDurationMs, remaining);\n\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) {\n const stillRemaining = this.getRemainingAdMs();\n if (stillRemaining >= 1000) {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] 🛑 Max failures reached but break still active — resetting and continuing filler\");\n }\n this.consecutiveFailures = 0;\n return;\n }\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] 🛑 Skipping placeholder - too many consecutive failures\");\n }\n this.handleAdPodComplete();\n return;\n }\n\n if (waitTime < 1000) {\n this.handleAdPodComplete();\n return;\n }\n\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] ⬛ Showing placeholder for ${waitTime}ms while waiting for ad response`);\n }\n\n if (!this.config.disableFiller) {\n this.isShowingPlaceholder = true;\n this.showPlaceholderLayer();\n this.adLayer.showPlaceholder();\n }\n\n const checkInterval = 300;\n const maxChecks = Math.floor(waitTime / checkInterval);\n\n for (let i = 0; i < maxChecks; i++) {\n await new Promise((resolve) => setTimeout(resolve, checkInterval));\n\n if (!this.inAdBreak) return;\n\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] 🛑 Too many failures during placeholder wait — resetting and continuing filler\");\n }\n this.consecutiveFailures = 0;\n break;\n }\n\n if (this.pendingNextAdBids != null && this.pendingNextAdBids.length > 0) {\n const bids = this.pendingNextAdBids;\n this.pendingNextAdBids = null;\n this.isShowingPlaceholder = false;\n this.adLayer.hidePlaceholder();\n this.currentAdIndex++;\n try {\n await this.adLayer.playAd(bids);\n this.consecutiveFailures = 0;\n } catch {\n this.consecutiveFailures++;\n await this.tryNextAvailableAdWithRateLimit();\n }\n return;\n }\n\n if (this.adLayer.isAdPlaying()) {\n this.isShowingPlaceholder = false;\n this.adLayer.hidePlaceholder();\n return;\n }\n }\n\n const stillRemaining = this.getRemainingAdMs();\n if (stillRemaining >= 1000) {\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] ⏰ Placeholder slot expired, ${stillRemaining}ms still remaining — continuing filler`);\n }\n this.isShowingPlaceholder = false;\n this.adLayer.hidePlaceholder();\n this.consecutiveFailures = 0;\n return;\n }\n\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] ⏰ Placeholder timeout, ending ad break\");\n }\n\n this.isShowingPlaceholder = false;\n this.adLayer.hidePlaceholder();\n this.handleAdPodComplete();\n }\n\n private onTimeUpdate(_currentTimeSec: number): void {\n if (this.adLayer.isAdPlaying()) return;\n }\n\n private 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 private clearAdStopTimer(): void {\n if (this.adStopTimerId != null) {\n clearTimeout(this.adStopTimerId);\n this.adStopTimerId = undefined;\n }\n }\n\n private ensureAdStoppedByTimer(): void {\n if (!this.inAdBreak) return;\n\n this.adStopTimerId = undefined;\n\n const adPlaying = this.adLayer.isAdPlaying();\n const pendingAds = this.adPodQueue.length > 0;\n const checkIntervalMs = Math.max(\n 250,\n Math.floor(this.config.adBreakCheckIntervalMs ?? 1000)\n );\n const maxExtensionMsConfig = this.config.maxAdBreakExtensionMs;\n const maxExtensionMs =\n typeof maxExtensionMsConfig === \"number\" && maxExtensionMsConfig > 0\n ? maxExtensionMsConfig\n : 60000;\n\n let elapsedSinceStartMs = 0;\n if (this.currentAdBreakStartWallClockMs != null) {\n elapsedSinceStartMs = Date.now() - this.currentAdBreakStartWallClockMs;\n }\n const expectedDurationMs = this.expectedAdBreakDurationMs ?? 0;\n const overrunMs = Math.max(0, elapsedSinceStartMs - expectedDurationMs);\n\n const shouldExtendAdBreak =\n (adPlaying || pendingAds || this.showAds) && overrunMs < maxExtensionMs;\n\n if (shouldExtendAdBreak) {\n this.scheduleAdStopCountdown(checkIntervalMs);\n return;\n }\n\n if (adPlaying) {\n this.adLayer.stop().catch(() => {});\n }\n\n this.handleAdPodComplete();\n }\n\n private handleAdPodComplete(): void {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] 🏁 Ad pod complete - cleaning up\");\n }\n\n this.clearAdRequestWatchdog();\n this.clearAdFailsafeTimer();\n this.clearAdInsertionOffsetTimer();\n this.activeAdRequestToken = null;\n\n this.isInAdTransition = false;\n this.stopContinuousFetching();\n this.stopFillerBreakTimer();\n this.hidePlaceholderLayer();\n this.clearPendingAdBreak();\n this.cancelAndClearPreloadedTokens();\n this.pendingNextAdBids = null;\n\n if (this.isShowingPlaceholder) {\n this.adLayer.hidePlaceholder();\n this.isShowingPlaceholder = false;\n }\n\n this.inAdBreak = false;\n this.expectedAdBreakDurationMs = undefined;\n this.currentAdBreakStartWallClockMs = undefined;\n this.clearAdStopTimer();\n this.adPodQueue = [];\n this.showAds = false;\n this.currentAdIndex = 0;\n this.totalAdsInBreak = 0;\n this.totalAdRequestsInBreak = 0;\n this.consecutiveFailures = 0;\n\n const restoredMuted = this.savedMutedStateBeforeAd?.muted ?? this.adLayer.getOriginalMutedState();\n const restoredVolume = this.savedMutedStateBeforeAd?.volume ?? this.adLayer.getOriginalVolume();\n this.adLayer.updateOriginalMutedState(restoredMuted, restoredVolume);\n\n this.adLayer.stop().catch(() => {});\n\n if (this.video.muted !== restoredMuted) {\n this.video.muted = restoredMuted;\n }\n if (Math.abs(this.video.volume - restoredVolume) > 0.01) {\n this.video.volume = restoredVolume;\n }\n\n const browser = detectBrowser();\n const isSmartTV = browser.tizenVersion !== undefined || browser.webOSVersion !== undefined || !!this.config.singlePipelineMode;\n if (isSmartTV && this.hls) {\n const hlsRef = this.hls;\n const savedMuted = restoredMuted;\n const savedVolume = restoredVolume;\n const videoRef = this.video;\n const debugEnabled = this.config.debugAdTiming;\n\n const tryPlay = (attempt: number) => {\n if (this.inAdBreak || this.adLayer.isAdPlaying()) return;\n videoRef.play()?.catch(() => {\n if (attempt < 3) {\n if (debugEnabled) {\n console.log(`[StormcloudVideoPlayer] Smart TV: play() retry ${attempt + 1}/3 in ${500 * (attempt + 1)}ms`);\n }\n setTimeout(() => tryPlay(attempt + 1), 500 * (attempt + 1));\n }\n });\n };\n\n const onManifestParsedRestore = () => {\n hlsRef.off(Hls.Events.MANIFEST_PARSED, onManifestParsedRestore);\n if (!this.inAdBreak && !this.adLayer.isAdPlaying()) {\n if (videoRef.muted !== savedMuted) videoRef.muted = savedMuted;\n if (Math.abs(videoRef.volume - savedVolume) > 0.01) videoRef.volume = savedVolume;\n if (debugEnabled) {\n console.log(\"[StormcloudVideoPlayer] Smart TV: audio state restored on MANIFEST_PARSED after re-attach\");\n }\n hlsRef.startLoad(-1);\n if (debugEnabled) {\n console.log(\"[StormcloudVideoPlayer] Smart TV: seeking to live edge and resuming playback after re-attach\");\n }\n }\n };\n hlsRef.on(Hls.Events.MANIFEST_PARSED, onManifestParsedRestore);\n\n const pipelineDelayMs = 300;\n if (debugEnabled) {\n console.log(`[StormcloudVideoPlayer] Smart TV: waiting ${pipelineDelayMs}ms for hardware pipeline release before re-attach`);\n }\n setTimeout(() => {\n if (this.inAdBreak || this.adLayer.isAdPlaying()) return;\n if (this.hls) {\n this.hls.attachMedia(this.video);\n if (debugEnabled) {\n console.log(\"[StormcloudVideoPlayer] Smart TV: re-attached HLS to video element after ad break to restore media pipeline\");\n }\n }\n }, pipelineDelayMs);\n } else {\n if (this.shouldContinueLiveStreamDuringAds()) {\n if (this.config.debugAdTiming) {\n if (this.video.paused) {\n console.log(\"[StormcloudVideoPlayer] Content video paused in live mode after ads, resuming playback\");\n } else {\n console.log(\"[StormcloudVideoPlayer] Content video already playing in live mode after ads\");\n }\n }\n this.video.play()?.catch(() => {});\n } else if (this.video.paused) {\n this.video.play()?.catch(() => {});\n }\n }\n\n this.syncMainContentAudioWhenVisible();\n\n if (!restoredMuted) {\n requestAnimationFrame(() => {\n this.syncMainContentAudioWhenVisible();\n });\n setTimeout(() => {\n this.syncMainContentAudioWhenVisible();\n }, 0);\n setTimeout(() => {\n this.syncMainContentAudioWhenVisible();\n }, 50);\n setTimeout(() => {\n this.syncMainContentAudioWhenVisible();\n }, 100);\n setTimeout(() => {\n this.syncMainContentAudioWhenVisible();\n }, 150);\n }\n\n if (isSmartTV && !restoredMuted) {\n [500, 1000, 2000, 3000, 5000].forEach(delay => {\n setTimeout(() => {\n if (!this.inAdBreak && !this.adLayer.isAdPlaying()) {\n if (this.video.muted !== restoredMuted) this.video.muted = restoredMuted;\n if (Math.abs(this.video.volume - restoredVolume) > 0.01) this.video.volume = restoredVolume;\n }\n }, delay);\n });\n }\n\n this.savedMutedStateBeforeAd = null;\n }\n\n private handleAdFailure(): void {\n this.consecutiveFailures++;\n if (this.config.debugAdTiming) {\n console.log(\n `[CONTINUOUS-FETCH] Ad failure: consecutiveFailures=${this.consecutiveFailures}`\n );\n }\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) {\n if (this.config.debugAdTiming) {\n console.log(`[CONTINUOUS-FETCH] 🛑 Max consecutive failures reached (${this.consecutiveFailures}), ending ad break gracefully`);\n }\n this.handleAdPodComplete();\n return;\n }\n\n if (this.inAdBreak && !this.config.disableFiller) {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Ad failure in active break — showing filler while awaiting next ad\");\n }\n this.showPlaceholderLayer();\n this.adLayer.showPlaceholder();\n } else if (this.inAdBreak) {\n if (this.config.debugAdTiming) {\n console.log(\"[CONTINUOUS-FETCH] Ad failure with no filler — restoring main video temporarily\");\n }\n this.adLayer.hidePlaceholder();\n if (!this.adLayer.isAdPlaying() && this.video.paused && this.video.readyState >= 2) {\n this.video.play()?.catch(() => {});\n }\n }\n }\n\n private 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.handleAdFailure();\n }, timeoutMs) as unknown as number;\n\n this.logAdState(\"ad_request_watchdog_started\", { token, timeoutMs });\n }\n\n private 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 private 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 imaAdPlaying: this.adLayer.isAdPlaying(),\n });\n\n this.handleAdFailure();\n }, failsafeMs) as unknown as number;\n\n this.logAdState(\"ad_failsafe_started\", { token, failsafeMs });\n }\n\n private 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 private logAdState(event: string, extra: Record<string, unknown> = {}): void {\n if (!this.config.debugAdTiming) {\n return;\n }\n this.pushDebugLog(\"info\", \"ad-state\", event, extra);\n\n console.log(\"[StormcloudVideoPlayer][AdState]\", {\n event,\n timestamp: new Date().toISOString(),\n showAds: this.showAds,\n adPlaying: this.adLayer.isAdPlaying(),\n inAdBreak: this.inAdBreak,\n activeAdRequestToken: this.activeAdRequestToken,\n ...extra,\n });\n }\n\n private getRemainingAdMs(): number {\n if (this.currentAdBreakStartWallClockMs == null) return 0;\n if (this.expectedAdBreakDurationMs == null) return Number.MAX_SAFE_INTEGER;\n const elapsed = Date.now() - this.currentAdBreakStartWallClockMs;\n return Math.max(0, this.expectedAdBreakDurationMs - elapsed);\n }\n\n private pushDebugLog(\n level: DebugLogLevel,\n category: string,\n message: string,\n details?: Record<string, unknown>\n ): void {\n if (!this.config.debugAdTiming) return;\n this.debugLogEntries.push({\n timestampMs: Date.now(),\n level,\n category,\n message,\n ...(details ? { details } : {}),\n });\n if (this.debugLogEntries.length > DEBUG_HISTORY_LIMIT) {\n this.debugLogEntries = this.debugLogEntries.slice(-DEBUG_HISTORY_LIMIT);\n }\n }\n\n private pushAdInsertionDebug(\n event: AdInsertionDebugEvent,\n segmentName: string,\n opts?: { offsetSeconds?: number; updatedAt?: string; detail?: string }\n ): void {\n if (!this.config.debugAdTiming) return;\n this.adInsertionDebugHistory.push({\n timestampMs: Date.now(),\n event,\n segmentName,\n ...(opts?.offsetSeconds !== undefined ? { offsetSeconds: opts.offsetSeconds } : {}),\n ...(opts?.updatedAt ? { updatedAt: opts.updatedAt } : {}),\n ...(opts?.detail ? { detail: opts.detail } : {}),\n });\n if (this.adInsertionDebugHistory.length > DEBUG_HISTORY_LIMIT) {\n this.adInsertionDebugHistory = this.adInsertionDebugHistory.slice(-DEBUG_HISTORY_LIMIT);\n }\n }\n\n getAdInsertionDebugLog(): ReadonlyArray<{\n timestampMs: number;\n event: string;\n segmentName: string;\n offsetSeconds?: number;\n updatedAt?: string;\n detail?: string;\n }> {\n return this.adInsertionDebugHistory.slice();\n }\n\n getDebugLogs(): ReadonlyArray<{\n timestampMs: number;\n level: DebugLogLevel;\n category: string;\n message: string;\n details?: Record<string, unknown>;\n }> {\n return this.debugLogEntries.slice();\n }\n\n toggleMute(): void {\n if (this.adLayer.isAdPlaying()) {\n const isAdCurrentlyMuted = this.adLayer.getAdVolume() === 0;\n if (isAdCurrentlyMuted) {\n const savedVolume = this.adLayer.getOriginalVolume() || 1;\n this.adLayer.setAdVolume(savedVolume);\n this.adLayer.updateOriginalMutedState(false, savedVolume);\n } else {\n const currentAdVolume = this.adLayer.getAdVolume();\n this.adLayer.setAdVolume(0);\n this.adLayer.updateOriginalMutedState(true, currentAdVolume);\n }\n\n if (this.config.debugAdTiming) {\n console.log(\n \"[StormcloudVideoPlayer] Mute toggle during ad:\", isAdCurrentlyMuted ? \"unmuted\" : \"muted\"\n );\n }\n } else {\n this.video.muted = !this.video.muted;\n this.adLayer.updateOriginalMutedState(this.video.muted, this.video.volume);\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Muted:\", this.video.muted);\n }\n }\n }\n\n toggleFullscreen(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!document.fullscreenElement) {\n const container = this.video.parentElement;\n if (!container) {\n reject(new Error(\"No parent container found for fullscreen\"));\n return;\n }\n container\n .requestFullscreen()\n .then(() => {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Entered fullscreen\");\n }\n resolve();\n })\n .catch((err) => {\n if (this.config.debugAdTiming) {\n console.error(\"[StormcloudVideoPlayer] Fullscreen error:\", err);\n }\n reject(err);\n });\n } else {\n document\n .exitFullscreen()\n .then(() => {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Exited fullscreen\");\n }\n resolve();\n })\n .catch((err) => {\n if (this.config.debugAdTiming) {\n console.error(\n \"[StormcloudVideoPlayer] Exit fullscreen error:\",\n err\n );\n }\n reject(err);\n });\n }\n });\n }\n\n isMuted(): boolean {\n if (this.adLayer.isAdPlaying()) {\n const adMuted = this.adLayer.getAdVolume() === 0;\n if (this.config.debugAdTiming) {\n console.log(\n \"[StormcloudVideoPlayer] isMuted() during ad playback ->\", adMuted\n );\n }\n return adMuted;\n }\n return this.video.muted;\n }\n\n setMuted(muted: boolean): void {\n const adPlaying = this.adLayer.isAdPlaying();\n\n if (adPlaying) {\n const savedVolume = this.adLayer.getOriginalVolume() || 1;\n this.adLayer.setAdVolume(muted ? 0 : savedVolume);\n this.adLayer.updateOriginalMutedState(muted, savedVolume);\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] setMuted applied to ad layer (content stays muted)\", {\n muted, savedVolume,\n });\n }\n return;\n }\n\n this.video.muted = muted;\n\n if (!this.inAdBreak) {\n this.adLayer.updateOriginalMutedState(muted, this.video.volume);\n }\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] setMuted called:\", muted);\n }\n }\n\n setVolume(volume: number): void {\n const clampedVolume = Math.max(0, Math.min(1, volume));\n const adPlaying = this.adLayer.isAdPlaying();\n\n if (adPlaying) {\n this.adLayer.setAdVolume(clampedVolume);\n const preservedVolume = clampedVolume > 0 ? clampedVolume : this.adLayer.getOriginalVolume();\n this.adLayer.updateOriginalMutedState(clampedVolume === 0, preservedVolume);\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] setVolume applied during ad\", {\n volume: clampedVolume,\n });\n }\n } else {\n this.video.volume = clampedVolume;\n this.video.muted = clampedVolume === 0;\n if (!this.inAdBreak) {\n this.adLayer.updateOriginalMutedState(clampedVolume === 0, clampedVolume);\n }\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] setVolume called:\", clampedVolume);\n }\n }\n }\n\n getVolume(): number {\n const adPlaying = this.adLayer.isAdPlaying();\n if (adPlaying) {\n return this.adLayer.getAdVolume();\n }\n return this.video.volume;\n }\n\n isFullscreen(): boolean {\n return !!document.fullscreenElement;\n }\n\n isLive(): boolean {\n return this.isLiveStream;\n }\n\n getMinHlsResolution(): { width: number; height: number } | null {\n const levels = this.hls?.levels;\n if (!levels || levels.length === 0) return null;\n\n let min: { width: number; height: number } | null = null;\n let minPixels = Infinity;\n\n for (const level of levels) {\n if (level.width && level.height) {\n const pixels = level.width * level.height;\n if (pixels < minPixels) {\n minPixels = pixels;\n min = { width: level.width, height: level.height };\n }\n }\n }\n return min;\n }\n\n getCurrentHlsSegmentDurationMs(): number | null {\n const fallbackMs = 4000;\n\n if (this.nativeHlsMode) {\n return fallbackMs;\n }\n\n const hls = this.hls;\n if (!hls) return null;\n\n const levelCandidates = [hls.currentLevel, hls.nextLoadLevel, hls.loadLevel];\n for (const levelIndex of levelCandidates) {\n if (typeof levelIndex !== \"number\" || levelIndex < 0) continue;\n const details = hls.levels?.[levelIndex]?.details as\n | { targetduration?: number; partTarget?: number }\n | undefined;\n if (!details) continue;\n\n const targetDurationSec =\n typeof details.partTarget === \"number\" && details.partTarget > 0\n ? details.partTarget\n : typeof details.targetduration === \"number\" && details.targetduration > 0\n ? details.targetduration\n : undefined;\n\n if (targetDurationSec !== undefined) {\n return Math.max(800, Math.floor(targetDurationSec * 1000));\n }\n }\n\n return fallbackMs;\n }\n\n get videoElement(): HTMLVideoElement {\n return this.video;\n }\n\n resize(): void {\n if (this.config.debugAdTiming) {\n console.log(\"[StormcloudVideoPlayer] Resizing player\");\n }\n\n if (this.adLayer && this.adLayer.isAdPlaying()) {\n const width = this.video.clientWidth || 640;\n const height = this.video.clientHeight || 480;\n\n if (this.config.debugAdTiming) {\n console.log(\n `[StormcloudVideoPlayer] Resizing ads manager to ${width}x${height}`\n );\n }\n\n this.adLayer.resize(width, height);\n }\n }\n\n destroy(): void {\n this.stopAdInsertionPolling();\n this.clearAdInsertionOffsetTimer();\n this.stopContinuousFetching();\n this.stopFillerBreakTimer();\n this.clearAdStopTimer();\n this.clearAdFailsafeTimer();\n this.clearAdRequestWatchdog();\n this.clearPendingAdBreak();\n \n if (this.fillerVideo) {\n this.fillerVideo.pause();\n if (this.fillerVideo.parentElement) {\n this.fillerVideo.parentElement.removeChild(this.fillerVideo);\n }\n this.fillerVideo = undefined;\n }\n \n if (this.timeUpdateHandler) {\n this.video.removeEventListener(\"timeupdate\", this.timeUpdateHandler);\n delete this.timeUpdateHandler;\n }\n if (this.emptiedHandler) {\n this.video.removeEventListener(\"emptied\", this.emptiedHandler);\n delete this.emptiedHandler;\n }\n \n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n this.heartbeatInterval = undefined;\n }\n this.hls?.destroy();\n this.adLayer?.destroy();\n this.consecutiveFailures = 0;\n this.debugLogEntries = [];\n this.adInsertionDebugHistory = [];\n }\n}\n","export interface VastMediaFile {\n url: string;\n type: string;\n width: number;\n height: number;\n bitrate?: number | undefined;\n}\n\nexport interface VastTrackingUrls {\n impression: string[];\n start: string[];\n firstQuartile: string[];\n midpoint: string[];\n thirdQuartile: string[];\n complete: string[];\n mute: string[];\n unmute: string[];\n pause: string[];\n resume: string[];\n fullscreen: string[];\n exitFullscreen: string[];\n skip: string[];\n error: string[];\n}\n\nexport interface VastAd {\n id: string;\n title: string;\n duration: number;\n mediaFiles: VastMediaFile[];\n trackingUrls: VastTrackingUrls;\n clickThrough?: string | undefined;\n}\n\nexport type MediaFileFilter = \"hls-only\" | \"mp4-first\" | \"all\";\n\nfunction isHlsType(type: string): boolean {\n return type === \"application/x-mpegURL\" || type.includes(\"m3u8\");\n}\n\nfunction isMp4Type(type: string): boolean {\n return type === \"video/mp4\" || type.includes(\"mp4\");\n}\n\nexport function parseVastXml(\n xmlString: string,\n filter: MediaFileFilter = \"all\",\n logPrefix = \"[VastParser]\"\n): VastAd | null {\n try {\n const parser = new DOMParser();\n const xmlDoc = parser.parseFromString(xmlString, \"text/xml\");\n\n const parserError = xmlDoc.querySelector(\"parsererror\");\n if (parserError) {\n console.error(\n `${logPrefix} XML parsing error (malformed VAST XML):`,\n parserError.textContent\n );\n return null;\n }\n\n const adElement = xmlDoc.querySelector(\"Ad\");\n if (!adElement) {\n console.warn(`${logPrefix} No Ad element found in VAST XML`);\n return null;\n }\n\n const adId = adElement.getAttribute(\"id\") || \"unknown\";\n const title = xmlDoc.querySelector(\"AdTitle\")?.textContent || \"Ad\";\n\n const isNoAdAvailable =\n adId === \"empty\" ||\n title.toLowerCase().includes(\"no ad available\") ||\n title.toLowerCase() === \"no ad available\";\n\n const durationText =\n xmlDoc.querySelector(\"Duration\")?.textContent || \"00:00:30\";\n const durationParts = durationText.split(\":\");\n const duration =\n parseInt(durationParts[0] || \"0\", 10) * 3600 +\n parseInt(durationParts[1] || \"0\", 10) * 60 +\n Math.round(parseFloat(durationParts[2] || \"0\"));\n\n const mediaFileElements = xmlDoc.querySelectorAll(\"MediaFile\");\n const mediaFiles: VastMediaFile[] = [];\n\n console.log(\n `${logPrefix} Found ${mediaFileElements.length} MediaFile element(s) in VAST XML`\n );\n\n mediaFileElements.forEach((mf, index) => {\n const type = mf.getAttribute(\"type\") || \"\";\n const url = mf.textContent?.trim() || \"\";\n const width = mf.getAttribute(\"width\") || \"\";\n const height = mf.getAttribute(\"height\") || \"\";\n\n console.log(\n `${logPrefix} MediaFile ${index}: type=\"${type}\", url=\"${url.substring(0, 80)}...\", width=\"${width}\", height=\"${height}\"`\n );\n\n if (!url) {\n console.warn(`${logPrefix} MediaFile ${index} has empty URL`);\n return;\n }\n\n const isHls = isHlsType(type);\n const isMp4 = isMp4Type(type);\n\n let accepted = false;\n if (filter === \"hls-only\") {\n accepted = isHls;\n } else if (filter === \"mp4-first\") {\n accepted = isMp4 || isHls;\n } else {\n accepted = true;\n }\n\n if (!accepted) {\n console.log(\n `${logPrefix} MediaFile ${index} ignored (type=\"${type}\" not accepted by filter \"${filter}\")`\n );\n return;\n }\n\n const bitrateAttr = mf.getAttribute(\"bitrate\");\n const bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : undefined;\n\n mediaFiles.push({\n url,\n type,\n width: parseInt(width || \"1920\", 10),\n height: parseInt(height || \"1080\", 10),\n bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : undefined,\n });\n\n console.log(`${logPrefix} Added MediaFile: type=\"${type}\" url=\"${url.substring(0, 80)}...\"`);\n });\n\n if (filter === \"mp4-first\" && mediaFiles.length > 1) {\n mediaFiles.sort((a, b) => {\n const aIsMp4 = isMp4Type(a.type) ? 0 : 1;\n const bIsMp4 = isMp4Type(b.type) ? 0 : 1;\n return aIsMp4 - bIsMp4;\n });\n }\n\n if (mediaFiles.length === 0) {\n if (isNoAdAvailable) {\n console.warn(\n `${logPrefix} No ads available (VAST response indicates no ads)`\n );\n } else {\n console.warn(`${logPrefix} No compatible media files found in VAST XML`);\n }\n return null;\n }\n\n const trackingUrls: VastTrackingUrls = {\n impression: [],\n start: [],\n firstQuartile: [],\n midpoint: [],\n thirdQuartile: [],\n complete: [],\n mute: [],\n unmute: [],\n pause: [],\n resume: [],\n fullscreen: [],\n exitFullscreen: [],\n skip: [],\n error: [],\n };\n\n xmlDoc.querySelectorAll(\"Impression\").forEach((el) => {\n const url = el.textContent?.trim();\n if (url) trackingUrls.impression.push(url);\n });\n\n xmlDoc.querySelectorAll(\"Tracking\").forEach((el) => {\n const event = el.getAttribute(\"event\");\n const url = el.textContent?.trim();\n if (event && url) {\n const eventKey = event as keyof VastTrackingUrls;\n if (trackingUrls[eventKey]) {\n trackingUrls[eventKey].push(url);\n }\n }\n });\n\n const clickThrough = xmlDoc\n .querySelector(\"ClickThrough\")\n ?.textContent?.trim();\n\n return {\n id: adId,\n title,\n duration,\n mediaFiles,\n trackingUrls,\n clickThrough,\n };\n } catch (error) {\n console.error(`${logPrefix} Error parsing VAST XML:`, error);\n return null;\n }\n}\n\nexport async function fetchAndParseVastAd(\n vastTagUrl: string,\n filter: MediaFileFilter = \"all\",\n logPrefix = \"[VastParser]\"\n): Promise<VastAd | null> {\n const response = await fetch(vastTagUrl, {\n mode: \"cors\",\n credentials: \"include\",\n headers: {\n Accept: \"application/xml, text/xml, */*\",\n },\n referrerPolicy: \"no-referrer-when-downgrade\",\n });\n if (!response.ok) {\n throw new Error(`Failed to fetch VAST: ${response.statusText}`);\n }\n\n const vastXml = await response.text();\n console.log(`${logPrefix} VAST XML received`);\n console.log(\n `${logPrefix} VAST XML content (first 2000 chars):`,\n vastXml.substring(0, 2000)\n );\n\n return parseVastXml(vastXml, filter, logPrefix);\n}\n\nexport function createEmptyTrackingState() {\n return {\n impression: false,\n start: false,\n firstQuartile: false,\n midpoint: false,\n thirdQuartile: false,\n complete: false,\n };\n}\n\nasync function firePixelWithRetry(\n url: string,\n retries = 2,\n delayMs = 500,\n logPrefix = \"[VastParser]\"\n): Promise<void> {\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n await fetch(url, {\n method: \"GET\",\n mode: \"no-cors\",\n cache: \"no-cache\",\n keepalive: true,\n });\n return;\n } catch {\n if (attempt < retries) {\n await new Promise((r) => setTimeout(r, delayMs * Math.pow(2, attempt)));\n } else {\n console.warn(`${logPrefix} Tracking pixel failed after ${retries + 1} attempts: ${url}`);\n }\n }\n }\n}\n\nexport function fireTrackingPixels(\n urls: string[],\n sessionId?: string,\n logPrefix = \"[VastParser]\"\n): void {\n if (!urls || urls.length === 0) return;\n\n urls.forEach((url) => {\n try {\n let trackingUrl = url;\n\n if (sessionId) {\n trackingUrl = `${trackingUrl}${\n trackingUrl.includes(\"?\") ? \"&\" : \"?\"\n }session_id=${sessionId}`;\n }\n\n if (typeof fetch !== \"undefined\") {\n firePixelWithRetry(trackingUrl, 2, 500, logPrefix).catch(() => {});\n } else {\n const img = new Image(1, 1);\n img.onerror = () => {};\n img.src = trackingUrl;\n }\n\n console.log(`${logPrefix} Fired tracking pixel: ${trackingUrl}`);\n } catch (error) {\n console.warn(`${logPrefix} Error firing tracking pixel:`, error);\n }\n });\n}\n","import type { AdController, AdBreakContext } from \"../types\";\nimport { fireTrackingPixels as fireTrackingPixelsShared } from \"./vastParser\";\n\ninterface VastMediaFile {\n url: string;\n type: string;\n width: number;\n height: number;\n bitrate?: number | undefined;\n}\n\nconst SUPPORTED_VIDEO_EXTENSIONS = ['.mp4', '.webm', '.ogg', '.m3u8', '.ts'];\nconst UNSUPPORTED_VIDEO_EXTENSIONS = ['.flv', '.f4v', '.swf', '.wmv', '.avi', '.mov', '.mkv'];\nconst REQUEST_TIMEOUT_MS = 5000;\nconst REQUEST_MAX_RETRIES = 3;\nconst REQUEST_RETRY_BACKOFF_MS = 1500;\nconst AD_LAYER_Z_INDEX = \"30\";\nconst COUNTDOWN_Z_INDEX = \"31\";\nconst STALL_TIMEOUT_MS = 8000;\n\nfunction getFileExtension(url: string): string {\n try {\n const pathname = new URL(url, 'http://dummy').pathname;\n const lastDot = pathname.lastIndexOf('.');\n if (lastDot === -1) return '';\n return pathname.slice(lastDot).toLowerCase();\n } catch {\n const lastDot = url.lastIndexOf('.');\n if (lastDot === -1) return '';\n const ext = url.slice(lastDot).split(/[?#]/)[0];\n return (ext || '').toLowerCase();\n }\n}\n\nfunction isUnsupportedFormat(url: string): boolean {\n const ext = getFileExtension(url);\n return UNSUPPORTED_VIDEO_EXTENSIONS.indexOf(ext) !== -1;\n}\n\nfunction replaceFlvExtension(url: string): string {\n const ext = getFileExtension(url);\n if (ext === '.flv') {\n return url.replace(/\\.flv(\\?|$)/i, '.mp4$1');\n }\n return url;\n}\n\nfunction isSupportedFormat(url: string, mimeType: string): boolean {\n if (isUnsupportedFormat(url)) {\n return false;\n }\n \n const ext = getFileExtension(url);\n \n if (SUPPORTED_VIDEO_EXTENSIONS.indexOf(ext) !== -1) {\n return true;\n }\n \n if (ext === '' || ext === '.') {\n return mimeType.includes('video/mp4') || \n mimeType.includes('video/webm') || \n mimeType.includes('m3u8') ||\n mimeType.includes('application/x-mpegurl');\n }\n \n return false;\n}\n\ninterface VastTrackingUrls {\n impression: string[];\n start: string[];\n firstQuartile: string[];\n midpoint: string[];\n thirdQuartile: string[];\n complete: string[];\n mute: string[];\n unmute: string[];\n pause: string[];\n resume: string[];\n error: string[];\n}\n\ninterface VastAd {\n id: string;\n title: string;\n duration: number;\n mediaFiles: VastMediaFile[];\n trackingUrls: VastTrackingUrls;\n clickThrough?: string | undefined;\n}\n\nexport interface AdStormPlayerOptions {\n licenseKey: string;\n debug?: boolean;\n}\n\nexport interface AdStormLayerOptionsUpdate {\n continueLiveStreamDuringAds?: boolean;\n mainHlsInstance?: unknown;\n}\n\nexport interface AdStormAdLayer extends AdController {\n requestAds: (duration?: string) => Promise<void>;\n updateOptions: (opts: AdStormLayerOptionsUpdate) => void;\n playAd: (requestContext?: unknown) => Promise<void>;\n preloadAd: (arg1: unknown, arg2?: unknown) => Promise<void>;\n playPreloaded: (token: string) => Promise<void>;\n hasPreloaded: (token: string) => boolean;\n cancelPreload: (token: string) => void;\n}\n\nexport function createAdStormPlayer(\n contentVideo: HTMLVideoElement,\n options: AdStormPlayerOptions\n): AdStormAdLayer {\n const { licenseKey, debug = false } = options;\n \n let adPlaying = false;\n let originalMutedState = false;\n let originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));\n const listeners = new Map<string, Set<(payload?: any) => void>>();\n \n let adVideoElement: HTMLVideoElement | undefined;\n let adContainerEl: HTMLDivElement | undefined;\n let adCountdownEl: HTMLDivElement | undefined;\n let currentAd: VastAd | undefined;\n let destroyed = false;\n let tornDown = false;\n let continueLiveStreamDuringAds = false;\n let sessionId: string | undefined;\n let adStallTimerId: ReturnType<typeof setTimeout> | undefined;\n let adCountdownTimerId: ReturnType<typeof setInterval> | undefined;\n let adHideTimerId: ReturnType<typeof setTimeout> | undefined;\n let lastCountdownSecond = -1;\n let adListenersBound = false;\n let parentPositionOverridden = false;\n\n const adHandlers = {\n timeupdate: () => {\n if (!currentAd || !adVideoElement || destroyed || tornDown) return;\n const progress = adVideoElement.currentTime / currentAd.duration;\n\n if (progress >= 0.25 && !trackingFired.firstQuartile) {\n trackingFired.firstQuartile = true;\n fireTrackingPixels(currentAd.trackingUrls.firstQuartile);\n }\n if (progress >= 0.5 && !trackingFired.midpoint) {\n trackingFired.midpoint = true;\n fireTrackingPixels(currentAd.trackingUrls.midpoint);\n }\n if (progress >= 0.75 && !trackingFired.thirdQuartile) {\n trackingFired.thirdQuartile = true;\n fireTrackingPixels(currentAd.trackingUrls.thirdQuartile);\n }\n updateAdCountdown();\n },\n playing: () => {\n clearAdStallTimer();\n if (!currentAd || trackingFired.start || destroyed || tornDown) return;\n trackingFired.start = true;\n fireTrackingPixels(currentAd.trackingUrls.start);\n startAdCountdown();\n log(\"Ad started playing\");\n },\n ended: () => {\n if (!currentAd || trackingFired.complete || destroyed || tornDown) return;\n trackingFired.complete = true;\n fireTrackingPixels(currentAd.trackingUrls.complete);\n log(\"Ad completed\");\n handleAdComplete();\n },\n error: (e: Event) => {\n if (destroyed || tornDown) return;\n console.error(\"[AdStormPlayer] Ad video error:\", e);\n if (currentAd) fireTrackingPixels(currentAd.trackingUrls.error);\n handleAdError();\n },\n waiting: () => {\n clearAdStallTimer();\n adStallTimerId = setTimeout(() => {\n adStallTimerId = undefined;\n if (!adPlaying || destroyed || tornDown) return;\n console.warn(\"[AdStormPlayer] Ad playback stalled too long\");\n handleAdError();\n }, STALL_TIMEOUT_MS);\n },\n volumechange: () => {\n if (!currentAd || !adVideoElement || destroyed || tornDown) return;\n if (adVideoElement.muted || adVideoElement.volume <= 0) {\n fireTrackingPixels(currentAd.trackingUrls.mute);\n } else {\n fireTrackingPixels(currentAd.trackingUrls.unmute);\n }\n },\n pause: () => {\n if (!currentAd || !adVideoElement || destroyed || tornDown) return;\n if (!adVideoElement.ended) {\n fireTrackingPixels(currentAd.trackingUrls.pause);\n }\n },\n play: () => {\n if (!currentAd || !adVideoElement || destroyed || tornDown) return;\n if (adVideoElement.currentTime > 0) {\n fireTrackingPixels(currentAd.trackingUrls.resume);\n }\n },\n };\n \n let trackingFired = {\n impression: false,\n start: false,\n firstQuartile: false,\n midpoint: false,\n thirdQuartile: false,\n complete: false,\n };\n const preloadSlots = new Map<string, { ad: VastAd }>();\n\n function log(...args: any[]): void {\n if (debug) {\n console.log(\"[AdStormPlayer]\", ...args);\n }\n }\n\n function emit(event: string, payload?: any): void {\n const set = listeners.get(event);\n if (!set) return;\n for (const fn of Array.from(set)) {\n try {\n fn(payload);\n } catch (error) {\n console.warn(`[AdStormPlayer] Error in event listener for ${event}:`, error);\n }\n }\n }\n\n function fireTrackingPixels(urls: string[]): void {\n fireTrackingPixelsShared(urls, sessionId, \"[AdStormPlayer]\");\n }\n\n function clearAdStallTimer(): void {\n if (adStallTimerId) {\n clearTimeout(adStallTimerId);\n adStallTimerId = undefined;\n }\n }\n\n function clearAdCountdownTimer(): void {\n if (adCountdownTimerId) {\n clearInterval(adCountdownTimerId);\n adCountdownTimerId = undefined;\n }\n lastCountdownSecond = -1;\n }\n\n function updateAdCountdown(): void {\n if (!adCountdownEl || !adVideoElement || !currentAd || !adPlaying) return;\n const remainingSec = Math.max(\n 0,\n Math.ceil((currentAd.duration || 0) - adVideoElement.currentTime)\n );\n if (remainingSec === lastCountdownSecond) return;\n lastCountdownSecond = remainingSec;\n adCountdownEl.textContent = `Ad ${remainingSec}s`;\n emit(\"ad_countdown\", {\n remainingSec,\n durationSec: currentAd.duration,\n currentTimeSec: adVideoElement.currentTime,\n });\n }\n\n function startAdCountdown(): void {\n clearAdCountdownTimer();\n updateAdCountdown();\n adCountdownTimerId = setInterval(updateAdCountdown, 250);\n }\n\n function generateSessionId(): string {\n return `adstorm-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;\n }\n\n function bindAdEventListeners(): void {\n if (!adVideoElement || adListenersBound) return;\n adVideoElement.addEventListener(\"timeupdate\", adHandlers.timeupdate);\n adVideoElement.addEventListener(\"playing\", adHandlers.playing);\n adVideoElement.addEventListener(\"ended\", adHandlers.ended);\n adVideoElement.addEventListener(\"error\", adHandlers.error);\n adVideoElement.addEventListener(\"waiting\", adHandlers.waiting);\n adVideoElement.addEventListener(\"volumechange\", adHandlers.volumechange);\n adVideoElement.addEventListener(\"pause\", adHandlers.pause);\n adVideoElement.addEventListener(\"play\", adHandlers.play);\n adListenersBound = true;\n }\n\n function unbindAdEventListeners(): void {\n if (!adVideoElement || !adListenersBound) return;\n adVideoElement.removeEventListener(\"timeupdate\", adHandlers.timeupdate);\n adVideoElement.removeEventListener(\"playing\", adHandlers.playing);\n adVideoElement.removeEventListener(\"ended\", adHandlers.ended);\n adVideoElement.removeEventListener(\"error\", adHandlers.error);\n adVideoElement.removeEventListener(\"waiting\", adHandlers.waiting);\n adVideoElement.removeEventListener(\"volumechange\", adHandlers.volumechange);\n adVideoElement.removeEventListener(\"pause\", adHandlers.pause);\n adVideoElement.removeEventListener(\"play\", adHandlers.play);\n adListenersBound = false;\n }\n\n function teardownCurrentPlayback(): void {\n unbindAdEventListeners();\n clearAdStallTimer();\n clearAdCountdownTimer();\n if (!adVideoElement) return;\n adVideoElement.pause();\n adVideoElement.removeAttribute(\"src\");\n adVideoElement.load();\n }\n\n function buildVastUrl(durationSeconds: number): string {\n const baseUrl = `https://adstorm.co/api-adstorm-dev/adstorm/nab/vast/pod`;\n\n return `${baseUrl}?duration=${Math.ceil(durationSeconds)}`;\n }\n\n function parseVastXml(xmlString: string): VastAd[] {\n const ads: VastAd[] = [];\n \n try {\n const parser = new DOMParser();\n const xmlDoc = parser.parseFromString(xmlString, \"text/xml\");\n \n const parserError = xmlDoc.querySelector(\"parsererror\");\n if (parserError) {\n console.error(\"[AdStormPlayer] XML parsing error:\", parserError.textContent);\n return [];\n }\n \n const adElements = xmlDoc.querySelectorAll(\"Ad\");\n \n adElements.forEach((adElement) => {\n const adId = adElement.getAttribute(\"id\") || \"unknown\";\n const title = adElement.querySelector(\"AdTitle\")?.textContent || \"Ad\";\n \n const durationText = adElement.querySelector(\"Duration\")?.textContent || \"00:00:30\";\n const durationParts = durationText.split(\":\");\n const duration =\n parseInt(durationParts[0] || \"0\", 10) * 3600 +\n parseInt(durationParts[1] || \"0\", 10) * 60 +\n parseFloat(durationParts[2] || \"0\");\n \n const mediaFileElements = adElement.querySelectorAll(\"MediaFile\");\n const mediaFiles: VastMediaFile[] = [];\n \n mediaFileElements.forEach((mf) => {\n const type = mf.getAttribute(\"type\") || \"\";\n let url = mf.textContent?.trim() || \"\";\n const width = parseInt(mf.getAttribute(\"width\") || \"1920\", 10);\n const height = parseInt(mf.getAttribute(\"height\") || \"1080\", 10);\n const bitrate = mf.getAttribute(\"bitrate\") \n ? parseInt(mf.getAttribute(\"bitrate\")!, 10) \n : undefined;\n \n if (!url) {\n log(`Skipping empty MediaFile URL`);\n return;\n }\n \n const originalUrl = url;\n url = replaceFlvExtension(url);\n if (url !== originalUrl) {\n log(`Converted FLV to MP4: ${originalUrl} -> ${url}`);\n }\n \n if (isUnsupportedFormat(url)) {\n const ext = getFileExtension(url);\n log(`Skipping unsupported format: ${url} (extension: ${ext}, declared type: ${type})`);\n return;\n }\n \n if (isSupportedFormat(url, type)) {\n mediaFiles.push({ url, type, width, height, bitrate });\n log(`Found media file: ${url} (${type}, ${width}x${height})`);\n } else {\n log(`Skipping incompatible media file: ${url} (type: ${type})`);\n }\n });\n \n if (mediaFiles.length === 0) {\n log(\"No valid media files found in ad:\", adId);\n return;\n }\n \n const trackingUrls: VastTrackingUrls = {\n impression: [],\n start: [],\n firstQuartile: [],\n midpoint: [],\n thirdQuartile: [],\n complete: [],\n mute: [],\n unmute: [],\n pause: [],\n resume: [],\n error: [],\n };\n \n adElement.querySelectorAll(\"Impression\").forEach((el) => {\n const url = el.textContent?.trim();\n if (url) trackingUrls.impression.push(url);\n });\n \n adElement.querySelectorAll(\"Tracking\").forEach((el) => {\n const event = el.getAttribute(\"event\");\n const url = el.textContent?.trim();\n if (event && url) {\n const eventKey = event as keyof VastTrackingUrls;\n if (trackingUrls[eventKey]) {\n trackingUrls[eventKey].push(url);\n }\n }\n });\n \n const clickThrough = adElement.querySelector(\"ClickThrough\")?.textContent?.trim();\n \n ads.push({\n id: adId,\n title,\n duration,\n mediaFiles,\n trackingUrls,\n clickThrough,\n });\n \n log(`Parsed ad: ${title}, duration: ${duration}s, media files: ${mediaFiles.length}`);\n });\n \n } catch (error) {\n console.error(\"[AdStormPlayer] Error parsing VAST XML:\", error);\n }\n \n return ads;\n }\n\n function selectBestMediaFile(mediaFiles: VastMediaFile[]): VastMediaFile | null {\n if (mediaFiles.length === 0) return null;\n if (mediaFiles.length === 1) return mediaFiles[0]!;\n \n const mp4Files = mediaFiles.filter(mf => mf.type.includes(\"video/mp4\"));\n const candidates = mp4Files.length > 0 ? mp4Files : mediaFiles;\n \n const targetWidth = contentVideo.videoWidth || 1280;\n const targetHeight = contentVideo.videoHeight || 720;\n \n candidates.sort((a, b) => {\n const diffA = Math.abs(a.width - targetWidth) + Math.abs(a.height - targetHeight);\n const diffB = Math.abs(b.width - targetWidth) + Math.abs(b.height - targetHeight);\n return diffA - diffB;\n });\n \n return candidates[0] || null;\n }\n\n function createAdVideoElement(): HTMLVideoElement {\n const video = document.createElement(\"video\");\n video.style.position = \"absolute\";\n video.style.left = \"0\";\n video.style.top = \"0\";\n video.style.width = \"100%\";\n video.style.height = \"100%\";\n video.style.objectFit = \"contain\";\n video.style.backgroundColor = \"#000\";\n video.style.zIndex = \"1\";\n video.playsInline = true;\n video.preload = \"auto\";\n video.muted = originalMutedState;\n video.volume = originalMutedState ? 0 : originalVolume;\n \n return video;\n }\n\n function setAdPlayingFlag(isPlaying: boolean): void {\n if (isPlaying) {\n contentVideo.dataset.stormcloudAdPlaying = \"true\";\n } else {\n delete contentVideo.dataset.stormcloudAdPlaying;\n }\n }\n\n function setupAdEventListeners(): void {\n bindAdEventListeners();\n }\n\n function handleAdComplete(): void {\n if (destroyed || tornDown) return;\n log(\"Handling ad completion\");\n adPlaying = false;\n setAdPlayingFlag(false);\n clearAdStallTimer();\n clearAdCountdownTimer();\n \n if (adContainerEl) {\n adContainerEl.style.opacity = \"0\";\n adHideTimerId = setTimeout(() => {\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n }, 300);\n }\n \n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n contentVideo.muted = originalMutedState;\n contentVideo.volume = originalVolume;\n currentAd = undefined;\n \n emit(\"content_resume\");\n emit(\"all_ads_completed\");\n }\n\n function handleAdError(): void {\n if (destroyed || tornDown) return;\n log(\"Handling ad error\");\n if (!adPlaying) return;\n adPlaying = false;\n setAdPlayingFlag(false);\n clearAdStallTimer();\n clearAdCountdownTimer();\n \n contentVideo.muted = originalMutedState;\n contentVideo.volume = originalVolume;\n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n \n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n \n currentAd = undefined;\n emit(\"ad_error\");\n emit(\"content_resume\");\n }\n\n async function fetchVastOnce(durationSeconds: number): Promise<VastAd[]> {\n const vastUrl = buildVastUrl(durationSeconds);\n log(\"Fetching VAST from:\", vastUrl);\n\n const controller =\n typeof AbortController !== \"undefined\" ? new AbortController() : null;\n const timeoutId = setTimeout(() => controller?.abort(), REQUEST_TIMEOUT_MS);\n\n try {\n const requestInit: RequestInit = {\n method: \"GET\",\n mode: \"cors\",\n credentials: \"omit\",\n headers: {\n Accept: \"application/xml, text/xml, */*\",\n },\n referrerPolicy: \"no-referrer-when-downgrade\",\n };\n if (controller) {\n requestInit.signal = controller.signal;\n }\n\n const response = await fetch(vastUrl, requestInit);\n\n if (!response.ok) {\n throw new Error(`Failed to fetch VAST: ${response.status} ${response.statusText}`);\n }\n\n const xmlText = await response.text();\n log(\"VAST response received, length:\", xmlText.length);\n return parseVastXml(xmlText);\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n async function fetchVast(durationSeconds: number): Promise<VastAd[]> {\n let lastError: unknown;\n for (let attempt = 1; attempt <= REQUEST_MAX_RETRIES; attempt++) {\n try {\n const ads = await fetchVastOnce(durationSeconds);\n if (ads.length > 0) return ads;\n log(`No ad returned from VAST on attempt ${attempt}/${REQUEST_MAX_RETRIES}`);\n } catch (error: any) {\n lastError = error;\n if (error?.name === \"AbortError\") {\n console.warn(\n `[AdStormPlayer] VAST request timed out (${REQUEST_TIMEOUT_MS}ms), attempt ${attempt}/${REQUEST_MAX_RETRIES}`\n );\n } else {\n console.warn(`[AdStormPlayer] VAST request failed on attempt ${attempt}/${REQUEST_MAX_RETRIES}:`, error);\n }\n }\n\n if (attempt < REQUEST_MAX_RETRIES) {\n const delay = REQUEST_RETRY_BACKOFF_MS * attempt;\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n if (lastError instanceof Error) {\n throw lastError;\n }\n return [];\n }\n\n function getDurationSecondsFromContext(requestContext?: unknown): number {\n if (!requestContext || typeof requestContext !== \"object\") {\n return 30;\n }\n const ctx = requestContext as AdBreakContext;\n const value = ctx.remainingBreakSec ?? ctx.breakDurationSec;\n if (typeof value !== \"number\" || Number.isNaN(value)) {\n return 30;\n }\n return Math.max(1, Math.ceil(value));\n }\n\n async function requestAdFromApi(requestContext?: unknown): Promise<VastAd | null> {\n const durationSeconds = getDurationSecondsFromContext(requestContext);\n const ads = await fetchVast(durationSeconds);\n return ads[0] || null;\n }\n\n function assignCurrentAd(ad: VastAd): void {\n currentAd = ad;\n sessionId = generateSessionId();\n trackingFired = {\n impression: false,\n start: false,\n firstQuartile: false,\n midpoint: false,\n thirdQuartile: false,\n complete: false,\n };\n fireTrackingPixels(currentAd.trackingUrls.impression);\n trackingFired.impression = true;\n emit(\"ad_impression\");\n }\n\n return {\n initialize() {\n log(\"Initializing\");\n \n if (!adContainerEl) {\n const parent = contentVideo.parentElement;\n if (parent) {\n const computed = window.getComputedStyle(parent).position;\n if (computed === \"static\") {\n parent.style.position = \"relative\";\n parentPositionOverridden = true;\n }\n }\n\n const container = document.createElement(\"div\");\n container.style.position = \"absolute\";\n container.style.left = \"0\";\n container.style.top = \"0\";\n container.style.right = \"0\";\n container.style.bottom = \"0\";\n container.style.display = \"none\";\n container.style.alignItems = \"center\";\n container.style.justifyContent = \"center\";\n container.style.pointerEvents = \"none\";\n container.style.zIndex = AD_LAYER_Z_INDEX;\n container.style.backgroundColor = \"#000\";\n container.style.transition = \"opacity 0.3s ease-in-out\";\n container.style.opacity = \"0\";\n container.style.isolation = \"isolate\";\n \n const countdown = document.createElement(\"div\");\n countdown.style.position = \"absolute\";\n countdown.style.left = \"12px\";\n countdown.style.top = \"12px\";\n countdown.style.padding = \"4px 8px\";\n countdown.style.borderRadius = \"4px\";\n countdown.style.background = \"rgba(0,0,0,0.75)\";\n countdown.style.color = \"#fff\";\n countdown.style.fontFamily = \"sans-serif\";\n countdown.style.fontSize = \"12px\";\n countdown.style.lineHeight = \"1.2\";\n countdown.style.pointerEvents = \"none\";\n countdown.style.zIndex = COUNTDOWN_Z_INDEX;\n countdown.textContent = \"Ad\";\n container.appendChild(countdown);\n\n contentVideo.parentElement?.appendChild(container);\n adContainerEl = container;\n adCountdownEl = countdown;\n }\n },\n\n async requestAds(duration?: string) {\n log(\"Requesting ads for duration:\", duration);\n \n if (adPlaying) {\n return Promise.reject(new Error(\"Ad already playing\"));\n }\n if (destroyed) {\n return Promise.reject(new Error(\"Player has been destroyed\"));\n }\n \n try {\n tornDown = false;\n let durationSeconds = 30;\n const parsed = parseInt(duration || \"\", 10);\n if (!isNaN(parsed) && parsed > 0) {\n durationSeconds = parsed;\n }\n \n const ads = await fetchVast(durationSeconds);\n \n if (ads.length === 0) {\n log(\"No ads available from VAST response\");\n emit(\"ad_error\");\n return Promise.resolve();\n }\n \n assignCurrentAd(ads[0]!);\n log(`Ad loaded: ${currentAd!.title}, duration: ${currentAd!.duration}s`);\n \n return Promise.resolve();\n } catch (error) {\n console.error(\"[AdStormPlayer] Error requesting ads:\", error);\n emit(\"ad_error\");\n return Promise.reject(error);\n }\n },\n\n async play() {\n if (!currentAd) {\n return Promise.reject(new Error(\"No ad loaded\"));\n }\n if (destroyed) {\n return Promise.reject(new Error(\"Player has been destroyed\"));\n }\n \n log(\"Starting ad playback\");\n \n try {\n tornDown = false;\n if (adHideTimerId) {\n clearTimeout(adHideTimerId);\n adHideTimerId = undefined;\n }\n\n if (!adVideoElement) {\n adVideoElement = createAdVideoElement();\n adContainerEl?.appendChild(adVideoElement);\n } else {\n teardownCurrentPlayback();\n }\n setupAdEventListeners();\n \n trackingFired = {\n impression: trackingFired.impression,\n start: false,\n firstQuartile: false,\n midpoint: false,\n thirdQuartile: false,\n complete: false,\n };\n \n contentVideo.style.transition = \"opacity 0.3s ease-in-out\";\n contentVideo.style.opacity = \"0\";\n setTimeout(() => {\n contentVideo.style.visibility = \"hidden\";\n }, 300);\n contentVideo.muted = true;\n contentVideo.volume = 0;\n \n if (!continueLiveStreamDuringAds) {\n contentVideo.pause();\n }\n \n adPlaying = true;\n setAdPlayingFlag(true);\n \n if (adVideoElement) {\n adVideoElement.volume = originalMutedState ? 0 : originalVolume;\n adVideoElement.muted = originalMutedState;\n }\n \n if (adContainerEl) {\n adContainerEl.style.display = \"flex\";\n adContainerEl.style.pointerEvents = \"auto\";\n adContainerEl.offsetHeight;\n adContainerEl.style.opacity = \"1\";\n }\n \n emit(\"content_pause\");\n \n const mediaFile = selectBestMediaFile(currentAd.mediaFiles);\n if (!mediaFile) {\n throw new Error(\"No media file available\");\n }\n \n log(\"Playing media file:\", mediaFile.url);\n adVideoElement!.src = mediaFile.url;\n adVideoElement!.load();\n \n await adVideoElement!.play();\n \n return Promise.resolve();\n } catch (error) {\n console.error(\"[AdStormPlayer] Error playing ad:\", error);\n handleAdError();\n return Promise.reject(error);\n }\n },\n\n async stop() {\n log(\"Stopping ad\");\n tornDown = true;\n adPlaying = false;\n setAdPlayingFlag(false);\n clearAdStallTimer();\n clearAdCountdownTimer();\n \n if (adContainerEl) {\n adContainerEl.style.opacity = \"0\";\n adHideTimerId = setTimeout(() => {\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n }, 300);\n }\n \n teardownCurrentPlayback();\n \n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n contentVideo.muted = originalMutedState;\n contentVideo.volume = originalVolume;\n \n currentAd = undefined;\n return Promise.resolve();\n },\n\n pause() {\n if (!adPlaying || !adVideoElement) return;\n try {\n if (!adVideoElement.paused) adVideoElement.pause();\n } catch (error) {\n console.warn(\"[AdStormPlayer] Error pausing ad:\", error);\n }\n },\n\n resume() {\n if (!adPlaying || !adVideoElement) return;\n try {\n if (adVideoElement.paused) adVideoElement.play().catch(() => {});\n } catch (error) {\n console.warn(\"[AdStormPlayer] Error resuming ad:\", error);\n }\n },\n\n destroy() {\n log(\"Destroying\");\n destroyed = true;\n tornDown = true;\n adPlaying = false;\n setAdPlayingFlag(false);\n clearAdStallTimer();\n clearAdCountdownTimer();\n if (adHideTimerId) {\n clearTimeout(adHideTimerId);\n adHideTimerId = undefined;\n }\n \n contentVideo.muted = originalMutedState;\n contentVideo.volume = originalVolume;\n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n \n teardownCurrentPlayback();\n adVideoElement?.remove();\n adVideoElement = undefined;\n \n if (adContainerEl?.parentElement) {\n adContainerEl.parentElement.removeChild(adContainerEl);\n }\n \n adContainerEl = undefined;\n adCountdownEl = undefined;\n currentAd = undefined;\n sessionId = undefined;\n preloadSlots.clear();\n listeners.clear();\n if (parentPositionOverridden && contentVideo.parentElement) {\n contentVideo.parentElement.style.position = \"\";\n parentPositionOverridden = false;\n }\n },\n\n updateOptions(opts: AdStormLayerOptionsUpdate) {\n if (opts.continueLiveStreamDuringAds !== undefined) {\n continueLiveStreamDuringAds = opts.continueLiveStreamDuringAds;\n }\n },\n\n async playAd(requestContext?: unknown) {\n if (destroyed) return Promise.reject(new Error(\"Player has been destroyed\"));\n if (!currentAd) {\n const ad = await requestAdFromApi(requestContext);\n if (!ad) {\n emit(\"ad_error\", { message: \"No valid ad from AdStorm API\" });\n return Promise.reject(new Error(\"No valid ad from AdStorm API\"));\n }\n assignCurrentAd(ad);\n }\n return this.play();\n },\n\n async preloadAd(arg1: unknown, arg2?: unknown) {\n if (destroyed) return;\n const token =\n typeof arg1 === \"string\"\n ? arg1\n : typeof arg2 === \"string\"\n ? arg2\n : undefined;\n if (!token) return;\n\n if (currentAd) {\n preloadSlots.set(token, { ad: currentAd });\n currentAd = undefined;\n return;\n }\n\n const requestContext = typeof arg1 === \"string\" ? arg2 : arg1;\n const ad = await requestAdFromApi(requestContext);\n if (!ad) return;\n preloadSlots.set(token, { ad });\n },\n\n async playPreloaded(token: string) {\n if (destroyed) return Promise.reject(new Error(\"Player has been destroyed\"));\n const slot = preloadSlots.get(token);\n if (!slot) {\n return Promise.reject(new Error(`No preloaded ad for token ${token}`));\n }\n preloadSlots.delete(token);\n assignCurrentAd(slot.ad);\n return this.play();\n },\n\n hasPreloaded(token: string): boolean {\n return preloadSlots.has(token);\n },\n\n cancelPreload(token: string) {\n preloadSlots.delete(token);\n },\n\n isAdPlaying() {\n return adPlaying;\n },\n\n resize(width: number, height: number) {\n log(`Resizing to ${width}x${height}`);\n \n if (adContainerEl) {\n adContainerEl.style.width = `${width}px`;\n adContainerEl.style.height = `${height}px`;\n }\n \n if (adVideoElement) {\n adVideoElement.style.width = `${width}px`;\n adVideoElement.style.height = `${height}px`;\n }\n },\n\n on(event: string, listener: (payload?: any) => void) {\n if (!listeners.has(event)) listeners.set(event, new Set());\n listeners.get(event)!.add(listener);\n },\n\n off(event: string, listener: (payload?: any) => void) {\n listeners.get(event)?.delete(listener);\n },\n\n updateOriginalMutedState(muted: boolean, volume?: number) {\n const nextVolume =\n typeof volume === \"number\" && !Number.isNaN(volume)\n ? Math.max(0, Math.min(1, volume))\n : originalVolume;\n log(`updateOriginalMutedState: muted=${muted}, volume=${nextVolume}`);\n originalMutedState = muted;\n originalVolume = nextVolume;\n },\n\n getOriginalMutedState() {\n return originalMutedState;\n },\n\n getOriginalVolume() {\n return originalVolume;\n },\n\n setAdVolume(volume: number) {\n if (adVideoElement && adPlaying) {\n adVideoElement.volume = Math.max(0, Math.min(1, volume));\n adVideoElement.muted = volume === 0;\n }\n },\n\n getAdVolume(): number {\n if (adVideoElement && adPlaying) {\n return adVideoElement.volume;\n }\n return 1;\n },\n\n showPlaceholder() {\n if (!adContainerEl) {\n const parent = contentVideo.parentElement;\n if (parent) {\n const computed = window.getComputedStyle(parent).position;\n if (computed === \"static\") {\n parent.style.position = \"relative\";\n parentPositionOverridden = true;\n }\n }\n\n const container = document.createElement(\"div\");\n container.style.position = \"absolute\";\n container.style.left = \"0\";\n container.style.top = \"0\";\n container.style.right = \"0\";\n container.style.bottom = \"0\";\n container.style.display = \"none\";\n container.style.alignItems = \"center\";\n container.style.justifyContent = \"center\";\n container.style.pointerEvents = \"none\";\n container.style.zIndex = AD_LAYER_Z_INDEX;\n container.style.backgroundColor = \"#000\";\n container.style.isolation = \"isolate\";\n\n const countdown = document.createElement(\"div\");\n countdown.style.position = \"absolute\";\n countdown.style.left = \"12px\";\n countdown.style.top = \"12px\";\n countdown.style.padding = \"4px 8px\";\n countdown.style.borderRadius = \"4px\";\n countdown.style.background = \"rgba(0,0,0,0.75)\";\n countdown.style.color = \"#fff\";\n countdown.style.fontFamily = \"sans-serif\";\n countdown.style.fontSize = \"12px\";\n countdown.style.lineHeight = \"1.2\";\n countdown.style.pointerEvents = \"none\";\n countdown.style.zIndex = COUNTDOWN_Z_INDEX;\n countdown.textContent = \"Ad\";\n container.appendChild(countdown);\n \n contentVideo.parentElement?.appendChild(container);\n adContainerEl = container;\n adCountdownEl = countdown;\n }\n \n if (adContainerEl) {\n adContainerEl.style.display = \"flex\";\n adContainerEl.style.opacity = \"1\";\n adContainerEl.style.pointerEvents = \"auto\";\n }\n },\n\n hidePlaceholder() {\n if (adContainerEl) {\n adContainerEl.style.opacity = \"0\";\n setTimeout(() => {\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n }, 300);\n }\n },\n };\n}\n\n","import type {\n ClientInfo,\n TrackingData,\n HeartbeatData,\n AdDetectInfo,\n AdLoadedInfo,\n AdImpressionInfo,\n} from \"../types\";\n\nlet cachedBrowserId: string | null = null;\n\nexport function getClientInfo(): ClientInfo {\n const ua = navigator.userAgent;\n const platform = navigator.platform;\n const vendor = navigator.vendor || \"\";\n const maxTouchPoints = navigator.maxTouchPoints || 0;\n const memory = (navigator as any).deviceMemory || null;\n const hardwareConcurrency = navigator.hardwareConcurrency || 1;\n\n const screenInfo = {\n width: screen?.width,\n height: screen?.height,\n availWidth: screen?.availWidth,\n availHeight: screen?.availHeight,\n orientation: (screen?.orientation as any)?.type || \"\",\n pixelDepth: screen?.pixelDepth,\n };\n\n let deviceType: \"tv\" | \"mobile\" | \"tablet\" | \"desktop\" = \"desktop\";\n let brand = \"Unknown\";\n let os = \"Unknown\";\n let model = \"\";\n let isSmartTV = false;\n let isAndroid = false;\n let isWebView = false;\n let isWebApp = false;\n\n if (ua.includes(\"Web0S\")) {\n brand = \"LG\";\n os = \"webOS\";\n isSmartTV = true;\n deviceType = \"tv\";\n const webosMatch = ua.match(/Web0S\\/([^\\s]+)/);\n model = webosMatch ? `webOS ${webosMatch[1]}` : \"webOS TV\";\n } else if (ua.includes(\"Tizen\")) {\n brand = \"Samsung\";\n os = \"Tizen\";\n isSmartTV = true;\n deviceType = \"tv\";\n const tizenMatch = ua.match(/Tizen\\/([^\\s]+)/);\n const tvMatch = ua.match(/(?:Smart-TV|SMART-TV|TV)/i) ? \"Smart TV\" : \"\";\n model = tizenMatch\n ? `Tizen ${tizenMatch[1]} ${tvMatch}`.trim()\n : \"Tizen TV\";\n } else if (ua.includes(\"Philips\")) {\n brand = \"Philips\";\n os = \"Saphi\";\n isSmartTV = true;\n deviceType = \"tv\";\n } else if (ua.includes(\"Sharp\") || ua.includes(\"AQUOS\")) {\n brand = \"Sharp\";\n os = \"Android TV\";\n isSmartTV = true;\n deviceType = \"tv\";\n } else if (\n ua.includes(\"Android\") &&\n (ua.includes(\"Sony\") || vendor.includes(\"Sony\"))\n ) {\n brand = \"Sony\";\n os = \"Android TV\";\n isSmartTV = true;\n deviceType = \"tv\";\n } else if (\n ua.includes(\"Android\") &&\n (ua.includes(\"NetCast\") || ua.includes(\"LG\"))\n ) {\n brand = \"LG\";\n os = \"Android TV\";\n isSmartTV = true;\n deviceType = \"tv\";\n } else if (ua.includes(\" Roku\") || ua.includes(\"Roku/\")) {\n brand = \"Roku\";\n os = \"Roku OS\";\n isSmartTV = true;\n deviceType = \"tv\";\n } else if (ua.includes(\"AppleTV\")) {\n brand = \"Apple\";\n os = \"tvOS\";\n isSmartTV = true;\n deviceType = \"tv\";\n }\n\n if (ua.includes(\"Android\")) {\n isAndroid = true;\n os = \"Android\";\n deviceType = /Mobile/.test(ua) ? \"mobile\" : \"tablet\";\n\n if (\n ua.includes(\"Android\") &&\n (maxTouchPoints === 0 ||\n ua.includes(\"Google TV\") ||\n ua.includes(\"XiaoMi\"))\n ) {\n deviceType = \"tv\";\n isSmartTV = true;\n brand = brand === \"Unknown\" ? \"Android TV\" : brand;\n }\n\n const androidModelMatch = ua.match(/\\(([^)]*Android[^)]*)\\)/);\n if (androidModelMatch && androidModelMatch[1]) {\n model = androidModelMatch[1];\n }\n }\n\n if (/iPad|iPhone|iPod/.test(ua)) {\n os = \"iOS\";\n deviceType = \"mobile\";\n brand = \"Apple\";\n if (navigator.maxTouchPoints > 1 && /iPad/.test(ua)) {\n deviceType = \"tablet\";\n }\n }\n\n if (!isAndroid && !isSmartTV && !/Mobile/.test(ua)) {\n if (ua.includes(\"Windows\")) {\n os = \"Windows\";\n deviceType = \"desktop\";\n } else if (ua.includes(\"Mac\") && !/iPhone/.test(ua)) {\n os = \"macOS\";\n deviceType = \"desktop\";\n if (maxTouchPoints > 1) deviceType = \"tablet\";\n } else if (ua.includes(\"Linux\")) {\n os = \"Linux\";\n deviceType = \"desktop\";\n }\n }\n\n if (brand === \"Unknown\") {\n if (vendor.includes(\"Google\") || ua.includes(\"Chrome\")) brand = \"Google\";\n if (vendor.includes(\"Apple\")) brand = \"Apple\";\n if (vendor.includes(\"Samsung\") || ua.includes(\"SM-\")) brand = \"Samsung\";\n }\n\n isWebView = /wv|WebView|Linux; U;/.test(ua);\n\n if (window?.outerHeight === 0 && window?.outerWidth === 0) {\n isWebView = true;\n }\n\n isWebApp =\n window.matchMedia(\"(display-mode: standalone)\").matches ||\n (window.navigator as any).standalone === true ||\n window.screen?.orientation?.angle !== undefined;\n\n return {\n brand,\n os,\n model: model || ua.substring(0, 50) + \"...\",\n deviceType,\n isSmartTV,\n isAndroid,\n isWebView,\n isWebApp,\n domain: window.location.hostname,\n origin: window.location.origin,\n path: window.location.pathname,\n userAgent: ua,\n vendor,\n platform,\n screen: screenInfo,\n hardwareConcurrency,\n deviceMemory: memory,\n maxTouchPoints,\n language: navigator.language,\n languages: navigator.languages?.join(\",\") || \"\",\n cookieEnabled: navigator.cookieEnabled,\n doNotTrack: navigator.doNotTrack || \"\",\n referrer: document.referrer,\n visibilityState: document.visibilityState,\n };\n}\n\nexport async function getBrowserID(clientInfo: ClientInfo): Promise<string> {\n if (cachedBrowserId) {\n return cachedBrowserId;\n }\n\n const fingerprintString = JSON.stringify(clientInfo);\n\n if (typeof crypto !== \"undefined\" && crypto.subtle && crypto.subtle.digest) {\n try {\n await crypto.subtle.digest(\"SHA-256\", new Uint8Array([1, 2, 3]));\n\n let encodedData: BufferSource;\n if (typeof TextEncoder !== \"undefined\") {\n encodedData = new TextEncoder().encode(fingerprintString);\n } else {\n const utf8 = unescape(encodeURIComponent(fingerprintString));\n const buffer = new Uint8Array(utf8.length);\n for (let i = 0; i < utf8.length; i++) {\n buffer[i] = utf8.charCodeAt(i);\n }\n encodedData = buffer;\n }\n\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", encodedData);\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n const hashHex = hashArray\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n cachedBrowserId = hashHex;\n return hashHex;\n } catch (error) {\n console.warn(\n \"[StormcloudVideoPlayer] crypto.subtle.digest not supported, using fallback hash\"\n );\n }\n }\n\n let hash = 0;\n for (let i = 0; i < fingerprintString.length; i++) {\n const char = fingerprintString.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash;\n }\n\n const fallbackHash = Math.abs(hash).toString(16).padStart(8, \"0\");\n const timestamp = Date.now().toString(16).padStart(12, \"0\");\n const random = Math.random().toString(16).substring(2, 14).padStart(12, \"0\");\n\n cachedBrowserId = (fallbackHash + timestamp + random).padEnd(64, \"0\");\n return cachedBrowserId;\n}\n\nconst TRACK_URL =\n \"https://adstorm.co/api-adstorm-dev/adstorm/player-tracking/track\";\n\nasync function sendTrackRequest(\n licenseKey: string | undefined,\n body: Record<string, unknown>\n): Promise<void> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (licenseKey) {\n headers[\"Authorization\"] = `Bearer ${licenseKey}`;\n }\n const response = await fetch(TRACK_URL, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n await response.json();\n}\n\nexport async function sendInitialTracking(licenseKey?: string): Promise<void> {\n try {\n const clientInfo = getClientInfo();\n const browserId = await getBrowserID(clientInfo);\n\n const trackingData: TrackingData = {\n browserId,\n ...clientInfo,\n };\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (licenseKey) {\n headers[\"Authorization\"] = `Bearer ${licenseKey}`;\n }\n\n const response = await fetch(TRACK_URL, {\n method: \"POST\",\n headers,\n body: JSON.stringify(trackingData),\n });\n\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n\n await response.json();\n } catch (error) {\n console.error(\n \"[StormcloudVideoPlayer] Error sending initial tracking data:\",\n error\n );\n }\n}\n\nexport async function sendAdDetectTracking(\n licenseKey: string | undefined,\n adDetectInfo: AdDetectInfo\n): Promise<void> {\n try {\n const clientInfo = getClientInfo();\n const browserId = await getBrowserID(clientInfo);\n const trackingData: TrackingData = { browserId, ...clientInfo };\n await sendTrackRequest(licenseKey, {\n ...trackingData,\n licenseKey,\n adDetectInfo,\n });\n } catch (error) {\n console.error(\n \"[StormcloudVideoPlayer] Error sending ad detect tracking:\",\n error\n );\n }\n}\n\nexport async function sendAdLoadedTracking(\n licenseKey: string | undefined,\n adLoadedInfo: AdLoadedInfo\n): Promise<void> {\n try {\n const clientInfo = getClientInfo();\n const browserId = await getBrowserID(clientInfo);\n const trackingData: TrackingData = { browserId, ...clientInfo };\n await sendTrackRequest(licenseKey, {\n ...trackingData,\n licenseKey,\n adLoadedInfo,\n });\n } catch (error) {\n console.error(\n \"[StormcloudVideoPlayer] Error sending ad loaded tracking:\",\n error\n );\n }\n}\n\nexport async function sendAdImpressionTracking(\n licenseKey: string | undefined,\n adImpressionInfo: AdImpressionInfo\n): Promise<void> {\n try {\n const clientInfo = getClientInfo();\n const browserId = await getBrowserID(clientInfo);\n const trackingData: TrackingData = { browserId, ...clientInfo };\n await sendTrackRequest(licenseKey, {\n ...trackingData,\n licenseKey,\n adImpressionInfo,\n });\n } catch (error) {\n console.error(\n \"[StormcloudVideoPlayer] Error sending ad impression tracking:\",\n error\n );\n }\n}\n\nexport async function sendHeartbeat(licenseKey?: string): Promise<void> {\n try {\n const clientInfo = getClientInfo();\n const browserId = await getBrowserID(clientInfo);\n\n const heartbeatData: HeartbeatData = {\n browserId,\n timestamp: new Date().toISOString(),\n };\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (licenseKey) {\n headers[\"Authorization\"] = `Bearer ${licenseKey}`;\n }\n\n const response = await fetch(\n \"https://adstorm.co/api-adstorm-dev/adstorm/player-tracking/heartbeat\",\n {\n method: \"POST\",\n headers,\n body: JSON.stringify(heartbeatData),\n }\n );\n\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n\n await response.json();\n } catch (error) {\n console.error(\"[StormcloudVideoPlayer] Error sending heartbeat:\", error);\n }\n}\n","export function polyfillURLSearchParams(): void {\n if (typeof URLSearchParams !== 'undefined') {\n return;\n }\n\n class URLSearchParamsPolyfill {\n private params: Map<string, string[]>;\n\n constructor(init?: string | URLSearchParamsPolyfill) {\n this.params = new Map();\n\n if (typeof init === 'string') {\n this.parseQueryString(init);\n } else if (init instanceof URLSearchParamsPolyfill) {\n init.forEach((value, key) => {\n this.append(key, value);\n });\n }\n }\n\n private parseQueryString(query: string): void {\n const cleanQuery = query.startsWith('?') ? query.slice(1) : query;\n if (!cleanQuery) return;\n\n cleanQuery.split('&').forEach((param) => {\n const [key, value] = param.split('=');\n if (key) {\n const decodedKey = this.safeDecodeURIComponent(key);\n const decodedValue = value ? this.safeDecodeURIComponent(value) : '';\n this.append(decodedKey, decodedValue);\n }\n });\n }\n\n private safeDecodeURIComponent(str: string): string {\n try {\n return decodeURIComponent(str.replace(/\\+/g, ' '));\n } catch (e) {\n return str;\n }\n }\n\n append(name: string, value: string): void {\n const values = this.params.get(name) || [];\n values.push(String(value));\n this.params.set(name, values);\n }\n\n delete(name: string): void {\n this.params.delete(name);\n }\n\n get(name: string): string | null {\n const values = this.params.get(name);\n return values && values.length > 0 && values[0] !== undefined ? values[0] : null;\n }\n\n getAll(name: string): string[] {\n return this.params.get(name) || [];\n }\n\n has(name: string): boolean {\n return this.params.has(name);\n }\n\n set(name: string, value: string): void {\n this.params.set(name, [String(value)]);\n }\n\n forEach(callback: (value: string, key: string, parent: URLSearchParamsPolyfill) => void): void {\n this.params.forEach((values, key) => {\n values.forEach((value) => {\n callback(value, key, this);\n });\n });\n }\n\n toString(): string {\n const parts: string[] = [];\n this.params.forEach((values, key) => {\n values.forEach((value) => {\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);\n });\n });\n return parts.join('&');\n }\n }\n\n // @ts-ignore\n window.URLSearchParams = URLSearchParamsPolyfill;\n}\n\nexport function polyfillTextEncoder(): void {\n if (typeof TextEncoder !== 'undefined') {\n return;\n }\n\n class TextEncoderPolyfill {\n encoding = 'utf-8';\n\n encode(str: string): Uint8Array {\n const utf8: number[] = [];\n for (let i = 0; i < str.length; i++) {\n let charcode = str.charCodeAt(i);\n if (charcode < 0x80) {\n utf8.push(charcode);\n } else if (charcode < 0x800) {\n utf8.push(0xc0 | (charcode >> 6), 0x80 | (charcode & 0x3f));\n } else if (charcode < 0xd800 || charcode >= 0xe000) {\n utf8.push(\n 0xe0 | (charcode >> 12),\n 0x80 | ((charcode >> 6) & 0x3f),\n 0x80 | (charcode & 0x3f)\n );\n } else {\n i++;\n charcode = 0x10000 + (((charcode & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff));\n utf8.push(\n 0xf0 | (charcode >> 18),\n 0x80 | ((charcode >> 12) & 0x3f),\n 0x80 | ((charcode >> 6) & 0x3f),\n 0x80 | (charcode & 0x3f)\n );\n }\n }\n return new Uint8Array(utf8);\n }\n }\n\n // @ts-ignore\n window.TextEncoder = TextEncoderPolyfill;\n}\n\nexport function polyfillPromiseFinally(): void {\n if (typeof Promise !== 'undefined' && !Promise.prototype.finally) {\n Promise.prototype.finally = function (callback: () => void) {\n const constructor = this.constructor as PromiseConstructor;\n return this.then(\n (value) => constructor.resolve(callback()).then(() => value),\n (reason) =>\n constructor.resolve(callback()).then(() => {\n throw reason;\n })\n );\n };\n }\n}\n\nexport function polyfillObjectAssign(): void {\n if (typeof Object.assign !== 'function') {\n Object.assign = function (target: any, ...sources: any[]) {\n if (target == null) {\n throw new TypeError('Cannot convert undefined or null to object');\n }\n\n const to = Object(target);\n\n for (let i = 0; i < sources.length; i++) {\n const nextSource = sources[i];\n\n if (nextSource != null) {\n for (const nextKey in nextSource) {\n if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {\n to[nextKey] = nextSource[nextKey];\n }\n }\n }\n }\n\n return to;\n };\n }\n}\n\nexport function polyfillArrayFrom(): void {\n if (!Array.from) {\n Array.from = function (arrayLike: any, mapFn?: any, thisArg?: any) {\n const items = Object(arrayLike);\n if (arrayLike == null) {\n throw new TypeError('Array.from requires an array-like object');\n }\n\n const len = items.length >>> 0;\n const result = new Array(len);\n\n for (let i = 0; i < len; i++) {\n if (mapFn) {\n result[i] = mapFn.call(thisArg, items[i], i);\n } else {\n result[i] = items[i];\n }\n }\n\n return result;\n };\n }\n}\n\nexport function polyfillStringStartsWith(): void {\n if (!String.prototype.startsWith) {\n String.prototype.startsWith = function (search: string, pos?: number) {\n pos = !pos || pos < 0 ? 0 : +pos;\n return this.substring(pos, pos + search.length) === search;\n };\n }\n}\n\nexport function polyfillStringEndsWith(): void {\n if (!String.prototype.endsWith) {\n String.prototype.endsWith = function (search: string, length?: number) {\n if (length === undefined || length > this.length) {\n length = this.length;\n }\n return this.substring(length - search.length, length) === search;\n };\n }\n}\n\nexport function polyfillStringIncludes(): void {\n if (!String.prototype.includes) {\n String.prototype.includes = function (search: string, start?: number) {\n if (typeof start !== 'number') {\n start = 0;\n }\n if (start + search.length > this.length) {\n return false;\n }\n return this.indexOf(search, start) !== -1;\n };\n }\n}\n\nexport function initializePolyfills(): void {\n polyfillObjectAssign();\n polyfillArrayFrom();\n polyfillStringStartsWith();\n polyfillStringEndsWith();\n polyfillStringIncludes();\n polyfillURLSearchParams();\n polyfillTextEncoder();\n polyfillPromiseFinally();\n}\n\n","interface NavigatorUAData {\n platform?: string;\n brands?: Array<{ brand: string; version: string }>;\n mobile?: boolean;\n}\n\ndeclare global {\n interface Navigator {\n userAgentData?: NavigatorUAData;\n }\n}\n\nexport interface BrowserInfo {\n name: string;\n version: string;\n majorVersion: number;\n isSmartTV: boolean;\n isLegacyTV: boolean;\n platform: string;\n supportsIMA: boolean;\n supportsModernJS: boolean;\n recommendedAdPlayer: 'ima' | 'hls';\n webOSVersion?: number | undefined;\n tizenVersion?: number | undefined;\n chromeVersion?: number | undefined;\n}\n\nfunction getChromeVersion(ua: string): number {\n const match = ua.match(/Chrome\\/(\\d+)/);\n return match && match[1] ? parseInt(match[1], 10) : 0;\n}\n\nfunction getWebKitVersion(ua: string): number {\n const match = ua.match(/AppleWebKit\\/(\\d+)/);\n return match && match[1] ? parseInt(match[1], 10) : 0;\n}\n\nfunction getPlatform(): string {\n if ('userAgentData' in navigator && navigator.userAgentData?.platform) {\n return navigator.userAgentData.platform;\n }\n\n const ua = navigator.userAgent;\n if (/Mac|iPhone|iPad|iPod/i.test(ua)) {\n return /iPhone|iPad|iPod/i.test(ua) ? 'iPhone' : 'MacIntel';\n }\n if (/Win/i.test(ua)) {\n return 'Win32';\n }\n if (/Linux/i.test(ua)) {\n return /Android/i.test(ua) ? 'Linux armv8l' : 'Linux x86_64';\n }\n if (/CrOS/i.test(ua)) {\n return 'CrOS';\n }\n\n // eslint-disable-next-line deprecation/deprecation\n return (navigator as any).platform || 'Unknown';\n}\n\nexport function detectBrowser(): BrowserInfo {\n const ua = navigator.userAgent;\n const platform = getPlatform();\n\n let name = 'Unknown';\n let version = '0';\n let majorVersion = 0;\n let isSmartTV = false;\n let isLegacyTV = false;\n let supportsIMA = true;\n let supportsModernJS = true;\n let recommendedAdPlayer: 'ima' | 'hls' = 'ima';\n let webOSVersion: number | undefined;\n let tizenVersion: number | undefined;\n let chromeVersionNum: number | undefined;\n\n const chromeVersion = getChromeVersion(ua);\n const webkitVersion = getWebKitVersion(ua);\n chromeVersionNum = chromeVersion > 0 ? chromeVersion : undefined;\n\n if (/Web0S|webOS|LG Browser|LGSTB/i.test(ua)) {\n name = 'LG WebOS';\n isSmartTV = true;\n \n let match = ua.match(/Web0S[/\\s]*([\\d.]+)/i) || ua.match(/webOS[/\\s]*([\\d.]+)/i);\n \n if (!match || !match[1]) {\n match = ua.match(/webOSTV[/\\s-]*([\\d.]+)/i) || ua.match(/webOS\\.TV[/\\s-]*([\\d.]+)/i);\n }\n \n if (match && match[1]) {\n version = match[1];\n const parts = version.split('.');\n majorVersion = parts[0] ? parseInt(parts[0], 10) : 0;\n webOSVersion = majorVersion;\n } else if (chromeVersion > 0) {\n if (chromeVersion >= 79) {\n webOSVersion = 6;\n version = '6.0';\n majorVersion = 6;\n } else if (chromeVersion >= 68) {\n webOSVersion = 5;\n version = '5.0';\n majorVersion = 5;\n } else if (chromeVersion >= 53) {\n webOSVersion = 4;\n version = '4.0';\n majorVersion = 4;\n } else if (chromeVersion >= 38) {\n webOSVersion = 3;\n version = '3.0';\n majorVersion = 3;\n } else {\n webOSVersion = 2;\n version = '2.0';\n majorVersion = 2;\n }\n } else {\n version = 'Unknown';\n webOSVersion = undefined;\n }\n\n if (webOSVersion !== undefined && webOSVersion >= 4) {\n supportsIMA = true;\n recommendedAdPlayer = 'ima';\n isLegacyTV = false;\n } else if (webOSVersion !== undefined && webOSVersion >= 3) {\n if (chromeVersion >= 53) {\n supportsIMA = true;\n recommendedAdPlayer = 'ima';\n isLegacyTV = false;\n } else {\n supportsIMA = false;\n recommendedAdPlayer = 'hls';\n isLegacyTV = true;\n }\n } else if (chromeVersion >= 53) {\n supportsIMA = true;\n recommendedAdPlayer = 'ima';\n isLegacyTV = false;\n } else {\n supportsIMA = false;\n recommendedAdPlayer = 'hls';\n isLegacyTV = true;\n }\n } else if (/Tizen/i.test(ua)) {\n name = 'Samsung Tizen';\n isSmartTV = true;\n const match = ua.match(/Tizen[/\\s]*([\\d.]+)/i);\n version = match && match[1] ? match[1] : 'Unknown';\n if (version !== 'Unknown') {\n const parts = version.split('.');\n majorVersion = parts[0] ? parseInt(parts[0], 10) : 0;\n tizenVersion = majorVersion;\n }\n \n if (tizenVersion !== undefined && tizenVersion >= 4) {\n supportsIMA = true;\n recommendedAdPlayer = 'ima';\n isLegacyTV = false;\n } else if (tizenVersion !== undefined && tizenVersion >= 3 && chromeVersion >= 47) {\n supportsIMA = true;\n recommendedAdPlayer = 'ima';\n isLegacyTV = false;\n } else if (chromeVersion >= 53) {\n supportsIMA = true;\n recommendedAdPlayer = 'ima';\n isLegacyTV = false;\n } else {\n supportsIMA = false;\n recommendedAdPlayer = 'hls';\n isLegacyTV = true;\n }\n } else if (/SMART-TV|SmartTV/i.test(ua)) {\n name = 'Smart TV';\n isSmartTV = true;\n if (chromeVersion >= 53) {\n supportsIMA = true;\n recommendedAdPlayer = 'ima';\n } else {\n supportsIMA = false;\n recommendedAdPlayer = 'hls';\n isLegacyTV = true;\n }\n } else if (/NetCast/i.test(ua)) {\n name = 'LG NetCast';\n isSmartTV = true;\n isLegacyTV = true;\n supportsIMA = false;\n recommendedAdPlayer = 'hls';\n } else if (/BRAVIA/i.test(ua)) {\n name = 'Sony BRAVIA';\n isSmartTV = true;\n if (chromeVersion >= 53) {\n supportsIMA = true;\n recommendedAdPlayer = 'ima';\n } else {\n supportsIMA = false;\n recommendedAdPlayer = 'hls';\n isLegacyTV = true;\n }\n } else {\n if (chromeVersion > 0) {\n name = 'Chrome';\n version = chromeVersion.toString();\n majorVersion = chromeVersion;\n\n if (chromeVersion < 50) {\n supportsIMA = false;\n supportsModernJS = false;\n recommendedAdPlayer = 'hls';\n }\n }\n\n if (webkitVersion > 0 && webkitVersion < 600) {\n supportsModernJS = false;\n if (chromeVersion < 50) {\n supportsIMA = false;\n recommendedAdPlayer = 'hls';\n }\n }\n }\n\n if (typeof Promise === 'undefined' ||\n typeof Map === 'undefined' ||\n typeof Set === 'undefined') {\n supportsModernJS = false;\n supportsIMA = false;\n recommendedAdPlayer = 'hls';\n }\n\n if (typeof URLSearchParams === 'undefined') {\n supportsModernJS = false;\n }\n\n return {\n name,\n version,\n majorVersion,\n isSmartTV,\n isLegacyTV,\n platform,\n supportsIMA,\n supportsModernJS,\n recommendedAdPlayer,\n webOSVersion,\n tizenVersion,\n chromeVersion: chromeVersionNum,\n };\n}\n\nexport function supportsGoogleIMA(): boolean {\n const browser = detectBrowser();\n\n if (browser.isLegacyTV) {\n return false;\n }\n\n if (typeof document === 'undefined' ||\n typeof document.createElement !== 'function') {\n return false;\n }\n\n try {\n const video = document.createElement('video');\n if (!video) {\n return false;\n }\n } catch (e) {\n return false;\n }\n\n if (typeof Promise === 'undefined') {\n return false;\n }\n\n return browser.supportsIMA;\n}\n\nexport function getRecommendedAdPlayer(): 'ima' | 'hls' {\n const browser = detectBrowser();\n return browser.recommendedAdPlayer;\n}\n\nexport function supportsModernJS(): boolean {\n try {\n return (\n typeof Promise !== 'undefined' &&\n typeof Map !== 'undefined' &&\n typeof Set !== 'undefined' &&\n typeof Array.from !== 'undefined' &&\n typeof Object.assign !== 'undefined' &&\n typeof Array.prototype.forEach !== 'undefined' &&\n typeof String.prototype.includes !== 'undefined'\n );\n } catch (e) {\n return false;\n }\n}\n\nexport function logBrowserInfo(debug: boolean = false): void {\n if (!debug) return;\n\n const browser = detectBrowser();\n const imaSupport = supportsGoogleIMA();\n\n console.log('[StormcloudVideoPlayer] Browser Compatibility Info:', {\n browser: `${browser.name} ${browser.version}`,\n platform: browser.platform,\n isSmartTV: browser.isSmartTV,\n isLegacyTV: browser.isLegacyTV,\n supportsIMA: imaSupport,\n supportsModernJS: browser.supportsModernJS,\n recommendedAdPlayer: browser.recommendedAdPlayer,\n ...(browser.webOSVersion !== undefined ? { webOSVersion: browser.webOSVersion } : {}),\n ...(browser.tizenVersion !== undefined ? { tizenVersion: browser.tizenVersion } : {}),\n ...(browser.chromeVersion !== undefined ? { chromeVersion: browser.chromeVersion } : {}),\n userAgent: navigator.userAgent,\n });\n}\n\nexport function getBrowserConfigOverrides(): {\n allowNativeHls?: boolean;\n} {\n const browser = detectBrowser();\n const overrides: { allowNativeHls?: boolean } = {};\n\n if (browser.isSmartTV) {\n overrides.allowNativeHls = true;\n }\n\n return overrides;\n}\n\nexport function supportsFeature(feature: string): boolean {\n switch (feature) {\n case 'ima':\n return supportsGoogleIMA();\n case 'urlsearchparams':\n return typeof URLSearchParams !== 'undefined';\n case 'textencoder':\n return typeof TextEncoder !== 'undefined';\n case 'promises':\n return typeof Promise !== 'undefined';\n case 'fetch':\n return typeof fetch !== 'undefined';\n case 'crypto':\n return typeof crypto !== 'undefined' && typeof crypto.subtle !== 'undefined';\n default:\n return false;\n }\n}\n\n"]}