{"version":3,"sources":["../../src/browser.ts","../../src/media/controls/controller.ts","../../src/hls/hls.ts","../../src/media/utils.ts","../../src/webrtc/shared.ts","../../src/webrtc/whep.ts","../../src/media/controls/fullscreen.ts","../../src/media/controls/pictureInPicture.ts","../../src/media/controls/volume.ts","../../src/media/controls/device.ts","../../src/media/metrics.ts"],"sourcesContent":["export {\n  addEventListeners,\n  getDeviceInfo,\n  type HlsConfig,\n} from \"./media/controls\";\nexport { addMediaMetrics } from \"./media/metrics\";\nexport { canPlayMediaNatively } from \"./media/utils\";\n","import {\n  ACCESS_CONTROL_ERROR_MESSAGE,\n  BFRAMES_ERROR_MESSAGE,\n  STREAM_OFFLINE_ERROR_MESSAGE,\n} from \"@livepeer/core/errors\";\nimport type { MediaControllerStore } from \"@livepeer/core/media\";\nimport { warn } from \"@livepeer/core/utils\";\nimport type { HlsConfig as HlsJsConfig } from \"hls.js\";\nimport { createNewHls, type HlsError } from \"../../hls/hls\";\nimport { createNewWHEP } from \"../../webrtc/whep\";\nimport {\n  addFullscreenEventListener,\n  enterFullscreen,\n  exitFullscreen,\n  isCurrentlyFullscreen,\n} from \"./fullscreen\";\nimport {\n  addEnterPictureInPictureEventListener,\n  addExitPictureInPictureEventListener,\n  enterPictureInPicture,\n  exitPictureInPicture,\n  isCurrentlyPictureInPicture,\n} from \"./pictureInPicture\";\nimport { isVolumeChangeSupported } from \"./volume\";\n\nexport type HlsConfig = Partial<HlsJsConfig>;\n\nconst MEDIA_CONTROLLER_INITIALIZED_ATTRIBUTE =\n  \"data-livepeer-controller-initialized\";\n\nconst allKeyTriggers = [\n  \"KeyF\",\n  \"KeyK\",\n  \"KeyM\",\n  \"KeyI\",\n  \"KeyV\",\n  \"KeyX\",\n  \"Space\",\n  \"ArrowRight\",\n  \"ArrowLeft\",\n] as const;\ntype KeyTrigger = (typeof allKeyTriggers)[number];\n\nconst delay = (ms: number) => {\n  return new Promise((resolve) => setTimeout(resolve, ms));\n};\n\nexport const addEventListeners = (\n  element: HTMLMediaElement,\n  store: MediaControllerStore,\n) => {\n  const initializedState = store.getState();\n\n  try {\n    isVolumeChangeSupported(\n      initializedState.currentSource?.type === \"audio\" ? \"audio\" : \"video\",\n    ).then((result) => {\n      store.setState(({ __device }) => ({\n        __device: {\n          ...__device,\n          isVolumeChangeSupported: result,\n        },\n      }));\n    });\n  } catch (e) {\n    console.error(e);\n  }\n\n  const onLoadedMetadata = () => {\n    store.getState().__controlsFunctions.onCanPlay();\n    store.getState().__controlsFunctions.requestMeasure();\n  };\n\n  const onLoadedData = () => {\n    store.getState().__controlsFunctions.requestMeasure();\n  };\n\n  const onPlay = () => {\n    store.getState().__controlsFunctions.onPlay();\n  };\n  const onPause = () => {\n    store.getState().__controlsFunctions.onPause();\n  };\n\n  const onDurationChange = () =>\n    store\n      .getState()\n      .__controlsFunctions.onDurationChange(element?.duration ?? 0);\n\n  const onKeyUp = (e: KeyboardEvent) => {\n    e.preventDefault();\n    e.stopPropagation();\n\n    const code = e.code as KeyTrigger;\n\n    store.getState().__controlsFunctions.updateLastInteraction();\n\n    const isNotBroadcast =\n      store.getState().__initialProps.hotkeys !== \"broadcast\";\n\n    if (allKeyTriggers.includes(code)) {\n      if ((code === \"Space\" || code === \"KeyK\") && isNotBroadcast) {\n        store.getState().__controlsFunctions.togglePlay();\n      } else if (code === \"ArrowRight\" && isNotBroadcast) {\n        store.getState().__controlsFunctions.requestSeekForward();\n      } else if (code === \"ArrowLeft\" && isNotBroadcast) {\n        store.getState().__controlsFunctions.requestSeekBack();\n      } else if (code === \"KeyM\" && isNotBroadcast) {\n        store.getState().__controlsFunctions.requestToggleMute();\n      } else if (code === \"KeyX\" && isNotBroadcast) {\n        store.getState().__controlsFunctions.requestClip();\n      } else if (code === \"KeyF\") {\n        store.getState().__controlsFunctions.requestToggleFullscreen();\n      } else if (code === \"KeyI\") {\n        store.getState().__controlsFunctions.requestTogglePictureInPicture();\n      }\n    }\n  };\n\n  const onMouseUpdate = () => {\n    store.getState().__controlsFunctions.updateLastInteraction();\n  };\n  const onTouchUpdate = async () => {\n    store.getState().__controlsFunctions.updateLastInteraction();\n  };\n\n  const onVolumeChange = () => {\n    store\n      .getState()\n      .__controlsFunctions.setVolume(element.muted ? 0 : (element.volume ?? 0));\n  };\n\n  const onRateChange = () => {\n    store.getState().__controlsFunctions.setPlaybackRate(element.playbackRate);\n  };\n\n  const onTimeUpdate = () => {\n    store.getState().__controlsFunctions.onProgress(element?.currentTime ?? 0);\n\n    if (element && (element?.duration ?? 0) > 0) {\n      const currentTime = element.currentTime;\n\n      const buffered = [...Array(element.buffered.length)].reduce(\n        (prev, _curr, i) => {\n          const start = element.buffered.start(element.buffered.length - 1 - i);\n          const end = element.buffered.end(element.buffered.length - 1 - i);\n\n          // if the TimeRange covers the current time, then use this value\n          if (start <= currentTime && end >= currentTime) {\n            return end;\n          }\n\n          return prev;\n        },\n        // default to no buffering\n        0,\n      );\n\n      store.getState().__controlsFunctions.updateBuffered(buffered);\n    }\n  };\n\n  const onError = async (e: ErrorEvent) => {\n    const source = store.getState().currentSource;\n\n    if (source?.type === \"video\") {\n      const sourceElement = e.target;\n      const parentElement = (sourceElement as HTMLSourceElement)?.parentElement;\n      const videoUrl =\n        (parentElement as HTMLVideoElement)?.currentSrc ??\n        (sourceElement as HTMLVideoElement)?.currentSrc;\n\n      if (videoUrl) {\n        try {\n          const response = await fetch(videoUrl);\n          if (response.status === 404) {\n            console.warn(\"Video not found\");\n            return store\n              .getState()\n              .__controlsFunctions?.onError?.(\n                new Error(STREAM_OFFLINE_ERROR_MESSAGE),\n              );\n          }\n          if (response.status === 401) {\n            console.warn(\"Unauthorized to view video\");\n            return store\n              .getState()\n              .__controlsFunctions?.onError?.(\n                new Error(ACCESS_CONTROL_ERROR_MESSAGE),\n              );\n          }\n        } catch (err) {\n          console.warn(err);\n          return store\n            .getState()\n            .__controlsFunctions?.onError?.(\n              new Error(\"Error fetching video URL\"),\n            );\n        }\n      }\n\n      console.warn(\"Unknown error loading video\");\n      return store\n        .getState()\n        .__controlsFunctions?.onError?.(\n          new Error(\"Unknown error loading video\"),\n        );\n    }\n\n    store.getState().__controlsFunctions.onError(new Error(e?.message));\n  };\n\n  const onWaiting = async () => {\n    store.getState().__controlsFunctions.onWaiting();\n  };\n\n  const onStalled = async () => {\n    store.getState().__controlsFunctions.onStalled();\n  };\n\n  const onLoadStart = async () => {\n    store.getState().__controlsFunctions.onLoading();\n  };\n\n  const onEnded = async () => {\n    store.getState().__controlsFunctions.onEnded();\n  };\n\n  const onResize = async () => {\n    store.getState().__controlsFunctions.requestMeasure();\n  };\n\n  const parentElementOrElement = element?.parentElement ?? element;\n\n  if (element) {\n    element.addEventListener(\"volumechange\", onVolumeChange);\n    element.addEventListener(\"ratechange\", onRateChange);\n\n    element.addEventListener(\"loadedmetadata\", onLoadedMetadata);\n    element.addEventListener(\"loadeddata\", onLoadedData);\n    element.addEventListener(\"play\", onPlay);\n    element.addEventListener(\"playing\", onPlay);\n    element.addEventListener(\"pause\", onPause);\n    element.addEventListener(\"durationchange\", onDurationChange);\n    element.addEventListener(\"timeupdate\", onTimeUpdate);\n    element.addEventListener(\"error\", onError);\n    element.addEventListener(\"waiting\", onWaiting);\n    element.addEventListener(\"stalled\", onStalled);\n    element.addEventListener(\"loadstart\", onLoadStart);\n    element.addEventListener(\"ended\", onEnded);\n\n    parentElementOrElement?.addEventListener(\"mouseout\", onMouseUpdate);\n    parentElementOrElement?.addEventListener(\"mousemove\", onMouseUpdate);\n\n    parentElementOrElement?.addEventListener(\"touchstart\", onTouchUpdate);\n    parentElementOrElement?.addEventListener(\"touchend\", onTouchUpdate);\n    parentElementOrElement?.addEventListener(\"touchmove\", onTouchUpdate);\n\n    if (typeof window !== \"undefined\") {\n      window?.addEventListener?.(\"resize\", onResize);\n    }\n\n    parentElementOrElement?.addEventListener(\"keyup\", onKeyUp);\n    parentElementOrElement?.setAttribute(\"tabindex\", \"0\");\n\n    element.setAttribute(MEDIA_CONTROLLER_INITIALIZED_ATTRIBUTE, \"true\");\n  }\n\n  const onFullscreenChange = () => {\n    store\n      .getState()\n      .__controlsFunctions.setFullscreen(isCurrentlyFullscreen(element));\n  };\n\n  const onEnterPictureInPicture = () => {\n    store.getState().__controlsFunctions.setPictureInPicture(true);\n  };\n  const onExitPictureInPicture = () => {\n    store.getState().__controlsFunctions.setPictureInPicture(false);\n  };\n\n  // add effects\n  const removeEffectsFromStore = addEffectsToStore(element, store);\n\n  // add fullscreen listener\n  const removeFullscreenListener = addFullscreenEventListener(\n    element,\n    onFullscreenChange,\n  );\n\n  // add picture in picture listeners\n  const removeEnterPictureInPictureListener =\n    addEnterPictureInPictureEventListener(element, onEnterPictureInPicture);\n  const removeExitPictureInPictureListener =\n    addExitPictureInPictureEventListener(element, onExitPictureInPicture);\n\n  return {\n    destroy: () => {\n      removeFullscreenListener?.();\n\n      removeEnterPictureInPictureListener?.();\n      removeExitPictureInPictureListener?.();\n\n      element?.removeEventListener?.(\"ratechange\", onRateChange);\n      element?.removeEventListener?.(\"volumechange\", onVolumeChange);\n      element?.removeEventListener?.(\"loadedmetadata\", onLoadedMetadata);\n      element?.removeEventListener?.(\"loadeddata\", onLoadedData);\n      element?.removeEventListener?.(\"play\", onPlay);\n      element?.removeEventListener?.(\"playing\", onPlay);\n      element?.removeEventListener?.(\"pause\", onPause);\n      element?.removeEventListener?.(\"durationchange\", onDurationChange);\n      element?.removeEventListener?.(\"timeupdate\", onTimeUpdate);\n      element?.removeEventListener?.(\"error\", onError);\n      element?.removeEventListener?.(\"waiting\", onWaiting);\n      element?.removeEventListener?.(\"stalled\", onStalled);\n      element?.removeEventListener?.(\"loadstart\", onLoadStart);\n      element?.removeEventListener?.(\"ended\", onEnded);\n\n      if (typeof window !== \"undefined\") {\n        window?.removeEventListener?.(\"resize\", onResize);\n      }\n\n      parentElementOrElement?.removeEventListener?.(\"mouseout\", onMouseUpdate);\n      parentElementOrElement?.removeEventListener?.(\"mousemove\", onMouseUpdate);\n\n      parentElementOrElement?.removeEventListener?.(\n        \"touchstart\",\n        onTouchUpdate,\n      );\n      parentElementOrElement?.removeEventListener?.(\"touchend\", onTouchUpdate);\n      parentElementOrElement?.removeEventListener?.(\"touchmove\", onTouchUpdate);\n\n      parentElementOrElement?.removeEventListener?.(\"keyup\", onKeyUp);\n\n      removeEffectsFromStore?.();\n\n      element?.removeAttribute?.(MEDIA_CONTROLLER_INITIALIZED_ATTRIBUTE);\n    },\n  };\n};\n\ntype Cleanup = () => void | Promise<void>;\n\n// Cleanup function for src side effects\nlet cleanupSource: Cleanup = () => {};\n// Cleanup function for poster image side effects\nlet cleanupPosterImage: Cleanup = () => {};\n\nconst addEffectsToStore = (\n  element: HTMLMediaElement,\n  store: MediaControllerStore,\n) => {\n  // Subscribe to source changes (and trigger playback based on these)\n  const destroySource = store.subscribe(\n    ({\n      __initialProps,\n      __controls,\n      currentSource,\n      errorCount,\n      progress,\n      mounted,\n      videoQuality,\n    }) => ({\n      aspectRatio: __initialProps.aspectRatio,\n      autoPlay: __initialProps.autoPlay,\n      backoff: __initialProps.backoff,\n      backoffMax: __initialProps.backoffMax,\n      calculateDelay: __initialProps.calculateDelay,\n      errorCount,\n      lastError: __controls.lastError,\n      hlsConfig: __controls.hlsConfig,\n      mounted,\n      progress,\n      source: currentSource,\n      timeout: __initialProps.timeout,\n      videoQuality,\n    }),\n    async ({\n      aspectRatio,\n      autoPlay,\n      // biome-ignore lint/correctness/noUnusedFunctionParameters: ignored using `--suppress`\n      backoff,\n      // biome-ignore lint/correctness/noUnusedFunctionParameters: ignored using `--suppress`\n      backoffMax,\n      calculateDelay,\n      errorCount,\n      // biome-ignore lint/correctness/noUnusedFunctionParameters: ignored using `--suppress`\n      lastError,\n      hlsConfig,\n      mounted,\n      progress,\n      source,\n      timeout,\n      videoQuality,\n    }) => {\n      if (!mounted) {\n        return;\n      }\n\n      await cleanupSource?.();\n\n      await delay(\n        Math.max(calculateDelay(errorCount), errorCount === 0 ? 0 : 100),\n      );\n\n      let unmounted = false;\n\n      if (!source) {\n        return;\n      }\n\n      let jumped = false;\n\n      const jumpToPreviousPosition = () => {\n        const live = store.getState().live;\n\n        if (!live && progress && !jumped) {\n          element.currentTime = progress;\n\n          jumped = true;\n        }\n      };\n\n      const onErrorComposed = (err: Error) => {\n        if (!unmounted) {\n          cleanupSource?.();\n\n          store.getState().__controlsFunctions?.onError?.(err);\n        }\n      };\n\n      if (source.type === \"webrtc\") {\n        const unsubscribeBframes = store.subscribe(\n          (state) => state?.__metadata,\n          (metadata) => {\n            let webrtcIsPossibleForOneTrack = false;\n\n            // Check if metadata and meta tracks are available\n            if (metadata?.meta?.tracks) {\n              // Iterate over each track in the metadata\n              for (const trackId of Object.keys(metadata.meta.tracks)) {\n                // Check if the track does not have bframes equal to 1\n                if (metadata?.meta?.tracks[trackId]?.bframes !== 1) {\n                  webrtcIsPossibleForOneTrack = true;\n                }\n              }\n            }\n\n            // Determine if fallback to HLS is necessary\n            const shouldNotFallBackToHLS =\n              webrtcIsPossibleForOneTrack || metadata?.meta?.bframes === 0;\n\n            // If fallback to HLS is needed and component is not unmounted, handle the error\n            if (!shouldNotFallBackToHLS && !unmounted) {\n              onErrorComposed(new Error(BFRAMES_ERROR_MESSAGE));\n            }\n          },\n        );\n\n        const { destroy } = createNewWHEP({\n          source: source.src,\n          element,\n          callbacks: {\n            onConnected: () => {\n              store.getState().__controlsFunctions.setLive(true);\n              jumpToPreviousPosition();\n            },\n            onError: onErrorComposed,\n            onPlaybackOffsetUpdated:\n              store.getState().__controlsFunctions.updatePlaybackOffsetMs,\n            onRedirect: store.getState().__controlsFunctions.onFinalUrl,\n          },\n          accessControl: {\n            jwt: store.getState().__initialProps.jwt,\n            accessKey: store.getState().__initialProps.accessKey,\n          },\n          sdpTimeout: timeout,\n          iceServers: store.getState().__initialProps.iceServers,\n        });\n\n        const id = setTimeout(() => {\n          if (!store.getState().canPlay && !unmounted) {\n            store.getState().__controlsFunctions.onWebRTCTimeout?.();\n\n            onErrorComposed(\n              new Error(\n                \"Timeout reached for canPlay - triggering playback error.\",\n              ),\n            );\n          }\n        }, timeout);\n\n        cleanupSource = () => {\n          unmounted = true;\n\n          clearTimeout(id);\n          destroy?.();\n          unsubscribeBframes?.();\n        };\n\n        return;\n      }\n\n      if (source.type === \"hls\") {\n        const indexUrl = /\\/hls\\/[^/\\s]+\\/index\\.m3u8/;\n\n        const onErrorCleaned = (error: HlsError) => {\n          const cleanError = new Error(\n            error?.response?.data?.toString?.() ??\n              (error?.response?.code === 401\n                ? ACCESS_CONTROL_ERROR_MESSAGE\n                : \"Error with HLS.js\"),\n          );\n\n          onErrorComposed?.(cleanError);\n        };\n\n        const hlsConfigResolved = hlsConfig as Partial<HlsConfig> | null;\n\n        const { destroy, setQuality } = createNewHls({\n          source: source?.src,\n          element,\n          initialQuality: videoQuality,\n          aspectRatio: aspectRatio ?? 16 / 9,\n          callbacks: {\n            onLive: store.getState().__controlsFunctions.setLive,\n            onDuration: store.getState().__controlsFunctions.onDurationChange,\n            onCanPlay: () => {\n              store.getState().__controlsFunctions.onCanPlay();\n              jumpToPreviousPosition();\n              store.getState().__controlsFunctions.onError(null);\n            },\n            onError: onErrorCleaned,\n            onPlaybackOffsetUpdated:\n              store.getState().__controlsFunctions.updatePlaybackOffsetMs,\n            onRedirect: store.getState().__controlsFunctions.onFinalUrl,\n          },\n          config: {\n            ...(hlsConfigResolved ?? {}),\n            async xhrSetup(xhr, url) {\n              if (hlsConfigResolved?.xhrSetup) {\n                await hlsConfigResolved?.xhrSetup?.(xhr, url);\n              } else {\n                const live = store.getState().live;\n\n                if (!live || url.match(indexUrl)) {\n                  const jwt = store.getState().__initialProps.jwt;\n                  const accessKey = store.getState().__initialProps.accessKey;\n\n                  if (accessKey)\n                    xhr.setRequestHeader(\"Livepeer-Access-Key\", accessKey);\n                  else if (jwt) xhr.setRequestHeader(\"Livepeer-Jwt\", jwt);\n                }\n              }\n            },\n            autoPlay,\n          },\n        });\n\n        const unsubscribeQualityUpdate = store.subscribe(\n          (state) => state.videoQuality,\n          (newQuality) => {\n            setQuality(newQuality);\n          },\n        );\n\n        cleanupSource = () => {\n          unmounted = true;\n          destroy?.();\n          unsubscribeQualityUpdate?.();\n        };\n\n        return;\n      }\n\n      if (source?.type === \"video\") {\n        store.getState().__controlsFunctions.onFinalUrl(source.src);\n\n        element.addEventListener(\"canplay\", jumpToPreviousPosition);\n\n        element.src = source.src;\n        element.load();\n\n        cleanupSource = () => {\n          unmounted = true;\n\n          element?.removeEventListener?.(\"canplay\", jumpToPreviousPosition);\n        };\n\n        return;\n      }\n    },\n    {\n      equalityFn: (a, b) => {\n        const errorCountChanged =\n          a.errorCount !== b.errorCount && b.errorCount !== 0;\n        const lastErrorChanged = a.lastError !== b.lastError;\n\n        const sourceChanged = a.source?.src !== b.source?.src;\n        const mountedChanged = a.mounted !== b.mounted;\n\n        const shouldReRender =\n          errorCountChanged ||\n          lastErrorChanged ||\n          sourceChanged ||\n          mountedChanged;\n\n        return !shouldReRender;\n      },\n    },\n  );\n\n  // Subscribe to poster image changes\n  const destroyPosterImage = store.subscribe(\n    ({ __controls, live, __controlsFunctions, __initialProps }) => ({\n      thumbnail: __controls.thumbnail?.src,\n      live,\n      setPoster: __controlsFunctions.setPoster,\n      posterLiveUpdate: __initialProps.posterLiveUpdate,\n    }),\n    async ({ thumbnail, live, setPoster, posterLiveUpdate }) => {\n      cleanupPosterImage?.();\n\n      if (thumbnail && live && posterLiveUpdate > 0) {\n        const interval = setInterval(() => {\n          const thumbnailUrl = new URL(thumbnail);\n\n          thumbnailUrl.searchParams.set(\"v\", Date.now().toFixed(0));\n\n          setPoster(thumbnailUrl.toString());\n        }, posterLiveUpdate);\n\n        cleanupPosterImage = () => clearInterval(interval);\n      }\n    },\n    {\n      equalityFn: (a, b) => a.thumbnail === b.thumbnail && a.live === b.live,\n    },\n  );\n\n  // Subscribe to play/pause changes\n  const destroyPlayPause = store.subscribe(\n    (state) => state.__controls.requestedPlayPauseLastTime,\n    async () => {\n      if (element.paused) {\n        await element.play();\n      } else {\n        await element.pause();\n      }\n    },\n  );\n\n  // Subscribe to playback rate changes\n  const destroyPlaybackRate = store.subscribe(\n    (state) => state.playbackRate,\n    (current) => {\n      element.playbackRate = current === \"constant\" ? 1 : current;\n    },\n  );\n\n  // Subscribe to volume changes\n  const destroyVolume = store.subscribe(\n    (state) => ({\n      playing: state.playing,\n      volume: state.volume,\n      isVolumeChangeSupported: state.__device.isVolumeChangeSupported,\n    }),\n    (current) => {\n      if (current.isVolumeChangeSupported) {\n        element.volume = current.volume;\n      }\n    },\n    {\n      equalityFn: (a, b) =>\n        a.volume === b.volume &&\n        a.playing === b.playing &&\n        a.isVolumeChangeSupported === b.isVolumeChangeSupported,\n    },\n  );\n\n  // Subscribe to mute changes\n  const destroyMute = store.subscribe(\n    (state) => state.__controls.muted,\n    (current, prev) => {\n      if (current !== prev) {\n        element.muted = current;\n      }\n    },\n  );\n\n  // Subscribe to seeking changes\n  const destroySeeking = store.subscribe(\n    (state) => state.__controls.requestedRangeToSeekTo,\n    (current) => {\n      if (typeof element.readyState === \"undefined\" || element.readyState > 0) {\n        element.currentTime = current;\n      }\n    },\n  );\n\n  // Subscribe to fullscreen changes\n  const destroyFullscreen = store.subscribe(\n    (state) => state.__controls.requestedFullscreenLastTime,\n    async () => {\n      const isFullscreen = isCurrentlyFullscreen(element);\n      if (isFullscreen) exitFullscreen(element);\n      else enterFullscreen(element);\n    },\n  );\n\n  // Subscribe to picture-in-picture changes\n  const destroyPictureInPicture = store.subscribe(\n    (state) => state.__controls.requestedPictureInPictureLastTime,\n    async () => {\n      try {\n        const isPictureInPicture = await isCurrentlyPictureInPicture(element);\n        if (isPictureInPicture) await exitPictureInPicture(element);\n        else await enterPictureInPicture(element);\n      } catch (e) {\n        warn((e as Error)?.message ?? \"Picture in picture is not supported\");\n\n        store.setState((state) => ({\n          __device: {\n            ...state.__device,\n            isPictureInPictureSupported: false,\n          },\n        }));\n      }\n    },\n  );\n\n  // Subscribe to autohide interactions\n  const destroyAutohide = store.subscribe(\n    (state) => ({\n      lastInteraction: state.__controls.lastInteraction,\n      autohide: state.__controls.autohide,\n    }),\n    async ({ lastInteraction, autohide }) => {\n      if (autohide && lastInteraction) {\n        store.getState().__controlsFunctions.setHidden(false);\n\n        await delay(autohide);\n\n        const parentElementOrElement = element?.parentElement ?? element;\n\n        // we check if any children of the parent element are in an \"open\" state, which is the radix\n        // data attribute for popovers and other elements\n        // this is the only way to reliably hide the controls while a popover is shown, and possibly\n        // is missing some data attributes for other primitives\n        const openElement = parentElementOrElement?.querySelector?.(\n          '[data-state=\"open\"]',\n        );\n\n        if (\n          !openElement &&\n          !store.getState().hidden &&\n          lastInteraction === store.getState().__controls.lastInteraction\n        ) {\n          store.getState().__controlsFunctions.setHidden(true);\n        }\n      }\n    },\n    {\n      equalityFn: (a, b) =>\n        a?.lastInteraction === b?.lastInteraction &&\n        a?.autohide === b?.autohide,\n    },\n  );\n\n  // Subscribe to sizing requests\n  const destroyRequestSizing = store.subscribe(\n    (state) => ({\n      lastTime: state.__controls.requestedMeasureLastTime,\n      fullscreen: state.fullscreen,\n    }),\n    async () => {\n      store.getState().__controlsFunctions.setSize({\n        ...((element as unknown as HTMLVideoElement)?.videoHeight &&\n        (element as unknown as HTMLVideoElement)?.videoWidth\n          ? {\n              media: {\n                height: (element as unknown as HTMLVideoElement).videoHeight,\n                width: (element as unknown as HTMLVideoElement).videoWidth,\n              },\n            }\n          : {}),\n        ...(element?.clientHeight && element?.clientWidth\n          ? {\n              container: {\n                height: element.clientHeight,\n                width: element.clientWidth,\n              },\n            }\n          : {}),\n        ...(typeof window !== \"undefined\" &&\n        window?.innerHeight &&\n        window?.innerWidth\n          ? {\n              window: {\n                height: window.innerHeight,\n                width: window.innerWidth,\n              },\n            }\n          : {}),\n      });\n    },\n    {\n      equalityFn: (a, b) =>\n        a?.fullscreen === b?.fullscreen && a?.lastTime === b?.lastTime,\n    },\n  );\n\n  // Subscribe to media sizing changes\n  const destroyMediaSizing = store.subscribe(\n    (state) => state.__controls.size?.media,\n    async (media) => {\n      const parentElementOrElement = element?.parentElement ?? element;\n\n      if (parentElementOrElement) {\n        if (media?.height && media?.width) {\n          const elementStyle = parentElementOrElement.style;\n          elementStyle.setProperty(\n            \"--livepeer-media-height\",\n            `${media.height}px`,\n          );\n          elementStyle.setProperty(\n            \"--livepeer-media-width\",\n            `${media.width}px`,\n          );\n        }\n      }\n    },\n    {\n      equalityFn: (a, b) => a?.height === b?.height && a?.width === b?.width,\n    },\n  );\n\n  // Subscribe to container sizing changes\n  const destroyContainerSizing = store.subscribe(\n    (state) => state.__controls.size?.container,\n    async (container) => {\n      const parentElementOrElement = element?.parentElement ?? element;\n\n      if (parentElementOrElement) {\n        if (container?.height && container?.width) {\n          const elementStyle = parentElementOrElement.style;\n          elementStyle.setProperty(\n            \"--livepeer-container-height\",\n            `${container.height}px`,\n          );\n          elementStyle.setProperty(\n            \"--livepeer-container-width\",\n            `${container.width}px`,\n          );\n        }\n      }\n    },\n    {\n      equalityFn: (a, b) => a?.height === b?.height && a?.width === b?.width,\n    },\n  );\n\n  return () => {\n    destroyAutohide?.();\n    destroyContainerSizing?.();\n    destroyFullscreen?.();\n    destroyMediaSizing?.();\n    destroyMute?.();\n    destroyPictureInPicture?.();\n    destroyPlaybackRate?.();\n    destroyPlayPause?.();\n    destroyPosterImage?.();\n    destroyRequestSizing?.();\n    destroySeeking?.();\n    destroyVolume?.();\n    destroySource?.();\n\n    cleanupPosterImage?.();\n    cleanupSource?.();\n  };\n};\n","import {\n  calculateVideoQualityDimensions,\n  type VideoQuality,\n} from \"@livepeer/core/media\";\nimport Hls, { type ErrorData, type HlsConfig } from \"hls.js\";\nimport { isClient } from \"../media/utils\";\n\nexport const VIDEO_HLS_INITIALIZED_ATTRIBUTE =\n  \"data-livepeer-video-hls-initialized\";\n\nexport type HlsError = ErrorData;\n\nexport type VideoConfig = { autoplay?: boolean };\nexport type HlsVideoConfig = Partial<HlsConfig> & {\n  autoPlay?: boolean;\n};\n\n/**\n * Checks if hls.js can play in the browser.\n */\nexport const isHlsSupported = () => (isClient() ? Hls.isSupported() : true);\n\n/**\n * Create an hls.js instance and attach to the provided media element.\n */\nexport const createNewHls = <TElement extends HTMLMediaElement>({\n  source,\n  element,\n  callbacks,\n  aspectRatio,\n  config,\n  initialQuality,\n}: {\n  source: string;\n  element: TElement;\n  initialQuality: VideoQuality;\n  aspectRatio: number;\n  callbacks: {\n    onLive?: (v: boolean) => void;\n    onPlaybackOffsetUpdated?: (d: number) => void;\n    onDuration?: (v: number) => void;\n    onCanPlay?: () => void;\n    onError?: (data: HlsError) => void;\n    onRedirect?: (url: string | null) => void;\n  };\n  config: HlsVideoConfig;\n}): {\n  setQuality: (quality: VideoQuality) => void;\n  destroy: () => void;\n} => {\n  // do not attach twice\n  if (element.getAttribute(VIDEO_HLS_INITIALIZED_ATTRIBUTE) === \"true\") {\n    return {\n      setQuality: () => {\n        //\n      },\n      destroy: () => {\n        //\n      },\n    };\n  }\n\n  element.setAttribute(VIDEO_HLS_INITIALIZED_ATTRIBUTE, \"true\");\n\n  const hls = new Hls({\n    backBufferLength: 60 * 1.5,\n    manifestLoadingMaxRetry: 0,\n    fragLoadingMaxRetry: 0,\n    levelLoadingMaxRetry: 0,\n    appendErrorMaxRetry: 0,\n    ...config,\n    ...(config?.liveSyncDurationCount\n      ? {\n          liveSyncDurationCount: config.liveSyncDurationCount,\n        }\n      : {\n          liveMaxLatencyDurationCount: 7,\n          liveSyncDurationCount: 3,\n        }),\n  });\n\n  const onDestroy = () => {\n    hls?.destroy?.();\n    element?.removeAttribute?.(VIDEO_HLS_INITIALIZED_ATTRIBUTE);\n  };\n\n  if (element) {\n    hls.attachMedia(element);\n  }\n\n  let redirected = false;\n\n  hls.on(Hls.Events.LEVEL_LOADED, async (_e, data) => {\n    const { live, totalduration: duration, url } = data.details;\n\n    if (!redirected) {\n      callbacks?.onRedirect?.(url ?? null);\n      redirected = true;\n    }\n\n    callbacks?.onLive?.(Boolean(live));\n    callbacks?.onDuration?.(duration ?? 0);\n  });\n\n  hls.on(Hls.Events.MEDIA_ATTACHED, async () => {\n    hls.loadSource(source);\n\n    hls.on(Hls.Events.MANIFEST_PARSED, (_event, _data) => {\n      setQuality({\n        hls: hls ?? null,\n        quality: initialQuality,\n        aspectRatio,\n      });\n\n      callbacks?.onCanPlay?.();\n      if (config.autoPlay) element?.play?.();\n    });\n  });\n\n  hls.on(Hls.Events.ERROR, async (_event, data) => {\n    const { details, fatal } = data;\n\n    const isManifestParsingError = details === \"manifestParsingError\";\n\n    if (!fatal && !isManifestParsingError) return;\n    callbacks?.onError?.(data);\n\n    if (fatal) {\n      console.error(`Fatal error : ${data.details}`);\n      switch (data.type) {\n        case Hls.ErrorTypes.MEDIA_ERROR:\n          hls.recoverMediaError();\n          break;\n        case Hls.ErrorTypes.NETWORK_ERROR:\n          console.error(`A network error occurred: ${data.details}`);\n          break;\n        default:\n          console.error(`An unrecoverable error occurred: ${data.details}`);\n          hls.destroy();\n          break;\n      }\n    }\n  });\n\n  function updateOffset() {\n    const currentDate = Date.now();\n    const newDate = hls.playingDate;\n\n    if (newDate && currentDate) {\n      callbacks?.onPlaybackOffsetUpdated?.(currentDate - newDate.getTime());\n    }\n  }\n\n  const updateOffsetInterval = setInterval(updateOffset, 2000);\n\n  return {\n    destroy: () => {\n      onDestroy?.();\n      clearInterval?.(updateOffsetInterval);\n      element?.removeAttribute?.(VIDEO_HLS_INITIALIZED_ATTRIBUTE);\n    },\n    setQuality: (videoQuality) => {\n      setQuality({\n        hls: hls ?? null,\n        quality: videoQuality,\n        aspectRatio,\n      });\n    },\n  };\n};\n\nconst setQuality = ({\n  hls,\n  quality,\n  aspectRatio,\n}: {\n  hls: Hls | null;\n  quality: VideoQuality;\n  aspectRatio: number;\n}) => {\n  if (hls) {\n    const { width } = calculateVideoQualityDimensions(quality, aspectRatio);\n\n    if (!width || quality === \"auto\") {\n      hls.currentLevel = -1; // Auto level\n      return;\n    }\n\n    if (hls.levels && hls.levels.length > 0) {\n      // Sort levels by the absolute difference between their width and the desired width\n      const sortedLevels = hls.levels\n        .map((level, index) => ({ ...level, index }))\n        .sort(\n          (a, b) =>\n            Math.abs((width ?? 0) - a.width) - Math.abs((width ?? 0) - b.width),\n        );\n\n      // Choose the level with the smallest difference in width\n      const bestMatchLevel = sortedLevels?.[0];\n\n      if ((bestMatchLevel?.index ?? -1) >= 0) {\n        hls.currentLevel = bestMatchLevel.index;\n      } else {\n        hls.currentLevel = -1;\n      }\n    }\n  }\n};\n","import type { Src } from \"@livepeer/core/media\";\nimport { noop } from \"@livepeer/core/utils\";\n\nexport const isClient = () => typeof window !== \"undefined\";\nexport const ua = () =>\n  isClient() ? window?.navigator?.userAgent?.toLowerCase() : \"\";\nexport const isIos = () => /iphone|ipad|ipod|ios|CriOS|FxiOS/.test(ua());\nexport const isAndroid = () => /android/.test(ua());\nexport const isMobile = () => isClient() && (isIos() || isAndroid());\nexport const isIphone = () =>\n  isClient() && /(iPhone|iPod)/gi.test(window?.navigator?.platform);\nexport const isFirefox = () => /firefox/.test(ua());\nexport const isChrome = () => isClient() && !!window?.chrome;\nexport const isSafari = () =>\n  Boolean(\n    isClient() &&\n      !isChrome() &&\n      (window?.safari || isIos() || /(apple|safari)/.test(ua())),\n  );\n\n/**\n * To detect autoplay, we create a video element and call play on it, if it is `paused` after\n * a `play()` call, autoplay is supported. Although this unintuitive, it works across browsers\n * and is currently the lightest way to detect autoplay without using a data source.\n *\n * @see {@link https://github.com/ampproject/amphtml/blob/9bc8756536956780e249d895f3e1001acdee0bc0/src/utils/video.js#L25}\n */\nexport const canAutoplay = (\n  muted = true,\n  playsinline = true,\n): Promise<boolean> => {\n  if (!isClient()) return Promise.resolve(false);\n\n  const video = document.createElement(\"video\");\n\n  if (muted) {\n    video.setAttribute(\"muted\", \"\");\n    video.muted = true;\n  }\n\n  if (playsinline) {\n    video.setAttribute(\"playsinline\", \"\");\n    video.setAttribute(\"webkit-playsinline\", \"\");\n  }\n\n  video.setAttribute(\"height\", \"0\");\n  video.setAttribute(\"width\", \"0\");\n\n  video.style.position = \"fixed\";\n  video.style.top = \"0\";\n  video.style.width = \"0\";\n  video.style.height = \"0\";\n  video.style.opacity = \"0\";\n\n  // Promise wrapped this way to catch both sync throws and async rejections.\n  // More info: https://github.com/tc39/proposal-promise-try\n  new Promise((resolve) => resolve(video.play())).catch(noop);\n\n  return Promise.resolve(!video.paused);\n};\n\n/**\n * Checks if the native HTML5 video player can play the mime type.\n */\nexport const canPlayMediaNatively = (src: Src): boolean => {\n  if (isClient() && src?.mime) {\n    if (src?.type?.includes(\"audio\")) {\n      const audio = document.createElement(\"audio\");\n      return audio.canPlayType(src.mime).length > 0;\n    }\n\n    const video = document.createElement(\"video\");\n    return video.canPlayType(src.mime).length > 0;\n  }\n\n  return true;\n};\n","import { NOT_ACCEPTABLE_ERROR_MESSAGE } from \"@livepeer/core/errors\";\nimport type { AccessControlParams } from \"@livepeer/core/media\";\nimport { isClient } from \"../media/utils\";\n\n/**\n * Checks if WebRTC is supported and returns the appropriate RTCPeerConnection constructor.\n */\nexport const getRTCPeerConnectionConstructor = () => {\n  // Check if the current environment is a client (browser)\n  if (!isClient()) {\n    return null; // If not a client, WebRTC is not supported\n  }\n\n  // Return the constructor for RTCPeerConnection with any vendor prefixes\n  return (\n    window.RTCPeerConnection ||\n    window.webkitRTCPeerConnection ||\n    window.mozRTCPeerConnection ||\n    null // Return null if none of the constructors are available\n  );\n};\n\n/**\n * Creates a new RTCPeerConnection instance with the given STUN and TURN servers.\n */\nexport function createPeerConnection(\n  host: string | null,\n  iceServers?: RTCIceServer | RTCIceServer[],\n): RTCPeerConnection | null {\n  const RTCPeerConnectionConstructor = getRTCPeerConnectionConstructor();\n\n  if (!RTCPeerConnectionConstructor) {\n    throw new Error(\"No RTCPeerConnection constructor found in this browser.\");\n  }\n\n  // Defaults to Mist behavior\n  const hostNoPort = host?.split(\":\")[0];\n  const defaultIceServers = host\n    ? [\n        {\n          urls: `stun:${hostNoPort}`,\n        },\n        {\n          urls: `turn:${hostNoPort}`,\n          username: \"livepeer\",\n          credential: \"livepeer\",\n        },\n      ]\n    : [];\n\n  return new RTCPeerConnectionConstructor({\n    iceServers: iceServers\n      ? Array.isArray(iceServers)\n        ? iceServers\n        : [iceServers]\n      : defaultIceServers,\n  });\n}\n\nconst DEFAULT_TIMEOUT = 10000;\n\n/**\n * Performs the actual SDP exchange.\n *\n * 1. Sends the SDP offer to the server,\n * 2. Awaits the server's offer.\n *\n * SDP describes what kind of media we can send and how the server and client communicate.\n *\n * https://developer.mozilla.org/en-US/docs/Glossary/SDP\n * https://www.ietf.org/archive/id/draft-ietf-wish-whip-01.html#name-protocol-operation\n */\nexport async function negotiateConnectionWithClientOffer(\n  peerConnection: RTCPeerConnection | null | undefined,\n  endpoint: string | null | undefined,\n  ofr: RTCSessionDescription | null,\n  controller: AbortController,\n  accessControl: AccessControlParams,\n  sdpTimeout: number | null,\n): Promise<Date> {\n  if (peerConnection && endpoint && ofr) {\n    /**\n     * This response contains the server's SDP offer.\n     * This specifies how the client should communicate,\n     * and what kind of media client and server have negotiated to exchange.\n     */\n    const response = await postSDPOffer(\n      endpoint,\n      ofr.sdp,\n      controller,\n      accessControl,\n      sdpTimeout,\n    );\n    if (response.ok) {\n      const answerSDP = await response.text();\n      await peerConnection.setRemoteDescription(\n        new RTCSessionDescription({ type: \"answer\", sdp: answerSDP }),\n      );\n\n      const playheadUtc = response.headers.get(\"Playhead-Utc\");\n\n      return new Date(playheadUtc ?? new Date());\n    }\n    if (response.status === 406) {\n      throw new Error(NOT_ACCEPTABLE_ERROR_MESSAGE);\n    }\n\n    const errorMessage = await response.text();\n    throw new Error(errorMessage);\n  }\n\n  throw new Error(\"Peer connection not defined.\");\n}\n\n/**\n * Helper function to prefer H264 codec in SDP\n */\nfunction preferCodec(sdp: string, codec: string): string {\n  const lines = sdp.split(\"\\r\\n\");\n  const mLineIndex = lines.findIndex((line) => line.startsWith(\"m=video\"));\n\n  if (mLineIndex === -1) return sdp;\n\n  const codecRegex = new RegExp(`a=rtpmap:(\\\\d+) ${codec}(/\\\\d+)+`);\n  const codecLine = lines.find((line) => codecRegex.test(line));\n\n  if (!codecLine) return sdp;\n\n  // biome-ignore lint/style/noNonNullAssertion: todo: fix this\n  const codecPayload = codecRegex.exec(codecLine)![1];\n  const mLineElements = lines[mLineIndex].split(\" \");\n\n  const reorderedMLine = [\n    ...mLineElements.slice(0, 3),\n    codecPayload,\n    ...mLineElements.slice(3).filter((payload) => payload !== codecPayload),\n  ];\n\n  lines[mLineIndex] = reorderedMLine.join(\" \");\n  return lines.join(\"\\r\\n\");\n}\n\n/**\n * Constructs the client's SDP offer with H264 codec preference\n *\n * SDP describes what kind of media we can send and how the server and client communicate.\n *\n * https://developer.mozilla.org/en-US/docs/Glossary/SDP\n * https://www.ietf.org/archive/id/draft-ietf-wish-whip-01.html#name-protocol-operation\n */\nexport async function constructClientOffer(\n  peerConnection: RTCPeerConnection | null | undefined,\n  endpoint: string | null | undefined,\n  noIceGathering?: boolean,\n) {\n  if (peerConnection && endpoint) {\n    // Override createOffer to include H264 codec preference\n    const originalCreateOffer = peerConnection.createOffer.bind(peerConnection);\n    // @ts-ignore (TODO: fix this)\n    peerConnection.createOffer = async function (...args) {\n      // @ts-ignore (TODO: fix this)\n      const originalOffer = await originalCreateOffer.apply(this, args);\n      return new RTCSessionDescription({\n        // @ts-ignore (TODO: fix this)\n        type: originalOffer.type,\n        // @ts-ignore (TODO: fix this)\n        sdp: preferCodec(originalOffer.sdp, \"H264\"),\n      });\n    };\n\n    /** https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createOffer */\n    const offer = await peerConnection.createOffer();\n\n    /** https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/setLocalDescription */\n    await peerConnection.setLocalDescription(offer);\n\n    /** Wait for ICE gathering to complete */\n    if (noIceGathering) {\n      return peerConnection.localDescription;\n    }\n    const ofr = await waitToCompleteICEGathering(peerConnection);\n    if (!ofr) {\n      throw Error(\"failed to gather ICE candidates for offer\");\n    }\n\n    return ofr;\n  }\n\n  return null;\n}\n\n// Regular expression to match the playback ID at the end of the URL\n// It looks for a string that follows the last \"+\" or \"/\" and continues to the end of the pathname\nconst playbackIdPattern = /([/+])([^/+?]+)$/;\nconst REPLACE_PLACEHOLDER = \"PLAYBACK_ID\";\n\nconst MAX_REDIRECT_CACHE_SIZE = 10;\nconst redirectUrlCache = new Map<string, URL>();\n\nfunction getCachedTemplate(key: string): URL | undefined {\n  const cachedItem = redirectUrlCache.get(key);\n\n  if (cachedItem) {\n    redirectUrlCache.delete(key);\n    redirectUrlCache.set(key, cachedItem);\n  }\n\n  return cachedItem;\n}\n\nfunction setCachedTemplate(key: string, value: URL): void {\n  if (redirectUrlCache.has(key)) {\n    redirectUrlCache.delete(key);\n  } else if (redirectUrlCache.size >= MAX_REDIRECT_CACHE_SIZE) {\n    const oldestKey = redirectUrlCache.keys().next().value;\n    if (oldestKey) {\n      redirectUrlCache.delete(oldestKey);\n    }\n  }\n\n  redirectUrlCache.set(key, value);\n}\n\nasync function postSDPOffer(\n  endpoint: string,\n  data: string,\n  controller: AbortController,\n  accessControl: AccessControlParams,\n  sdpTimeout: number | null,\n) {\n  const id = setTimeout(\n    () => controller.abort(),\n    sdpTimeout ?? DEFAULT_TIMEOUT,\n  );\n\n  const urlForPost = new URL(endpoint);\n  const parsedMatches = urlForPost.pathname.match(playbackIdPattern);\n  const currentPlaybackId = parsedMatches?.[2];\n\n  const cachedTemplateUrl = getCachedTemplate(endpoint);\n\n  // if we both have a cached redirect URL and a match for the playback ID,\n  // use these to shortcut the typical webrtc redirect flow\n  if (cachedTemplateUrl && currentPlaybackId) {\n    urlForPost.host = cachedTemplateUrl.host;\n    urlForPost.pathname = cachedTemplateUrl.pathname.replace(\n      REPLACE_PLACEHOLDER,\n      currentPlaybackId,\n    );\n    urlForPost.search = cachedTemplateUrl.search;\n  }\n\n  const response = await fetch(urlForPost.toString(), {\n    method: \"POST\",\n    mode: \"cors\",\n    headers: {\n      \"content-type\": \"application/sdp\",\n      ...(accessControl?.accessKey\n        ? {\n            \"Livepeer-Access-Key\": accessControl.accessKey,\n          }\n        : {}),\n      ...(accessControl?.jwt\n        ? {\n            \"Livepeer-Jwt\": accessControl.jwt,\n          }\n        : {}),\n    },\n    body: data,\n    signal: controller.signal,\n  });\n\n  clearTimeout(id);\n\n  return response;\n}\n\nexport async function getRedirectUrl(\n  endpoint: string,\n  abortController: AbortController,\n  timeout: number | null,\n) {\n  try {\n    const cachedTemplateUrl = getCachedTemplate(endpoint);\n\n    if (cachedTemplateUrl) {\n      const currentIngestUrl = new URL(endpoint);\n      const matches = currentIngestUrl.pathname.match(playbackIdPattern);\n      const currentPlaybackId = matches?.[2];\n\n      if (currentPlaybackId) {\n        const finalRedirectUrl = new URL(cachedTemplateUrl);\n        finalRedirectUrl.pathname = cachedTemplateUrl.pathname.replace(\n          REPLACE_PLACEHOLDER,\n          currentPlaybackId,\n        );\n        return finalRedirectUrl;\n      }\n    }\n\n    const id = setTimeout(\n      () => abortController.abort(),\n      timeout ?? DEFAULT_TIMEOUT,\n    );\n\n    const response = await fetch(endpoint, {\n      method: \"HEAD\",\n      signal: abortController.signal,\n    });\n\n    // consume response body\n    await response.text();\n\n    clearTimeout(id);\n\n    const actualRedirectedUrl = new URL(response.url);\n\n    if (actualRedirectedUrl) {\n      const templateForCache = new URL(actualRedirectedUrl);\n      templateForCache.pathname = templateForCache.pathname.replace(\n        playbackIdPattern,\n        `$1${REPLACE_PLACEHOLDER}`,\n      );\n\n      if (\n        !templateForCache.searchParams.has(\"ingestpb\") ||\n        templateForCache.searchParams.get(\"ingestpb\") !== \"true\"\n      ) {\n        setCachedTemplate(endpoint, templateForCache);\n      }\n    }\n    return actualRedirectedUrl;\n    // biome-ignore lint/correctness/noUnusedVariables: ignored using `--suppress`\n  } catch (e) {\n    return null;\n  }\n}\n\n/**\n * Receives an RTCPeerConnection and waits until\n * the connection is initialized or a timeout passes.\n *\n * https://www.ietf.org/archive/id/draft-ietf-wish-whip-01.html#section-4.1\n * https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/iceGatheringState\n * https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/icegatheringstatechange_event\n */\nasync function waitToCompleteICEGathering(peerConnection: RTCPeerConnection) {\n  return new Promise<RTCSessionDescription | null>((resolve) => {\n    /** Wait at most five seconds for ICE gathering. */\n    setTimeout(() => {\n      resolve(peerConnection.localDescription);\n    }, 5000);\n    peerConnection.onicegatheringstatechange = (_ev) => {\n      if (peerConnection.iceGatheringState === \"complete\") {\n        resolve(peerConnection.localDescription);\n      }\n    };\n  });\n}\n\n/**\n * Parses the ICE servers from the `Link` headers returned during SDP negotiation.\n */\n// function parseIceServersFromLinkHeader(\n//   iceString: string | null,\n// ): NonNullable<RTCConfiguration['iceServers']> | null {\n//   try {\n//     const servers = iceString\n//       ?.split(', ')\n//       .map((serverStr) => {\n//         const parts = serverStr.split('; ');\n//         const server: NonNullable<RTCConfiguration['iceServers']>[number] = {\n//           urls: '',\n//         };\n\n//         for (const part of parts) {\n//           if (part.startsWith('stun:') || part.startsWith('turn:')) {\n//             server.urls = part;\n//           } else if (part.startsWith('username=')) {\n//             server.username = part.slice('username=\"'.length, -1);\n//           } else if (part.startsWith('credential=')) {\n//             server.credential = part.slice('credential=\"'.length, -1);\n//           }\n//         }\n\n//         return server;\n//       })\n//       .filter((server) => server.urls);\n\n//     return servers && (servers?.length ?? 0) > 0 ? servers : null;\n//   } catch (e) {\n//     console.error(e);\n//   }\n\n//   return null;\n// }\n","import type { AccessControlParams } from \"@livepeer/core/media\";\n\nimport {\n  constructClientOffer,\n  createPeerConnection,\n  getRedirectUrl,\n  negotiateConnectionWithClientOffer,\n} from \"./shared\";\n\nexport const VIDEO_WEBRTC_INITIALIZED_ATTRIBUTE =\n  \"data-livepeer-video-whep-initialized\";\n\n/**\n * Client that uses WHEP to play back video over WebRTC.\n *\n * https://www.ietf.org/id/draft-murillo-whep-00.html\n */\nexport const createNewWHEP = <TElement extends HTMLMediaElement>({\n  source,\n  element,\n  callbacks,\n  accessControl,\n  sdpTimeout,\n  iceServers,\n}: {\n  source: string;\n  element: TElement;\n  callbacks: {\n    onConnected?: () => void;\n    onPlaybackOffsetUpdated?: (d: number) => void;\n    onError?: (data: Error) => void;\n    onRedirect?: (url: string | null) => void;\n  };\n  accessControl: AccessControlParams;\n  sdpTimeout: number | null;\n  iceServers?: RTCIceServer | RTCIceServer[];\n}): {\n  destroy: () => void;\n} => {\n  // do not attach twice\n  if (element.getAttribute(VIDEO_WEBRTC_INITIALIZED_ATTRIBUTE) === \"true\") {\n    return {\n      destroy: () => {\n        //\n      },\n    };\n  }\n\n  element.setAttribute(VIDEO_WEBRTC_INITIALIZED_ATTRIBUTE, \"true\");\n\n  let destroyed = false;\n\n  const abortController = new AbortController();\n\n  let peerConnection: RTCPeerConnection | null = null;\n  const stream = new MediaStream();\n\n  const errorComposed = (e: Error) => {\n    callbacks?.onError?.(e as Error);\n\n    if (element) {\n      element.srcObject = null;\n    }\n  };\n\n  getRedirectUrl(source, abortController, sdpTimeout)\n    .then((redirectUrl) => {\n      if (destroyed || !redirectUrl) {\n        return;\n      }\n\n      const redirectUrlString = redirectUrl.toString();\n\n      callbacks?.onRedirect?.(redirectUrlString ?? null);\n\n      /**\n       * Create a new WebRTC connection, using public STUN servers with ICE,\n       * allowing the client to discover its own IP address.\n       * https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Protocols#ice\n       */\n      peerConnection = createPeerConnection(redirectUrl.host, iceServers);\n\n      if (peerConnection) {\n        /** https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addTransceiver */\n        peerConnection.addTransceiver(\"video\", {\n          direction: \"recvonly\",\n        });\n        peerConnection.addTransceiver(\"audio\", {\n          direction: \"recvonly\",\n        });\n\n        /**\n         * When new tracks are received in the connection, store local references,\n         * so that they can be added to a MediaStream, and to the <video> element.\n         *\n         * https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/track_event\n         */\n        peerConnection.ontrack = (event) => {\n          if (destroyed) {\n            return;\n          }\n\n          try {\n            if (stream) {\n              const track = event.track;\n              const currentTracks = stream.getTracks();\n              const streamAlreadyHasVideoTrack = currentTracks.some(\n                (track) => track.kind === \"video\",\n              );\n              const streamAlreadyHasAudioTrack = currentTracks.some(\n                (track) => track.kind === \"audio\",\n              );\n              switch (track.kind) {\n                case \"video\":\n                  if (streamAlreadyHasVideoTrack) {\n                    break;\n                  }\n                  stream.addTrack(track);\n                  break;\n                case \"audio\":\n                  if (streamAlreadyHasAudioTrack) {\n                    break;\n                  }\n                  stream.addTrack(track);\n                  break;\n                default:\n                  console.log(`received unknown track ${track}`);\n              }\n            }\n          } catch (e) {\n            errorComposed(e as Error);\n          }\n        };\n\n        peerConnection.addEventListener(\"connectionstatechange\", (_ev) => {\n          if (destroyed) {\n            return;\n          }\n\n          try {\n            if (peerConnection?.connectionState === \"failed\") {\n              callbacks?.onError?.(new Error(\"Failed to connect to peer.\"));\n            }\n\n            if (\n              peerConnection?.connectionState === \"connected\" &&\n              !element.srcObject\n            ) {\n              element.srcObject = stream;\n              callbacks?.onConnected?.();\n            }\n          } catch (e) {\n            errorComposed(e as Error);\n          }\n        });\n\n        peerConnection.addEventListener(\"negotiationneeded\", async (_ev) => {\n          if (destroyed) {\n            return;\n          }\n\n          try {\n            const ofr = await constructClientOffer(\n              peerConnection,\n              redirectUrlString,\n            );\n\n            if (destroyed) {\n              return;\n            }\n\n            const response = await negotiateConnectionWithClientOffer(\n              peerConnection,\n              source,\n              ofr,\n              abortController,\n              accessControl,\n              sdpTimeout,\n            );\n\n            if (destroyed) {\n              return;\n            }\n\n            const currentDate = Date.now();\n\n            if (response && currentDate) {\n              callbacks?.onPlaybackOffsetUpdated?.(\n                currentDate - response.getTime(),\n              );\n            }\n          } catch (e) {\n            errorComposed(e as Error);\n          }\n        });\n      }\n    })\n    .catch((e) => errorComposed(e as Error));\n\n  return {\n    destroy: () => {\n      destroyed = true;\n      abortController?.abort?.();\n\n      peerConnection?.close?.();\n\n      // Remove the WebRTC source\n      if (element) {\n        element.srcObject = null;\n      }\n\n      element?.removeAttribute?.(VIDEO_WEBRTC_INITIALIZED_ATTRIBUTE);\n    },\n  };\n};\n","import { isClient } from \"../utils\";\n\nconst methodsList = [\n  // modern browsers\n  {\n    requestFullscreen: \"requestFullscreen\",\n    exitFullscreen: \"exitFullscreen\",\n    fullscreenElement: \"fullscreenElement\",\n    fullscreenEnabled: \"fullscreenEnabled\",\n    fullscreenchange: \"fullscreenchange\",\n    fullscreenerror: \"fullscreenerror\",\n  },\n  // new WebKit\n  {\n    requestFullscreen: \"webkitRequestFullscreen\",\n    exitFullscreen: \"webkitExitFullscreen\",\n    fullscreenElement: \"webkitFullscreenElement\",\n    fullscreenEnabled: \"webkitFullscreenEnabled\",\n    fullscreenchange: \"webkitfullscreenchange\",\n    fullscreenerror: \"webkitfullscreenerror\",\n  },\n  // old WebKit\n  {\n    requestFullscreen: \"webkitRequestFullScreen\",\n    exitFullscreen: \"webkitCancelFullScreen\",\n    fullscreenElement: \"webkitCurrentFullScreenElement\",\n    fullscreenEnabled: \"webkitCancelFullScreen\",\n    fullscreenchange: \"webkitfullscreenchange\",\n    fullscreenerror: \"webkitfullscreenerror\",\n  },\n  // old firefox\n  {\n    requestFullscreen: \"mozRequestFullScreen\",\n    exitFullscreen: \"mozCancelFullScreen\",\n    fullscreenElement: \"mozFullScreenElement\",\n    fullscreenEnabled: \"mozFullScreenEnabled\",\n    fullscreenchange: \"mozfullscreenchange\",\n    fullscreenerror: \"mozfullscreenerror\",\n  },\n  // old IE\n  {\n    requestFullscreen: \"msRequestFullscreen\",\n    exitFullscreen: \"msExitFullscreen\",\n    fullscreenElement: \"msFullscreenElement\",\n    fullscreenEnabled: \"msFullscreenEnabled\",\n    fullscreenchange: \"MSFullscreenChange\",\n    fullscreenerror: \"MSFullscreenError\",\n  },\n] as const;\n\n// iOS API (on the video element itself!)\nconst iosMethods = {\n  requestFullscreen: \"webkitEnterFullscreen\",\n  exitFullscreen: \"webkitExitFullscreen\",\n  fullscreenElement: null,\n  fullscreenEnabled: \"webkitDisplayingFullscreen\",\n  fullscreenchange: \"fullscreenchange\",\n  fullscreenerror: \"fullscreenerror\",\n} as const;\n\nexport const isFullscreenSupported = () => {\n  if (typeof document === \"undefined\") {\n    return true;\n  }\n\n  const videoElement = document.createElement(\"video\");\n\n  const result = Boolean(getFullscreenMethods(videoElement));\n\n  videoElement.remove();\n\n  return result;\n};\n\nexport const isCurrentlyFullscreen = (\n  inputElement: HTMLMediaElement | null,\n) => {\n  const { methods, element } = getFullscreenMethods(inputElement);\n\n  if (methods?.fullscreenElement) {\n    return Boolean(document[methods.fullscreenElement]);\n  }\n  // handle iOS API\n  return Boolean(element?.webkitPresentationMode === \"fullscreen\");\n};\n\nexport const enterFullscreen = (inputElement: HTMLMediaElement | null) => {\n  const { methods, element } = getFullscreenMethods(inputElement);\n\n  if (methods) {\n    return new Promise<void>((resolve, reject) => {\n      const fullscreenMethod = methods.requestFullscreen;\n\n      const onFullScreen = () => {\n        removeFullscreenEventListener(inputElement, onFullScreen);\n        resolve();\n      };\n\n      addFullscreenEventListener(inputElement, onFullScreen);\n\n      const returnPromise: Promise<void> | void | null =\n        methods.fullscreenElement\n          ? element?.parentElement?.[\n              fullscreenMethod as \"requestFullscreen\"\n            ]?.()\n          : (element?.[fullscreenMethod]?.() ?? null);\n\n      if (returnPromise === null) {\n        return resolve();\n      }\n\n      if (returnPromise instanceof Promise) {\n        returnPromise.then(onFullScreen).catch(reject);\n      }\n    });\n  }\n\n  return false;\n};\n\nexport const exitFullscreen = (inputElement: HTMLMediaElement | null) => {\n  const { methods, element } = getFullscreenMethods(inputElement);\n\n  if (methods) {\n    return new Promise<void>((resolve, reject) => {\n      if (!isCurrentlyFullscreen(inputElement)) {\n        resolve();\n        return;\n      }\n\n      const onFullScreenExit = () => {\n        removeFullscreenEventListener(inputElement, onFullScreenExit);\n        resolve();\n      };\n\n      addFullscreenEventListener(inputElement, onFullScreenExit);\n\n      const returnPromise: Promise<void> | void | null =\n        methods.fullscreenElement\n          ? document?.[methods.exitFullscreen]?.()\n          : (element?.[methods.exitFullscreen]?.() ?? null);\n\n      if (returnPromise instanceof Promise) {\n        returnPromise.then(onFullScreenExit).catch(reject);\n      }\n    });\n  }\n\n  return false;\n};\n\nexport const addFullscreenEventListener = (\n  inputElement: HTMLMediaElement | null,\n  callback: EventListener,\n) => {\n  const { methods, element } = getFullscreenMethods(inputElement);\n\n  if (methods && element) {\n    const parentElementOrElement = element?.parentElement ?? element;\n\n    parentElementOrElement?.addEventListener(\n      methods.fullscreenchange,\n      callback,\n      false,\n    );\n\n    return () => {\n      removeFullscreenEventListener(inputElement, callback);\n    };\n  }\n\n  return null;\n};\n\nconst removeFullscreenEventListener = (\n  inputElement: HTMLMediaElement | null,\n  callback: EventListenerOrEventListenerObject,\n) => {\n  const { methods, element } = getFullscreenMethods(inputElement);\n\n  if (methods && element) {\n    const parentElementOrElement = element?.parentElement ?? element;\n\n    parentElementOrElement?.removeEventListener(\n      methods.fullscreenchange,\n      callback,\n      false,\n    );\n\n    return true;\n  }\n\n  return false;\n};\n\nconst getFullscreenMethods = (element: HTMLMediaElement | null) => {\n  if (isClient()) {\n    for (const methods of methodsList) {\n      const exitFullscreenMethod = methods.exitFullscreen;\n\n      if (exitFullscreenMethod in document) {\n        return { methods, element: element as HTMLVideoElement };\n      }\n    }\n\n    if (element && iosMethods.requestFullscreen in element) {\n      return { methods: iosMethods, element: element as HTMLVideoElement };\n    }\n  }\n\n  return { methods: null };\n};\n","import { isClient } from \"../utils\";\n\nexport const isPictureInPictureSupported = (\n  element?: HTMLMediaElement | null,\n) => {\n  if (typeof document === \"undefined\") {\n    return true;\n  }\n\n  const videoElement = element ?? document.createElement(\"video\");\n\n  const isPiPDisabled = Boolean(\n    (videoElement as HTMLVideoElement).disablePictureInPicture,\n  );\n\n  const { apiType } = getPictureInPictureMode(videoElement);\n\n  return Boolean(apiType) && !isPiPDisabled;\n};\n\nexport const isCurrentlyPictureInPicture = (\n  inputElement?: HTMLMediaElement | null,\n) => {\n  const { apiType, element } = getPictureInPictureMode(inputElement);\n\n  if (apiType === \"w3c\") {\n    return Boolean(document?.pictureInPictureElement);\n  }\n  if (apiType === \"webkit\") {\n    return element?.webkitPresentationMode === \"picture-in-picture\";\n  }\n\n  return false;\n};\n\nexport const enterPictureInPicture = async (\n  inputElement?: HTMLMediaElement | null,\n) => {\n  const { apiType, element } = getPictureInPictureMode(inputElement);\n\n  if (apiType === \"w3c\") {\n    await element?.requestPictureInPicture?.();\n  } else if (apiType === \"webkit\") {\n    await element?.webkitSetPresentationMode?.(\"picture-in-picture\");\n  }\n\n  return null;\n};\n\nexport const exitPictureInPicture = (\n  inputElement?: HTMLMediaElement | null,\n) => {\n  const { apiType, element } = getPictureInPictureMode(inputElement);\n\n  if (apiType === \"w3c\") {\n    return document?.exitPictureInPicture?.() ?? null;\n  }\n  if (apiType === \"webkit\") {\n    return element?.webkitSetPresentationMode?.(\"inline\") ?? null;\n  }\n\n  return null;\n};\n\nexport const addEnterPictureInPictureEventListener = (\n  inputElement: HTMLMediaElement | null,\n  callback: EventListener,\n) => {\n  const { apiType, element } = getPictureInPictureMode(inputElement);\n\n  if (apiType === \"w3c\" && element) {\n    element.addEventListener(\"enterpictureinpicture\", callback, false);\n\n    return () => {\n      element.removeEventListener(\"enterpictureinpicture\", callback, false);\n    };\n  }\n\n  if (apiType === \"webkit\" && element) {\n    const callbackComposed = (e: Event) => {\n      if (element?.webkitPresentationMode === \"picture-in-picture\") {\n        callback?.(e);\n      }\n    };\n\n    document.addEventListener(\n      \"webkitpresentationmodechanged\",\n      callbackComposed,\n      false,\n    );\n\n    return () => {\n      document.removeEventListener(\n        \"webkitpresentationmodechanged\",\n        callbackComposed,\n        false,\n      );\n    };\n  }\n\n  return null;\n};\n\nexport const addExitPictureInPictureEventListener = (\n  inputElement: HTMLMediaElement | null,\n  callback: EventListener,\n) => {\n  const { apiType, element } = getPictureInPictureMode(inputElement);\n\n  if (apiType === \"w3c\" && element) {\n    element.addEventListener(\"leavepictureinpicture\", callback, false);\n\n    return () => {\n      element.removeEventListener(\"leavepictureinpicture\", callback, false);\n    };\n  }\n\n  if (apiType === \"webkit\" && element) {\n    const callbackComposed = (e: Event) => {\n      if (element?.webkitPresentationMode === \"inline\") {\n        callback?.(e);\n      }\n    };\n\n    document.addEventListener(\n      \"webkitpresentationmodechanged\",\n      callbackComposed,\n      false,\n    );\n\n    return () => {\n      document.removeEventListener(\n        \"webkitpresentationmodechanged\",\n        callbackComposed,\n        false,\n      );\n    };\n  }\n\n  return null;\n};\n\nconst getPictureInPictureMode = (element?: HTMLMediaElement | null) => {\n  if (isClient() && element instanceof HTMLVideoElement) {\n    // we disable the next line since we handle missing Safari versions in the next statement\n    if (document?.pictureInPictureEnabled) {\n      return { apiType: \"w3c\", element } as const;\n    }\n\n    // fallback to trying webkit\n    if (element?.webkitSupportsPresentationMode?.(\"picture-in-picture\")) {\n      return { apiType: \"webkit\", element } as const;\n    }\n  }\n\n  return { apiType: null };\n};\n","// if volume change is unsupported, the element will always return 1\n// similar to https://github.com/videojs/video.js/pull/7514/files\nexport const isVolumeChangeSupported = (type: \"audio\" | \"video\") => {\n  return new Promise<boolean>((resolve) => {\n    if (typeof window === \"undefined\") {\n      return false;\n    }\n\n    const testElement = document.createElement(type);\n    const newVolume = 0.342;\n\n    testElement.volume = newVolume;\n\n    setTimeout(() => {\n      const isSupported = testElement.volume !== 1;\n\n      testElement.remove();\n\n      resolve(isSupported);\n    });\n  });\n};\n","import type { DeviceInformation } from \"@livepeer/core/media\";\n\nimport { isHlsSupported } from \"../../hls/hls\";\nimport { getRTCPeerConnectionConstructor } from \"../../webrtc/shared\";\nimport { isAndroid, isIos, isMobile } from \"../utils\";\nimport { isFullscreenSupported } from \"./fullscreen\";\nimport { isPictureInPictureSupported } from \"./pictureInPicture\";\n\nexport const getDeviceInfo = (version: string): DeviceInformation => ({\n  version,\n  isAndroid: isAndroid(),\n  isIos: isIos(),\n  isMobile: isMobile(),\n  userAgent:\n    typeof navigator !== \"undefined\"\n      ? navigator.userAgent\n      : \"Node.js or unknown\",\n  screenWidth:\n    typeof window !== \"undefined\" && window?.screen\n      ? (window?.screen?.width ?? null)\n      : null,\n\n  isFullscreenSupported: isFullscreenSupported(),\n  isWebRTCSupported: Boolean(getRTCPeerConnectionConstructor()),\n  isPictureInPictureSupported: isPictureInPictureSupported(),\n  isHlsSupported: isHlsSupported(),\n  isVolumeChangeSupported: true,\n});\n","import {\n  addLegacyMediaMetricsToStore,\n  addMetricsToStore,\n  createControllerStore,\n  type InitialProps,\n  type PlaybackError,\n  type PlaybackEvent,\n} from \"@livepeer/core/media\";\nimport { createStorage, noopStorage } from \"@livepeer/core/storage\";\nimport { version } from \"@livepeer/core/version\";\nimport { addEventListeners, getDeviceInfo } from \"./controls\";\n\nexport type MediaMetricsOptions = Pick<InitialProps, \"viewerId\"> & {\n  /**\n   * Sets a custom source URL for playback, such as `https://livepeercdn.studio/hls/{playbackId}/index.m3u8`.\n   * If not specified, the function defaults to using the `src` attribute of the HTMLMediaElement.\n   * Note: For custom players that do not set the `src` attribute of the `video` element, opting instead for formats like `blob:<src>` or omitting `src` altogether, metrics collection may not function correctly.\n   */\n  src?: string;\n\n  /**\n   * Sets a custom playback ID for playback.\n   * If not specified, the function defaults to parsing the `src` attribute of the HTMLMediaElement to get the playback ID.\n   */\n  playbackId?: string;\n\n  /**\n   * Disables the `progress` event listener, which is used to monitor when media is in a \"playing\" state.\n   */\n  disableProgressListener?: boolean;\n\n  /**\n   * The interval at which metrics are sent via HTTP, in ms. Default 5000.\n   */\n  interval?: number;\n\n  /**\n   * Callback called when there is an error.\n   */\n  // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n  onError?: ((error: PlaybackError) => any) | null | undefined;\n\n  /**\n   * A callback that is called when the player's metrics events are emitted.\n   * This can be used to integrate with other analytics providers.\n   */\n  // biome-ignore lint/suspicious/noExplicitAny: allow any for incoming callback\n  onPlaybackEvents?: (events: PlaybackEvent[]) => Promise<any> | any;\n};\n\n/**\n * Initializes media playback metrics collection for a video or audio element.\n * This adds event listeners to the media element with a store that updates on events and send them to a websocket.\n * Returns a `destroy` function which must be called when the video element is removed from the DOM.\n *\n * @param {HTMLMediaElement | undefined | null} element The media element from which to capture playback metrics.\n * @param {Partial<MediaMetricsOptions>} opts Optional configuration options including:\n *   - `src`: Overrides the `src` URL for playback - defaults to the `src` attribute of the HTMLMediaElement. Use this with custom players that do not set the `src` attribute of the `video` element.\n *   - `playbackId`: Overrides the `playbackId` - defaults to parsing from the `src` attribute of the HTMLMediaElement. Use this with custom players that do not have a valid src URL which contains a playback ID.\n *   - `onError`: A callback function that is called when an error occurs in the metrics collection process.\n *   - `viewerId`: An identifier for the viewer to associate metrics with a specific user or session.\n *\n * @returns An object containing a `destroy` function to clean up resources.\n * The `destroy` function must be used to remove event listeners and perform other cleanup actions on unmount.\n */\nexport function addMediaMetrics(\n  element: HTMLMediaElement | undefined | null,\n  opts: Partial<MediaMetricsOptions> = {},\n) {\n  if (element) {\n    const source = opts?.src ?? element?.src ?? null;\n    const { store, destroy } = createControllerStore({\n      src: source,\n      playbackId: opts?.playbackId,\n      device: getDeviceInfo(version.core),\n      storage: createStorage({ storage: noopStorage }),\n      initialProps: {\n        autoPlay: Boolean(element?.autoplay),\n        volume: element?.muted ? 0 : element?.volume,\n        preload: element?.preload === \"\" ? \"auto\" : element?.preload,\n        playbackRate: element?.playbackRate,\n        hotkeys: false,\n        posterLiveUpdate: 0,\n        ...opts,\n        onError(error) {\n          if (error) {\n            opts?.onError?.(error);\n          }\n        },\n      },\n    });\n\n    const { destroy: destroyListeners } = addEventListeners(element, store);\n\n    const { destroy: destroyMetrics } = addMetricsToStore(store, {\n      disableProgressListener: opts.disableProgressListener,\n      interval: opts.interval,\n      onPlaybackEvents: opts.onPlaybackEvents,\n    });\n    const { destroy: destroyLegacyMetrics, metrics: legacyMetrics } =\n      addLegacyMediaMetricsToStore(store, {\n        disableProgressListener: opts.disableProgressListener,\n      });\n\n    store\n      .getState()\n      .__controlsFunctions.onFinalUrl(\n        source ?? \"https://vod-cdn.lp-playback.studio\",\n      );\n\n    return {\n      /** @deprecated */\n      legacyMetrics,\n      destroy: () => {\n        destroy?.();\n        destroyListeners?.();\n        destroyMetrics?.();\n        destroyLegacyMetrics?.();\n      },\n    };\n  }\n\n  return {\n    destroy: () => {},\n  };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,iBAIO;AAEP,IAAAC,gBAAqB;;;ACNrB,mBAGO;AACP,iBAAoD;;;ACHpD,mBAAqB;AAEd,IAAM,WAAW,MAAM,OAAO,WAAW;AACzC,IAAM,KAAK,MAChB,SAAS,IAAI,QAAQ,WAAW,WAAW,YAAY,IAAI;AACtD,IAAM,QAAQ,MAAM,mCAAmC,KAAK,GAAG,CAAC;AAChE,IAAM,YAAY,MAAM,UAAU,KAAK,GAAG,CAAC;AAC3C,IAAM,WAAW,MAAM,SAAS,MAAM,MAAM,KAAK,UAAU;AAwD3D,IAAM,uBAAuB,CAAC,QAAsB;AACzD,MAAI,SAAS,KAAK,KAAK,MAAM;AAC3B,QAAI,KAAK,MAAM,SAAS,OAAO,GAAG;AAChC,YAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,aAAO,MAAM,YAAY,IAAI,IAAI,EAAE,SAAS;AAAA,IAC9C;AAEA,UAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,WAAO,MAAM,YAAY,IAAI,IAAI,EAAE,SAAS;AAAA,EAC9C;AAEA,SAAO;AACT;;;ADrEO,IAAM,kCACX;AAYK,IAAM,iBAAiB,MAAO,SAAS,IAAI,WAAAC,QAAI,YAAY,IAAI;AAK/D,IAAM,eAAe,CAAoC;AAAA,EAC9D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAiBK;AAEH,MAAI,QAAQ,aAAa,+BAA+B,MAAM,QAAQ;AACpE,WAAO;AAAA,MACL,YAAY,MAAM;AAAA,MAElB;AAAA,MACA,SAAS,MAAM;AAAA,MAEf;AAAA,IACF;AAAA,EACF;AAEA,UAAQ,aAAa,iCAAiC,MAAM;AAE5D,QAAM,MAAM,IAAI,WAAAA,QAAI;AAAA,IAClB,kBAAkB,KAAK;AAAA,IACvB,yBAAyB;AAAA,IACzB,qBAAqB;AAAA,IACrB,sBAAsB;AAAA,IACtB,qBAAqB;AAAA,IACrB,GAAG;AAAA,IACH,GAAI,QAAQ,wBACR;AAAA,MACE,uBAAuB,OAAO;AAAA,IAChC,IACA;AAAA,MACE,6BAA6B;AAAA,MAC7B,uBAAuB;AAAA,IACzB;AAAA,EACN,CAAC;AAED,QAAM,YAAY,MAAM;AACtB,SAAK,UAAU;AACf,aAAS,kBAAkB,+BAA+B;AAAA,EAC5D;AAEA,MAAI,SAAS;AACX,QAAI,YAAY,OAAO;AAAA,EACzB;AAEA,MAAI,aAAa;AAEjB,MAAI,GAAG,WAAAA,QAAI,OAAO,cAAc,OAAO,IAAI,SAAS;AAClD,UAAM,EAAE,MAAM,eAAe,UAAU,IAAI,IAAI,KAAK;AAEpD,QAAI,CAAC,YAAY;AACf,iBAAW,aAAa,OAAO,IAAI;AACnC,mBAAa;AAAA,IACf;AAEA,eAAW,SAAS,QAAQ,IAAI,CAAC;AACjC,eAAW,aAAa,YAAY,CAAC;AAAA,EACvC,CAAC;AAED,MAAI,GAAG,WAAAA,QAAI,OAAO,gBAAgB,YAAY;AAC5C,QAAI,WAAW,MAAM;AAErB,QAAI,GAAG,WAAAA,QAAI,OAAO,iBAAiB,CAAC,QAAQ,UAAU;AACpD,iBAAW;AAAA,QACT,KAAK,OAAO;AAAA,QACZ,SAAS;AAAA,QACT;AAAA,MACF,CAAC;AAED,iBAAW,YAAY;AACvB,UAAI,OAAO,SAAU,UAAS,OAAO;AAAA,IACvC,CAAC;AAAA,EACH,CAAC;AAED,MAAI,GAAG,WAAAA,QAAI,OAAO,OAAO,OAAO,QAAQ,SAAS;AAC/C,UAAM,EAAE,SAAS,MAAM,IAAI;AAE3B,UAAM,yBAAyB,YAAY;AAE3C,QAAI,CAAC,SAAS,CAAC,uBAAwB;AACvC,eAAW,UAAU,IAAI;AAEzB,QAAI,OAAO;AACT,cAAQ,MAAM,iBAAiB,KAAK,OAAO,EAAE;AAC7C,cAAQ,KAAK,MAAM;AAAA,QACjB,KAAK,WAAAA,QAAI,WAAW;AAClB,cAAI,kBAAkB;AACtB;AAAA,QACF,KAAK,WAAAA,QAAI,WAAW;AAClB,kBAAQ,MAAM,6BAA6B,KAAK,OAAO,EAAE;AACzD;AAAA,QACF;AACE,kBAAQ,MAAM,oCAAoC,KAAK,OAAO,EAAE;AAChE,cAAI,QAAQ;AACZ;AAAA,MACJ;AAAA,IACF;AAAA,EACF,CAAC;AAED,WAAS,eAAe;AACtB,UAAM,cAAc,KAAK,IAAI;AAC7B,UAAM,UAAU,IAAI;AAEpB,QAAI,WAAW,aAAa;AAC1B,iBAAW,0BAA0B,cAAc,QAAQ,QAAQ,CAAC;AAAA,IACtE;AAAA,EACF;AAEA,QAAM,uBAAuB,YAAY,cAAc,GAAI;AAE3D,SAAO;AAAA,IACL,SAAS,MAAM;AACb,kBAAY;AACZ,sBAAgB,oBAAoB;AACpC,eAAS,kBAAkB,+BAA+B;AAAA,IAC5D;AAAA,IACA,YAAY,CAAC,iBAAiB;AAC5B,iBAAW;AAAA,QACT,KAAK,OAAO;AAAA,QACZ,SAAS;AAAA,QACT;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,IAAM,aAAa,CAAC;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AACF,MAIM;AACJ,MAAI,KAAK;AACP,UAAM,EAAE,MAAM,QAAI,8CAAgC,SAAS,WAAW;AAEtE,QAAI,CAAC,SAAS,YAAY,QAAQ;AAChC,UAAI,eAAe;AACnB;AAAA,IACF;AAEA,QAAI,IAAI,UAAU,IAAI,OAAO,SAAS,GAAG;AAEvC,YAAM,eAAe,IAAI,OACtB,IAAI,CAAC,OAAO,WAAW,EAAE,GAAG,OAAO,MAAM,EAAE,EAC3C;AAAA,QACC,CAAC,GAAG,MACF,KAAK,KAAK,SAAS,KAAK,EAAE,KAAK,IAAI,KAAK,KAAK,SAAS,KAAK,EAAE,KAAK;AAAA,MACtE;AAGF,YAAM,iBAAiB,eAAe,CAAC;AAEvC,WAAK,gBAAgB,SAAS,OAAO,GAAG;AACtC,YAAI,eAAe,eAAe;AAAA,MACpC,OAAO;AACL,YAAI,eAAe;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AACF;;;AE/MA,oBAA6C;AAOtC,IAAM,kCAAkC,MAAM;AAEnD,MAAI,CAAC,SAAS,GAAG;AACf,WAAO;AAAA,EACT;AAGA,SACE,OAAO,qBACP,OAAO,2BACP,OAAO,wBACP;AAEJ;AAKO,SAAS,qBACd,MACA,YAC0B;AAC1B,QAAM,+BAA+B,gCAAgC;AAErE,MAAI,CAAC,8BAA8B;AACjC,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AAGA,QAAM,aAAa,MAAM,MAAM,GAAG,EAAE,CAAC;AACrC,QAAM,oBAAoB,OACtB;AAAA,IACE;AAAA,MACE,MAAM,QAAQ,UAAU;AAAA,IAC1B;AAAA,IACA;AAAA,MACE,MAAM,QAAQ,UAAU;AAAA,MACxB,UAAU;AAAA,MACV,YAAY;AAAA,IACd;AAAA,EACF,IACA,CAAC;AAEL,SAAO,IAAI,6BAA6B;AAAA,IACtC,YAAY,aACR,MAAM,QAAQ,UAAU,IACtB,aACA,CAAC,UAAU,IACb;AAAA,EACN,CAAC;AACH;AAEA,IAAM,kBAAkB;AAaxB,eAAsB,mCACpB,gBACA,UACA,KACA,YACA,eACA,YACe;AACf,MAAI,kBAAkB,YAAY,KAAK;AAMrC,UAAM,WAAW,MAAM;AAAA,MACrB;AAAA,MACA,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,QAAI,SAAS,IAAI;AACf,YAAM,YAAY,MAAM,SAAS,KAAK;AACtC,YAAM,eAAe;AAAA,QACnB,IAAI,sBAAsB,EAAE,MAAM,UAAU,KAAK,UAAU,CAAC;AAAA,MAC9D;AAEA,YAAM,cAAc,SAAS,QAAQ,IAAI,cAAc;AAEvD,aAAO,IAAI,KAAK,eAAe,oBAAI,KAAK,CAAC;AAAA,IAC3C;AACA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,MAAM,0CAA4B;AAAA,IAC9C;AAEA,UAAM,eAAe,MAAM,SAAS,KAAK;AACzC,UAAM,IAAI,MAAM,YAAY;AAAA,EAC9B;AAEA,QAAM,IAAI,MAAM,8BAA8B;AAChD;AAKA,SAAS,YAAY,KAAa,OAAuB;AACvD,QAAM,QAAQ,IAAI,MAAM,MAAM;AAC9B,QAAM,aAAa,MAAM,UAAU,CAAC,SAAS,KAAK,WAAW,SAAS,CAAC;AAEvE,MAAI,eAAe,GAAI,QAAO;AAE9B,QAAM,aAAa,IAAI,OAAO,mBAAmB,KAAK,UAAU;AAChE,QAAM,YAAY,MAAM,KAAK,CAAC,SAAS,WAAW,KAAK,IAAI,CAAC;AAE5D,MAAI,CAAC,UAAW,QAAO;AAGvB,QAAM,eAAe,WAAW,KAAK,SAAS,EAAG,CAAC;AAClD,QAAM,gBAAgB,MAAM,UAAU,EAAE,MAAM,GAAG;AAEjD,QAAM,iBAAiB;AAAA,IACrB,GAAG,cAAc,MAAM,GAAG,CAAC;AAAA,IAC3B;AAAA,IACA,GAAG,cAAc,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,YAAY,YAAY;AAAA,EACxE;AAEA,QAAM,UAAU,IAAI,eAAe,KAAK,GAAG;AAC3C,SAAO,MAAM,KAAK,MAAM;AAC1B;AAUA,eAAsB,qBACpB,gBACA,UACA,gBACA;AACA,MAAI,kBAAkB,UAAU;AAE9B,UAAM,sBAAsB,eAAe,YAAY,KAAK,cAAc;AAE1E,mBAAe,cAAc,kBAAmB,MAAM;AAEpD,YAAM,gBAAgB,MAAM,oBAAoB,MAAM,MAAM,IAAI;AAChE,aAAO,IAAI,sBAAsB;AAAA;AAAA,QAE/B,MAAM,cAAc;AAAA;AAAA,QAEpB,KAAK,YAAY,cAAc,KAAK,MAAM;AAAA,MAC5C,CAAC;AAAA,IACH;AAGA,UAAM,QAAQ,MAAM,eAAe,YAAY;AAG/C,UAAM,eAAe,oBAAoB,KAAK;AAG9C,QAAI,gBAAgB;AAClB,aAAO,eAAe;AAAA,IACxB;AACA,UAAM,MAAM,MAAM,2BAA2B,cAAc;AAC3D,QAAI,CAAC,KAAK;AACR,YAAM,MAAM,2CAA2C;AAAA,IACzD;AAEA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAIA,IAAM,oBAAoB;AAC1B,IAAM,sBAAsB;AAE5B,IAAM,0BAA0B;AAChC,IAAM,mBAAmB,oBAAI,IAAiB;AAE9C,SAAS,kBAAkB,KAA8B;AACvD,QAAM,aAAa,iBAAiB,IAAI,GAAG;AAE3C,MAAI,YAAY;AACd,qBAAiB,OAAO,GAAG;AAC3B,qBAAiB,IAAI,KAAK,UAAU;AAAA,EACtC;AAEA,SAAO;AACT;AAEA,SAAS,kBAAkB,KAAa,OAAkB;AACxD,MAAI,iBAAiB,IAAI,GAAG,GAAG;AAC7B,qBAAiB,OAAO,GAAG;AAAA,EAC7B,WAAW,iBAAiB,QAAQ,yBAAyB;AAC3D,UAAM,YAAY,iBAAiB,KAAK,EAAE,KAAK,EAAE;AACjD,QAAI,WAAW;AACb,uBAAiB,OAAO,SAAS;AAAA,IACnC;AAAA,EACF;AAEA,mBAAiB,IAAI,KAAK,KAAK;AACjC;AAEA,eAAe,aACb,UACA,MACA,YACA,eACA,YACA;AACA,QAAM,KAAK;AAAA,IACT,MAAM,WAAW,MAAM;AAAA,IACvB,cAAc;AAAA,EAChB;AAEA,QAAM,aAAa,IAAI,IAAI,QAAQ;AACnC,QAAM,gBAAgB,WAAW,SAAS,MAAM,iBAAiB;AACjE,QAAM,oBAAoB,gBAAgB,CAAC;AAE3C,QAAM,oBAAoB,kBAAkB,QAAQ;AAIpD,MAAI,qBAAqB,mBAAmB;AAC1C,eAAW,OAAO,kBAAkB;AACpC,eAAW,WAAW,kBAAkB,SAAS;AAAA,MAC/C;AAAA,MACA;AAAA,IACF;AACA,eAAW,SAAS,kBAAkB;AAAA,EACxC;AAEA,QAAM,WAAW,MAAM,MAAM,WAAW,SAAS,GAAG;AAAA,IAClD,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,SAAS;AAAA,MACP,gBAAgB;AAAA,MAChB,GAAI,eAAe,YACf;AAAA,QACE,uBAAuB,cAAc;AAAA,MACvC,IACA,CAAC;AAAA,MACL,GAAI,eAAe,MACf;AAAA,QACE,gBAAgB,cAAc;AAAA,MAChC,IACA,CAAC;AAAA,IACP;AAAA,IACA,MAAM;AAAA,IACN,QAAQ,WAAW;AAAA,EACrB,CAAC;AAED,eAAa,EAAE;AAEf,SAAO;AACT;AAEA,eAAsB,eACpB,UACA,iBACA,SACA;AACA,MAAI;AACF,UAAM,oBAAoB,kBAAkB,QAAQ;AAEpD,QAAI,mBAAmB;AACrB,YAAM,mBAAmB,IAAI,IAAI,QAAQ;AACzC,YAAM,UAAU,iBAAiB,SAAS,MAAM,iBAAiB;AACjE,YAAM,oBAAoB,UAAU,CAAC;AAErC,UAAI,mBAAmB;AACrB,cAAM,mBAAmB,IAAI,IAAI,iBAAiB;AAClD,yBAAiB,WAAW,kBAAkB,SAAS;AAAA,UACrD;AAAA,UACA;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAEA,UAAM,KAAK;AAAA,MACT,MAAM,gBAAgB,MAAM;AAAA,MAC5B,WAAW;AAAA,IACb;AAEA,UAAM,WAAW,MAAM,MAAM,UAAU;AAAA,MACrC,QAAQ;AAAA,MACR,QAAQ,gBAAgB;AAAA,IAC1B,CAAC;AAGD,UAAM,SAAS,KAAK;AAEpB,iBAAa,EAAE;AAEf,UAAM,sBAAsB,IAAI,IAAI,SAAS,GAAG;AAEhD,QAAI,qBAAqB;AACvB,YAAM,mBAAmB,IAAI,IAAI,mBAAmB;AACpD,uBAAiB,WAAW,iBAAiB,SAAS;AAAA,QACpD;AAAA,QACA,KAAK,mBAAmB;AAAA,MAC1B;AAEA,UACE,CAAC,iBAAiB,aAAa,IAAI,UAAU,KAC7C,iBAAiB,aAAa,IAAI,UAAU,MAAM,QAClD;AACA,0BAAkB,UAAU,gBAAgB;AAAA,MAC9C;AAAA,IACF;AACA,WAAO;AAAA,EAET,SAAS,GAAG;AACV,WAAO;AAAA,EACT;AACF;AAUA,eAAe,2BAA2B,gBAAmC;AAC3E,SAAO,IAAI,QAAsC,CAAC,YAAY;AAE5D,eAAW,MAAM;AACf,cAAQ,eAAe,gBAAgB;AAAA,IACzC,GAAG,GAAI;AACP,mBAAe,4BAA4B,CAAC,QAAQ;AAClD,UAAI,eAAe,sBAAsB,YAAY;AACnD,gBAAQ,eAAe,gBAAgB;AAAA,MACzC;AAAA,IACF;AAAA,EACF,CAAC;AACH;;;AC7VO,IAAM,qCACX;AAOK,IAAM,gBAAgB,CAAoC;AAAA,EAC/D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAcK;AAEH,MAAI,QAAQ,aAAa,kCAAkC,MAAM,QAAQ;AACvE,WAAO;AAAA,MACL,SAAS,MAAM;AAAA,MAEf;AAAA,IACF;AAAA,EACF;AAEA,UAAQ,aAAa,oCAAoC,MAAM;AAE/D,MAAI,YAAY;AAEhB,QAAM,kBAAkB,IAAI,gBAAgB;AAE5C,MAAI,iBAA2C;AAC/C,QAAM,SAAS,IAAI,YAAY;AAE/B,QAAM,gBAAgB,CAAC,MAAa;AAClC,eAAW,UAAU,CAAU;AAE/B,QAAI,SAAS;AACX,cAAQ,YAAY;AAAA,IACtB;AAAA,EACF;AAEA,iBAAe,QAAQ,iBAAiB,UAAU,EAC/C,KAAK,CAAC,gBAAgB;AACrB,QAAI,aAAa,CAAC,aAAa;AAC7B;AAAA,IACF;AAEA,UAAM,oBAAoB,YAAY,SAAS;AAE/C,eAAW,aAAa,qBAAqB,IAAI;AAOjD,qBAAiB,qBAAqB,YAAY,MAAM,UAAU;AAElE,QAAI,gBAAgB;AAElB,qBAAe,eAAe,SAAS;AAAA,QACrC,WAAW;AAAA,MACb,CAAC;AACD,qBAAe,eAAe,SAAS;AAAA,QACrC,WAAW;AAAA,MACb,CAAC;AAQD,qBAAe,UAAU,CAAC,UAAU;AAClC,YAAI,WAAW;AACb;AAAA,QACF;AAEA,YAAI;AACF,cAAI,QAAQ;AACV,kBAAM,QAAQ,MAAM;AACpB,kBAAM,gBAAgB,OAAO,UAAU;AACvC,kBAAM,6BAA6B,cAAc;AAAA,cAC/C,CAACC,WAAUA,OAAM,SAAS;AAAA,YAC5B;AACA,kBAAM,6BAA6B,cAAc;AAAA,cAC/C,CAACA,WAAUA,OAAM,SAAS;AAAA,YAC5B;AACA,oBAAQ,MAAM,MAAM;AAAA,cAClB,KAAK;AACH,oBAAI,4BAA4B;AAC9B;AAAA,gBACF;AACA,uBAAO,SAAS,KAAK;AACrB;AAAA,cACF,KAAK;AACH,oBAAI,4BAA4B;AAC9B;AAAA,gBACF;AACA,uBAAO,SAAS,KAAK;AACrB;AAAA,cACF;AACE,wBAAQ,IAAI,0BAA0B,KAAK,EAAE;AAAA,YACjD;AAAA,UACF;AAAA,QACF,SAAS,GAAG;AACV,wBAAc,CAAU;AAAA,QAC1B;AAAA,MACF;AAEA,qBAAe,iBAAiB,yBAAyB,CAAC,QAAQ;AAChE,YAAI,WAAW;AACb;AAAA,QACF;AAEA,YAAI;AACF,cAAI,gBAAgB,oBAAoB,UAAU;AAChD,uBAAW,UAAU,IAAI,MAAM,4BAA4B,CAAC;AAAA,UAC9D;AAEA,cACE,gBAAgB,oBAAoB,eACpC,CAAC,QAAQ,WACT;AACA,oBAAQ,YAAY;AACpB,uBAAW,cAAc;AAAA,UAC3B;AAAA,QACF,SAAS,GAAG;AACV,wBAAc,CAAU;AAAA,QAC1B;AAAA,MACF,CAAC;AAED,qBAAe,iBAAiB,qBAAqB,OAAO,QAAQ;AAClE,YAAI,WAAW;AACb;AAAA,QACF;AAEA,YAAI;AACF,gBAAM,MAAM,MAAM;AAAA,YAChB;AAAA,YACA;AAAA,UACF;AAEA,cAAI,WAAW;AACb;AAAA,UACF;AAEA,gBAAM,WAAW,MAAM;AAAA,YACrB;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAEA,cAAI,WAAW;AACb;AAAA,UACF;AAEA,gBAAM,cAAc,KAAK,IAAI;AAE7B,cAAI,YAAY,aAAa;AAC3B,uBAAW;AAAA,cACT,cAAc,SAAS,QAAQ;AAAA,YACjC;AAAA,UACF;AAAA,QACF,SAAS,GAAG;AACV,wBAAc,CAAU;AAAA,QAC1B;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,CAAC,EACA,MAAM,CAAC,MAAM,cAAc,CAAU,CAAC;AAEzC,SAAO;AAAA,IACL,SAAS,MAAM;AACb,kBAAY;AACZ,uBAAiB,QAAQ;AAEzB,sBAAgB,QAAQ;AAGxB,UAAI,SAAS;AACX,gBAAQ,YAAY;AAAA,MACtB;AAEA,eAAS,kBAAkB,kCAAkC;AAAA,IAC/D;AAAA,EACF;AACF;;;ACpNA,IAAM,cAAc;AAAA;AAAA,EAElB;AAAA,IACE,mBAAmB;AAAA,IACnB,gBAAgB;AAAA,IAChB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,EACnB;AAAA;AAAA,EAEA;AAAA,IACE,mBAAmB;AAAA,IACnB,gBAAgB;AAAA,IAChB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,EACnB;AAAA;AAAA,EAEA;AAAA,IACE,mBAAmB;AAAA,IACnB,gBAAgB;AAAA,IAChB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,EACnB;AAAA;AAAA,EAEA;AAAA,IACE,mBAAmB;AAAA,IACnB,gBAAgB;AAAA,IAChB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,EACnB;AAAA;AAAA,EAEA;AAAA,IACE,mBAAmB;AAAA,IACnB,gBAAgB;AAAA,IAChB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,EACnB;AACF;AAGA,IAAM,aAAa;AAAA,EACjB,mBAAmB;AAAA,EACnB,gBAAgB;AAAA,EAChB,mBAAmB;AAAA,EACnB,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB,iBAAiB;AACnB;AAEO,IAAM,wBAAwB,MAAM;AACzC,MAAI,OAAO,aAAa,aAAa;AACnC,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,SAAS,cAAc,OAAO;AAEnD,QAAM,SAAS,QAAQ,qBAAqB,YAAY,CAAC;AAEzD,eAAa,OAAO;AAEpB,SAAO;AACT;AAEO,IAAM,wBAAwB,CACnC,iBACG;AACH,QAAM,EAAE,SAAS,QAAQ,IAAI,qBAAqB,YAAY;AAE9D,MAAI,SAAS,mBAAmB;AAC9B,WAAO,QAAQ,SAAS,QAAQ,iBAAiB,CAAC;AAAA,EACpD;AAEA,SAAO,QAAQ,SAAS,2BAA2B,YAAY;AACjE;AAEO,IAAM,kBAAkB,CAAC,iBAA0C;AACxE,QAAM,EAAE,SAAS,QAAQ,IAAI,qBAAqB,YAAY;AAE9D,MAAI,SAAS;AACX,WAAO,IAAI,QAAc,CAAC,SAAS,WAAW;AAC5C,YAAM,mBAAmB,QAAQ;AAEjC,YAAM,eAAe,MAAM;AACzB,sCAA8B,cAAc,YAAY;AACxD,gBAAQ;AAAA,MACV;AAEA,iCAA2B,cAAc,YAAY;AAErD,YAAM,gBACJ,QAAQ,oBACJ,SAAS,gBACP,gBACF,IAAI,IACH,UAAU,gBAAgB,IAAI,KAAK;AAE1C,UAAI,kBAAkB,MAAM;AAC1B,eAAO,QAAQ;AAAA,MACjB;AAEA,UAAI,yBAAyB,SAAS;AACpC,sBAAc,KAAK,YAAY,EAAE,MAAM,MAAM;AAAA,MAC/C;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAEO,IAAM,iBAAiB,CAAC,iBAA0C;AACvE,QAAM,EAAE,SAAS,QAAQ,IAAI,qBAAqB,YAAY;AAE9D,MAAI,SAAS;AACX,WAAO,IAAI,QAAc,CAAC,SAAS,WAAW;AAC5C,UAAI,CAAC,sBAAsB,YAAY,GAAG;AACxC,gBAAQ;AACR;AAAA,MACF;AAEA,YAAM,mBAAmB,MAAM;AAC7B,sCAA8B,cAAc,gBAAgB;AAC5D,gBAAQ;AAAA,MACV;AAEA,iCAA2B,cAAc,gBAAgB;AAEzD,YAAM,gBACJ,QAAQ,oBACJ,WAAW,QAAQ,cAAc,IAAI,IACpC,UAAU,QAAQ,cAAc,IAAI,KAAK;AAEhD,UAAI,yBAAyB,SAAS;AACpC,sBAAc,KAAK,gBAAgB,EAAE,MAAM,MAAM;AAAA,MACnD;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAEO,IAAM,6BAA6B,CACxC,cACA,aACG;AACH,QAAM,EAAE,SAAS,QAAQ,IAAI,qBAAqB,YAAY;AAE9D,MAAI,WAAW,SAAS;AACtB,UAAM,yBAAyB,SAAS,iBAAiB;AAEzD,4BAAwB;AAAA,MACtB,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAEA,WAAO,MAAM;AACX,oCAA8B,cAAc,QAAQ;AAAA,IACtD;AAAA,EACF;AAEA,SAAO;AACT;AAEA,IAAM,gCAAgC,CACpC,cACA,aACG;AACH,QAAM,EAAE,SAAS,QAAQ,IAAI,qBAAqB,YAAY;AAE9D,MAAI,WAAW,SAAS;AACtB,UAAM,yBAAyB,SAAS,iBAAiB;AAEzD,4BAAwB;AAAA,MACtB,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,IAAM,uBAAuB,CAAC,YAAqC;AACjE,MAAI,SAAS,GAAG;AACd,eAAW,WAAW,aAAa;AACjC,YAAM,uBAAuB,QAAQ;AAErC,UAAI,wBAAwB,UAAU;AACpC,eAAO,EAAE,SAAS,QAAqC;AAAA,MACzD;AAAA,IACF;AAEA,QAAI,WAAW,WAAW,qBAAqB,SAAS;AACtD,aAAO,EAAE,SAAS,YAAY,QAAqC;AAAA,IACrE;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,KAAK;AACzB;;;ACjNO,IAAM,8BAA8B,CACzC,YACG;AACH,MAAI,OAAO,aAAa,aAAa;AACnC,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,WAAW,SAAS,cAAc,OAAO;AAE9D,QAAM,gBAAgB;AAAA,IACnB,aAAkC;AAAA,EACrC;AAEA,QAAM,EAAE,QAAQ,IAAI,wBAAwB,YAAY;AAExD,SAAO,QAAQ,OAAO,KAAK,CAAC;AAC9B;AAEO,IAAM,8BAA8B,CACzC,iBACG;AACH,QAAM,EAAE,SAAS,QAAQ,IAAI,wBAAwB,YAAY;AAEjE,MAAI,YAAY,OAAO;AACrB,WAAO,QAAQ,UAAU,uBAAuB;AAAA,EAClD;AACA,MAAI,YAAY,UAAU;AACxB,WAAO,SAAS,2BAA2B;AAAA,EAC7C;AAEA,SAAO;AACT;AAEO,IAAM,wBAAwB,OACnC,iBACG;AACH,QAAM,EAAE,SAAS,QAAQ,IAAI,wBAAwB,YAAY;AAEjE,MAAI,YAAY,OAAO;AACrB,UAAM,SAAS,0BAA0B;AAAA,EAC3C,WAAW,YAAY,UAAU;AAC/B,UAAM,SAAS,4BAA4B,oBAAoB;AAAA,EACjE;AAEA,SAAO;AACT;AAEO,IAAM,uBAAuB,CAClC,iBACG;AACH,QAAM,EAAE,SAAS,QAAQ,IAAI,wBAAwB,YAAY;AAEjE,MAAI,YAAY,OAAO;AACrB,WAAO,UAAU,uBAAuB,KAAK;AAAA,EAC/C;AACA,MAAI,YAAY,UAAU;AACxB,WAAO,SAAS,4BAA4B,QAAQ,KAAK;AAAA,EAC3D;AAEA,SAAO;AACT;AAEO,IAAM,wCAAwC,CACnD,cACA,aACG;AACH,QAAM,EAAE,SAAS,QAAQ,IAAI,wBAAwB,YAAY;AAEjE,MAAI,YAAY,SAAS,SAAS;AAChC,YAAQ,iBAAiB,yBAAyB,UAAU,KAAK;AAEjE,WAAO,MAAM;AACX,cAAQ,oBAAoB,yBAAyB,UAAU,KAAK;AAAA,IACtE;AAAA,EACF;AAEA,MAAI,YAAY,YAAY,SAAS;AACnC,UAAM,mBAAmB,CAAC,MAAa;AACrC,UAAI,SAAS,2BAA2B,sBAAsB;AAC5D,mBAAW,CAAC;AAAA,MACd;AAAA,IACF;AAEA,aAAS;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,WAAO,MAAM;AACX,eAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEO,IAAM,uCAAuC,CAClD,cACA,aACG;AACH,QAAM,EAAE,SAAS,QAAQ,IAAI,wBAAwB,YAAY;AAEjE,MAAI,YAAY,SAAS,SAAS;AAChC,YAAQ,iBAAiB,yBAAyB,UAAU,KAAK;AAEjE,WAAO,MAAM;AACX,cAAQ,oBAAoB,yBAAyB,UAAU,KAAK;AAAA,IACtE;AAAA,EACF;AAEA,MAAI,YAAY,YAAY,SAAS;AACnC,UAAM,mBAAmB,CAAC,MAAa;AACrC,UAAI,SAAS,2BAA2B,UAAU;AAChD,mBAAW,CAAC;AAAA,MACd;AAAA,IACF;AAEA,aAAS;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,WAAO,MAAM;AACX,eAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,IAAM,0BAA0B,CAAC,YAAsC;AACrE,MAAI,SAAS,KAAK,mBAAmB,kBAAkB;AAErD,QAAI,UAAU,yBAAyB;AACrC,aAAO,EAAE,SAAS,OAAO,QAAQ;AAAA,IACnC;AAGA,QAAI,SAAS,iCAAiC,oBAAoB,GAAG;AACnE,aAAO,EAAE,SAAS,UAAU,QAAQ;AAAA,IACtC;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,KAAK;AACzB;;;AC1JO,IAAM,0BAA0B,CAAC,SAA4B;AAClE,SAAO,IAAI,QAAiB,CAAC,YAAY;AACvC,QAAI,OAAO,WAAW,aAAa;AACjC,aAAO;AAAA,IACT;AAEA,UAAM,cAAc,SAAS,cAAc,IAAI;AAC/C,UAAM,YAAY;AAElB,gBAAY,SAAS;AAErB,eAAW,MAAM;AACf,YAAM,cAAc,YAAY,WAAW;AAE3C,kBAAY,OAAO;AAEnB,cAAQ,WAAW;AAAA,IACrB,CAAC;AAAA,EACH,CAAC;AACH;;;APMA,IAAM,yCACJ;AAEF,IAAM,iBAAiB;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,IAAM,QAAQ,CAAC,OAAe;AAC5B,SAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AACzD;AAEO,IAAM,oBAAoB,CAC/B,SACA,UACG;AACH,QAAM,mBAAmB,MAAM,SAAS;AAExC,MAAI;AACF;AAAA,MACE,iBAAiB,eAAe,SAAS,UAAU,UAAU;AAAA,IAC/D,EAAE,KAAK,CAAC,WAAW;AACjB,YAAM,SAAS,CAAC,EAAE,SAAS,OAAO;AAAA,QAChC,UAAU;AAAA,UACR,GAAG;AAAA,UACH,yBAAyB;AAAA,QAC3B;AAAA,MACF,EAAE;AAAA,IACJ,CAAC;AAAA,EACH,SAAS,GAAG;AACV,YAAQ,MAAM,CAAC;AAAA,EACjB;AAEA,QAAM,mBAAmB,MAAM;AAC7B,UAAM,SAAS,EAAE,oBAAoB,UAAU;AAC/C,UAAM,SAAS,EAAE,oBAAoB,eAAe;AAAA,EACtD;AAEA,QAAM,eAAe,MAAM;AACzB,UAAM,SAAS,EAAE,oBAAoB,eAAe;AAAA,EACtD;AAEA,QAAM,SAAS,MAAM;AACnB,UAAM,SAAS,EAAE,oBAAoB,OAAO;AAAA,EAC9C;AACA,QAAM,UAAU,MAAM;AACpB,UAAM,SAAS,EAAE,oBAAoB,QAAQ;AAAA,EAC/C;AAEA,QAAM,mBAAmB,MACvB,MACG,SAAS,EACT,oBAAoB,iBAAiB,SAAS,YAAY,CAAC;AAEhE,QAAM,UAAU,CAAC,MAAqB;AACpC,MAAE,eAAe;AACjB,MAAE,gBAAgB;AAElB,UAAM,OAAO,EAAE;AAEf,UAAM,SAAS,EAAE,oBAAoB,sBAAsB;AAE3D,UAAM,iBACJ,MAAM,SAAS,EAAE,eAAe,YAAY;AAE9C,QAAI,eAAe,SAAS,IAAI,GAAG;AACjC,WAAK,SAAS,WAAW,SAAS,WAAW,gBAAgB;AAC3D,cAAM,SAAS,EAAE,oBAAoB,WAAW;AAAA,MAClD,WAAW,SAAS,gBAAgB,gBAAgB;AAClD,cAAM,SAAS,EAAE,oBAAoB,mBAAmB;AAAA,MAC1D,WAAW,SAAS,eAAe,gBAAgB;AACjD,cAAM,SAAS,EAAE,oBAAoB,gBAAgB;AAAA,MACvD,WAAW,SAAS,UAAU,gBAAgB;AAC5C,cAAM,SAAS,EAAE,oBAAoB,kBAAkB;AAAA,MACzD,WAAW,SAAS,UAAU,gBAAgB;AAC5C,cAAM,SAAS,EAAE,oBAAoB,YAAY;AAAA,MACnD,WAAW,SAAS,QAAQ;AAC1B,cAAM,SAAS,EAAE,oBAAoB,wBAAwB;AAAA,MAC/D,WAAW,SAAS,QAAQ;AAC1B,cAAM,SAAS,EAAE,oBAAoB,8BAA8B;AAAA,MACrE;AAAA,IACF;AAAA,EACF;AAEA,QAAM,gBAAgB,MAAM;AAC1B,UAAM,SAAS,EAAE,oBAAoB,sBAAsB;AAAA,EAC7D;AACA,QAAM,gBAAgB,YAAY;AAChC,UAAM,SAAS,EAAE,oBAAoB,sBAAsB;AAAA,EAC7D;AAEA,QAAM,iBAAiB,MAAM;AAC3B,UACG,SAAS,EACT,oBAAoB,UAAU,QAAQ,QAAQ,IAAK,QAAQ,UAAU,CAAE;AAAA,EAC5E;AAEA,QAAM,eAAe,MAAM;AACzB,UAAM,SAAS,EAAE,oBAAoB,gBAAgB,QAAQ,YAAY;AAAA,EAC3E;AAEA,QAAM,eAAe,MAAM;AACzB,UAAM,SAAS,EAAE,oBAAoB,WAAW,SAAS,eAAe,CAAC;AAEzE,QAAI,YAAY,SAAS,YAAY,KAAK,GAAG;AAC3C,YAAM,cAAc,QAAQ;AAE5B,YAAM,WAAW,CAAC,GAAG,MAAM,QAAQ,SAAS,MAAM,CAAC,EAAE;AAAA,QACnD,CAAC,MAAM,OAAO,MAAM;AAClB,gBAAM,QAAQ,QAAQ,SAAS,MAAM,QAAQ,SAAS,SAAS,IAAI,CAAC;AACpE,gBAAM,MAAM,QAAQ,SAAS,IAAI,QAAQ,SAAS,SAAS,IAAI,CAAC;AAGhE,cAAI,SAAS,eAAe,OAAO,aAAa;AAC9C,mBAAO;AAAA,UACT;AAEA,iBAAO;AAAA,QACT;AAAA;AAAA,QAEA;AAAA,MACF;AAEA,YAAM,SAAS,EAAE,oBAAoB,eAAe,QAAQ;AAAA,IAC9D;AAAA,EACF;AAEA,QAAM,UAAU,OAAO,MAAkB;AACvC,UAAM,SAAS,MAAM,SAAS,EAAE;AAEhC,QAAI,QAAQ,SAAS,SAAS;AAC5B,YAAM,gBAAgB,EAAE;AACxB,YAAM,gBAAiB,eAAqC;AAC5D,YAAM,WACH,eAAoC,cACpC,eAAoC;AAEvC,UAAI,UAAU;AACZ,YAAI;AACF,gBAAM,WAAW,MAAM,MAAM,QAAQ;AACrC,cAAI,SAAS,WAAW,KAAK;AAC3B,oBAAQ,KAAK,iBAAiB;AAC9B,mBAAO,MACJ,SAAS,EACT,qBAAqB;AAAA,cACpB,IAAI,MAAM,2CAA4B;AAAA,YACxC;AAAA,UACJ;AACA,cAAI,SAAS,WAAW,KAAK;AAC3B,oBAAQ,KAAK,4BAA4B;AACzC,mBAAO,MACJ,SAAS,EACT,qBAAqB;AAAA,cACpB,IAAI,MAAM,2CAA4B;AAAA,YACxC;AAAA,UACJ;AAAA,QACF,SAAS,KAAK;AACZ,kBAAQ,KAAK,GAAG;AAChB,iBAAO,MACJ,SAAS,EACT,qBAAqB;AAAA,YACpB,IAAI,MAAM,0BAA0B;AAAA,UACtC;AAAA,QACJ;AAAA,MACF;AAEA,cAAQ,KAAK,6BAA6B;AAC1C,aAAO,MACJ,SAAS,EACT,qBAAqB;AAAA,QACpB,IAAI,MAAM,6BAA6B;AAAA,MACzC;AAAA,IACJ;AAEA,UAAM,SAAS,EAAE,oBAAoB,QAAQ,IAAI,MAAM,GAAG,OAAO,CAAC;AAAA,EACpE;AAEA,QAAM,YAAY,YAAY;AAC5B,UAAM,SAAS,EAAE,oBAAoB,UAAU;AAAA,EACjD;AAEA,QAAM,YAAY,YAAY;AAC5B,UAAM,SAAS,EAAE,oBAAoB,UAAU;AAAA,EACjD;AAEA,QAAM,cAAc,YAAY;AAC9B,UAAM,SAAS,EAAE,oBAAoB,UAAU;AAAA,EACjD;AAEA,QAAM,UAAU,YAAY;AAC1B,UAAM,SAAS,EAAE,oBAAoB,QAAQ;AAAA,EAC/C;AAEA,QAAM,WAAW,YAAY;AAC3B,UAAM,SAAS,EAAE,oBAAoB,eAAe;AAAA,EACtD;AAEA,QAAM,yBAAyB,SAAS,iBAAiB;AAEzD,MAAI,SAAS;AACX,YAAQ,iBAAiB,gBAAgB,cAAc;AACvD,YAAQ,iBAAiB,cAAc,YAAY;AAEnD,YAAQ,iBAAiB,kBAAkB,gBAAgB;AAC3D,YAAQ,iBAAiB,cAAc,YAAY;AACnD,YAAQ,iBAAiB,QAAQ,MAAM;AACvC,YAAQ,iBAAiB,WAAW,MAAM;AAC1C,YAAQ,iBAAiB,SAAS,OAAO;AACzC,YAAQ,iBAAiB,kBAAkB,gBAAgB;AAC3D,YAAQ,iBAAiB,cAAc,YAAY;AACnD,YAAQ,iBAAiB,SAAS,OAAO;AACzC,YAAQ,iBAAiB,WAAW,SAAS;AAC7C,YAAQ,iBAAiB,WAAW,SAAS;AAC7C,YAAQ,iBAAiB,aAAa,WAAW;AACjD,YAAQ,iBAAiB,SAAS,OAAO;AAEzC,4BAAwB,iBAAiB,YAAY,aAAa;AAClE,4BAAwB,iBAAiB,aAAa,aAAa;AAEnE,4BAAwB,iBAAiB,cAAc,aAAa;AACpE,4BAAwB,iBAAiB,YAAY,aAAa;AAClE,4BAAwB,iBAAiB,aAAa,aAAa;AAEnE,QAAI,OAAO,WAAW,aAAa;AACjC,cAAQ,mBAAmB,UAAU,QAAQ;AAAA,IAC/C;AAEA,4BAAwB,iBAAiB,SAAS,OAAO;AACzD,4BAAwB,aAAa,YAAY,GAAG;AAEpD,YAAQ,aAAa,wCAAwC,MAAM;AAAA,EACrE;AAEA,QAAM,qBAAqB,MAAM;AAC/B,UACG,SAAS,EACT,oBAAoB,cAAc,sBAAsB,OAAO,CAAC;AAAA,EACrE;AAEA,QAAM,0BAA0B,MAAM;AACpC,UAAM,SAAS,EAAE,oBAAoB,oBAAoB,IAAI;AAAA,EAC/D;AACA,QAAM,yBAAyB,MAAM;AACnC,UAAM,SAAS,EAAE,oBAAoB,oBAAoB,KAAK;AAAA,EAChE;AAGA,QAAM,yBAAyB,kBAAkB,SAAS,KAAK;AAG/D,QAAM,2BAA2B;AAAA,IAC/B;AAAA,IACA;AAAA,EACF;AAGA,QAAM,sCACJ,sCAAsC,SAAS,uBAAuB;AACxE,QAAM,qCACJ,qCAAqC,SAAS,sBAAsB;AAEtE,SAAO;AAAA,IACL,SAAS,MAAM;AACb,iCAA2B;AAE3B,4CAAsC;AACtC,2CAAqC;AAErC,eAAS,sBAAsB,cAAc,YAAY;AACzD,eAAS,sBAAsB,gBAAgB,cAAc;AAC7D,eAAS,sBAAsB,kBAAkB,gBAAgB;AACjE,eAAS,sBAAsB,cAAc,YAAY;AACzD,eAAS,sBAAsB,QAAQ,MAAM;AAC7C,eAAS,sBAAsB,WAAW,MAAM;AAChD,eAAS,sBAAsB,SAAS,OAAO;AAC/C,eAAS,sBAAsB,kBAAkB,gBAAgB;AACjE,eAAS,sBAAsB,cAAc,YAAY;AACzD,eAAS,sBAAsB,SAAS,OAAO;AAC/C,eAAS,sBAAsB,WAAW,SAAS;AACnD,eAAS,sBAAsB,WAAW,SAAS;AACnD,eAAS,sBAAsB,aAAa,WAAW;AACvD,eAAS,sBAAsB,SAAS,OAAO;AAE/C,UAAI,OAAO,WAAW,aAAa;AACjC,gBAAQ,sBAAsB,UAAU,QAAQ;AAAA,MAClD;AAEA,8BAAwB,sBAAsB,YAAY,aAAa;AACvE,8BAAwB,sBAAsB,aAAa,aAAa;AAExE,8BAAwB;AAAA,QACtB;AAAA,QACA;AAAA,MACF;AACA,8BAAwB,sBAAsB,YAAY,aAAa;AACvE,8BAAwB,sBAAsB,aAAa,aAAa;AAExE,8BAAwB,sBAAsB,SAAS,OAAO;AAE9D,+BAAyB;AAEzB,eAAS,kBAAkB,sCAAsC;AAAA,IACnE;AAAA,EACF;AACF;AAKA,IAAI,gBAAyB,MAAM;AAAC;AAEpC,IAAI,qBAA8B,MAAM;AAAC;AAEzC,IAAM,oBAAoB,CACxB,SACA,UACG;AAEH,QAAM,gBAAgB,MAAM;AAAA,IAC1B,CAAC;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,OAAO;AAAA,MACL,aAAa,eAAe;AAAA,MAC5B,UAAU,eAAe;AAAA,MACzB,SAAS,eAAe;AAAA,MACxB,YAAY,eAAe;AAAA,MAC3B,gBAAgB,eAAe;AAAA,MAC/B;AAAA,MACA,WAAW,WAAW;AAAA,MACtB,WAAW,WAAW;AAAA,MACtB;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR,SAAS,eAAe;AAAA,MACxB;AAAA,IACF;AAAA,IACA,OAAO;AAAA,MACL;AAAA,MACA;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,MAAM;AACJ,UAAI,CAAC,SAAS;AACZ;AAAA,MACF;AAEA,YAAM,gBAAgB;AAEtB,YAAM;AAAA,QACJ,KAAK,IAAI,eAAe,UAAU,GAAG,eAAe,IAAI,IAAI,GAAG;AAAA,MACjE;AAEA,UAAI,YAAY;AAEhB,UAAI,CAAC,QAAQ;AACX;AAAA,MACF;AAEA,UAAI,SAAS;AAEb,YAAM,yBAAyB,MAAM;AACnC,cAAM,OAAO,MAAM,SAAS,EAAE;AAE9B,YAAI,CAAC,QAAQ,YAAY,CAAC,QAAQ;AAChC,kBAAQ,cAAc;AAEtB,mBAAS;AAAA,QACX;AAAA,MACF;AAEA,YAAM,kBAAkB,CAAC,QAAe;AACtC,YAAI,CAAC,WAAW;AACd,0BAAgB;AAEhB,gBAAM,SAAS,EAAE,qBAAqB,UAAU,GAAG;AAAA,QACrD;AAAA,MACF;AAEA,UAAI,OAAO,SAAS,UAAU;AAC5B,cAAM,qBAAqB,MAAM;AAAA,UAC/B,CAAC,UAAU,OAAO;AAAA,UAClB,CAAC,aAAa;AACZ,gBAAI,8BAA8B;AAGlC,gBAAI,UAAU,MAAM,QAAQ;AAE1B,yBAAW,WAAW,OAAO,KAAK,SAAS,KAAK,MAAM,GAAG;AAEvD,oBAAI,UAAU,MAAM,OAAO,OAAO,GAAG,YAAY,GAAG;AAClD,gDAA8B;AAAA,gBAChC;AAAA,cACF;AAAA,YACF;AAGA,kBAAM,yBACJ,+BAA+B,UAAU,MAAM,YAAY;AAG7D,gBAAI,CAAC,0BAA0B,CAAC,WAAW;AACzC,8BAAgB,IAAI,MAAM,oCAAqB,CAAC;AAAA,YAClD;AAAA,UACF;AAAA,QACF;AAEA,cAAM,EAAE,QAAQ,IAAI,cAAc;AAAA,UAChC,QAAQ,OAAO;AAAA,UACf;AAAA,UACA,WAAW;AAAA,YACT,aAAa,MAAM;AACjB,oBAAM,SAAS,EAAE,oBAAoB,QAAQ,IAAI;AACjD,qCAAuB;AAAA,YACzB;AAAA,YACA,SAAS;AAAA,YACT,yBACE,MAAM,SAAS,EAAE,oBAAoB;AAAA,YACvC,YAAY,MAAM,SAAS,EAAE,oBAAoB;AAAA,UACnD;AAAA,UACA,eAAe;AAAA,YACb,KAAK,MAAM,SAAS,EAAE,eAAe;AAAA,YACrC,WAAW,MAAM,SAAS,EAAE,eAAe;AAAA,UAC7C;AAAA,UACA,YAAY;AAAA,UACZ,YAAY,MAAM,SAAS,EAAE,eAAe;AAAA,QAC9C,CAAC;AAED,cAAM,KAAK,WAAW,MAAM;AAC1B,cAAI,CAAC,MAAM,SAAS,EAAE,WAAW,CAAC,WAAW;AAC3C,kBAAM,SAAS,EAAE,oBAAoB,kBAAkB;AAEvD;AAAA,cACE,IAAI;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF,GAAG,OAAO;AAEV,wBAAgB,MAAM;AACpB,sBAAY;AAEZ,uBAAa,EAAE;AACf,oBAAU;AACV,+BAAqB;AAAA,QACvB;AAEA;AAAA,MACF;AAEA,UAAI,OAAO,SAAS,OAAO;AACzB,cAAM,WAAW;AAEjB,cAAM,iBAAiB,CAAC,UAAoB;AAC1C,gBAAM,aAAa,IAAI;AAAA,YACrB,OAAO,UAAU,MAAM,WAAW,MAC/B,OAAO,UAAU,SAAS,MACvB,8CACA;AAAA,UACR;AAEA,4BAAkB,UAAU;AAAA,QAC9B;AAEA,cAAM,oBAAoB;AAE1B,cAAM,EAAE,SAAS,YAAAC,YAAW,IAAI,aAAa;AAAA,UAC3C,QAAQ,QAAQ;AAAA,UAChB;AAAA,UACA,gBAAgB;AAAA,UAChB,aAAa,eAAe,KAAK;AAAA,UACjC,WAAW;AAAA,YACT,QAAQ,MAAM,SAAS,EAAE,oBAAoB;AAAA,YAC7C,YAAY,MAAM,SAAS,EAAE,oBAAoB;AAAA,YACjD,WAAW,MAAM;AACf,oBAAM,SAAS,EAAE,oBAAoB,UAAU;AAC/C,qCAAuB;AACvB,oBAAM,SAAS,EAAE,oBAAoB,QAAQ,IAAI;AAAA,YACnD;AAAA,YACA,SAAS;AAAA,YACT,yBACE,MAAM,SAAS,EAAE,oBAAoB;AAAA,YACvC,YAAY,MAAM,SAAS,EAAE,oBAAoB;AAAA,UACnD;AAAA,UACA,QAAQ;AAAA,YACN,GAAI,qBAAqB,CAAC;AAAA,YAC1B,MAAM,SAAS,KAAK,KAAK;AACvB,kBAAI,mBAAmB,UAAU;AAC/B,sBAAM,mBAAmB,WAAW,KAAK,GAAG;AAAA,cAC9C,OAAO;AACL,sBAAM,OAAO,MAAM,SAAS,EAAE;AAE9B,oBAAI,CAAC,QAAQ,IAAI,MAAM,QAAQ,GAAG;AAChC,wBAAM,MAAM,MAAM,SAAS,EAAE,eAAe;AAC5C,wBAAM,YAAY,MAAM,SAAS,EAAE,eAAe;AAElD,sBAAI;AACF,wBAAI,iBAAiB,uBAAuB,SAAS;AAAA,2BAC9C,IAAK,KAAI,iBAAiB,gBAAgB,GAAG;AAAA,gBACxD;AAAA,cACF;AAAA,YACF;AAAA,YACA;AAAA,UACF;AAAA,QACF,CAAC;AAED,cAAM,2BAA2B,MAAM;AAAA,UACrC,CAAC,UAAU,MAAM;AAAA,UACjB,CAAC,eAAe;AACd,YAAAA,YAAW,UAAU;AAAA,UACvB;AAAA,QACF;AAEA,wBAAgB,MAAM;AACpB,sBAAY;AACZ,oBAAU;AACV,qCAA2B;AAAA,QAC7B;AAEA;AAAA,MACF;AAEA,UAAI,QAAQ,SAAS,SAAS;AAC5B,cAAM,SAAS,EAAE,oBAAoB,WAAW,OAAO,GAAG;AAE1D,gBAAQ,iBAAiB,WAAW,sBAAsB;AAE1D,gBAAQ,MAAM,OAAO;AACrB,gBAAQ,KAAK;AAEb,wBAAgB,MAAM;AACpB,sBAAY;AAEZ,mBAAS,sBAAsB,WAAW,sBAAsB;AAAA,QAClE;AAEA;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,YAAY,CAAC,GAAG,MAAM;AACpB,cAAM,oBACJ,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe;AACpD,cAAM,mBAAmB,EAAE,cAAc,EAAE;AAE3C,cAAM,gBAAgB,EAAE,QAAQ,QAAQ,EAAE,QAAQ;AAClD,cAAM,iBAAiB,EAAE,YAAY,EAAE;AAEvC,cAAM,iBACJ,qBACA,oBACA,iBACA;AAEF,eAAO,CAAC;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAGA,QAAM,qBAAqB,MAAM;AAAA,IAC/B,CAAC,EAAE,YAAY,MAAM,qBAAqB,eAAe,OAAO;AAAA,MAC9D,WAAW,WAAW,WAAW;AAAA,MACjC;AAAA,MACA,WAAW,oBAAoB;AAAA,MAC/B,kBAAkB,eAAe;AAAA,IACnC;AAAA,IACA,OAAO,EAAE,WAAW,MAAM,WAAW,iBAAiB,MAAM;AAC1D,2BAAqB;AAErB,UAAI,aAAa,QAAQ,mBAAmB,GAAG;AAC7C,cAAM,WAAW,YAAY,MAAM;AACjC,gBAAM,eAAe,IAAI,IAAI,SAAS;AAEtC,uBAAa,aAAa,IAAI,KAAK,KAAK,IAAI,EAAE,QAAQ,CAAC,CAAC;AAExD,oBAAU,aAAa,SAAS,CAAC;AAAA,QACnC,GAAG,gBAAgB;AAEnB,6BAAqB,MAAM,cAAc,QAAQ;AAAA,MACnD;AAAA,IACF;AAAA,IACA;AAAA,MACE,YAAY,CAAC,GAAG,MAAM,EAAE,cAAc,EAAE,aAAa,EAAE,SAAS,EAAE;AAAA,IACpE;AAAA,EACF;AAGA,QAAM,mBAAmB,MAAM;AAAA,IAC7B,CAAC,UAAU,MAAM,WAAW;AAAA,IAC5B,YAAY;AACV,UAAI,QAAQ,QAAQ;AAClB,cAAM,QAAQ,KAAK;AAAA,MACrB,OAAO;AACL,cAAM,QAAQ,MAAM;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAGA,QAAM,sBAAsB,MAAM;AAAA,IAChC,CAAC,UAAU,MAAM;AAAA,IACjB,CAAC,YAAY;AACX,cAAQ,eAAe,YAAY,aAAa,IAAI;AAAA,IACtD;AAAA,EACF;AAGA,QAAM,gBAAgB,MAAM;AAAA,IAC1B,CAAC,WAAW;AAAA,MACV,SAAS,MAAM;AAAA,MACf,QAAQ,MAAM;AAAA,MACd,yBAAyB,MAAM,SAAS;AAAA,IAC1C;AAAA,IACA,CAAC,YAAY;AACX,UAAI,QAAQ,yBAAyB;AACnC,gBAAQ,SAAS,QAAQ;AAAA,MAC3B;AAAA,IACF;AAAA,IACA;AAAA,MACE,YAAY,CAAC,GAAG,MACd,EAAE,WAAW,EAAE,UACf,EAAE,YAAY,EAAE,WAChB,EAAE,4BAA4B,EAAE;AAAA,IACpC;AAAA,EACF;AAGA,QAAM,cAAc,MAAM;AAAA,IACxB,CAAC,UAAU,MAAM,WAAW;AAAA,IAC5B,CAAC,SAAS,SAAS;AACjB,UAAI,YAAY,MAAM;AACpB,gBAAQ,QAAQ;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AAGA,QAAM,iBAAiB,MAAM;AAAA,IAC3B,CAAC,UAAU,MAAM,WAAW;AAAA,IAC5B,CAAC,YAAY;AACX,UAAI,OAAO,QAAQ,eAAe,eAAe,QAAQ,aAAa,GAAG;AACvE,gBAAQ,cAAc;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AAGA,QAAM,oBAAoB,MAAM;AAAA,IAC9B,CAAC,UAAU,MAAM,WAAW;AAAA,IAC5B,YAAY;AACV,YAAM,eAAe,sBAAsB,OAAO;AAClD,UAAI,aAAc,gBAAe,OAAO;AAAA,UACnC,iBAAgB,OAAO;AAAA,IAC9B;AAAA,EACF;AAGA,QAAM,0BAA0B,MAAM;AAAA,IACpC,CAAC,UAAU,MAAM,WAAW;AAAA,IAC5B,YAAY;AACV,UAAI;AACF,cAAM,qBAAqB,MAAM,4BAA4B,OAAO;AACpE,YAAI,mBAAoB,OAAM,qBAAqB,OAAO;AAAA,YACrD,OAAM,sBAAsB,OAAO;AAAA,MAC1C,SAAS,GAAG;AACV,gCAAM,GAAa,WAAW,qCAAqC;AAEnE,cAAM,SAAS,CAAC,WAAW;AAAA,UACzB,UAAU;AAAA,YACR,GAAG,MAAM;AAAA,YACT,6BAA6B;AAAA,UAC/B;AAAA,QACF,EAAE;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AAGA,QAAM,kBAAkB,MAAM;AAAA,IAC5B,CAAC,WAAW;AAAA,MACV,iBAAiB,MAAM,WAAW;AAAA,MAClC,UAAU,MAAM,WAAW;AAAA,IAC7B;AAAA,IACA,OAAO,EAAE,iBAAiB,SAAS,MAAM;AACvC,UAAI,YAAY,iBAAiB;AAC/B,cAAM,SAAS,EAAE,oBAAoB,UAAU,KAAK;AAEpD,cAAM,MAAM,QAAQ;AAEpB,cAAM,yBAAyB,SAAS,iBAAiB;AAMzD,cAAM,cAAc,wBAAwB;AAAA,UAC1C;AAAA,QACF;AAEA,YACE,CAAC,eACD,CAAC,MAAM,SAAS,EAAE,UAClB,oBAAoB,MAAM,SAAS,EAAE,WAAW,iBAChD;AACA,gBAAM,SAAS,EAAE,oBAAoB,UAAU,IAAI;AAAA,QACrD;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,YAAY,CAAC,GAAG,MACd,GAAG,oBAAoB,GAAG,mBAC1B,GAAG,aAAa,GAAG;AAAA,IACvB;AAAA,EACF;AAGA,QAAM,uBAAuB,MAAM;AAAA,IACjC,CAAC,WAAW;AAAA,MACV,UAAU,MAAM,WAAW;AAAA,MAC3B,YAAY,MAAM;AAAA,IACpB;AAAA,IACA,YAAY;AACV,YAAM,SAAS,EAAE,oBAAoB,QAAQ;AAAA,QAC3C,GAAK,SAAyC,eAC7C,SAAyC,aACtC;AAAA,UACE,OAAO;AAAA,YACL,QAAS,QAAwC;AAAA,YACjD,OAAQ,QAAwC;AAAA,UAClD;AAAA,QACF,IACA,CAAC;AAAA,QACL,GAAI,SAAS,gBAAgB,SAAS,cAClC;AAAA,UACE,WAAW;AAAA,YACT,QAAQ,QAAQ;AAAA,YAChB,OAAO,QAAQ;AAAA,UACjB;AAAA,QACF,IACA,CAAC;AAAA,QACL,GAAI,OAAO,WAAW,eACtB,QAAQ,eACR,QAAQ,aACJ;AAAA,UACE,QAAQ;AAAA,YACN,QAAQ,OAAO;AAAA,YACf,OAAO,OAAO;AAAA,UAChB;AAAA,QACF,IACA,CAAC;AAAA,MACP,CAAC;AAAA,IACH;AAAA,IACA;AAAA,MACE,YAAY,CAAC,GAAG,MACd,GAAG,eAAe,GAAG,cAAc,GAAG,aAAa,GAAG;AAAA,IAC1D;AAAA,EACF;AAGA,QAAM,qBAAqB,MAAM;AAAA,IAC/B,CAAC,UAAU,MAAM,WAAW,MAAM;AAAA,IAClC,OAAO,UAAU;AACf,YAAM,yBAAyB,SAAS,iBAAiB;AAEzD,UAAI,wBAAwB;AAC1B,YAAI,OAAO,UAAU,OAAO,OAAO;AACjC,gBAAM,eAAe,uBAAuB;AAC5C,uBAAa;AAAA,YACX;AAAA,YACA,GAAG,MAAM,MAAM;AAAA,UACjB;AACA,uBAAa;AAAA,YACX;AAAA,YACA,GAAG,MAAM,KAAK;AAAA,UAChB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,YAAY,CAAC,GAAG,MAAM,GAAG,WAAW,GAAG,UAAU,GAAG,UAAU,GAAG;AAAA,IACnE;AAAA,EACF;AAGA,QAAM,yBAAyB,MAAM;AAAA,IACnC,CAAC,UAAU,MAAM,WAAW,MAAM;AAAA,IAClC,OAAO,cAAc;AACnB,YAAM,yBAAyB,SAAS,iBAAiB;AAEzD,UAAI,wBAAwB;AAC1B,YAAI,WAAW,UAAU,WAAW,OAAO;AACzC,gBAAM,eAAe,uBAAuB;AAC5C,uBAAa;AAAA,YACX;AAAA,YACA,GAAG,UAAU,MAAM;AAAA,UACrB;AACA,uBAAa;AAAA,YACX;AAAA,YACA,GAAG,UAAU,KAAK;AAAA,UACpB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,YAAY,CAAC,GAAG,MAAM,GAAG,WAAW,GAAG,UAAU,GAAG,UAAU,GAAG;AAAA,IACnE;AAAA,EACF;AAEA,SAAO,MAAM;AACX,sBAAkB;AAClB,6BAAyB;AACzB,wBAAoB;AACpB,yBAAqB;AACrB,kBAAc;AACd,8BAA0B;AAC1B,0BAAsB;AACtB,uBAAmB;AACnB,yBAAqB;AACrB,2BAAuB;AACvB,qBAAiB;AACjB,oBAAgB;AAChB,oBAAgB;AAEhB,yBAAqB;AACrB,oBAAgB;AAAA,EAClB;AACF;;;AQx2BO,IAAM,gBAAgB,CAACC,cAAwC;AAAA,EACpE,SAAAA;AAAA,EACA,WAAW,UAAU;AAAA,EACrB,OAAO,MAAM;AAAA,EACb,UAAU,SAAS;AAAA,EACnB,WACE,OAAO,cAAc,cACjB,UAAU,YACV;AAAA,EACN,aACE,OAAO,WAAW,eAAe,QAAQ,SACpC,QAAQ,QAAQ,SAAS,OAC1B;AAAA,EAEN,uBAAuB,sBAAsB;AAAA,EAC7C,mBAAmB,QAAQ,gCAAgC,CAAC;AAAA,EAC5D,6BAA6B,4BAA4B;AAAA,EACzD,gBAAgB,eAAe;AAAA,EAC/B,yBAAyB;AAC3B;;;AC3BA,IAAAC,gBAOO;AACP,qBAA2C;AAC3C,qBAAwB;AAwDjB,SAAS,gBACd,SACA,OAAqC,CAAC,GACtC;AACA,MAAI,SAAS;AACX,UAAM,SAAS,MAAM,OAAO,SAAS,OAAO;AAC5C,UAAM,EAAE,OAAO,QAAQ,QAAI,qCAAsB;AAAA,MAC/C,KAAK;AAAA,MACL,YAAY,MAAM;AAAA,MAClB,QAAQ,cAAc,uBAAQ,IAAI;AAAA,MAClC,aAAS,8BAAc,EAAE,SAAS,2BAAY,CAAC;AAAA,MAC/C,cAAc;AAAA,QACZ,UAAU,QAAQ,SAAS,QAAQ;AAAA,QACnC,QAAQ,SAAS,QAAQ,IAAI,SAAS;AAAA,QACtC,SAAS,SAAS,YAAY,KAAK,SAAS,SAAS;AAAA,QACrD,cAAc,SAAS;AAAA,QACvB,SAAS;AAAA,QACT,kBAAkB;AAAA,QAClB,GAAG;AAAA,QACH,QAAQ,OAAO;AACb,cAAI,OAAO;AACT,kBAAM,UAAU,KAAK;AAAA,UACvB;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAED,UAAM,EAAE,SAAS,iBAAiB,IAAI,kBAAkB,SAAS,KAAK;AAEtE,UAAM,EAAE,SAAS,eAAe,QAAI,iCAAkB,OAAO;AAAA,MAC3D,yBAAyB,KAAK;AAAA,MAC9B,UAAU,KAAK;AAAA,MACf,kBAAkB,KAAK;AAAA,IACzB,CAAC;AACD,UAAM,EAAE,SAAS,sBAAsB,SAAS,cAAc,QAC5D,4CAA6B,OAAO;AAAA,MAClC,yBAAyB,KAAK;AAAA,IAChC,CAAC;AAEH,UACG,SAAS,EACT,oBAAoB;AAAA,MACnB,UAAU;AAAA,IACZ;AAEF,WAAO;AAAA;AAAA,MAEL;AAAA,MACA,SAAS,MAAM;AACb,kBAAU;AACV,2BAAmB;AACnB,yBAAiB;AACjB,+BAAuB;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,SAAS,MAAM;AAAA,IAAC;AAAA,EAClB;AACF;","names":["import_errors","import_utils","Hls","track","setQuality","version","import_media"]}