markdown-flow-ui 0.2.26-dev.2 → 0.2.26-dev.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/markdown-flow-ui.css +1 -1
- package/dist/components/Slide/Player.cjs +1 -1
- package/dist/components/Slide/Player.cjs.map +1 -1
- package/dist/components/Slide/Player.d.ts +2 -1
- package/dist/components/Slide/Player.es.js +192 -195
- package/dist/components/Slide/Player.es.js.map +1 -1
- package/dist/components/Slide/Slide.cjs +1 -1
- package/dist/components/Slide/Slide.cjs.map +1 -1
- package/dist/components/Slide/Slide.d.ts +3 -1
- package/dist/components/Slide/Slide.es.js +685 -671
- package/dist/components/Slide/Slide.es.js.map +1 -1
- package/dist/markdown-flow-ui.css +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Player.cjs","sources":["../../../src/components/Slide/Player.tsx"],"sourcesContent":["import React, {\n memo,\n useCallback,\n useContext,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport {\n Captions,\n CaptionsOff,\n EllipsisVertical,\n FastForward,\n Maximize,\n Rewind,\n ScanLine,\n SkipBack,\n SkipForward,\n Volume2,\n} from \"lucide-react\";\n\nimport {\n getMarkdownFlowDirection,\n getMarkdownFlowLanguage,\n type MarkdownFlowLocale,\n} from \"../../lib/locale\";\nimport { useDetachedLanguage } from \"../../lib/useDetachedLanguage\";\nimport { useResolvedDirection } from \"../../lib/useResolvedDirection\";\nimport { cn } from \"../../lib/utils\";\nimport MobilePlayerSettingsSheet from \"./MobilePlayerSettingsSheet\";\nimport { getSlidePlayerTexts, type SlidePlayerLocaleTexts } from \"./slideI18n\";\nimport type { SlideAudioItem } from \"./useSlide\";\nimport type {\n ElementSubtitleCue,\n SlidePlayerCustomActionContext,\n SlidePlayerCustomActions,\n} from \"./types\";\nimport {\n DEFAULT_MOBILE_VIEW_MODE,\n type MobileViewMode,\n} from \"./utils/mobileScreenMode\";\nimport { hasReachedAudioEnd } from \"./utils/audioCompletion\";\nimport { PlayerKeyboardShortcutContext } from \"./utils/playerKeyboardShortcutContext\";\nimport {\n activatePlayerKeyboardShortcutOwner,\n getPlayerKeyboardShortcutAction,\n isActivePlayerKeyboardShortcutOwner,\n registerPlayerKeyboardShortcutOwner,\n shouldIgnorePlayerKeyboardShortcutEvent,\n type PlayerKeyboardShortcutAction,\n} from \"./utils/playerKeyboardShortcuts\";\nimport {\n resolveAudioPlaybackSourceType,\n type AudioPlaybackSourceType,\n} from \"./utils/playbackSource\";\nimport { shouldKeepPlayingAfterNavigation } from \"./utils/playbackPreference\";\nimport { toPlayerCustomActionList } from \"./utils/playerCustomActions\";\nimport { suppressPlayerControlsWakeAfterNavigation } from \"./utils/playerNavigationContext\";\nimport {\n isPlaybackTimeCoveredBySegments,\n resolveSegmentSeekTarget,\n} from \"./utils/segmentSeek\";\nimport { getSortedAudioSegments } from \"./utils/audioSegments\";\nimport {\n getSubtitleCueJumpTarget,\n shouldClearSubtitleCueJumpTarget,\n type SubtitleCueJumpDirection,\n type SubtitleCueJumpTarget,\n type SubtitleCueJumpTrack,\n} from \"./utils/subtitleCue\";\nimport \"./player.css\";\n\nconst audioPreloadElementCache = new Map<string, HTMLAudioElement>();\n\n/**\n * Labels and accessibility text used by the slide player controls.\n *\n * Missing fields fall back to the selected `locale`; pass a `texts` object when\n * a consumer needs custom control labels or tooltip text.\n *\n * @example\n * ```tsx\n * <Player locale=\"zh-CN\" texts={{ playLabel: \"播放\", nextLabel: \"下一页\" }} />\n * ```\n */\nexport type SlidePlayerTexts = Partial<SlidePlayerLocaleTexts>;\n\nexport type SlidePlayerLoadingReason = \"loadingAudio\" | \"waitingForMoreAudio\";\n\nexport interface SlidePlayerPlaybackRestoreRequest {\n id: number | string;\n timeMs: number;\n}\n\nexport interface SlidePlayerPlaybackCheckpoint {\n /** Identifies the logical audio item that produced this checkpoint. */\n audioKey: string;\n isComplete: boolean;\n timeMs: number;\n}\n\nexport interface SlidePlayerProgress {\n ariaLabel: string;\n currentIndex: number;\n totalSteps: number;\n}\n\nexport interface SlidePlayerNavigationContext {\n shouldContinuePlayback: boolean;\n /** Set false when navigation should not reveal hidden player controls. */\n shouldWakeControls?: boolean;\n}\n\nexport type SlidePlayerSubtitleJumpTarget = SubtitleCueJumpTarget;\n\nexport interface SlidePlayerSubtitleSeekRequest\n extends SlidePlayerSubtitleJumpTarget {\n id: number | string;\n}\n\nconst preloadAudioUrl = (url?: string) => {\n if (typeof window === \"undefined\" || !url) {\n return;\n }\n\n if (audioPreloadElementCache.has(url)) {\n return;\n }\n\n // Use a detached audio element so warm-up follows the same media loading\n // path as the visible player instead of relying on link preload hints.\n const audio = window.document.createElement(\"audio\");\n audio.preload = \"auto\";\n audio.setAttribute(\"playsinline\", \"true\");\n audio.src = url;\n audio.load();\n\n audioPreloadElementCache.set(url, audio);\n};\n\ntype SubtitleCueList = ElementSubtitleCue[] | undefined;\n\ninterface SubtitleCueTracksCache {\n audioList: SlideAudioItem[];\n subtitleCueLists: SubtitleCueList[];\n subtitleCueLengths: number[];\n tracks: SubtitleCueJumpTrack[];\n}\n\nconst hasCurrentSubtitleCueTracksCache = (\n audioList: SlideAudioItem[],\n cache: SubtitleCueTracksCache | null\n): cache is SubtitleCueTracksCache =>\n cache !== null &&\n cache.audioList === audioList &&\n cache.subtitleCueLists.length === audioList.length &&\n audioList.every((audioItem, index) => {\n const subtitleCues = audioItem.element?.subtitle_cues;\n\n return (\n cache.subtitleCueLists[index] === subtitleCues &&\n cache.subtitleCueLengths[index] === (subtitleCues?.length ?? 0)\n );\n });\n\nconst createSubtitleCueTracksCache = (\n audioList: SlideAudioItem[]\n): SubtitleCueTracksCache => {\n const subtitleCueLists = audioList.map(\n (audioItem) => audioItem.element?.subtitle_cues\n );\n\n return {\n audioList,\n subtitleCueLists,\n subtitleCueLengths: subtitleCueLists.map(\n (subtitleCues) => subtitleCues?.length ?? 0\n ),\n tracks: subtitleCueLists.map((subtitleCues) => ({\n subtitleCues: subtitleCues ?? [],\n })),\n };\n};\n\nexport type PlayerProps = Omit<React.ComponentProps<\"div\">, \"onEnded\"> & {\n audioList?: SlideAudioItem[];\n currentAudioIndex?: number;\n defaultPlaying?: boolean;\n isPlaybackPaused?: boolean;\n isAutoAdvanceEnabled?: boolean;\n useAutoAdvanceToggle?: boolean;\n onLoadingChange?: (state: {\n loading: boolean;\n reason: SlidePlayerLoadingReason | null;\n }) => void;\n onPlaybackPreferenceChange?: (playing: boolean) => void;\n onPlaybackStarted?: () => void;\n onPlaybackTimeChange?: (timeMs: number) => void;\n /** Emits durable checkpoint candidates at lifecycle boundaries, never per frame. */\n onPlaybackCheckpoint?: (checkpoint: SlidePlayerPlaybackCheckpoint) => void;\n /** Restores the current logical audio item and resumes normal autoplay. */\n playbackRestoreRequest?: SlidePlayerPlaybackRestoreRequest | null;\n /** Called after a restore request has been applied to the active audio item. */\n onPlaybackRestoreComplete?: (requestId: number | string) => void;\n onSubtitleToggle?: () => void;\n onPrev?: (context: SlidePlayerNavigationContext) => void;\n onNext?: (context: SlidePlayerNavigationContext) => void;\n /**\n * Handles subtitle jumps that target a different audio track.\n *\n * Return `true` when the parent accepted the jump; return `false` or `void`\n * when the player should treat the jump as rejected.\n */\n onSubtitleJump?: (\n target: SlidePlayerSubtitleJumpTarget,\n context: SlidePlayerNavigationContext\n ) => boolean | void;\n /** Returns whether a cross-audio subtitle jump target is currently reachable. */\n canJumpToSubtitleTarget?: (target: SlidePlayerSubtitleJumpTarget) => boolean;\n onFullscreen?: () => void;\n isFullscreen?: boolean;\n mobileViewMode?: MobileViewMode;\n settingsPortalContainer?: HTMLElement | null;\n onMobileViewModeChange?: (viewMode: MobileViewMode) => void;\n onEnded?: (audioIndex: number) => void;\n onAutoAdvanceToggle?: (enabled: boolean) => void;\n /** @deprecated Manual interaction toggling is no longer exposed by the player. */\n onInteractionToggle?: () => void;\n /** @deprecated Manual interaction toggling is no longer exposed by the player. */\n hasInteraction?: boolean;\n isInteractionOpen?: boolean;\n isSubtitleEnabled?: boolean;\n prevDisabled?: boolean;\n nextDisabled?: boolean;\n /** Shows or hides the visual controls without disabling audio, callbacks, or keyboard shortcuts. */\n showControls?: boolean;\n /** Fired when the pointer enters the controls container to pause auto-hide. */\n onControlsPointerEnter?: React.PointerEventHandler<HTMLDivElement>;\n /** Fired when the pointer leaves the controls container to resume auto-hide. */\n onControlsPointerLeave?: React.PointerEventHandler<HTMLDivElement>;\n /** Read-only segmented progress for the generated slide sequence. */\n slideProgress?: SlidePlayerProgress | null;\n /**\n * Enables document-level keyboard shortcuts for existing player actions.\n *\n * Defaults to `true`. Set to `false` when the page should not advertise or\n * handle player shortcuts for this standalone player instance.\n *\n * @example\n * ```tsx\n * <Player enableKeyboardShortcuts={false} />\n * ```\n */\n enableKeyboardShortcuts?: boolean;\n /** Requests a subtitle seek after the parent moves to the target audio track. */\n subtitleSeekRequest?: SlidePlayerSubtitleSeekRequest | null;\n customActions?: SlidePlayerCustomActions;\n customActionContext?: SlidePlayerCustomActionContext;\n /** Locale used for built-in control labels when `texts` does not provide them. */\n locale?: MarkdownFlowLocale;\n texts?: SlidePlayerTexts;\n};\n\nconst PauseIcon = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"34\"\n height=\"34\"\n viewBox=\"0 0 34 34\"\n fill=\"none\"\n >\n <path\n d=\"M16.6667 33.3333C25.8714 33.3333 33.3333 25.8714 33.3333 16.6667C33.3333 7.46192 25.8714 0 16.6667 0C7.46192 0 0 7.46192 0 16.6667C0 25.8714 7.46192 33.3333 16.6667 33.3333Z\"\n fill=\"#0A0A0A\"\n />\n <path d=\"M12 10H16V24H12V10ZM18 10H22V24H18V10Z\" fill=\"white\" />\n </svg>\n);\n\nconst PlayIcon = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"34\"\n height=\"34\"\n viewBox=\"0 0 34 34\"\n fill=\"none\"\n >\n <path\n d=\"M16.6667 33.3333C25.8714 33.3333 33.3333 25.8714 33.3333 16.6667C33.3333 7.46192 25.8714 0 16.6667 0C7.46192 0 0 7.46192 0 16.6667C0 25.8714 7.46192 33.3333 16.6667 33.3333Z\"\n fill=\"#0A0A0A\"\n />\n <path d=\"M13.3333 10L23.3333 16.6667L13.3333 23.3333V10Z\" fill=\"white\" />\n </svg>\n);\n\nconst PLAYER_SHORTCUT_LABELS = {\n fullscreen: \"F\",\n next: \"→\",\n nextSubtitle: \"Shift+→\",\n previous: \"←\",\n previousSubtitle: \"Shift+←\",\n subtitle: \"C\",\n} as const;\n\nconst SUBTITLE_JUMP_AVAILABILITY_UPDATE_INTERVAL_MS = 250;\nconst PLAYBACK_RESTORE_WAIT_TIMEOUT_MS = 15_000;\n\nconst getShortcutTitle = (label: string | undefined, shortcut: string) =>\n label ? `${label} (${shortcut})` : shortcut;\n\nconst Player = ({\n audioList = [],\n className,\n currentAudioIndex = -1,\n defaultPlaying = true,\n isPlaybackPaused = false,\n isAutoAdvanceEnabled = true,\n useAutoAdvanceToggle = false,\n onLoadingChange,\n onPlaybackPreferenceChange,\n onPlaybackStarted,\n onPlaybackTimeChange,\n onPlaybackCheckpoint,\n playbackRestoreRequest = null,\n onPlaybackRestoreComplete,\n onSubtitleToggle,\n onPrev,\n onNext,\n onSubtitleJump,\n canJumpToSubtitleTarget,\n onFullscreen,\n isFullscreen = false,\n mobileViewMode = DEFAULT_MOBILE_VIEW_MODE,\n settingsPortalContainer,\n onMobileViewModeChange,\n onEnded,\n onAutoAdvanceToggle,\n onInteractionToggle: _deprecatedOnInteractionToggle,\n hasInteraction: _deprecatedHasInteraction,\n isInteractionOpen = false,\n isSubtitleEnabled = true,\n prevDisabled = false,\n nextDisabled = false,\n showControls = true,\n onControlsPointerEnter,\n onControlsPointerLeave,\n slideProgress = null,\n enableKeyboardShortcuts = true,\n subtitleSeekRequest = null,\n customActions,\n customActionContext,\n locale,\n texts,\n onFocusCapture,\n onPointerDown,\n ...props\n}: PlayerProps) => {\n const direction = props.dir ?? getMarkdownFlowDirection(locale);\n const language = props.lang ?? getMarkdownFlowLanguage(locale);\n const localKeyboardShortcutOwnerId = useId();\n const keyboardShortcutContext = useContext(PlayerKeyboardShortcutContext);\n const audioRef = useRef<HTMLAudioElement | null>(null);\n const { resolvedDirection: shortcutDirection, readDirection } =\n useResolvedDirection(audioRef, direction);\n const isRtlNavigation = shortcutDirection === \"rtl\";\n const portalLanguage = useDetachedLanguage(audioRef, language);\n const previousInteractionOpenRef = useRef(isInteractionOpen);\n const audioSrcRef = useRef<string | null>(null);\n const currentAudioKeyRef = useRef<string | null>(null);\n const currentSegmentIndexRef = useRef(0);\n const waitingSegmentIndexRef = useRef<number | null>(null);\n const currentAudioRef = useRef<SlideAudioItem | undefined>(undefined);\n const currentAudioSegmentsRef = useRef<\n NonNullable<SlideAudioItem[\"audioSegments\"]>\n >([]);\n const playbackPreferenceRef = useRef(\n useAutoAdvanceToggle ? isAutoAdvanceEnabled : defaultPlaying\n );\n const wasPlayingBeforeExternalPauseRef = useRef(false);\n const isLoadingRef = useRef(false);\n const isPausedByUserRef = useRef(false);\n const activeSourceTypeRef = useRef<\"url\" | \"segment\" | null>(null);\n const preferredSourceTypeRef = useRef<AudioPlaybackSourceType | null>(null);\n const isWaitingForSegmentRef = useRef(false);\n const pendingAutoPlayRef = useRef(false);\n const pendingSeekTimeRef = useRef<number | null>(null);\n const isSwitchingSegmentRef = useRef(false);\n const playbackAnimationFrameRef = useRef<number | null>(null);\n const playbackTimeMsRef = useRef(0);\n const updateSubtitleJumpAvailabilityRef = useRef<\n (currentTimeMs: number) => void\n >(() => {});\n const lastSubtitleJumpAvailabilityTimeMsRef = useRef<number | null>(null);\n const lastSubtitleJumpTargetRef =\n useRef<SlidePlayerSubtitleJumpTarget | null>(null);\n const lastSubtitleSeekRequestIdRef = useRef<number | string | null>(null);\n const lastPlaybackRestoreRequestIdRef = useRef<number | string | null>(null);\n const lastPlaybackCheckpointAtRef = useRef(0);\n const hasCompletedCurrentAudioRef = useRef(false);\n const isResettingAudioRef = useRef(false);\n const onPlaybackCheckpointRef = useRef(onPlaybackCheckpoint);\n const getCurrentPlaybackTimeMsRef = useRef<() => number>(() => 0);\n const subtitleCueTracksCacheRef = useRef<SubtitleCueTracksCache | null>(null);\n const playbackAccessModeRef = useRef<\n \"unknown\" | \"auto\" | \"manual\" | \"blocked\"\n >(\"unknown\");\n const [isPlaying, setIsPlaying] = useState(defaultPlaying);\n const [isMobileMoreOpen, setIsMobileMoreOpen] = useState(false);\n const [subtitleJumpAvailability, setSubtitleJumpAvailability] = useState({\n next: false,\n previous: false,\n });\n const keyboardShortcutOwnerId =\n keyboardShortcutContext?.ownerId ?? localKeyboardShortcutOwnerId;\n const shouldEnableKeyboardShortcuts =\n enableKeyboardShortcuts && (keyboardShortcutContext?.enabled ?? true);\n const currentAudio =\n currentAudioIndex >= 0 ? audioList[currentAudioIndex] : undefined;\n const currentAudioUrl = currentAudio?.audioUrl;\n const currentAudioSegmentList = currentAudio?.audioSegments;\n const currentAudioSegmentCount = currentAudioSegmentList?.length ?? 0;\n const currentAudioSegments = useMemo(\n () => getSortedAudioSegments(currentAudio),\n [currentAudio, currentAudioSegmentCount, currentAudioSegmentList]\n );\n let subtitleCueTracksCache = subtitleCueTracksCacheRef.current;\n\n if (!hasCurrentSubtitleCueTracksCache(audioList, subtitleCueTracksCache)) {\n subtitleCueTracksCache = createSubtitleCueTracksCache(audioList);\n subtitleCueTracksCacheRef.current = subtitleCueTracksCache;\n }\n\n const subtitleCueTracks = subtitleCueTracksCache.tracks;\n const customActionList = useMemo(\n () => toPlayerCustomActionList(customActions, customActionContext),\n [customActionContext, customActions]\n );\n const mobileVisibleActionCount = customActionList.length + 6;\n const controlsStyle = useMemo(\n () =>\n ({\n \"--slide-player-mobile-control-count\": String(mobileVisibleActionCount),\n }) as React.CSSProperties,\n [mobileVisibleActionCount]\n );\n const playerTexts = useMemo(\n () => ({\n ...getSlidePlayerTexts(locale),\n ...texts,\n }),\n [locale, texts]\n );\n const currentAudioKey = useMemo(() => {\n if (!currentAudio) {\n return \"none\";\n }\n\n return (\n currentAudio.audioKey ??\n `${String(currentAudio.sequenceNumber ?? \"none\")}:${String(currentAudio.audioUrl ?? \"\")}`\n );\n }, [currentAudio]);\n const isTogglePlaying = useAutoAdvanceToggle\n ? isAutoAdvanceEnabled\n : isPlaying;\n const toggleAriaLabel = useAutoAdvanceToggle\n ? isAutoAdvanceEnabled\n ? playerTexts.pauseAutoplayLabel\n : playerTexts.playAutoplayLabel\n : isPlaying\n ? playerTexts.pauseLabel\n : playerTexts.playLabel;\n const fullscreenAriaLabel = isFullscreen\n ? playerTexts.exitFullscreenLabel\n : playerTexts.enterFullscreenLabel;\n const getShortcutMetadata = useCallback(\n (label: string | undefined, shortcutText: string, ariaKey: string) => ({\n ariaKeyShortcuts: shouldEnableKeyboardShortcuts ? ariaKey : undefined,\n title: shouldEnableKeyboardShortcuts\n ? getShortcutTitle(label, shortcutText)\n : label,\n }),\n [shouldEnableKeyboardShortcuts]\n );\n const subtitleShortcutMetadata = getShortcutMetadata(\n playerTexts.subtitleToggleAriaLabel,\n PLAYER_SHORTCUT_LABELS.subtitle,\n \"c\"\n );\n const previousShortcutMetadata = getShortcutMetadata(\n playerTexts.previousLabel,\n isRtlNavigation\n ? PLAYER_SHORTCUT_LABELS.next\n : PLAYER_SHORTCUT_LABELS.previous,\n isRtlNavigation ? \"ArrowRight\" : \"ArrowLeft\"\n );\n const previousSubtitleShortcutMetadata = getShortcutMetadata(\n playerTexts.previousSubtitleLabel,\n PLAYER_SHORTCUT_LABELS.previousSubtitle,\n \"Shift+ArrowLeft\"\n );\n const playbackShortcutMetadata = getShortcutMetadata(\n toggleAriaLabel,\n playerTexts.playbackShortcutLabel,\n \"Space\"\n );\n const nextShortcutMetadata = getShortcutMetadata(\n playerTexts.nextLabel,\n isRtlNavigation\n ? PLAYER_SHORTCUT_LABELS.previous\n : PLAYER_SHORTCUT_LABELS.next,\n isRtlNavigation ? \"ArrowLeft\" : \"ArrowRight\"\n );\n const nextSubtitleShortcutMetadata = getShortcutMetadata(\n playerTexts.nextSubtitleLabel,\n PLAYER_SHORTCUT_LABELS.nextSubtitle,\n \"Shift+ArrowRight\"\n );\n const fullscreenShortcutMetadata = getShortcutMetadata(\n fullscreenAriaLabel,\n PLAYER_SHORTCUT_LABELS.fullscreen,\n \"f\"\n );\n const activateKeyboardShortcutOwner = useCallback(() => {\n if (!shouldEnableKeyboardShortcuts) {\n return;\n }\n\n activatePlayerKeyboardShortcutOwner(keyboardShortcutOwnerId);\n }, [keyboardShortcutOwnerId, shouldEnableKeyboardShortcuts]);\n\n const handleRootPointerDown = useCallback(\n (event: React.PointerEvent<HTMLDivElement>) => {\n activateKeyboardShortcutOwner();\n onPointerDown?.(event);\n },\n [activateKeyboardShortcutOwner, onPointerDown]\n );\n\n const handleRootFocusCapture = useCallback(\n (event: React.FocusEvent<HTMLDivElement>) => {\n activateKeyboardShortcutOwner();\n onFocusCapture?.(event);\n },\n [activateKeyboardShortcutOwner, onFocusCapture]\n );\n\n useEffect(() => {\n currentAudioRef.current = currentAudio;\n }, [currentAudio]);\n\n useEffect(() => {\n playbackPreferenceRef.current = useAutoAdvanceToggle\n ? isAutoAdvanceEnabled\n : defaultPlaying;\n }, [defaultPlaying, isAutoAdvanceEnabled, useAutoAdvanceToggle]);\n\n useEffect(() => {\n if (showControls) {\n return;\n }\n\n setIsMobileMoreOpen(false);\n }, [showControls]);\n\n useEffect(() => {\n if (!previousInteractionOpenRef.current && isInteractionOpen) {\n setIsMobileMoreOpen(false);\n }\n\n previousInteractionOpenRef.current = isInteractionOpen;\n }, [isInteractionOpen]);\n\n useEffect(() => {\n currentAudioSegmentsRef.current = currentAudioSegments;\n }, [currentAudioSegments]);\n\n useEffect(() => {\n const currentUrl = currentAudio?.audioUrl;\n const nextUrl =\n currentAudioIndex >= 0\n ? audioList[currentAudioIndex + 1]?.audioUrl\n : undefined;\n\n preloadAudioUrl(currentUrl);\n preloadAudioUrl(nextUrl);\n }, [audioList, currentAudio?.audioUrl, currentAudioIndex]);\n\n const updateLoading = useCallback(\n (loading: boolean, reason: SlidePlayerLoadingReason | null = null) => {\n if (isLoadingRef.current === loading && (!loading || reason === null)) {\n return;\n }\n\n isLoadingRef.current = loading;\n onLoadingChange?.({\n loading,\n reason: loading ? reason : null,\n });\n },\n [onLoadingChange]\n );\n\n const updatePlaybackPreference = useCallback(\n (playing: boolean) => {\n playbackPreferenceRef.current = playing;\n onPlaybackPreferenceChange?.(playing);\n },\n [onPlaybackPreferenceChange]\n );\n\n const getNavigationContext = useCallback((): SlidePlayerNavigationContext => {\n if (useAutoAdvanceToggle) {\n return {\n shouldContinuePlayback: playbackPreferenceRef.current,\n };\n }\n\n return {\n shouldContinuePlayback: shouldKeepPlayingAfterNavigation({\n defaultPlaying: playbackPreferenceRef.current,\n isPausedByUser: isPausedByUserRef.current,\n }),\n };\n }, [useAutoAdvanceToggle]);\n\n const isAutoplayBlockedError = useCallback((error: unknown) => {\n if (!(error instanceof DOMException)) {\n return false;\n }\n\n return error.name === \"NotAllowedError\" || error.name === \"SecurityError\";\n }, []);\n\n const canStartPlaybackAutomatically = useCallback(() => {\n return (\n defaultPlaying &&\n !isPlaybackPaused &&\n !isPausedByUserRef.current &&\n playbackAccessModeRef.current !== \"blocked\"\n );\n }, [defaultPlaying, isPlaybackPaused]);\n\n const getSegmentSrc = useCallback((audioData: string) => {\n if (!audioData) {\n return \"\";\n }\n\n if (audioData.startsWith(\"data:\")) {\n return audioData;\n }\n\n return `data:audio/mpeg;base64,${audioData}`;\n }, []);\n\n const getWaitingSegmentSeekTime = useCallback(() => {\n const waitingSegmentIndex = waitingSegmentIndexRef.current;\n\n if (waitingSegmentIndex == null || waitingSegmentIndex <= 0) {\n return 0;\n }\n\n return (\n currentAudioSegmentsRef.current\n .slice(0, waitingSegmentIndex)\n .reduce(\n (totalDurationMs, segment) =>\n totalDurationMs + Math.max(Number(segment.duration_ms ?? 0), 0),\n 0\n ) / 1000\n );\n }, []);\n\n const getSegmentStartTimeMs = useCallback((segmentIndex: number) => {\n if (segmentIndex <= 0) {\n return 0;\n }\n\n return currentAudioSegmentsRef.current\n .slice(0, segmentIndex)\n .reduce(\n (totalDurationMs, segment) =>\n totalDurationMs + Math.max(Number(segment.duration_ms ?? 0), 0),\n 0\n );\n }, []);\n\n const canSeekToAudioPlaybackTimeMs = useCallback(\n (audioItem: SlideAudioItem | undefined, timeMs: number) => {\n if (!audioItem || isPlaybackPaused) {\n return false;\n }\n\n if (audioItem.audioUrl) {\n return true;\n }\n\n return isPlaybackTimeCoveredBySegments(\n getSortedAudioSegments(audioItem),\n timeMs\n );\n },\n [isPlaybackPaused]\n );\n\n const getSubtitleJumpTarget = useCallback(\n (\n direction: SubtitleCueJumpDirection,\n currentTimeMs: number,\n options: {\n excludeTarget?: SlidePlayerSubtitleJumpTarget | null;\n } = {}\n ) => {\n const target = getSubtitleCueJumpTarget({\n currentAudioIndex,\n currentTimeMs,\n direction,\n excludeTarget: options.excludeTarget,\n tracks: subtitleCueTracks,\n });\n\n if (\n !target ||\n !canSeekToAudioPlaybackTimeMs(\n audioList[target.audioIndex],\n target.timeMs\n )\n ) {\n return null;\n }\n\n if (target.audioIndex !== currentAudioIndex) {\n if (!onSubtitleJump) {\n return null;\n }\n\n if (canJumpToSubtitleTarget && !canJumpToSubtitleTarget(target)) {\n return null;\n }\n }\n\n return target;\n },\n [\n audioList,\n canJumpToSubtitleTarget,\n canSeekToAudioPlaybackTimeMs,\n currentAudioIndex,\n onSubtitleJump,\n subtitleCueTracks,\n ]\n );\n\n const updateSubtitleJumpAvailability = useCallback(\n (currentTimeMs: number, force = false) => {\n const normalizedCurrentTimeMs = Math.max(Number(currentTimeMs), 0);\n\n if (\n !force &&\n lastSubtitleJumpAvailabilityTimeMsRef.current !== null &&\n Math.abs(\n normalizedCurrentTimeMs -\n lastSubtitleJumpAvailabilityTimeMsRef.current\n ) < SUBTITLE_JUMP_AVAILABILITY_UPDATE_INTERVAL_MS\n ) {\n return;\n }\n\n lastSubtitleJumpAvailabilityTimeMsRef.current = normalizedCurrentTimeMs;\n\n const nextAvailability = {\n previous:\n getSubtitleJumpTarget(\"previous\", normalizedCurrentTimeMs) !== null,\n next: getSubtitleJumpTarget(\"next\", normalizedCurrentTimeMs) !== null,\n };\n\n setSubtitleJumpAvailability((previousAvailability) => {\n if (\n previousAvailability.previous === nextAvailability.previous &&\n previousAvailability.next === nextAvailability.next\n ) {\n return previousAvailability;\n }\n\n return nextAvailability;\n });\n },\n [getSubtitleJumpTarget]\n );\n\n useEffect(() => {\n updateSubtitleJumpAvailabilityRef.current = updateSubtitleJumpAvailability;\n updateSubtitleJumpAvailability(playbackTimeMsRef.current, true);\n }, [updateSubtitleJumpAvailability]);\n\n const getCurrentPlaybackTimeMs = useCallback(() => {\n const audioElement = audioRef.current;\n\n if (!audioElement) {\n return waitingSegmentIndexRef.current != null\n ? getSegmentStartTimeMs(waitingSegmentIndexRef.current)\n : 0;\n }\n\n if (activeSourceTypeRef.current === \"segment\") {\n return (\n getSegmentStartTimeMs(currentSegmentIndexRef.current) +\n Math.max(audioElement.currentTime, 0) * 1000\n );\n }\n\n if (pendingSeekTimeRef.current !== null && audioElement.readyState === 0) {\n return pendingSeekTimeRef.current * 1000;\n }\n\n return Math.max(audioElement.currentTime, 0) * 1000;\n }, [getSegmentStartTimeMs]);\n\n useEffect(() => {\n onPlaybackCheckpointRef.current = onPlaybackCheckpoint;\n }, [onPlaybackCheckpoint]);\n\n useEffect(() => {\n getCurrentPlaybackTimeMsRef.current = getCurrentPlaybackTimeMs;\n }, [getCurrentPlaybackTimeMs]);\n\n const publishPlaybackTime = useCallback(\n (timeMs: number) => {\n const nextPlaybackTimeMs = Math.max(timeMs, 0);\n\n if (playbackTimeMsRef.current === nextPlaybackTimeMs) {\n return;\n }\n\n playbackTimeMsRef.current = nextPlaybackTimeMs;\n if (\n shouldClearSubtitleCueJumpTarget({\n currentAudioIndex,\n currentTimeMs: nextPlaybackTimeMs,\n target: lastSubtitleJumpTargetRef.current,\n })\n ) {\n lastSubtitleJumpTargetRef.current = null;\n }\n\n onPlaybackTimeChange?.(nextPlaybackTimeMs);\n updateSubtitleJumpAvailabilityRef.current(nextPlaybackTimeMs);\n },\n [currentAudioIndex, onPlaybackTimeChange]\n );\n\n const syncPlaybackTime = useCallback(() => {\n publishPlaybackTime(getCurrentPlaybackTimeMs());\n }, [getCurrentPlaybackTimeMs, publishPlaybackTime]);\n\n const emitPlaybackCheckpoint = useCallback(\n (force = false, isComplete = false) => {\n const audioKey = currentAudioKeyRef.current;\n\n if (!onPlaybackCheckpoint || !audioKey) {\n return;\n }\n\n const now = Date.now();\n if (!force && now - lastPlaybackCheckpointAtRef.current < 5_000) {\n return;\n }\n\n lastPlaybackCheckpointAtRef.current = now;\n hasCompletedCurrentAudioRef.current = isComplete;\n onPlaybackCheckpoint({\n audioKey,\n isComplete,\n timeMs: getCurrentPlaybackTimeMs(),\n });\n },\n [getCurrentPlaybackTimeMs, onPlaybackCheckpoint]\n );\n\n useEffect(\n () => () => {\n if (hasCompletedCurrentAudioRef.current) {\n return;\n }\n\n onPlaybackCheckpointRef.current?.({\n audioKey: currentAudioKeyRef.current ?? \"none\",\n isComplete: false,\n timeMs: getCurrentPlaybackTimeMsRef.current(),\n });\n },\n []\n );\n\n useEffect(() => {\n hasCompletedCurrentAudioRef.current = false;\n }, [currentAudioIndex]);\n\n const stopPlaybackTimeLoop = useCallback(() => {\n if (\n typeof window === \"undefined\" ||\n playbackAnimationFrameRef.current === null\n ) {\n return;\n }\n\n window.cancelAnimationFrame(playbackAnimationFrameRef.current);\n playbackAnimationFrameRef.current = null;\n }, []);\n\n const startPlaybackTimeLoop = useCallback(() => {\n if (\n typeof window === \"undefined\" ||\n playbackAnimationFrameRef.current !== null\n ) {\n return;\n }\n\n const updateFrame = () => {\n syncPlaybackTime();\n\n const audioElement = audioRef.current;\n\n if (!audioElement || audioElement.paused || audioElement.ended) {\n playbackAnimationFrameRef.current = null;\n return;\n }\n\n playbackAnimationFrameRef.current =\n window.requestAnimationFrame(updateFrame);\n };\n\n playbackAnimationFrameRef.current =\n window.requestAnimationFrame(updateFrame);\n }, [syncPlaybackTime]);\n\n const resetAudio = useCallback(() => {\n const audioElement = audioRef.current;\n\n if (!audioElement) {\n return;\n }\n\n stopPlaybackTimeLoop();\n pendingAutoPlayRef.current = false;\n isPausedByUserRef.current = false;\n wasPlayingBeforeExternalPauseRef.current = false;\n activeSourceTypeRef.current = null;\n pendingSeekTimeRef.current = null;\n isWaitingForSegmentRef.current = false;\n isSwitchingSegmentRef.current = false;\n preferredSourceTypeRef.current = null;\n audioElement.pause();\n audioElement.removeAttribute(\"src\");\n audioElement.load();\n audioSrcRef.current = null;\n currentSegmentIndexRef.current = 0;\n waitingSegmentIndexRef.current = null;\n publishPlaybackTime(0);\n setIsPlaying(false);\n updateLoading(false);\n }, [publishPlaybackTime, stopPlaybackTimeLoop, updateLoading]);\n\n const tryPlayCurrentAudio = useCallback(\n (_reason: string) => {\n const audioElement = audioRef.current;\n\n if (!audioElement) {\n return false;\n }\n\n const playPromise = audioElement.play();\n\n if (playPromise && typeof playPromise.then === \"function\") {\n void playPromise\n .then(() => {\n if (playbackAccessModeRef.current === \"unknown\") {\n playbackAccessModeRef.current = \"auto\";\n }\n\n pendingAutoPlayRef.current = false;\n isSwitchingSegmentRef.current = false;\n })\n .catch((error: unknown) => {\n if (\n playbackAccessModeRef.current === \"unknown\" &&\n isAutoplayBlockedError(error)\n ) {\n // Lock autoplay after the first browser rejection.\n playbackAccessModeRef.current = \"blocked\";\n pendingAutoPlayRef.current = false;\n updateLoading(false);\n }\n\n isSwitchingSegmentRef.current = false;\n setIsPlaying(false);\n });\n }\n\n return true;\n },\n [isAutoplayBlockedError, updateLoading]\n );\n\n const startSegmentPlayback = useCallback(\n (\n segmentIndex: number,\n _reason: string,\n options: {\n seekTimeSeconds?: number;\n shouldResume?: boolean;\n } = {}\n ) => {\n const audioElement = audioRef.current;\n const segment = currentAudioSegmentsRef.current[segmentIndex];\n\n if (!audioElement || !segment) {\n return false;\n }\n\n const nextAudioSrc = getSegmentSrc(segment.audio_data);\n const nextSeekTimeSeconds = Math.max(\n Number(options.seekTimeSeconds ?? 0),\n 0\n );\n\n currentSegmentIndexRef.current = segmentIndex;\n waitingSegmentIndexRef.current = null;\n isWaitingForSegmentRef.current = false;\n isSwitchingSegmentRef.current = true;\n preferredSourceTypeRef.current = \"segment\";\n publishPlaybackTime(\n getSegmentStartTimeMs(segmentIndex) + nextSeekTimeSeconds * 1000\n );\n const shouldAutoResume =\n options.shouldResume ?? canStartPlaybackAutomatically();\n\n pendingAutoPlayRef.current = shouldAutoResume;\n updateLoading(false);\n\n const hasNewSrc = audioSrcRef.current !== nextAudioSrc;\n\n activeSourceTypeRef.current = \"segment\";\n\n if (hasNewSrc) {\n audioElement.pause();\n audioElement.removeAttribute(\"src\");\n audioElement.load();\n audioSrcRef.current = nextAudioSrc;\n audioElement.src = nextAudioSrc;\n audioElement.load();\n }\n\n pendingSeekTimeRef.current = nextSeekTimeSeconds;\n\n if (audioElement.readyState > 0) {\n audioElement.currentTime = nextSeekTimeSeconds;\n pendingSeekTimeRef.current = null;\n }\n\n if (!shouldAutoResume) {\n pendingAutoPlayRef.current = false;\n isSwitchingSegmentRef.current = false;\n audioElement.pause();\n setIsPlaying(false);\n return true;\n }\n\n return tryPlayCurrentAudio(`start-segment:${_reason}`);\n },\n [\n canStartPlaybackAutomatically,\n getSegmentSrc,\n getSegmentStartTimeMs,\n publishPlaybackTime,\n tryPlayCurrentAudio,\n updateLoading,\n ]\n );\n\n const seekUrlPlayback = useCallback(\n (audioUrl: string, timeMs: number) => {\n const audioElement = audioRef.current;\n\n if (!audioElement) {\n return false;\n }\n\n const targetTimeSeconds = Math.max(Number(timeMs), 0) / 1000;\n if (audioSrcRef.current !== audioUrl) {\n audioElement.pause();\n audioElement.removeAttribute(\"src\");\n audioElement.load();\n audioSrcRef.current = audioUrl;\n activeSourceTypeRef.current = \"url\";\n preferredSourceTypeRef.current = \"url\";\n audioElement.src = audioUrl;\n audioElement.load();\n }\n\n pendingSeekTimeRef.current = targetTimeSeconds;\n publishPlaybackTime(targetTimeSeconds * 1000);\n if (audioElement.readyState > 0) {\n audioElement.currentTime = targetTimeSeconds;\n pendingSeekTimeRef.current = null;\n }\n\n return true;\n },\n [publishPlaybackTime]\n );\n\n const seekToPlaybackTimeMs = useCallback(\n (timeMs: number) => {\n const audioElement = audioRef.current;\n\n if (!audioElement || !currentAudio || isPlaybackPaused) {\n return false;\n }\n\n const targetTimeMs = Math.max(Number(timeMs), 0);\n const shouldResumePlayback =\n (!audioElement.paused && !audioElement.ended) ||\n pendingAutoPlayRef.current ||\n isSwitchingSegmentRef.current ||\n (waitingSegmentIndexRef.current !== null &&\n playbackPreferenceRef.current &&\n !isPausedByUserRef.current);\n const segmentSeekTarget = isPlaybackTimeCoveredBySegments(\n currentAudioSegmentsRef.current,\n targetTimeMs\n )\n ? resolveSegmentSeekTarget(\n currentAudioSegmentsRef.current,\n targetTimeMs\n )\n : null;\n\n lastSubtitleJumpAvailabilityTimeMsRef.current = null;\n stopPlaybackTimeLoop();\n pendingAutoPlayRef.current = shouldResumePlayback;\n updateLoading(false);\n\n if (shouldResumePlayback) {\n playbackAccessModeRef.current = \"manual\";\n isPausedByUserRef.current = false;\n updatePlaybackPreference(true);\n }\n\n if (\n segmentSeekTarget &&\n (activeSourceTypeRef.current === \"segment\" || !currentAudioUrl)\n ) {\n return startSegmentPlayback(\n segmentSeekTarget.segmentIndex,\n \"subtitle-seek-segment\",\n {\n seekTimeSeconds: segmentSeekTarget.segmentTimeSeconds,\n shouldResume: shouldResumePlayback,\n }\n );\n }\n\n if (currentAudioUrl && seekUrlPlayback(currentAudioUrl, targetTimeMs)) {\n if (!shouldResumePlayback) {\n pendingAutoPlayRef.current = false;\n audioElement.pause();\n setIsPlaying(false);\n return true;\n }\n\n return tryPlayCurrentAudio(\"subtitle-seek-url\");\n }\n\n return false;\n },\n [\n currentAudio,\n currentAudioUrl,\n isPlaybackPaused,\n seekUrlPlayback,\n startSegmentPlayback,\n stopPlaybackTimeLoop,\n tryPlayCurrentAudio,\n updateLoading,\n updatePlaybackPreference,\n ]\n );\n\n const restorePlaybackTimeMs = useCallback(\n (timeMs: number) => {\n const audioElement = audioRef.current;\n\n if (!audioElement || !currentAudio) {\n return false;\n }\n\n const targetTimeMs = Math.max(Number(timeMs), 0);\n const segmentSeekTarget = isPlaybackTimeCoveredBySegments(\n currentAudioSegmentsRef.current,\n targetTimeMs\n )\n ? resolveSegmentSeekTarget(\n currentAudioSegmentsRef.current,\n targetTimeMs\n )\n : null;\n\n pendingAutoPlayRef.current = true;\n updateLoading(false);\n\n if (\n segmentSeekTarget &&\n (activeSourceTypeRef.current === \"segment\" || !currentAudioUrl)\n ) {\n return startSegmentPlayback(segmentSeekTarget.segmentIndex, \"restore\", {\n seekTimeSeconds: segmentSeekTarget.segmentTimeSeconds,\n shouldResume: true,\n });\n }\n\n if (!currentAudioUrl || !seekUrlPlayback(currentAudioUrl, targetTimeMs)) {\n return false;\n }\n\n tryPlayCurrentAudio(\"restore\");\n return true;\n },\n [\n currentAudio,\n currentAudioUrl,\n seekUrlPlayback,\n startSegmentPlayback,\n tryPlayCurrentAudio,\n updateLoading,\n ]\n );\n\n const jumpToSubtitleCue = useCallback(\n (direction: SubtitleCueJumpDirection) => {\n const target = getSubtitleJumpTarget(\n direction,\n getCurrentPlaybackTimeMs(),\n {\n excludeTarget:\n direction === \"previous\" ? lastSubtitleJumpTargetRef.current : null,\n }\n );\n\n if (target === null) {\n return false;\n }\n\n if (target.audioIndex === currentAudioIndex) {\n const didSeek = seekToPlaybackTimeMs(target.timeMs);\n\n if (didSeek) {\n lastSubtitleJumpTargetRef.current = target;\n }\n\n return didSeek;\n }\n\n const didJump = Boolean(\n onSubtitleJump?.(\n target,\n suppressPlayerControlsWakeAfterNavigation(getNavigationContext())\n )\n );\n\n if (didJump) {\n lastSubtitleJumpTargetRef.current = target;\n }\n\n return didJump;\n },\n [\n currentAudioIndex,\n getCurrentPlaybackTimeMs,\n getNavigationContext,\n getSubtitleJumpTarget,\n onSubtitleJump,\n seekToPlaybackTimeMs,\n ]\n );\n\n const finishAudioItem = useCallback(\n (_reason?: string) => {\n stopPlaybackTimeLoop();\n pendingAutoPlayRef.current = false;\n isWaitingForSegmentRef.current = false;\n isSwitchingSegmentRef.current = false;\n syncPlaybackTime();\n setIsPlaying(false);\n updateLoading(false);\n\n if (currentAudioIndex >= 0) {\n onEnded?.(currentAudioIndex);\n }\n },\n [\n currentAudioIndex,\n onEnded,\n stopPlaybackTimeLoop,\n syncPlaybackTime,\n updateLoading,\n ]\n );\n\n const finishUrlAudioIfSeekedToEnd = useCallback(\n (_reason: string) => {\n const audioElement = audioRef.current;\n\n if (!audioElement || activeSourceTypeRef.current !== \"url\") {\n return false;\n }\n\n if (\n !hasReachedAudioEnd({\n currentTimeSeconds: Math.max(audioElement.currentTime, 0),\n durationSeconds: audioElement.duration,\n })\n ) {\n return false;\n }\n\n pendingAutoPlayRef.current = false;\n audioElement.pause();\n finishAudioItem(_reason);\n return true;\n },\n [finishAudioItem]\n );\n\n const handleSegmentEnded = useCallback(() => {\n const nextSegmentIndex = currentSegmentIndexRef.current + 1;\n const segments = currentAudioSegmentsRef.current;\n const nextSegment = segments[nextSegmentIndex];\n const activeAudio = currentAudioRef.current;\n const hasFinal = segments.some((segment) => segment.is_final);\n\n if (nextSegment) {\n startSegmentPlayback(nextSegmentIndex, \"ended\");\n return;\n }\n\n if (activeAudio?.isAudioStreaming || !hasFinal) {\n currentSegmentIndexRef.current = nextSegmentIndex;\n waitingSegmentIndexRef.current = nextSegmentIndex;\n isWaitingForSegmentRef.current = true;\n pendingAutoPlayRef.current = defaultPlaying;\n publishPlaybackTime(getSegmentStartTimeMs(nextSegmentIndex));\n setIsPlaying(false);\n updateLoading(true, \"waitingForMoreAudio\");\n\n return;\n }\n\n finishAudioItem(\"segments-completed\");\n }, [\n defaultPlaying,\n finishAudioItem,\n getSegmentStartTimeMs,\n publishPlaybackTime,\n startSegmentPlayback,\n updateLoading,\n ]);\n\n useEffect(() => {\n if (currentAudioKeyRef.current === currentAudioKey) {\n return;\n }\n\n // The DOM pause event is delivered after React has rendered the new audio\n // item. Save the outgoing item before changing its identity, then suppress\n // that synthetic pause so it cannot be attributed to the new item.\n emitPlaybackCheckpoint(true);\n currentAudioKeyRef.current = currentAudioKey;\n currentSegmentIndexRef.current = 0;\n waitingSegmentIndexRef.current = null;\n isWaitingForSegmentRef.current = false;\n isPausedByUserRef.current = false;\n wasPlayingBeforeExternalPauseRef.current = false;\n pendingAutoPlayRef.current = false;\n isSwitchingSegmentRef.current = false;\n activeSourceTypeRef.current = null;\n preferredSourceTypeRef.current = null;\n audioSrcRef.current = null;\n stopPlaybackTimeLoop();\n publishPlaybackTime(0);\n updateLoading(false);\n\n const audioElement = audioRef.current;\n\n if (!audioElement) {\n return;\n }\n\n isResettingAudioRef.current = true;\n audioElement.pause();\n audioElement.removeAttribute(\"src\");\n audioElement.load();\n isResettingAudioRef.current = false;\n setIsPlaying(false);\n }, [\n currentAudioIndex,\n currentAudioKey,\n currentAudioSegments.length,\n currentAudioUrl,\n emitPlaybackCheckpoint,\n publishPlaybackTime,\n stopPlaybackTimeLoop,\n updateLoading,\n ]);\n\n useEffect(() => {\n const audioElement = audioRef.current;\n\n if (!audioElement) {\n return;\n }\n\n if (isPlaybackPaused) {\n wasPlayingBeforeExternalPauseRef.current = Boolean(\n currentAudioRef.current &&\n !isPausedByUserRef.current &&\n (!audioElement.paused ||\n pendingAutoPlayRef.current ||\n waitingSegmentIndexRef.current !== null)\n );\n\n pendingAutoPlayRef.current = false;\n updateLoading(false);\n audioElement.pause();\n setIsPlaying(false);\n return;\n }\n\n if (\n !wasPlayingBeforeExternalPauseRef.current ||\n !currentAudioRef.current ||\n isPausedByUserRef.current\n ) {\n return;\n }\n\n wasPlayingBeforeExternalPauseRef.current = false;\n\n if (waitingSegmentIndexRef.current !== null) {\n if (\n waitingSegmentIndexRef.current < currentAudioSegmentsRef.current.length\n ) {\n startSegmentPlayback(waitingSegmentIndexRef.current, \"external-resume\");\n return;\n }\n\n pendingAutoPlayRef.current = true;\n updateLoading(true, \"waitingForMoreAudio\");\n return;\n }\n\n if (!audioSrcRef.current && currentAudioSegmentsRef.current.length > 0) {\n startSegmentPlayback(\n Math.min(\n currentSegmentIndexRef.current,\n currentAudioSegmentsRef.current.length - 1\n ),\n \"external-resume-init\"\n );\n return;\n }\n\n if (!audioElement.paused) {\n return;\n }\n\n pendingAutoPlayRef.current = true;\n tryPlayCurrentAudio(\"external-resume\");\n }, [\n isPlaybackPaused,\n startSegmentPlayback,\n tryPlayCurrentAudio,\n updateLoading,\n ]);\n\n useEffect(() => {\n const audioElement = audioRef.current;\n\n if (!audioElement) {\n return;\n }\n\n if (!currentAudio) {\n resetAudio();\n return;\n }\n\n // A restore can target a segment that has not arrived yet. Do not start the\n // first available segment while the restore effect waits for the requested\n // offset to become seekable.\n if (\n playbackRestoreRequest &&\n playbackRestoreRequest.id !== lastPlaybackRestoreRequestIdRef.current\n ) {\n return;\n }\n\n if (isPlaybackPaused) {\n pendingAutoPlayRef.current = false;\n updateLoading(false);\n audioElement.pause();\n setIsPlaying(false);\n return;\n }\n\n const resolvedSourceType = resolveAudioPlaybackSourceType({\n activeSourceType: activeSourceTypeRef.current,\n hasAudioUrl: Boolean(currentAudioUrl),\n segmentCount: currentAudioSegments.length,\n preferredSourceType: preferredSourceTypeRef.current,\n waitingSegmentIndex: waitingSegmentIndexRef.current,\n });\n\n if (\n resolvedSourceType &&\n preferredSourceTypeRef.current !== resolvedSourceType\n ) {\n preferredSourceTypeRef.current = resolvedSourceType;\n }\n\n if (resolvedSourceType === \"url\" && currentAudioUrl) {\n const hasNewSrc = audioSrcRef.current !== currentAudioUrl;\n const shouldAutoResume = canStartPlaybackAutomatically();\n\n if (hasNewSrc) {\n const nextSeekTime =\n waitingSegmentIndexRef.current !== null\n ? getWaitingSegmentSeekTime()\n : 0;\n seekUrlPlayback(currentAudioUrl, nextSeekTime * 1000);\n }\n\n pendingAutoPlayRef.current = shouldAutoResume;\n isWaitingForSegmentRef.current = false;\n isSwitchingSegmentRef.current = false;\n updateLoading(false);\n\n if (!shouldAutoResume) {\n pendingAutoPlayRef.current = false;\n audioElement.pause();\n setIsPlaying(false);\n return;\n }\n\n tryPlayCurrentAudio(hasNewSrc ? \"sync-url-init\" : \"sync-url\");\n return;\n }\n\n if (\n resolvedSourceType === \"segment\" &&\n waitingSegmentIndexRef.current !== null\n ) {\n if (waitingSegmentIndexRef.current < currentAudioSegments.length) {\n if (isPausedByUserRef.current) {\n setIsPlaying(false);\n updateLoading(false);\n return;\n }\n\n startSegmentPlayback(waitingSegmentIndexRef.current, \"wait-resume\");\n return;\n }\n\n isWaitingForSegmentRef.current = true;\n pendingAutoPlayRef.current = canStartPlaybackAutomatically();\n setIsPlaying(false);\n updateLoading(canStartPlaybackAutomatically());\n return;\n }\n\n if (resolvedSourceType === \"segment\" && !currentAudioSegments.length) {\n if (currentAudio.isAudioStreaming) {\n waitingSegmentIndexRef.current = currentSegmentIndexRef.current;\n isWaitingForSegmentRef.current = true;\n pendingAutoPlayRef.current = canStartPlaybackAutomatically();\n setIsPlaying(false);\n updateLoading(canStartPlaybackAutomatically());\n return;\n }\n\n resetAudio();\n return;\n }\n\n if (resolvedSourceType === \"segment\" && !audioSrcRef.current) {\n startSegmentPlayback(\n Math.min(\n currentSegmentIndexRef.current,\n currentAudioSegments.length - 1\n ),\n \"effect-init\"\n );\n return;\n }\n\n if (resolvedSourceType !== \"segment\") {\n resetAudio();\n return;\n }\n\n if (!defaultPlaying || isPausedByUserRef.current) {\n pendingAutoPlayRef.current = false;\n audioElement.pause();\n setIsPlaying(false);\n return;\n }\n\n if (audioElement.paused) {\n pendingAutoPlayRef.current = true;\n tryPlayCurrentAudio(\"sync-paused-retry\");\n }\n }, [\n currentAudio,\n currentAudioIndex,\n currentAudioSegments,\n currentAudioUrl,\n defaultPlaying,\n isPlaybackPaused,\n playbackRestoreRequest,\n canStartPlaybackAutomatically,\n resetAudio,\n seekUrlPlayback,\n startSegmentPlayback,\n tryPlayCurrentAudio,\n getWaitingSegmentSeekTime,\n updateLoading,\n ]);\n\n useEffect(() => {\n if (!subtitleSeekRequest) {\n return;\n }\n\n if (\n subtitleSeekRequest.id === lastSubtitleSeekRequestIdRef.current ||\n subtitleSeekRequest.audioIndex !== currentAudioIndex\n ) {\n return;\n }\n\n const targetAudio = audioList[subtitleSeekRequest.audioIndex];\n\n if (\n !canSeekToAudioPlaybackTimeMs(targetAudio, subtitleSeekRequest.timeMs)\n ) {\n return;\n }\n\n lastSubtitleSeekRequestIdRef.current = subtitleSeekRequest.id;\n seekToPlaybackTimeMs(subtitleSeekRequest.timeMs);\n }, [\n audioList,\n canSeekToAudioPlaybackTimeMs,\n currentAudioIndex,\n seekToPlaybackTimeMs,\n subtitleSeekRequest,\n ]);\n\n useEffect(() => {\n if (\n !playbackRestoreRequest ||\n playbackRestoreRequest.id === lastPlaybackRestoreRequestIdRef.current ||\n currentAudioIndex < 0\n ) {\n return;\n }\n\n if (restorePlaybackTimeMs(playbackRestoreRequest.timeMs)) {\n lastPlaybackRestoreRequestIdRef.current = playbackRestoreRequest.id;\n onPlaybackRestoreComplete?.(playbackRestoreRequest.id);\n return;\n }\n\n // A completed item can no longer produce the requested offset. Release\n // the restore guard so normal playback is not suppressed indefinitely.\n if (!currentAudio?.isAudioStreaming) {\n lastPlaybackRestoreRequestIdRef.current = playbackRestoreRequest.id;\n onPlaybackRestoreComplete?.(playbackRestoreRequest.id);\n }\n }, [\n currentAudio?.isAudioStreaming,\n currentAudioIndex,\n onPlaybackRestoreComplete,\n playbackRestoreRequest,\n restorePlaybackTimeMs,\n ]);\n\n useEffect(() => {\n if (\n !playbackRestoreRequest ||\n playbackRestoreRequest.id === lastPlaybackRestoreRequestIdRef.current ||\n currentAudioIndex < 0 ||\n !currentAudio?.isAudioStreaming\n ) {\n return;\n }\n\n const timeoutId = window.setTimeout(() => {\n if (\n playbackRestoreRequest.id === lastPlaybackRestoreRequestIdRef.current\n ) {\n return;\n }\n\n lastPlaybackRestoreRequestIdRef.current = playbackRestoreRequest.id;\n onPlaybackRestoreComplete?.(playbackRestoreRequest.id);\n }, PLAYBACK_RESTORE_WAIT_TIMEOUT_MS);\n\n return () => {\n window.clearTimeout(timeoutId);\n };\n }, [\n currentAudio?.isAudioStreaming,\n currentAudioIndex,\n onPlaybackRestoreComplete,\n playbackRestoreRequest,\n ]);\n\n useEffect(() => resetAudio, [resetAudio]);\n\n useEffect(() => stopPlaybackTimeLoop, [stopPlaybackTimeLoop]);\n\n const handleAudioPlay = useCallback(() => {\n syncPlaybackTime();\n startPlaybackTimeLoop();\n setIsPlaying(true);\n updateLoading(false);\n onPlaybackStarted?.();\n }, [\n onPlaybackStarted,\n startPlaybackTimeLoop,\n syncPlaybackTime,\n updateLoading,\n ]);\n\n const handleAudioPause = useCallback(() => {\n if (\n isResettingAudioRef.current ||\n isWaitingForSegmentRef.current ||\n isSwitchingSegmentRef.current\n ) {\n return;\n }\n\n stopPlaybackTimeLoop();\n syncPlaybackTime();\n emitPlaybackCheckpoint(true);\n setIsPlaying(false);\n }, [emitPlaybackCheckpoint, stopPlaybackTimeLoop, syncPlaybackTime]);\n\n const handleAudioCanPlay = useCallback(() => {\n const audioElement = audioRef.current;\n\n if (audioElement && pendingSeekTimeRef.current !== null) {\n audioElement.currentTime = pendingSeekTimeRef.current;\n pendingSeekTimeRef.current = null;\n }\n\n syncPlaybackTime();\n\n if (finishUrlAudioIfSeekedToEnd(\"canplay-seek-finished\")) {\n return;\n }\n\n if (!pendingAutoPlayRef.current || !defaultPlaying) {\n return;\n }\n\n tryPlayCurrentAudio(\"canplay\");\n }, [\n currentAudioIndex,\n defaultPlaying,\n finishUrlAudioIfSeekedToEnd,\n syncPlaybackTime,\n tryPlayCurrentAudio,\n ]);\n\n const handleLoadedMetadata = useCallback(() => {\n const audioElement = audioRef.current;\n\n if (audioElement && pendingSeekTimeRef.current !== null) {\n audioElement.currentTime = pendingSeekTimeRef.current;\n pendingSeekTimeRef.current = null;\n }\n\n syncPlaybackTime();\n\n finishUrlAudioIfSeekedToEnd(\"metadata-seek-finished\");\n }, [currentAudioIndex, finishUrlAudioIfSeekedToEnd, syncPlaybackTime]);\n\n const handleAudioTimeUpdate = useCallback(() => {\n syncPlaybackTime();\n emitPlaybackCheckpoint();\n }, [emitPlaybackCheckpoint, syncPlaybackTime]);\n\n const handleAudioLoadStart = useCallback(() => {\n if (isWaitingForSegmentRef.current) {\n return;\n }\n\n updateLoading(true, \"loadingAudio\");\n }, [updateLoading]);\n\n const handleAudioWaiting = useCallback(() => {\n if (isWaitingForSegmentRef.current) {\n updateLoading(true, \"waitingForMoreAudio\");\n return;\n }\n\n updateLoading(true, \"loadingAudio\");\n }, [updateLoading]);\n\n const handleAudioSeeking = useCallback(() => {\n syncPlaybackTime();\n }, [syncPlaybackTime]);\n\n const handleAudioEnded = useCallback(() => {\n const activeAudio = currentAudioRef.current;\n const shouldFinishAsUrl =\n activeSourceTypeRef.current === \"url\" ||\n currentAudioSegmentsRef.current.length === 0;\n const hasNextSegment = Boolean(\n currentAudioSegmentsRef.current[currentSegmentIndexRef.current + 1]\n );\n const isFinalSegment = currentAudioSegmentsRef.current.some(\n (segment) => segment.is_final\n );\n const isStreamingAudio = Boolean(activeAudio?.isAudioStreaming);\n\n // A segment ending is not necessarily the end of the logical audio item.\n // Clearing its checkpoint here would lose the resume point while the next\n // segment is loading or while a stream is still being generated.\n emitPlaybackCheckpoint(\n true,\n shouldFinishAsUrl ||\n (!isStreamingAudio && !hasNextSegment && isFinalSegment)\n );\n\n stopPlaybackTimeLoop();\n isSwitchingSegmentRef.current = false;\n\n if (shouldFinishAsUrl) {\n finishAudioItem(\"url-ended\");\n return;\n }\n\n handleSegmentEnded();\n }, [\n emitPlaybackCheckpoint,\n finishAudioItem,\n handleSegmentEnded,\n stopPlaybackTimeLoop,\n ]);\n\n const handleAudioError = useCallback(() => {\n stopPlaybackTimeLoop();\n syncPlaybackTime();\n setIsPlaying(false);\n updateLoading(false);\n }, [stopPlaybackTimeLoop, syncPlaybackTime, updateLoading]);\n const handleMobileViewModeChange = useCallback(\n (nextViewMode: MobileViewMode) => {\n onMobileViewModeChange?.(nextViewMode);\n setIsMobileMoreOpen(false);\n },\n [onMobileViewModeChange]\n );\n\n const togglePlayback = useCallback(() => {\n if (useAutoAdvanceToggle) {\n const nextAutoAdvanceEnabled = !isAutoAdvanceEnabled;\n\n updatePlaybackPreference(nextAutoAdvanceEnabled);\n onAutoAdvanceToggle?.(nextAutoAdvanceEnabled);\n return true;\n }\n\n const audioElement = audioRef.current;\n\n if (isPlaybackPaused || !audioElement || !currentAudio) {\n return false;\n }\n\n if (waitingSegmentIndexRef.current !== null) {\n if (isPlaying) {\n updatePlaybackPreference(false);\n pendingAutoPlayRef.current = false;\n isPausedByUserRef.current = true;\n waitingSegmentIndexRef.current = null;\n isWaitingForSegmentRef.current = false;\n setIsPlaying(false);\n updateLoading(false);\n audioElement.pause();\n return true;\n }\n\n updatePlaybackPreference(true);\n playbackAccessModeRef.current = \"manual\";\n isPausedByUserRef.current = false;\n pendingAutoPlayRef.current = true;\n updateLoading(true, \"waitingForMoreAudio\");\n return true;\n }\n\n if (!audioElement.src && currentAudioSegments.length > 0) {\n updatePlaybackPreference(true);\n playbackAccessModeRef.current = \"manual\";\n isPausedByUserRef.current = false;\n startSegmentPlayback(\n Math.min(\n currentSegmentIndexRef.current,\n currentAudioSegments.length - 1\n ),\n \"toggle\"\n );\n return true;\n }\n\n if (audioElement.paused) {\n updatePlaybackPreference(true);\n playbackAccessModeRef.current = \"manual\";\n isPausedByUserRef.current = false;\n pendingAutoPlayRef.current = true;\n tryPlayCurrentAudio(\"toggle-resume\");\n return true;\n }\n\n updatePlaybackPreference(false);\n pendingAutoPlayRef.current = false;\n isPausedByUserRef.current = true;\n audioElement.pause();\n return true;\n }, [\n currentAudio,\n currentAudioSegments.length,\n isAutoAdvanceEnabled,\n isPlaybackPaused,\n isPlaying,\n onAutoAdvanceToggle,\n startSegmentPlayback,\n tryPlayCurrentAudio,\n updateLoading,\n updatePlaybackPreference,\n useAutoAdvanceToggle,\n ]);\n\n useEffect(() => {\n if (!shouldEnableKeyboardShortcuts) {\n return;\n }\n\n return registerPlayerKeyboardShortcutOwner(keyboardShortcutOwnerId);\n }, [keyboardShortcutOwnerId, shouldEnableKeyboardShortcuts]);\n\n const keyboardShortcutHandlers = useMemo<\n Record<PlayerKeyboardShortcutAction, () => boolean>\n >(\n () => ({\n fullscreen: () => {\n if (!onFullscreen) {\n return false;\n }\n\n onFullscreen();\n return true;\n },\n next: () => {\n if (!onNext) {\n return false;\n }\n\n if (!nextDisabled) {\n onNext(\n suppressPlayerControlsWakeAfterNavigation(getNavigationContext())\n );\n }\n\n return true;\n },\n nextSubtitle: () => {\n if (!subtitleJumpAvailability.next) {\n return true;\n }\n\n return jumpToSubtitleCue(\"next\");\n },\n previous: () => {\n if (!onPrev) {\n return false;\n }\n\n if (!prevDisabled) {\n onPrev(\n suppressPlayerControlsWakeAfterNavigation(getNavigationContext())\n );\n }\n\n return true;\n },\n previousSubtitle: () => {\n if (!subtitleJumpAvailability.previous) {\n return true;\n }\n\n return jumpToSubtitleCue(\"previous\");\n },\n subtitle: () => {\n if (!onSubtitleToggle) {\n return false;\n }\n\n onSubtitleToggle();\n return true;\n },\n togglePlayback: () => {\n togglePlayback();\n return true;\n },\n }),\n [\n getNavigationContext,\n jumpToSubtitleCue,\n nextDisabled,\n onFullscreen,\n onNext,\n onPrev,\n onSubtitleToggle,\n prevDisabled,\n subtitleJumpAvailability.next,\n subtitleJumpAvailability.previous,\n togglePlayback,\n ]\n );\n const keyboardShortcutHandlersRef = useRef(keyboardShortcutHandlers);\n\n useEffect(() => {\n keyboardShortcutHandlersRef.current = keyboardShortcutHandlers;\n }, [keyboardShortcutHandlers]);\n\n useEffect(() => {\n if (!shouldEnableKeyboardShortcuts || typeof document === \"undefined\") {\n return;\n }\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (!isActivePlayerKeyboardShortcutOwner(keyboardShortcutOwnerId)) {\n return;\n }\n\n const action = getPlayerKeyboardShortcutAction(event, readDirection());\n\n if (!action || shouldIgnorePlayerKeyboardShortcutEvent(event, action)) {\n return;\n }\n\n let handled = false;\n const handler = keyboardShortcutHandlersRef.current[action];\n\n handled = handler();\n\n if (!handled) {\n return;\n }\n\n event.preventDefault();\n };\n\n document.addEventListener(\"keydown\", handleKeyDown);\n\n return () => {\n document.removeEventListener(\"keydown\", handleKeyDown);\n };\n }, [keyboardShortcutOwnerId, readDirection, shouldEnableKeyboardShortcuts]);\n\n useEffect(() => {\n onPlaybackTimeChange?.(playbackTimeMsRef.current);\n }, [onPlaybackTimeChange]);\n\n return (\n <div\n {...props}\n dir={direction}\n lang={language}\n data-slide-player-shortcut-owner={keyboardShortcutOwnerId}\n className={cn(\"slide-player\", className)}\n onFocusCapture={handleRootFocusCapture}\n onPointerDown={handleRootPointerDown}\n >\n <audio\n ref={audioRef}\n preload=\"auto\"\n playsInline\n onLoadStart={handleAudioLoadStart}\n onLoadedMetadata={handleLoadedMetadata}\n onCanPlay={handleAudioCanPlay}\n onPlay={handleAudioPlay}\n onPause={handleAudioPause}\n onWaiting={handleAudioWaiting}\n onSeeking={handleAudioSeeking}\n onSeeked={handleAudioSeeking}\n onTimeUpdate={handleAudioTimeUpdate}\n onEnded={handleAudioEnded}\n onError={handleAudioError}\n />\n\n {showControls ? (\n <>\n <MobilePlayerSettingsSheet\n container={settingsPortalContainer}\n dir={direction ?? shortcutDirection}\n lang={portalLanguage}\n labels={{\n closeSettings: playerTexts.closeSettingsLabel,\n fullscreen: playerTexts.fullscreenLabel,\n nonFullscreen: playerTexts.nonFullscreenLabel,\n screen: playerTexts.screenLabel,\n screenMode: playerTexts.screenModeLabel,\n subtitle: playerTexts.subtitleLabel,\n subtitleToggle: playerTexts.subtitleToggleAriaLabel,\n title: playerTexts.settingsTitle,\n }}\n isSubtitleEnabled={isSubtitleEnabled}\n onClose={() => setIsMobileMoreOpen(false)}\n onOpenChange={setIsMobileMoreOpen}\n onSubtitleToggle={onSubtitleToggle ?? (() => {})}\n onViewModeChange={handleMobileViewModeChange}\n open={isMobileMoreOpen}\n viewMode={mobileViewMode}\n />\n\n <div\n className=\"slide-player__controls\"\n onPointerEnter={onControlsPointerEnter}\n onPointerLeave={onControlsPointerLeave}\n style={controlsStyle}\n >\n <div className=\"slide-player__group\">\n <button\n aria-expanded={isMobileMoreOpen}\n aria-haspopup=\"dialog\"\n aria-label={playerTexts.moreOptionsAriaLabel}\n className=\"slide-player__action slide-player__action--mobile-more\"\n onClick={() => {\n setIsMobileMoreOpen((prevOpen) => !prevOpen);\n }}\n type=\"button\"\n >\n <EllipsisVertical\n className=\"slide-player__icon\"\n strokeWidth={2.25}\n />\n </button>\n <button\n aria-label={playerTexts.volumeAriaLabel}\n className=\"hidden\"\n type=\"button\"\n >\n <Volume2 className=\"slide-player__icon\" strokeWidth={2.25} />\n </button>\n <button\n aria-label={toggleAriaLabel}\n aria-keyshortcuts={playbackShortcutMetadata.ariaKeyShortcuts}\n className=\"slide-player__toggle slide-player__toggle--playback\"\n onClick={() => {\n togglePlayback();\n }}\n title={playbackShortcutMetadata.title}\n type=\"button\"\n >\n {isTogglePlaying ? <PauseIcon /> : <PlayIcon />}\n </button>\n <button\n aria-keyshortcuts={previousShortcutMetadata.ariaKeyShortcuts}\n aria-label={playerTexts.previousLabel}\n className=\"slide-player__action slide-player__action--prev\"\n disabled={prevDisabled}\n onClick={() => {\n onPrev?.(getNavigationContext());\n }}\n title={previousShortcutMetadata.title}\n type=\"button\"\n >\n <SkipBack className=\"slide-player__icon\" strokeWidth={2.25} />\n </button>\n <button\n aria-keyshortcuts={nextShortcutMetadata.ariaKeyShortcuts}\n aria-label={playerTexts.nextLabel}\n className=\"slide-player__action slide-player__action--next\"\n disabled={nextDisabled}\n onClick={() => {\n onNext?.(getNavigationContext());\n }}\n title={nextShortcutMetadata.title}\n type=\"button\"\n >\n <SkipForward\n className=\"slide-player__icon\"\n strokeWidth={2.25}\n />\n </button>\n <button\n aria-keyshortcuts={\n previousSubtitleShortcutMetadata.ariaKeyShortcuts\n }\n aria-label={playerTexts.previousSubtitleLabel}\n className=\"slide-player__action slide-player__action--prev-subtitle\"\n disabled={!subtitleJumpAvailability.previous}\n onClick={() => {\n jumpToSubtitleCue(\"previous\");\n }}\n title={previousSubtitleShortcutMetadata.title}\n type=\"button\"\n >\n <Rewind className=\"slide-player__icon\" strokeWidth={2.25} />\n </button>\n <button\n aria-keyshortcuts={\n nextSubtitleShortcutMetadata.ariaKeyShortcuts\n }\n aria-label={playerTexts.nextSubtitleLabel}\n className=\"slide-player__action slide-player__action--next-subtitle\"\n disabled={!subtitleJumpAvailability.next}\n onClick={() => {\n jumpToSubtitleCue(\"next\");\n }}\n title={nextSubtitleShortcutMetadata.title}\n type=\"button\"\n >\n <FastForward\n className=\"slide-player__icon\"\n strokeWidth={2.25}\n />\n </button>\n <button\n aria-label={playerTexts.subtitleToggleAriaLabel}\n aria-keyshortcuts={subtitleShortcutMetadata.ariaKeyShortcuts}\n aria-pressed={isSubtitleEnabled}\n className=\"slide-player__action slide-player__action--subtitle\"\n onClick={onSubtitleToggle}\n title={subtitleShortcutMetadata.title}\n type=\"button\"\n >\n {isSubtitleEnabled ? (\n <Captions className=\"slide-player__icon\" strokeWidth={2.25} />\n ) : (\n <CaptionsOff\n className=\"slide-player__icon\"\n strokeWidth={2.25}\n />\n )}\n </button>\n {onFullscreen ? (\n <button\n aria-label={fullscreenAriaLabel}\n aria-keyshortcuts={\n fullscreenShortcutMetadata.ariaKeyShortcuts\n }\n className=\"slide-player__action slide-player__action--fullscreen\"\n onClick={onFullscreen}\n title={fullscreenShortcutMetadata.title}\n type=\"button\"\n >\n {isFullscreen ? (\n <ScanLine\n className=\"slide-player__icon\"\n strokeWidth={2.25}\n />\n ) : (\n <Maximize\n className=\"slide-player__icon\"\n strokeWidth={2.25}\n />\n )}\n </button>\n ) : null}\n </div>\n\n {customActionList.length > 0 ? (\n <>\n <div className=\"slide-player__separator\" />\n\n <div className=\"slide-player__group slide-player__group--custom-actions\">\n {customActionList.map((customAction, customActionIndex) => (\n <React.Fragment key={`custom-action-${customActionIndex}`}>\n {customAction}\n </React.Fragment>\n ))}\n </div>\n </>\n ) : null}\n </div>\n {slideProgress && slideProgress.totalSteps > 1 ? (\n <div\n aria-label={slideProgress.ariaLabel}\n aria-valuemax={slideProgress.totalSteps}\n aria-valuemin={1}\n aria-valuenow={Math.min(\n Math.max(slideProgress.currentIndex + 1, 1),\n slideProgress.totalSteps\n )}\n className=\"slide-player__slide-progress\"\n role=\"progressbar\"\n >\n {Array.from({ length: slideProgress.totalSteps }, (_, index) => (\n <span\n aria-hidden=\"true\"\n className=\"slide-player__slide-progress-segment\"\n data-state={\n index < slideProgress.currentIndex\n ? \"completed\"\n : index === slideProgress.currentIndex\n ? \"current\"\n : \"upcoming\"\n }\n key={index}\n />\n ))}\n </div>\n ) : null}\n </>\n ) : null}\n </div>\n );\n};\n\nconst MemoizedPlayer = memo(Player);\n\nMemoizedPlayer.displayName = \"Player\";\n\nexport default MemoizedPlayer;\n"],"names":["audioPreloadElementCache","preloadAudioUrl","url","audio","hasCurrentSubtitleCueTracksCache","audioList","cache","audioItem","index","subtitleCues","createSubtitleCueTracksCache","subtitleCueLists","PauseIcon","jsxs","jsx","PlayIcon","PLAYER_SHORTCUT_LABELS","SUBTITLE_JUMP_AVAILABILITY_UPDATE_INTERVAL_MS","PLAYBACK_RESTORE_WAIT_TIMEOUT_MS","getShortcutTitle","label","shortcut","Player","className","currentAudioIndex","defaultPlaying","isPlaybackPaused","isAutoAdvanceEnabled","useAutoAdvanceToggle","onLoadingChange","onPlaybackPreferenceChange","onPlaybackStarted","onPlaybackTimeChange","onPlaybackCheckpoint","playbackRestoreRequest","onPlaybackRestoreComplete","onSubtitleToggle","onPrev","onNext","onSubtitleJump","canJumpToSubtitleTarget","onFullscreen","isFullscreen","mobileViewMode","DEFAULT_MOBILE_VIEW_MODE","settingsPortalContainer","onMobileViewModeChange","onEnded","onAutoAdvanceToggle","_deprecatedOnInteractionToggle","_deprecatedHasInteraction","isInteractionOpen","isSubtitleEnabled","prevDisabled","nextDisabled","showControls","onControlsPointerEnter","onControlsPointerLeave","slideProgress","enableKeyboardShortcuts","subtitleSeekRequest","customActions","customActionContext","locale","texts","onFocusCapture","onPointerDown","props","direction","getMarkdownFlowDirection","language","getMarkdownFlowLanguage","localKeyboardShortcutOwnerId","useId","keyboardShortcutContext","useContext","PlayerKeyboardShortcutContext","audioRef","useRef","shortcutDirection","readDirection","useResolvedDirection","isRtlNavigation","portalLanguage","useDetachedLanguage","previousInteractionOpenRef","audioSrcRef","currentAudioKeyRef","currentSegmentIndexRef","waitingSegmentIndexRef","currentAudioRef","currentAudioSegmentsRef","playbackPreferenceRef","wasPlayingBeforeExternalPauseRef","isLoadingRef","isPausedByUserRef","activeSourceTypeRef","preferredSourceTypeRef","isWaitingForSegmentRef","pendingAutoPlayRef","pendingSeekTimeRef","isSwitchingSegmentRef","playbackAnimationFrameRef","playbackTimeMsRef","updateSubtitleJumpAvailabilityRef","lastSubtitleJumpAvailabilityTimeMsRef","lastSubtitleJumpTargetRef","lastSubtitleSeekRequestIdRef","lastPlaybackRestoreRequestIdRef","lastPlaybackCheckpointAtRef","hasCompletedCurrentAudioRef","isResettingAudioRef","onPlaybackCheckpointRef","getCurrentPlaybackTimeMsRef","subtitleCueTracksCacheRef","playbackAccessModeRef","isPlaying","setIsPlaying","useState","isMobileMoreOpen","setIsMobileMoreOpen","subtitleJumpAvailability","setSubtitleJumpAvailability","keyboardShortcutOwnerId","shouldEnableKeyboardShortcuts","currentAudio","currentAudioUrl","currentAudioSegmentList","currentAudioSegmentCount","currentAudioSegments","useMemo","getSortedAudioSegments","subtitleCueTracksCache","subtitleCueTracks","customActionList","toPlayerCustomActionList","mobileVisibleActionCount","controlsStyle","playerTexts","getSlidePlayerTexts","currentAudioKey","isTogglePlaying","toggleAriaLabel","fullscreenAriaLabel","getShortcutMetadata","useCallback","shortcutText","ariaKey","subtitleShortcutMetadata","previousShortcutMetadata","previousSubtitleShortcutMetadata","playbackShortcutMetadata","nextShortcutMetadata","nextSubtitleShortcutMetadata","fullscreenShortcutMetadata","activateKeyboardShortcutOwner","activatePlayerKeyboardShortcutOwner","handleRootPointerDown","event","handleRootFocusCapture","useEffect","currentUrl","nextUrl","updateLoading","loading","reason","updatePlaybackPreference","playing","getNavigationContext","shouldKeepPlayingAfterNavigation","isAutoplayBlockedError","error","canStartPlaybackAutomatically","getSegmentSrc","audioData","getWaitingSegmentSeekTime","waitingSegmentIndex","totalDurationMs","segment","getSegmentStartTimeMs","segmentIndex","canSeekToAudioPlaybackTimeMs","timeMs","isPlaybackTimeCoveredBySegments","getSubtitleJumpTarget","currentTimeMs","options","target","getSubtitleCueJumpTarget","updateSubtitleJumpAvailability","force","normalizedCurrentTimeMs","nextAvailability","previousAvailability","getCurrentPlaybackTimeMs","audioElement","publishPlaybackTime","nextPlaybackTimeMs","shouldClearSubtitleCueJumpTarget","syncPlaybackTime","emitPlaybackCheckpoint","isComplete","audioKey","now","stopPlaybackTimeLoop","startPlaybackTimeLoop","updateFrame","resetAudio","tryPlayCurrentAudio","_reason","playPromise","startSegmentPlayback","nextAudioSrc","nextSeekTimeSeconds","shouldAutoResume","hasNewSrc","seekUrlPlayback","audioUrl","targetTimeSeconds","seekToPlaybackTimeMs","targetTimeMs","shouldResumePlayback","segmentSeekTarget","resolveSegmentSeekTarget","restorePlaybackTimeMs","jumpToSubtitleCue","didSeek","didJump","suppressPlayerControlsWakeAfterNavigation","finishAudioItem","finishUrlAudioIfSeekedToEnd","hasReachedAudioEnd","handleSegmentEnded","nextSegmentIndex","segments","nextSegment","activeAudio","hasFinal","resolvedSourceType","resolveAudioPlaybackSourceType","nextSeekTime","targetAudio","timeoutId","handleAudioPlay","handleAudioPause","handleAudioCanPlay","handleLoadedMetadata","handleAudioTimeUpdate","handleAudioLoadStart","handleAudioWaiting","handleAudioSeeking","handleAudioEnded","shouldFinishAsUrl","hasNextSegment","isFinalSegment","isStreamingAudio","handleAudioError","handleMobileViewModeChange","nextViewMode","togglePlayback","nextAutoAdvanceEnabled","registerPlayerKeyboardShortcutOwner","keyboardShortcutHandlers","keyboardShortcutHandlersRef","handleKeyDown","isActivePlayerKeyboardShortcutOwner","action","getPlayerKeyboardShortcutAction","shouldIgnorePlayerKeyboardShortcutEvent","handled","handler","cn","Fragment","MobilePlayerSettingsSheet","prevOpen","EllipsisVertical","Volume2","SkipBack","SkipForward","Rewind","FastForward","Captions","CaptionsOff","ScanLine","Maximize","customAction","customActionIndex","React","_","MemoizedPlayer","memo"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Player.cjs","sources":["../../../src/components/Slide/Player.tsx"],"sourcesContent":["import React, {\n memo,\n useCallback,\n useContext,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport {\n Captions,\n CaptionsOff,\n EllipsisVertical,\n FastForward,\n Maximize,\n Rewind,\n ScanLine,\n SkipBack,\n SkipForward,\n Volume2,\n} from \"lucide-react\";\n\nimport {\n getMarkdownFlowDirection,\n getMarkdownFlowLanguage,\n type MarkdownFlowLocale,\n} from \"../../lib/locale\";\nimport { useDetachedLanguage } from \"../../lib/useDetachedLanguage\";\nimport { useResolvedDirection } from \"../../lib/useResolvedDirection\";\nimport { cn } from \"../../lib/utils\";\nimport MobilePlayerSettingsSheet from \"./MobilePlayerSettingsSheet\";\nimport { getSlidePlayerTexts, type SlidePlayerLocaleTexts } from \"./slideI18n\";\nimport type { SlideAudioItem } from \"./useSlide\";\nimport type {\n ElementSubtitleCue,\n SlidePlayerCustomActionContext,\n SlidePlayerCustomActions,\n} from \"./types\";\nimport {\n DEFAULT_MOBILE_VIEW_MODE,\n type MobileViewMode,\n} from \"./utils/mobileScreenMode\";\nimport { hasReachedAudioEnd } from \"./utils/audioCompletion\";\nimport { PlayerKeyboardShortcutContext } from \"./utils/playerKeyboardShortcutContext\";\nimport {\n activatePlayerKeyboardShortcutOwner,\n getPlayerKeyboardShortcutAction,\n isActivePlayerKeyboardShortcutOwner,\n registerPlayerKeyboardShortcutOwner,\n shouldIgnorePlayerKeyboardShortcutEvent,\n type PlayerKeyboardShortcutAction,\n} from \"./utils/playerKeyboardShortcuts\";\nimport {\n resolveAudioPlaybackSourceType,\n type AudioPlaybackSourceType,\n} from \"./utils/playbackSource\";\nimport { shouldKeepPlayingAfterNavigation } from \"./utils/playbackPreference\";\nimport { toPlayerCustomActionList } from \"./utils/playerCustomActions\";\nimport { suppressPlayerControlsWakeAfterNavigation } from \"./utils/playerNavigationContext\";\nimport {\n isPlaybackTimeCoveredBySegments,\n resolveSegmentSeekTarget,\n} from \"./utils/segmentSeek\";\nimport { getSortedAudioSegments } from \"./utils/audioSegments\";\nimport {\n getSubtitleCueJumpTarget,\n shouldClearSubtitleCueJumpTarget,\n type SubtitleCueJumpDirection,\n type SubtitleCueJumpTarget,\n type SubtitleCueJumpTrack,\n} from \"./utils/subtitleCue\";\nimport \"./player.css\";\n\nconst audioPreloadElementCache = new Map<string, HTMLAudioElement>();\n\n/**\n * Labels and accessibility text used by the slide player controls.\n *\n * Missing fields fall back to the selected `locale`; pass a `texts` object when\n * a consumer needs custom control labels or tooltip text.\n *\n * @example\n * ```tsx\n * <Player locale=\"zh-CN\" texts={{ playLabel: \"播放\", nextLabel: \"下一页\" }} />\n * ```\n */\nexport type SlidePlayerTexts = Partial<SlidePlayerLocaleTexts>;\n\nexport type SlidePlayerLoadingReason = \"loadingAudio\" | \"waitingForMoreAudio\";\n\nexport interface SlidePlayerPlaybackRestoreRequest {\n id: number | string;\n timeMs: number;\n}\n\nexport interface SlidePlayerPlaybackCheckpoint {\n /** Identifies the logical audio item that produced this checkpoint. */\n audioKey: string;\n isComplete: boolean;\n timeMs: number;\n}\n\nexport interface SlidePlayerProgress {\n ariaLabel: string;\n currentIndex: number;\n onNavigate?: (index: number) => void;\n totalSteps: number;\n}\n\nexport interface SlidePlayerNavigationContext {\n shouldContinuePlayback: boolean;\n /** Set false when navigation should not reveal hidden player controls. */\n shouldWakeControls?: boolean;\n}\n\nexport type SlidePlayerSubtitleJumpTarget = SubtitleCueJumpTarget;\n\nexport interface SlidePlayerSubtitleSeekRequest\n extends SlidePlayerSubtitleJumpTarget {\n id: number | string;\n}\n\nconst preloadAudioUrl = (url?: string) => {\n if (typeof window === \"undefined\" || !url) {\n return;\n }\n\n if (audioPreloadElementCache.has(url)) {\n return;\n }\n\n // Use a detached audio element so warm-up follows the same media loading\n // path as the visible player instead of relying on link preload hints.\n const audio = window.document.createElement(\"audio\");\n audio.preload = \"auto\";\n audio.setAttribute(\"playsinline\", \"true\");\n audio.src = url;\n audio.load();\n\n audioPreloadElementCache.set(url, audio);\n};\n\ntype SubtitleCueList = ElementSubtitleCue[] | undefined;\n\ninterface SubtitleCueTracksCache {\n audioList: SlideAudioItem[];\n subtitleCueLists: SubtitleCueList[];\n subtitleCueLengths: number[];\n tracks: SubtitleCueJumpTrack[];\n}\n\nconst hasCurrentSubtitleCueTracksCache = (\n audioList: SlideAudioItem[],\n cache: SubtitleCueTracksCache | null\n): cache is SubtitleCueTracksCache =>\n cache !== null &&\n cache.audioList === audioList &&\n cache.subtitleCueLists.length === audioList.length &&\n audioList.every((audioItem, index) => {\n const subtitleCues = audioItem.element?.subtitle_cues;\n\n return (\n cache.subtitleCueLists[index] === subtitleCues &&\n cache.subtitleCueLengths[index] === (subtitleCues?.length ?? 0)\n );\n });\n\nconst createSubtitleCueTracksCache = (\n audioList: SlideAudioItem[]\n): SubtitleCueTracksCache => {\n const subtitleCueLists = audioList.map(\n (audioItem) => audioItem.element?.subtitle_cues\n );\n\n return {\n audioList,\n subtitleCueLists,\n subtitleCueLengths: subtitleCueLists.map(\n (subtitleCues) => subtitleCues?.length ?? 0\n ),\n tracks: subtitleCueLists.map((subtitleCues) => ({\n subtitleCues: subtitleCues ?? [],\n })),\n };\n};\n\nexport type PlayerProps = Omit<React.ComponentProps<\"div\">, \"onEnded\"> & {\n audioList?: SlideAudioItem[];\n currentAudioIndex?: number;\n defaultPlaying?: boolean;\n isPlaybackPaused?: boolean;\n isAutoAdvanceEnabled?: boolean;\n useAutoAdvanceToggle?: boolean;\n onLoadingChange?: (state: {\n loading: boolean;\n reason: SlidePlayerLoadingReason | null;\n }) => void;\n onPlaybackPreferenceChange?: (playing: boolean) => void;\n onPlaybackStarted?: () => void;\n onPlaybackTimeChange?: (timeMs: number) => void;\n /** Emits durable checkpoint candidates at lifecycle boundaries, never per frame. */\n onPlaybackCheckpoint?: (checkpoint: SlidePlayerPlaybackCheckpoint) => void;\n /** Restores the current logical audio item and resumes normal autoplay. */\n playbackRestoreRequest?: SlidePlayerPlaybackRestoreRequest | null;\n /** Called after a restore request has been applied to the active audio item. */\n onPlaybackRestoreComplete?: (requestId: number | string) => void;\n onSubtitleToggle?: () => void;\n onPrev?: (context: SlidePlayerNavigationContext) => void;\n onNext?: (context: SlidePlayerNavigationContext) => void;\n /**\n * Handles subtitle jumps that target a different audio track.\n *\n * Return `true` when the parent accepted the jump; return `false` or `void`\n * when the player should treat the jump as rejected.\n */\n onSubtitleJump?: (\n target: SlidePlayerSubtitleJumpTarget,\n context: SlidePlayerNavigationContext\n ) => boolean | void;\n /** Returns whether a cross-audio subtitle jump target is currently reachable. */\n canJumpToSubtitleTarget?: (target: SlidePlayerSubtitleJumpTarget) => boolean;\n onFullscreen?: () => void;\n isFullscreen?: boolean;\n mobileViewMode?: MobileViewMode;\n settingsPortalContainer?: HTMLElement | null;\n onMobileViewModeChange?: (viewMode: MobileViewMode) => void;\n onEnded?: (audioIndex: number) => void;\n onAutoAdvanceToggle?: (enabled: boolean) => void;\n /** @deprecated Manual interaction toggling is no longer exposed by the player. */\n onInteractionToggle?: () => void;\n /** @deprecated Manual interaction toggling is no longer exposed by the player. */\n hasInteraction?: boolean;\n isInteractionOpen?: boolean;\n isSubtitleEnabled?: boolean;\n prevDisabled?: boolean;\n nextDisabled?: boolean;\n /** Shows or hides the visual controls without disabling audio, callbacks, or keyboard shortcuts. */\n showControls?: boolean;\n /** Fired when the pointer enters the controls container to pause auto-hide. */\n onControlsPointerEnter?: React.PointerEventHandler<HTMLDivElement>;\n /** Fired when the pointer leaves the controls container to resume auto-hide. */\n onControlsPointerLeave?: React.PointerEventHandler<HTMLDivElement>;\n /** Interactive navigation timeline for the generated slide sequence. */\n slideProgress?: SlidePlayerProgress | null;\n /**\n * Enables document-level keyboard shortcuts for existing player actions.\n *\n * Defaults to `true`. Set to `false` when the page should not advertise or\n * handle player shortcuts for this standalone player instance.\n *\n * @example\n * ```tsx\n * <Player enableKeyboardShortcuts={false} />\n * ```\n */\n enableKeyboardShortcuts?: boolean;\n /** Requests a subtitle seek after the parent moves to the target audio track. */\n subtitleSeekRequest?: SlidePlayerSubtitleSeekRequest | null;\n customActions?: SlidePlayerCustomActions;\n customActionContext?: SlidePlayerCustomActionContext;\n /** Locale used for built-in control labels when `texts` does not provide them. */\n locale?: MarkdownFlowLocale;\n texts?: SlidePlayerTexts;\n};\n\nconst PauseIcon = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"34\"\n height=\"34\"\n viewBox=\"0 0 34 34\"\n fill=\"none\"\n >\n <path\n d=\"M16.6667 33.3333C25.8714 33.3333 33.3333 25.8714 33.3333 16.6667C33.3333 7.46192 25.8714 0 16.6667 0C7.46192 0 0 7.46192 0 16.6667C0 25.8714 7.46192 33.3333 16.6667 33.3333Z\"\n fill=\"#0A0A0A\"\n />\n <path d=\"M12 10H16V24H12V10ZM18 10H22V24H18V10Z\" fill=\"white\" />\n </svg>\n);\n\nconst PlayIcon = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"34\"\n height=\"34\"\n viewBox=\"0 0 34 34\"\n fill=\"none\"\n >\n <path\n d=\"M16.6667 33.3333C25.8714 33.3333 33.3333 25.8714 33.3333 16.6667C33.3333 7.46192 25.8714 0 16.6667 0C7.46192 0 0 7.46192 0 16.6667C0 25.8714 7.46192 33.3333 16.6667 33.3333Z\"\n fill=\"#0A0A0A\"\n />\n <path d=\"M13.3333 10L23.3333 16.6667L13.3333 23.3333V10Z\" fill=\"white\" />\n </svg>\n);\n\nconst PLAYER_SHORTCUT_LABELS = {\n fullscreen: \"F\",\n next: \"→\",\n nextSubtitle: \"Shift+→\",\n previous: \"←\",\n previousSubtitle: \"Shift+←\",\n subtitle: \"C\",\n} as const;\n\nconst SUBTITLE_JUMP_AVAILABILITY_UPDATE_INTERVAL_MS = 250;\nconst PLAYBACK_RESTORE_WAIT_TIMEOUT_MS = 15_000;\n\nconst getShortcutTitle = (label: string | undefined, shortcut: string) =>\n label ? `${label} (${shortcut})` : shortcut;\n\nconst Player = ({\n audioList = [],\n className,\n currentAudioIndex = -1,\n defaultPlaying = true,\n isPlaybackPaused = false,\n isAutoAdvanceEnabled = true,\n useAutoAdvanceToggle = false,\n onLoadingChange,\n onPlaybackPreferenceChange,\n onPlaybackStarted,\n onPlaybackTimeChange,\n onPlaybackCheckpoint,\n playbackRestoreRequest = null,\n onPlaybackRestoreComplete,\n onSubtitleToggle,\n onPrev,\n onNext,\n onSubtitleJump,\n canJumpToSubtitleTarget,\n onFullscreen,\n isFullscreen = false,\n mobileViewMode = DEFAULT_MOBILE_VIEW_MODE,\n settingsPortalContainer,\n onMobileViewModeChange,\n onEnded,\n onAutoAdvanceToggle,\n onInteractionToggle: _deprecatedOnInteractionToggle,\n hasInteraction: _deprecatedHasInteraction,\n isInteractionOpen = false,\n isSubtitleEnabled = true,\n prevDisabled = false,\n nextDisabled = false,\n showControls = true,\n onControlsPointerEnter,\n onControlsPointerLeave,\n slideProgress = null,\n enableKeyboardShortcuts = true,\n subtitleSeekRequest = null,\n customActions,\n customActionContext,\n locale,\n texts,\n onFocusCapture,\n onPointerDown,\n ...props\n}: PlayerProps) => {\n const direction = props.dir ?? getMarkdownFlowDirection(locale);\n const language = props.lang ?? getMarkdownFlowLanguage(locale);\n const localKeyboardShortcutOwnerId = useId();\n const keyboardShortcutContext = useContext(PlayerKeyboardShortcutContext);\n const audioRef = useRef<HTMLAudioElement | null>(null);\n const { resolvedDirection: shortcutDirection, readDirection } =\n useResolvedDirection(audioRef, direction);\n const isRtlNavigation = shortcutDirection === \"rtl\";\n const portalLanguage = useDetachedLanguage(audioRef, language);\n const previousInteractionOpenRef = useRef(isInteractionOpen);\n const audioSrcRef = useRef<string | null>(null);\n const currentAudioKeyRef = useRef<string | null>(null);\n const currentSegmentIndexRef = useRef(0);\n const waitingSegmentIndexRef = useRef<number | null>(null);\n const currentAudioRef = useRef<SlideAudioItem | undefined>(undefined);\n const currentAudioSegmentsRef = useRef<\n NonNullable<SlideAudioItem[\"audioSegments\"]>\n >([]);\n const playbackPreferenceRef = useRef(\n useAutoAdvanceToggle ? isAutoAdvanceEnabled : defaultPlaying\n );\n const wasPlayingBeforeExternalPauseRef = useRef(false);\n const isLoadingRef = useRef(false);\n const isPausedByUserRef = useRef(false);\n const activeSourceTypeRef = useRef<\"url\" | \"segment\" | null>(null);\n const preferredSourceTypeRef = useRef<AudioPlaybackSourceType | null>(null);\n const isWaitingForSegmentRef = useRef(false);\n const pendingAutoPlayRef = useRef(false);\n const pendingSeekTimeRef = useRef<number | null>(null);\n const isSwitchingSegmentRef = useRef(false);\n const playbackAnimationFrameRef = useRef<number | null>(null);\n const playbackTimeMsRef = useRef(0);\n const updateSubtitleJumpAvailabilityRef = useRef<\n (currentTimeMs: number) => void\n >(() => {});\n const lastSubtitleJumpAvailabilityTimeMsRef = useRef<number | null>(null);\n const lastSubtitleJumpTargetRef =\n useRef<SlidePlayerSubtitleJumpTarget | null>(null);\n const lastSubtitleSeekRequestIdRef = useRef<number | string | null>(null);\n const lastPlaybackRestoreRequestIdRef = useRef<number | string | null>(null);\n const lastPlaybackCheckpointAtRef = useRef(0);\n const hasCompletedCurrentAudioRef = useRef(false);\n const isResettingAudioRef = useRef(false);\n const onPlaybackCheckpointRef = useRef(onPlaybackCheckpoint);\n const getCurrentPlaybackTimeMsRef = useRef<() => number>(() => 0);\n const subtitleCueTracksCacheRef = useRef<SubtitleCueTracksCache | null>(null);\n const playbackAccessModeRef = useRef<\n \"unknown\" | \"auto\" | \"manual\" | \"blocked\"\n >(\"unknown\");\n const [isPlaying, setIsPlaying] = useState(defaultPlaying);\n const [isMobileMoreOpen, setIsMobileMoreOpen] = useState(false);\n const [subtitleJumpAvailability, setSubtitleJumpAvailability] = useState({\n next: false,\n previous: false,\n });\n const keyboardShortcutOwnerId =\n keyboardShortcutContext?.ownerId ?? localKeyboardShortcutOwnerId;\n const shouldEnableKeyboardShortcuts =\n enableKeyboardShortcuts && (keyboardShortcutContext?.enabled ?? true);\n const currentAudio =\n currentAudioIndex >= 0 ? audioList[currentAudioIndex] : undefined;\n const currentAudioUrl = currentAudio?.audioUrl;\n const currentAudioSegmentList = currentAudio?.audioSegments;\n const currentAudioSegmentCount = currentAudioSegmentList?.length ?? 0;\n const currentAudioSegments = useMemo(\n () => getSortedAudioSegments(currentAudio),\n [currentAudio, currentAudioSegmentCount, currentAudioSegmentList]\n );\n let subtitleCueTracksCache = subtitleCueTracksCacheRef.current;\n\n if (!hasCurrentSubtitleCueTracksCache(audioList, subtitleCueTracksCache)) {\n subtitleCueTracksCache = createSubtitleCueTracksCache(audioList);\n subtitleCueTracksCacheRef.current = subtitleCueTracksCache;\n }\n\n const subtitleCueTracks = subtitleCueTracksCache.tracks;\n const customActionList = useMemo(\n () => toPlayerCustomActionList(customActions, customActionContext),\n [customActionContext, customActions]\n );\n const mobileVisibleActionCount = customActionList.length + 6;\n const controlsStyle = useMemo(\n () =>\n ({\n \"--slide-player-mobile-control-count\": String(mobileVisibleActionCount),\n }) as React.CSSProperties,\n [mobileVisibleActionCount]\n );\n const playerTexts = useMemo(\n () => ({\n ...getSlidePlayerTexts(locale),\n ...texts,\n }),\n [locale, texts]\n );\n const currentAudioKey = useMemo(() => {\n if (!currentAudio) {\n return \"none\";\n }\n\n return (\n currentAudio.audioKey ??\n `${String(currentAudio.sequenceNumber ?? \"none\")}:${String(currentAudio.audioUrl ?? \"\")}`\n );\n }, [currentAudio]);\n const isTogglePlaying = useAutoAdvanceToggle\n ? isAutoAdvanceEnabled\n : isPlaying;\n const toggleAriaLabel = useAutoAdvanceToggle\n ? isAutoAdvanceEnabled\n ? playerTexts.pauseAutoplayLabel\n : playerTexts.playAutoplayLabel\n : isPlaying\n ? playerTexts.pauseLabel\n : playerTexts.playLabel;\n const fullscreenAriaLabel = isFullscreen\n ? playerTexts.exitFullscreenLabel\n : playerTexts.enterFullscreenLabel;\n const getShortcutMetadata = useCallback(\n (label: string | undefined, shortcutText: string, ariaKey: string) => ({\n ariaKeyShortcuts: shouldEnableKeyboardShortcuts ? ariaKey : undefined,\n title: shouldEnableKeyboardShortcuts\n ? getShortcutTitle(label, shortcutText)\n : label,\n }),\n [shouldEnableKeyboardShortcuts]\n );\n const subtitleShortcutMetadata = getShortcutMetadata(\n playerTexts.subtitleToggleAriaLabel,\n PLAYER_SHORTCUT_LABELS.subtitle,\n \"c\"\n );\n const previousShortcutMetadata = getShortcutMetadata(\n playerTexts.previousLabel,\n isRtlNavigation\n ? PLAYER_SHORTCUT_LABELS.next\n : PLAYER_SHORTCUT_LABELS.previous,\n isRtlNavigation ? \"ArrowRight\" : \"ArrowLeft\"\n );\n const previousSubtitleShortcutMetadata = getShortcutMetadata(\n playerTexts.previousSubtitleLabel,\n PLAYER_SHORTCUT_LABELS.previousSubtitle,\n \"Shift+ArrowLeft\"\n );\n const playbackShortcutMetadata = getShortcutMetadata(\n toggleAriaLabel,\n playerTexts.playbackShortcutLabel,\n \"Space\"\n );\n const nextShortcutMetadata = getShortcutMetadata(\n playerTexts.nextLabel,\n isRtlNavigation\n ? PLAYER_SHORTCUT_LABELS.previous\n : PLAYER_SHORTCUT_LABELS.next,\n isRtlNavigation ? \"ArrowLeft\" : \"ArrowRight\"\n );\n const nextSubtitleShortcutMetadata = getShortcutMetadata(\n playerTexts.nextSubtitleLabel,\n PLAYER_SHORTCUT_LABELS.nextSubtitle,\n \"Shift+ArrowRight\"\n );\n const fullscreenShortcutMetadata = getShortcutMetadata(\n fullscreenAriaLabel,\n PLAYER_SHORTCUT_LABELS.fullscreen,\n \"f\"\n );\n const activateKeyboardShortcutOwner = useCallback(() => {\n if (!shouldEnableKeyboardShortcuts) {\n return;\n }\n\n activatePlayerKeyboardShortcutOwner(keyboardShortcutOwnerId);\n }, [keyboardShortcutOwnerId, shouldEnableKeyboardShortcuts]);\n\n const handleRootPointerDown = useCallback(\n (event: React.PointerEvent<HTMLDivElement>) => {\n activateKeyboardShortcutOwner();\n onPointerDown?.(event);\n },\n [activateKeyboardShortcutOwner, onPointerDown]\n );\n\n const handleRootFocusCapture = useCallback(\n (event: React.FocusEvent<HTMLDivElement>) => {\n activateKeyboardShortcutOwner();\n onFocusCapture?.(event);\n },\n [activateKeyboardShortcutOwner, onFocusCapture]\n );\n\n useEffect(() => {\n currentAudioRef.current = currentAudio;\n }, [currentAudio]);\n\n useEffect(() => {\n playbackPreferenceRef.current = useAutoAdvanceToggle\n ? isAutoAdvanceEnabled\n : defaultPlaying;\n }, [defaultPlaying, isAutoAdvanceEnabled, useAutoAdvanceToggle]);\n\n useEffect(() => {\n if (showControls) {\n return;\n }\n\n setIsMobileMoreOpen(false);\n }, [showControls]);\n\n useEffect(() => {\n if (!previousInteractionOpenRef.current && isInteractionOpen) {\n setIsMobileMoreOpen(false);\n }\n\n previousInteractionOpenRef.current = isInteractionOpen;\n }, [isInteractionOpen]);\n\n useEffect(() => {\n currentAudioSegmentsRef.current = currentAudioSegments;\n }, [currentAudioSegments]);\n\n useEffect(() => {\n const currentUrl = currentAudio?.audioUrl;\n const nextUrl =\n currentAudioIndex >= 0\n ? audioList[currentAudioIndex + 1]?.audioUrl\n : undefined;\n\n preloadAudioUrl(currentUrl);\n preloadAudioUrl(nextUrl);\n }, [audioList, currentAudio?.audioUrl, currentAudioIndex]);\n\n const updateLoading = useCallback(\n (loading: boolean, reason: SlidePlayerLoadingReason | null = null) => {\n if (isLoadingRef.current === loading && (!loading || reason === null)) {\n return;\n }\n\n isLoadingRef.current = loading;\n onLoadingChange?.({\n loading,\n reason: loading ? reason : null,\n });\n },\n [onLoadingChange]\n );\n\n const updatePlaybackPreference = useCallback(\n (playing: boolean) => {\n playbackPreferenceRef.current = playing;\n onPlaybackPreferenceChange?.(playing);\n },\n [onPlaybackPreferenceChange]\n );\n\n const getNavigationContext = useCallback((): SlidePlayerNavigationContext => {\n if (useAutoAdvanceToggle) {\n return {\n shouldContinuePlayback: playbackPreferenceRef.current,\n };\n }\n\n return {\n shouldContinuePlayback: shouldKeepPlayingAfterNavigation({\n defaultPlaying: playbackPreferenceRef.current,\n isPausedByUser: isPausedByUserRef.current,\n }),\n };\n }, [useAutoAdvanceToggle]);\n\n const isAutoplayBlockedError = useCallback((error: unknown) => {\n if (!(error instanceof DOMException)) {\n return false;\n }\n\n return error.name === \"NotAllowedError\" || error.name === \"SecurityError\";\n }, []);\n\n const canStartPlaybackAutomatically = useCallback(() => {\n return (\n defaultPlaying &&\n !isPlaybackPaused &&\n !isPausedByUserRef.current &&\n playbackAccessModeRef.current !== \"blocked\"\n );\n }, [defaultPlaying, isPlaybackPaused]);\n\n const getSegmentSrc = useCallback((audioData: string) => {\n if (!audioData) {\n return \"\";\n }\n\n if (audioData.startsWith(\"data:\")) {\n return audioData;\n }\n\n return `data:audio/mpeg;base64,${audioData}`;\n }, []);\n\n const getWaitingSegmentSeekTime = useCallback(() => {\n const waitingSegmentIndex = waitingSegmentIndexRef.current;\n\n if (waitingSegmentIndex == null || waitingSegmentIndex <= 0) {\n return 0;\n }\n\n return (\n currentAudioSegmentsRef.current\n .slice(0, waitingSegmentIndex)\n .reduce(\n (totalDurationMs, segment) =>\n totalDurationMs + Math.max(Number(segment.duration_ms ?? 0), 0),\n 0\n ) / 1000\n );\n }, []);\n\n const getSegmentStartTimeMs = useCallback((segmentIndex: number) => {\n if (segmentIndex <= 0) {\n return 0;\n }\n\n return currentAudioSegmentsRef.current\n .slice(0, segmentIndex)\n .reduce(\n (totalDurationMs, segment) =>\n totalDurationMs + Math.max(Number(segment.duration_ms ?? 0), 0),\n 0\n );\n }, []);\n\n const canSeekToAudioPlaybackTimeMs = useCallback(\n (audioItem: SlideAudioItem | undefined, timeMs: number) => {\n if (!audioItem || isPlaybackPaused) {\n return false;\n }\n\n if (audioItem.audioUrl) {\n return true;\n }\n\n return isPlaybackTimeCoveredBySegments(\n getSortedAudioSegments(audioItem),\n timeMs\n );\n },\n [isPlaybackPaused]\n );\n\n const getSubtitleJumpTarget = useCallback(\n (\n direction: SubtitleCueJumpDirection,\n currentTimeMs: number,\n options: {\n excludeTarget?: SlidePlayerSubtitleJumpTarget | null;\n } = {}\n ) => {\n const target = getSubtitleCueJumpTarget({\n currentAudioIndex,\n currentTimeMs,\n direction,\n excludeTarget: options.excludeTarget,\n tracks: subtitleCueTracks,\n });\n\n if (\n !target ||\n !canSeekToAudioPlaybackTimeMs(\n audioList[target.audioIndex],\n target.timeMs\n )\n ) {\n return null;\n }\n\n if (target.audioIndex !== currentAudioIndex) {\n if (!onSubtitleJump) {\n return null;\n }\n\n if (canJumpToSubtitleTarget && !canJumpToSubtitleTarget(target)) {\n return null;\n }\n }\n\n return target;\n },\n [\n audioList,\n canJumpToSubtitleTarget,\n canSeekToAudioPlaybackTimeMs,\n currentAudioIndex,\n onSubtitleJump,\n subtitleCueTracks,\n ]\n );\n\n const updateSubtitleJumpAvailability = useCallback(\n (currentTimeMs: number, force = false) => {\n const normalizedCurrentTimeMs = Math.max(Number(currentTimeMs), 0);\n\n if (\n !force &&\n lastSubtitleJumpAvailabilityTimeMsRef.current !== null &&\n Math.abs(\n normalizedCurrentTimeMs -\n lastSubtitleJumpAvailabilityTimeMsRef.current\n ) < SUBTITLE_JUMP_AVAILABILITY_UPDATE_INTERVAL_MS\n ) {\n return;\n }\n\n lastSubtitleJumpAvailabilityTimeMsRef.current = normalizedCurrentTimeMs;\n\n const nextAvailability = {\n previous:\n getSubtitleJumpTarget(\"previous\", normalizedCurrentTimeMs) !== null,\n next: getSubtitleJumpTarget(\"next\", normalizedCurrentTimeMs) !== null,\n };\n\n setSubtitleJumpAvailability((previousAvailability) => {\n if (\n previousAvailability.previous === nextAvailability.previous &&\n previousAvailability.next === nextAvailability.next\n ) {\n return previousAvailability;\n }\n\n return nextAvailability;\n });\n },\n [getSubtitleJumpTarget]\n );\n\n useEffect(() => {\n updateSubtitleJumpAvailabilityRef.current = updateSubtitleJumpAvailability;\n updateSubtitleJumpAvailability(playbackTimeMsRef.current, true);\n }, [updateSubtitleJumpAvailability]);\n\n const getCurrentPlaybackTimeMs = useCallback(() => {\n const audioElement = audioRef.current;\n\n if (!audioElement) {\n return waitingSegmentIndexRef.current != null\n ? getSegmentStartTimeMs(waitingSegmentIndexRef.current)\n : 0;\n }\n\n if (activeSourceTypeRef.current === \"segment\") {\n return (\n getSegmentStartTimeMs(currentSegmentIndexRef.current) +\n Math.max(audioElement.currentTime, 0) * 1000\n );\n }\n\n if (pendingSeekTimeRef.current !== null && audioElement.readyState === 0) {\n return pendingSeekTimeRef.current * 1000;\n }\n\n return Math.max(audioElement.currentTime, 0) * 1000;\n }, [getSegmentStartTimeMs]);\n\n useEffect(() => {\n onPlaybackCheckpointRef.current = onPlaybackCheckpoint;\n }, [onPlaybackCheckpoint]);\n\n useEffect(() => {\n getCurrentPlaybackTimeMsRef.current = getCurrentPlaybackTimeMs;\n }, [getCurrentPlaybackTimeMs]);\n\n const publishPlaybackTime = useCallback(\n (timeMs: number) => {\n const nextPlaybackTimeMs = Math.max(timeMs, 0);\n\n if (playbackTimeMsRef.current === nextPlaybackTimeMs) {\n return;\n }\n\n playbackTimeMsRef.current = nextPlaybackTimeMs;\n if (\n shouldClearSubtitleCueJumpTarget({\n currentAudioIndex,\n currentTimeMs: nextPlaybackTimeMs,\n target: lastSubtitleJumpTargetRef.current,\n })\n ) {\n lastSubtitleJumpTargetRef.current = null;\n }\n\n onPlaybackTimeChange?.(nextPlaybackTimeMs);\n updateSubtitleJumpAvailabilityRef.current(nextPlaybackTimeMs);\n },\n [currentAudioIndex, onPlaybackTimeChange]\n );\n\n const syncPlaybackTime = useCallback(() => {\n publishPlaybackTime(getCurrentPlaybackTimeMs());\n }, [getCurrentPlaybackTimeMs, publishPlaybackTime]);\n\n const emitPlaybackCheckpoint = useCallback(\n (force = false, isComplete = false) => {\n const audioKey = currentAudioKeyRef.current;\n\n if (!onPlaybackCheckpoint || !audioKey) {\n return;\n }\n\n const now = Date.now();\n if (!force && now - lastPlaybackCheckpointAtRef.current < 5_000) {\n return;\n }\n\n lastPlaybackCheckpointAtRef.current = now;\n hasCompletedCurrentAudioRef.current = isComplete;\n onPlaybackCheckpoint({\n audioKey,\n isComplete,\n timeMs: getCurrentPlaybackTimeMs(),\n });\n },\n [getCurrentPlaybackTimeMs, onPlaybackCheckpoint]\n );\n\n useEffect(\n () => () => {\n if (hasCompletedCurrentAudioRef.current) {\n return;\n }\n\n onPlaybackCheckpointRef.current?.({\n audioKey: currentAudioKeyRef.current ?? \"none\",\n isComplete: false,\n timeMs: getCurrentPlaybackTimeMsRef.current(),\n });\n },\n []\n );\n\n useEffect(() => {\n hasCompletedCurrentAudioRef.current = false;\n }, [currentAudioIndex]);\n\n const stopPlaybackTimeLoop = useCallback(() => {\n if (\n typeof window === \"undefined\" ||\n playbackAnimationFrameRef.current === null\n ) {\n return;\n }\n\n window.cancelAnimationFrame(playbackAnimationFrameRef.current);\n playbackAnimationFrameRef.current = null;\n }, []);\n\n const startPlaybackTimeLoop = useCallback(() => {\n if (\n typeof window === \"undefined\" ||\n playbackAnimationFrameRef.current !== null\n ) {\n return;\n }\n\n const updateFrame = () => {\n syncPlaybackTime();\n\n const audioElement = audioRef.current;\n\n if (!audioElement || audioElement.paused || audioElement.ended) {\n playbackAnimationFrameRef.current = null;\n return;\n }\n\n playbackAnimationFrameRef.current =\n window.requestAnimationFrame(updateFrame);\n };\n\n playbackAnimationFrameRef.current =\n window.requestAnimationFrame(updateFrame);\n }, [syncPlaybackTime]);\n\n const resetAudio = useCallback(() => {\n const audioElement = audioRef.current;\n\n if (!audioElement) {\n return;\n }\n\n stopPlaybackTimeLoop();\n pendingAutoPlayRef.current = false;\n isPausedByUserRef.current = false;\n wasPlayingBeforeExternalPauseRef.current = false;\n activeSourceTypeRef.current = null;\n pendingSeekTimeRef.current = null;\n isWaitingForSegmentRef.current = false;\n isSwitchingSegmentRef.current = false;\n preferredSourceTypeRef.current = null;\n audioElement.pause();\n audioElement.removeAttribute(\"src\");\n audioElement.load();\n audioSrcRef.current = null;\n currentSegmentIndexRef.current = 0;\n waitingSegmentIndexRef.current = null;\n publishPlaybackTime(0);\n setIsPlaying(false);\n updateLoading(false);\n }, [publishPlaybackTime, stopPlaybackTimeLoop, updateLoading]);\n\n const tryPlayCurrentAudio = useCallback(\n (_reason: string) => {\n const audioElement = audioRef.current;\n\n if (!audioElement) {\n return false;\n }\n\n const playPromise = audioElement.play();\n\n if (playPromise && typeof playPromise.then === \"function\") {\n void playPromise\n .then(() => {\n if (playbackAccessModeRef.current === \"unknown\") {\n playbackAccessModeRef.current = \"auto\";\n }\n\n pendingAutoPlayRef.current = false;\n isSwitchingSegmentRef.current = false;\n })\n .catch((error: unknown) => {\n if (\n playbackAccessModeRef.current === \"unknown\" &&\n isAutoplayBlockedError(error)\n ) {\n // Lock autoplay after the first browser rejection.\n playbackAccessModeRef.current = \"blocked\";\n pendingAutoPlayRef.current = false;\n updateLoading(false);\n }\n\n isSwitchingSegmentRef.current = false;\n setIsPlaying(false);\n });\n }\n\n return true;\n },\n [isAutoplayBlockedError, updateLoading]\n );\n\n const startSegmentPlayback = useCallback(\n (\n segmentIndex: number,\n _reason: string,\n options: {\n seekTimeSeconds?: number;\n shouldResume?: boolean;\n } = {}\n ) => {\n const audioElement = audioRef.current;\n const segment = currentAudioSegmentsRef.current[segmentIndex];\n\n if (!audioElement || !segment) {\n return false;\n }\n\n const nextAudioSrc = getSegmentSrc(segment.audio_data);\n const nextSeekTimeSeconds = Math.max(\n Number(options.seekTimeSeconds ?? 0),\n 0\n );\n\n currentSegmentIndexRef.current = segmentIndex;\n waitingSegmentIndexRef.current = null;\n isWaitingForSegmentRef.current = false;\n isSwitchingSegmentRef.current = true;\n preferredSourceTypeRef.current = \"segment\";\n publishPlaybackTime(\n getSegmentStartTimeMs(segmentIndex) + nextSeekTimeSeconds * 1000\n );\n const shouldAutoResume =\n options.shouldResume ?? canStartPlaybackAutomatically();\n\n pendingAutoPlayRef.current = shouldAutoResume;\n updateLoading(false);\n\n const hasNewSrc = audioSrcRef.current !== nextAudioSrc;\n\n activeSourceTypeRef.current = \"segment\";\n\n if (hasNewSrc) {\n audioElement.pause();\n audioElement.removeAttribute(\"src\");\n audioElement.load();\n audioSrcRef.current = nextAudioSrc;\n audioElement.src = nextAudioSrc;\n audioElement.load();\n }\n\n pendingSeekTimeRef.current = nextSeekTimeSeconds;\n\n if (audioElement.readyState > 0) {\n audioElement.currentTime = nextSeekTimeSeconds;\n pendingSeekTimeRef.current = null;\n }\n\n if (!shouldAutoResume) {\n pendingAutoPlayRef.current = false;\n isSwitchingSegmentRef.current = false;\n audioElement.pause();\n setIsPlaying(false);\n return true;\n }\n\n return tryPlayCurrentAudio(`start-segment:${_reason}`);\n },\n [\n canStartPlaybackAutomatically,\n getSegmentSrc,\n getSegmentStartTimeMs,\n publishPlaybackTime,\n tryPlayCurrentAudio,\n updateLoading,\n ]\n );\n\n const seekUrlPlayback = useCallback(\n (audioUrl: string, timeMs: number) => {\n const audioElement = audioRef.current;\n\n if (!audioElement) {\n return false;\n }\n\n const targetTimeSeconds = Math.max(Number(timeMs), 0) / 1000;\n if (audioSrcRef.current !== audioUrl) {\n audioElement.pause();\n audioElement.removeAttribute(\"src\");\n audioElement.load();\n audioSrcRef.current = audioUrl;\n activeSourceTypeRef.current = \"url\";\n preferredSourceTypeRef.current = \"url\";\n audioElement.src = audioUrl;\n audioElement.load();\n }\n\n pendingSeekTimeRef.current = targetTimeSeconds;\n publishPlaybackTime(targetTimeSeconds * 1000);\n if (audioElement.readyState > 0) {\n audioElement.currentTime = targetTimeSeconds;\n pendingSeekTimeRef.current = null;\n }\n\n return true;\n },\n [publishPlaybackTime]\n );\n\n const seekToPlaybackTimeMs = useCallback(\n (timeMs: number) => {\n const audioElement = audioRef.current;\n\n if (!audioElement || !currentAudio || isPlaybackPaused) {\n return false;\n }\n\n const targetTimeMs = Math.max(Number(timeMs), 0);\n const shouldResumePlayback =\n (!audioElement.paused && !audioElement.ended) ||\n pendingAutoPlayRef.current ||\n isSwitchingSegmentRef.current ||\n (waitingSegmentIndexRef.current !== null &&\n playbackPreferenceRef.current &&\n !isPausedByUserRef.current);\n const segmentSeekTarget = isPlaybackTimeCoveredBySegments(\n currentAudioSegmentsRef.current,\n targetTimeMs\n )\n ? resolveSegmentSeekTarget(\n currentAudioSegmentsRef.current,\n targetTimeMs\n )\n : null;\n\n lastSubtitleJumpAvailabilityTimeMsRef.current = null;\n stopPlaybackTimeLoop();\n pendingAutoPlayRef.current = shouldResumePlayback;\n updateLoading(false);\n\n if (shouldResumePlayback) {\n playbackAccessModeRef.current = \"manual\";\n isPausedByUserRef.current = false;\n updatePlaybackPreference(true);\n }\n\n if (\n segmentSeekTarget &&\n (activeSourceTypeRef.current === \"segment\" || !currentAudioUrl)\n ) {\n return startSegmentPlayback(\n segmentSeekTarget.segmentIndex,\n \"subtitle-seek-segment\",\n {\n seekTimeSeconds: segmentSeekTarget.segmentTimeSeconds,\n shouldResume: shouldResumePlayback,\n }\n );\n }\n\n if (currentAudioUrl && seekUrlPlayback(currentAudioUrl, targetTimeMs)) {\n if (!shouldResumePlayback) {\n pendingAutoPlayRef.current = false;\n audioElement.pause();\n setIsPlaying(false);\n return true;\n }\n\n return tryPlayCurrentAudio(\"subtitle-seek-url\");\n }\n\n return false;\n },\n [\n currentAudio,\n currentAudioUrl,\n isPlaybackPaused,\n seekUrlPlayback,\n startSegmentPlayback,\n stopPlaybackTimeLoop,\n tryPlayCurrentAudio,\n updateLoading,\n updatePlaybackPreference,\n ]\n );\n\n const restorePlaybackTimeMs = useCallback(\n (timeMs: number) => {\n const audioElement = audioRef.current;\n\n if (!audioElement || !currentAudio) {\n return false;\n }\n\n const targetTimeMs = Math.max(Number(timeMs), 0);\n const segmentSeekTarget = isPlaybackTimeCoveredBySegments(\n currentAudioSegmentsRef.current,\n targetTimeMs\n )\n ? resolveSegmentSeekTarget(\n currentAudioSegmentsRef.current,\n targetTimeMs\n )\n : null;\n\n pendingAutoPlayRef.current = true;\n updateLoading(false);\n\n if (\n segmentSeekTarget &&\n (activeSourceTypeRef.current === \"segment\" || !currentAudioUrl)\n ) {\n return startSegmentPlayback(segmentSeekTarget.segmentIndex, \"restore\", {\n seekTimeSeconds: segmentSeekTarget.segmentTimeSeconds,\n shouldResume: true,\n });\n }\n\n if (!currentAudioUrl || !seekUrlPlayback(currentAudioUrl, targetTimeMs)) {\n return false;\n }\n\n tryPlayCurrentAudio(\"restore\");\n return true;\n },\n [\n currentAudio,\n currentAudioUrl,\n seekUrlPlayback,\n startSegmentPlayback,\n tryPlayCurrentAudio,\n updateLoading,\n ]\n );\n\n const jumpToSubtitleCue = useCallback(\n (direction: SubtitleCueJumpDirection) => {\n const target = getSubtitleJumpTarget(\n direction,\n getCurrentPlaybackTimeMs(),\n {\n excludeTarget:\n direction === \"previous\" ? lastSubtitleJumpTargetRef.current : null,\n }\n );\n\n if (target === null) {\n return false;\n }\n\n if (target.audioIndex === currentAudioIndex) {\n const didSeek = seekToPlaybackTimeMs(target.timeMs);\n\n if (didSeek) {\n lastSubtitleJumpTargetRef.current = target;\n }\n\n return didSeek;\n }\n\n const didJump = Boolean(\n onSubtitleJump?.(\n target,\n suppressPlayerControlsWakeAfterNavigation(getNavigationContext())\n )\n );\n\n if (didJump) {\n lastSubtitleJumpTargetRef.current = target;\n }\n\n return didJump;\n },\n [\n currentAudioIndex,\n getCurrentPlaybackTimeMs,\n getNavigationContext,\n getSubtitleJumpTarget,\n onSubtitleJump,\n seekToPlaybackTimeMs,\n ]\n );\n\n const finishAudioItem = useCallback(\n (_reason?: string) => {\n stopPlaybackTimeLoop();\n pendingAutoPlayRef.current = false;\n isWaitingForSegmentRef.current = false;\n isSwitchingSegmentRef.current = false;\n syncPlaybackTime();\n setIsPlaying(false);\n updateLoading(false);\n\n if (currentAudioIndex >= 0) {\n onEnded?.(currentAudioIndex);\n }\n },\n [\n currentAudioIndex,\n onEnded,\n stopPlaybackTimeLoop,\n syncPlaybackTime,\n updateLoading,\n ]\n );\n\n const finishUrlAudioIfSeekedToEnd = useCallback(\n (_reason: string) => {\n const audioElement = audioRef.current;\n\n if (!audioElement || activeSourceTypeRef.current !== \"url\") {\n return false;\n }\n\n if (\n !hasReachedAudioEnd({\n currentTimeSeconds: Math.max(audioElement.currentTime, 0),\n durationSeconds: audioElement.duration,\n })\n ) {\n return false;\n }\n\n pendingAutoPlayRef.current = false;\n audioElement.pause();\n finishAudioItem(_reason);\n return true;\n },\n [finishAudioItem]\n );\n\n const handleSegmentEnded = useCallback(() => {\n const nextSegmentIndex = currentSegmentIndexRef.current + 1;\n const segments = currentAudioSegmentsRef.current;\n const nextSegment = segments[nextSegmentIndex];\n const activeAudio = currentAudioRef.current;\n const hasFinal = segments.some((segment) => segment.is_final);\n\n if (nextSegment) {\n startSegmentPlayback(nextSegmentIndex, \"ended\");\n return;\n }\n\n if (activeAudio?.isAudioStreaming || !hasFinal) {\n currentSegmentIndexRef.current = nextSegmentIndex;\n waitingSegmentIndexRef.current = nextSegmentIndex;\n isWaitingForSegmentRef.current = true;\n pendingAutoPlayRef.current = defaultPlaying;\n publishPlaybackTime(getSegmentStartTimeMs(nextSegmentIndex));\n setIsPlaying(false);\n updateLoading(true, \"waitingForMoreAudio\");\n\n return;\n }\n\n finishAudioItem(\"segments-completed\");\n }, [\n defaultPlaying,\n finishAudioItem,\n getSegmentStartTimeMs,\n publishPlaybackTime,\n startSegmentPlayback,\n updateLoading,\n ]);\n\n useEffect(() => {\n if (currentAudioKeyRef.current === currentAudioKey) {\n return;\n }\n\n // The DOM pause event is delivered after React has rendered the new audio\n // item. Save the outgoing item before changing its identity, then suppress\n // that synthetic pause so it cannot be attributed to the new item.\n emitPlaybackCheckpoint(true);\n currentAudioKeyRef.current = currentAudioKey;\n currentSegmentIndexRef.current = 0;\n waitingSegmentIndexRef.current = null;\n isWaitingForSegmentRef.current = false;\n isPausedByUserRef.current = false;\n wasPlayingBeforeExternalPauseRef.current = false;\n pendingAutoPlayRef.current = false;\n isSwitchingSegmentRef.current = false;\n activeSourceTypeRef.current = null;\n preferredSourceTypeRef.current = null;\n audioSrcRef.current = null;\n stopPlaybackTimeLoop();\n publishPlaybackTime(0);\n updateLoading(false);\n\n const audioElement = audioRef.current;\n\n if (!audioElement) {\n return;\n }\n\n isResettingAudioRef.current = true;\n audioElement.pause();\n audioElement.removeAttribute(\"src\");\n audioElement.load();\n isResettingAudioRef.current = false;\n setIsPlaying(false);\n }, [\n currentAudioIndex,\n currentAudioKey,\n currentAudioSegments.length,\n currentAudioUrl,\n emitPlaybackCheckpoint,\n publishPlaybackTime,\n stopPlaybackTimeLoop,\n updateLoading,\n ]);\n\n useEffect(() => {\n const audioElement = audioRef.current;\n\n if (!audioElement) {\n return;\n }\n\n if (isPlaybackPaused) {\n wasPlayingBeforeExternalPauseRef.current = Boolean(\n currentAudioRef.current &&\n !isPausedByUserRef.current &&\n (!audioElement.paused ||\n pendingAutoPlayRef.current ||\n waitingSegmentIndexRef.current !== null)\n );\n\n pendingAutoPlayRef.current = false;\n updateLoading(false);\n audioElement.pause();\n setIsPlaying(false);\n return;\n }\n\n if (\n !wasPlayingBeforeExternalPauseRef.current ||\n !currentAudioRef.current ||\n isPausedByUserRef.current\n ) {\n return;\n }\n\n wasPlayingBeforeExternalPauseRef.current = false;\n\n if (waitingSegmentIndexRef.current !== null) {\n if (\n waitingSegmentIndexRef.current < currentAudioSegmentsRef.current.length\n ) {\n startSegmentPlayback(waitingSegmentIndexRef.current, \"external-resume\");\n return;\n }\n\n pendingAutoPlayRef.current = true;\n updateLoading(true, \"waitingForMoreAudio\");\n return;\n }\n\n if (!audioSrcRef.current && currentAudioSegmentsRef.current.length > 0) {\n startSegmentPlayback(\n Math.min(\n currentSegmentIndexRef.current,\n currentAudioSegmentsRef.current.length - 1\n ),\n \"external-resume-init\"\n );\n return;\n }\n\n if (!audioElement.paused) {\n return;\n }\n\n pendingAutoPlayRef.current = true;\n tryPlayCurrentAudio(\"external-resume\");\n }, [\n isPlaybackPaused,\n startSegmentPlayback,\n tryPlayCurrentAudio,\n updateLoading,\n ]);\n\n useEffect(() => {\n const audioElement = audioRef.current;\n\n if (!audioElement) {\n return;\n }\n\n if (!currentAudio) {\n resetAudio();\n return;\n }\n\n // A restore can target a segment that has not arrived yet. Do not start the\n // first available segment while the restore effect waits for the requested\n // offset to become seekable.\n if (\n playbackRestoreRequest &&\n playbackRestoreRequest.id !== lastPlaybackRestoreRequestIdRef.current\n ) {\n return;\n }\n\n if (isPlaybackPaused) {\n pendingAutoPlayRef.current = false;\n updateLoading(false);\n audioElement.pause();\n setIsPlaying(false);\n return;\n }\n\n const resolvedSourceType = resolveAudioPlaybackSourceType({\n activeSourceType: activeSourceTypeRef.current,\n hasAudioUrl: Boolean(currentAudioUrl),\n segmentCount: currentAudioSegments.length,\n preferredSourceType: preferredSourceTypeRef.current,\n waitingSegmentIndex: waitingSegmentIndexRef.current,\n });\n\n if (\n resolvedSourceType &&\n preferredSourceTypeRef.current !== resolvedSourceType\n ) {\n preferredSourceTypeRef.current = resolvedSourceType;\n }\n\n if (resolvedSourceType === \"url\" && currentAudioUrl) {\n const hasNewSrc = audioSrcRef.current !== currentAudioUrl;\n const shouldAutoResume = canStartPlaybackAutomatically();\n\n if (hasNewSrc) {\n const nextSeekTime =\n waitingSegmentIndexRef.current !== null\n ? getWaitingSegmentSeekTime()\n : 0;\n seekUrlPlayback(currentAudioUrl, nextSeekTime * 1000);\n }\n\n pendingAutoPlayRef.current = shouldAutoResume;\n isWaitingForSegmentRef.current = false;\n isSwitchingSegmentRef.current = false;\n updateLoading(false);\n\n if (!shouldAutoResume) {\n pendingAutoPlayRef.current = false;\n audioElement.pause();\n setIsPlaying(false);\n return;\n }\n\n tryPlayCurrentAudio(hasNewSrc ? \"sync-url-init\" : \"sync-url\");\n return;\n }\n\n if (\n resolvedSourceType === \"segment\" &&\n waitingSegmentIndexRef.current !== null\n ) {\n if (waitingSegmentIndexRef.current < currentAudioSegments.length) {\n if (isPausedByUserRef.current) {\n setIsPlaying(false);\n updateLoading(false);\n return;\n }\n\n startSegmentPlayback(waitingSegmentIndexRef.current, \"wait-resume\");\n return;\n }\n\n isWaitingForSegmentRef.current = true;\n pendingAutoPlayRef.current = canStartPlaybackAutomatically();\n setIsPlaying(false);\n updateLoading(canStartPlaybackAutomatically());\n return;\n }\n\n if (resolvedSourceType === \"segment\" && !currentAudioSegments.length) {\n if (currentAudio.isAudioStreaming) {\n waitingSegmentIndexRef.current = currentSegmentIndexRef.current;\n isWaitingForSegmentRef.current = true;\n pendingAutoPlayRef.current = canStartPlaybackAutomatically();\n setIsPlaying(false);\n updateLoading(canStartPlaybackAutomatically());\n return;\n }\n\n resetAudio();\n return;\n }\n\n if (resolvedSourceType === \"segment\" && !audioSrcRef.current) {\n startSegmentPlayback(\n Math.min(\n currentSegmentIndexRef.current,\n currentAudioSegments.length - 1\n ),\n \"effect-init\"\n );\n return;\n }\n\n if (resolvedSourceType !== \"segment\") {\n resetAudio();\n return;\n }\n\n if (!defaultPlaying || isPausedByUserRef.current) {\n pendingAutoPlayRef.current = false;\n audioElement.pause();\n setIsPlaying(false);\n return;\n }\n\n if (audioElement.paused) {\n pendingAutoPlayRef.current = true;\n tryPlayCurrentAudio(\"sync-paused-retry\");\n }\n }, [\n currentAudio,\n currentAudioIndex,\n currentAudioSegments,\n currentAudioUrl,\n defaultPlaying,\n isPlaybackPaused,\n playbackRestoreRequest,\n canStartPlaybackAutomatically,\n resetAudio,\n seekUrlPlayback,\n startSegmentPlayback,\n tryPlayCurrentAudio,\n getWaitingSegmentSeekTime,\n updateLoading,\n ]);\n\n useEffect(() => {\n if (!subtitleSeekRequest) {\n return;\n }\n\n if (\n subtitleSeekRequest.id === lastSubtitleSeekRequestIdRef.current ||\n subtitleSeekRequest.audioIndex !== currentAudioIndex\n ) {\n return;\n }\n\n const targetAudio = audioList[subtitleSeekRequest.audioIndex];\n\n if (\n !canSeekToAudioPlaybackTimeMs(targetAudio, subtitleSeekRequest.timeMs)\n ) {\n return;\n }\n\n lastSubtitleSeekRequestIdRef.current = subtitleSeekRequest.id;\n seekToPlaybackTimeMs(subtitleSeekRequest.timeMs);\n }, [\n audioList,\n canSeekToAudioPlaybackTimeMs,\n currentAudioIndex,\n seekToPlaybackTimeMs,\n subtitleSeekRequest,\n ]);\n\n useEffect(() => {\n if (\n !playbackRestoreRequest ||\n playbackRestoreRequest.id === lastPlaybackRestoreRequestIdRef.current ||\n currentAudioIndex < 0\n ) {\n return;\n }\n\n if (restorePlaybackTimeMs(playbackRestoreRequest.timeMs)) {\n lastPlaybackRestoreRequestIdRef.current = playbackRestoreRequest.id;\n onPlaybackRestoreComplete?.(playbackRestoreRequest.id);\n return;\n }\n\n // A completed item can no longer produce the requested offset. Release\n // the restore guard so normal playback is not suppressed indefinitely.\n if (!currentAudio?.isAudioStreaming) {\n lastPlaybackRestoreRequestIdRef.current = playbackRestoreRequest.id;\n onPlaybackRestoreComplete?.(playbackRestoreRequest.id);\n }\n }, [\n currentAudio?.isAudioStreaming,\n currentAudioIndex,\n onPlaybackRestoreComplete,\n playbackRestoreRequest,\n restorePlaybackTimeMs,\n ]);\n\n useEffect(() => {\n if (\n !playbackRestoreRequest ||\n playbackRestoreRequest.id === lastPlaybackRestoreRequestIdRef.current ||\n currentAudioIndex < 0 ||\n !currentAudio?.isAudioStreaming\n ) {\n return;\n }\n\n const timeoutId = window.setTimeout(() => {\n if (\n playbackRestoreRequest.id === lastPlaybackRestoreRequestIdRef.current\n ) {\n return;\n }\n\n lastPlaybackRestoreRequestIdRef.current = playbackRestoreRequest.id;\n onPlaybackRestoreComplete?.(playbackRestoreRequest.id);\n }, PLAYBACK_RESTORE_WAIT_TIMEOUT_MS);\n\n return () => {\n window.clearTimeout(timeoutId);\n };\n }, [\n currentAudio?.isAudioStreaming,\n currentAudioIndex,\n onPlaybackRestoreComplete,\n playbackRestoreRequest,\n ]);\n\n useEffect(() => resetAudio, [resetAudio]);\n\n useEffect(() => stopPlaybackTimeLoop, [stopPlaybackTimeLoop]);\n\n const handleAudioPlay = useCallback(() => {\n syncPlaybackTime();\n startPlaybackTimeLoop();\n setIsPlaying(true);\n updateLoading(false);\n onPlaybackStarted?.();\n }, [\n onPlaybackStarted,\n startPlaybackTimeLoop,\n syncPlaybackTime,\n updateLoading,\n ]);\n\n const handleAudioPause = useCallback(() => {\n if (\n isResettingAudioRef.current ||\n isWaitingForSegmentRef.current ||\n isSwitchingSegmentRef.current\n ) {\n return;\n }\n\n stopPlaybackTimeLoop();\n syncPlaybackTime();\n emitPlaybackCheckpoint(true);\n setIsPlaying(false);\n }, [emitPlaybackCheckpoint, stopPlaybackTimeLoop, syncPlaybackTime]);\n\n const handleAudioCanPlay = useCallback(() => {\n const audioElement = audioRef.current;\n\n if (audioElement && pendingSeekTimeRef.current !== null) {\n audioElement.currentTime = pendingSeekTimeRef.current;\n pendingSeekTimeRef.current = null;\n }\n\n syncPlaybackTime();\n\n if (finishUrlAudioIfSeekedToEnd(\"canplay-seek-finished\")) {\n return;\n }\n\n if (!pendingAutoPlayRef.current || !defaultPlaying) {\n return;\n }\n\n tryPlayCurrentAudio(\"canplay\");\n }, [\n currentAudioIndex,\n defaultPlaying,\n finishUrlAudioIfSeekedToEnd,\n syncPlaybackTime,\n tryPlayCurrentAudio,\n ]);\n\n const handleLoadedMetadata = useCallback(() => {\n const audioElement = audioRef.current;\n\n if (audioElement && pendingSeekTimeRef.current !== null) {\n audioElement.currentTime = pendingSeekTimeRef.current;\n pendingSeekTimeRef.current = null;\n }\n\n syncPlaybackTime();\n\n finishUrlAudioIfSeekedToEnd(\"metadata-seek-finished\");\n }, [currentAudioIndex, finishUrlAudioIfSeekedToEnd, syncPlaybackTime]);\n\n const handleAudioTimeUpdate = useCallback(() => {\n syncPlaybackTime();\n emitPlaybackCheckpoint();\n }, [emitPlaybackCheckpoint, syncPlaybackTime]);\n\n const handleAudioLoadStart = useCallback(() => {\n if (isWaitingForSegmentRef.current) {\n return;\n }\n\n updateLoading(true, \"loadingAudio\");\n }, [updateLoading]);\n\n const handleAudioWaiting = useCallback(() => {\n if (isWaitingForSegmentRef.current) {\n updateLoading(true, \"waitingForMoreAudio\");\n return;\n }\n\n updateLoading(true, \"loadingAudio\");\n }, [updateLoading]);\n\n const handleAudioSeeking = useCallback(() => {\n syncPlaybackTime();\n }, [syncPlaybackTime]);\n\n const handleAudioEnded = useCallback(() => {\n const activeAudio = currentAudioRef.current;\n const shouldFinishAsUrl =\n activeSourceTypeRef.current === \"url\" ||\n currentAudioSegmentsRef.current.length === 0;\n const hasNextSegment = Boolean(\n currentAudioSegmentsRef.current[currentSegmentIndexRef.current + 1]\n );\n const isFinalSegment = currentAudioSegmentsRef.current.some(\n (segment) => segment.is_final\n );\n const isStreamingAudio = Boolean(activeAudio?.isAudioStreaming);\n\n // A segment ending is not necessarily the end of the logical audio item.\n // Clearing its checkpoint here would lose the resume point while the next\n // segment is loading or while a stream is still being generated.\n emitPlaybackCheckpoint(\n true,\n shouldFinishAsUrl ||\n (!isStreamingAudio && !hasNextSegment && isFinalSegment)\n );\n\n stopPlaybackTimeLoop();\n isSwitchingSegmentRef.current = false;\n\n if (shouldFinishAsUrl) {\n finishAudioItem(\"url-ended\");\n return;\n }\n\n handleSegmentEnded();\n }, [\n emitPlaybackCheckpoint,\n finishAudioItem,\n handleSegmentEnded,\n stopPlaybackTimeLoop,\n ]);\n\n const handleAudioError = useCallback(() => {\n stopPlaybackTimeLoop();\n syncPlaybackTime();\n setIsPlaying(false);\n updateLoading(false);\n }, [stopPlaybackTimeLoop, syncPlaybackTime, updateLoading]);\n const handleMobileViewModeChange = useCallback(\n (nextViewMode: MobileViewMode) => {\n onMobileViewModeChange?.(nextViewMode);\n setIsMobileMoreOpen(false);\n },\n [onMobileViewModeChange]\n );\n\n const togglePlayback = useCallback(() => {\n if (useAutoAdvanceToggle) {\n const nextAutoAdvanceEnabled = !isAutoAdvanceEnabled;\n\n updatePlaybackPreference(nextAutoAdvanceEnabled);\n onAutoAdvanceToggle?.(nextAutoAdvanceEnabled);\n return true;\n }\n\n const audioElement = audioRef.current;\n\n if (isPlaybackPaused || !audioElement || !currentAudio) {\n return false;\n }\n\n if (waitingSegmentIndexRef.current !== null) {\n if (isPlaying) {\n updatePlaybackPreference(false);\n pendingAutoPlayRef.current = false;\n isPausedByUserRef.current = true;\n waitingSegmentIndexRef.current = null;\n isWaitingForSegmentRef.current = false;\n setIsPlaying(false);\n updateLoading(false);\n audioElement.pause();\n return true;\n }\n\n updatePlaybackPreference(true);\n playbackAccessModeRef.current = \"manual\";\n isPausedByUserRef.current = false;\n pendingAutoPlayRef.current = true;\n updateLoading(true, \"waitingForMoreAudio\");\n return true;\n }\n\n if (!audioElement.src && currentAudioSegments.length > 0) {\n updatePlaybackPreference(true);\n playbackAccessModeRef.current = \"manual\";\n isPausedByUserRef.current = false;\n startSegmentPlayback(\n Math.min(\n currentSegmentIndexRef.current,\n currentAudioSegments.length - 1\n ),\n \"toggle\"\n );\n return true;\n }\n\n if (audioElement.paused) {\n updatePlaybackPreference(true);\n playbackAccessModeRef.current = \"manual\";\n isPausedByUserRef.current = false;\n pendingAutoPlayRef.current = true;\n tryPlayCurrentAudio(\"toggle-resume\");\n return true;\n }\n\n updatePlaybackPreference(false);\n pendingAutoPlayRef.current = false;\n isPausedByUserRef.current = true;\n audioElement.pause();\n return true;\n }, [\n currentAudio,\n currentAudioSegments.length,\n isAutoAdvanceEnabled,\n isPlaybackPaused,\n isPlaying,\n onAutoAdvanceToggle,\n startSegmentPlayback,\n tryPlayCurrentAudio,\n updateLoading,\n updatePlaybackPreference,\n useAutoAdvanceToggle,\n ]);\n\n useEffect(() => {\n if (!shouldEnableKeyboardShortcuts) {\n return;\n }\n\n return registerPlayerKeyboardShortcutOwner(keyboardShortcutOwnerId);\n }, [keyboardShortcutOwnerId, shouldEnableKeyboardShortcuts]);\n\n const keyboardShortcutHandlers = useMemo<\n Record<PlayerKeyboardShortcutAction, () => boolean>\n >(\n () => ({\n fullscreen: () => {\n if (!onFullscreen) {\n return false;\n }\n\n onFullscreen();\n return true;\n },\n next: () => {\n if (!onNext) {\n return false;\n }\n\n if (!nextDisabled) {\n onNext(\n suppressPlayerControlsWakeAfterNavigation(getNavigationContext())\n );\n }\n\n return true;\n },\n nextSubtitle: () => {\n if (!subtitleJumpAvailability.next) {\n return true;\n }\n\n return jumpToSubtitleCue(\"next\");\n },\n previous: () => {\n if (!onPrev) {\n return false;\n }\n\n if (!prevDisabled) {\n onPrev(\n suppressPlayerControlsWakeAfterNavigation(getNavigationContext())\n );\n }\n\n return true;\n },\n previousSubtitle: () => {\n if (!subtitleJumpAvailability.previous) {\n return true;\n }\n\n return jumpToSubtitleCue(\"previous\");\n },\n subtitle: () => {\n if (!onSubtitleToggle) {\n return false;\n }\n\n onSubtitleToggle();\n return true;\n },\n togglePlayback: () => {\n togglePlayback();\n return true;\n },\n }),\n [\n getNavigationContext,\n jumpToSubtitleCue,\n nextDisabled,\n onFullscreen,\n onNext,\n onPrev,\n onSubtitleToggle,\n prevDisabled,\n subtitleJumpAvailability.next,\n subtitleJumpAvailability.previous,\n togglePlayback,\n ]\n );\n const keyboardShortcutHandlersRef = useRef(keyboardShortcutHandlers);\n\n useEffect(() => {\n keyboardShortcutHandlersRef.current = keyboardShortcutHandlers;\n }, [keyboardShortcutHandlers]);\n\n useEffect(() => {\n if (!shouldEnableKeyboardShortcuts || typeof document === \"undefined\") {\n return;\n }\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (!isActivePlayerKeyboardShortcutOwner(keyboardShortcutOwnerId)) {\n return;\n }\n\n const action = getPlayerKeyboardShortcutAction(event, readDirection());\n\n if (!action || shouldIgnorePlayerKeyboardShortcutEvent(event, action)) {\n return;\n }\n\n let handled = false;\n const handler = keyboardShortcutHandlersRef.current[action];\n\n handled = handler();\n\n if (!handled) {\n return;\n }\n\n event.preventDefault();\n };\n\n document.addEventListener(\"keydown\", handleKeyDown);\n\n return () => {\n document.removeEventListener(\"keydown\", handleKeyDown);\n };\n }, [keyboardShortcutOwnerId, readDirection, shouldEnableKeyboardShortcuts]);\n\n useEffect(() => {\n onPlaybackTimeChange?.(playbackTimeMsRef.current);\n }, [onPlaybackTimeChange]);\n\n return (\n <div\n {...props}\n dir={direction}\n lang={language}\n data-slide-player-shortcut-owner={keyboardShortcutOwnerId}\n className={cn(\"slide-player\", className)}\n onFocusCapture={handleRootFocusCapture}\n onPointerDown={handleRootPointerDown}\n >\n <audio\n ref={audioRef}\n preload=\"auto\"\n playsInline\n onLoadStart={handleAudioLoadStart}\n onLoadedMetadata={handleLoadedMetadata}\n onCanPlay={handleAudioCanPlay}\n onPlay={handleAudioPlay}\n onPause={handleAudioPause}\n onWaiting={handleAudioWaiting}\n onSeeking={handleAudioSeeking}\n onSeeked={handleAudioSeeking}\n onTimeUpdate={handleAudioTimeUpdate}\n onEnded={handleAudioEnded}\n onError={handleAudioError}\n />\n\n {showControls ? (\n <>\n <MobilePlayerSettingsSheet\n container={settingsPortalContainer}\n dir={direction ?? shortcutDirection}\n lang={portalLanguage}\n labels={{\n closeSettings: playerTexts.closeSettingsLabel,\n fullscreen: playerTexts.fullscreenLabel,\n nonFullscreen: playerTexts.nonFullscreenLabel,\n screen: playerTexts.screenLabel,\n screenMode: playerTexts.screenModeLabel,\n subtitle: playerTexts.subtitleLabel,\n subtitleToggle: playerTexts.subtitleToggleAriaLabel,\n title: playerTexts.settingsTitle,\n }}\n isSubtitleEnabled={isSubtitleEnabled}\n onClose={() => setIsMobileMoreOpen(false)}\n onOpenChange={setIsMobileMoreOpen}\n onSubtitleToggle={onSubtitleToggle ?? (() => {})}\n onViewModeChange={handleMobileViewModeChange}\n open={isMobileMoreOpen}\n viewMode={mobileViewMode}\n />\n\n <div\n className=\"slide-player__controls\"\n onPointerEnter={onControlsPointerEnter}\n onPointerLeave={onControlsPointerLeave}\n style={controlsStyle}\n >\n <div className=\"slide-player__group\">\n <button\n aria-expanded={isMobileMoreOpen}\n aria-haspopup=\"dialog\"\n aria-label={playerTexts.moreOptionsAriaLabel}\n className=\"slide-player__action slide-player__action--mobile-more\"\n onClick={() => {\n setIsMobileMoreOpen((prevOpen) => !prevOpen);\n }}\n type=\"button\"\n >\n <EllipsisVertical\n className=\"slide-player__icon\"\n strokeWidth={2.25}\n />\n </button>\n <button\n aria-label={playerTexts.volumeAriaLabel}\n className=\"hidden\"\n type=\"button\"\n >\n <Volume2 className=\"slide-player__icon\" strokeWidth={2.25} />\n </button>\n <button\n aria-label={toggleAriaLabel}\n aria-keyshortcuts={playbackShortcutMetadata.ariaKeyShortcuts}\n className=\"slide-player__toggle slide-player__toggle--playback\"\n onClick={() => {\n togglePlayback();\n }}\n title={playbackShortcutMetadata.title}\n type=\"button\"\n >\n {isTogglePlaying ? <PauseIcon /> : <PlayIcon />}\n </button>\n <button\n aria-keyshortcuts={previousShortcutMetadata.ariaKeyShortcuts}\n aria-label={playerTexts.previousLabel}\n className=\"slide-player__action slide-player__action--prev\"\n disabled={prevDisabled}\n onClick={() => {\n onPrev?.(getNavigationContext());\n }}\n title={previousShortcutMetadata.title}\n type=\"button\"\n >\n <SkipBack className=\"slide-player__icon\" strokeWidth={2.25} />\n </button>\n <button\n aria-keyshortcuts={nextShortcutMetadata.ariaKeyShortcuts}\n aria-label={playerTexts.nextLabel}\n className=\"slide-player__action slide-player__action--next\"\n disabled={nextDisabled}\n onClick={() => {\n onNext?.(getNavigationContext());\n }}\n title={nextShortcutMetadata.title}\n type=\"button\"\n >\n <SkipForward\n className=\"slide-player__icon\"\n strokeWidth={2.25}\n />\n </button>\n <button\n aria-keyshortcuts={\n previousSubtitleShortcutMetadata.ariaKeyShortcuts\n }\n aria-label={playerTexts.previousSubtitleLabel}\n className=\"slide-player__action slide-player__action--prev-subtitle\"\n disabled={!subtitleJumpAvailability.previous}\n onClick={() => {\n jumpToSubtitleCue(\"previous\");\n }}\n title={previousSubtitleShortcutMetadata.title}\n type=\"button\"\n >\n <Rewind className=\"slide-player__icon\" strokeWidth={2.25} />\n </button>\n <button\n aria-keyshortcuts={\n nextSubtitleShortcutMetadata.ariaKeyShortcuts\n }\n aria-label={playerTexts.nextSubtitleLabel}\n className=\"slide-player__action slide-player__action--next-subtitle\"\n disabled={!subtitleJumpAvailability.next}\n onClick={() => {\n jumpToSubtitleCue(\"next\");\n }}\n title={nextSubtitleShortcutMetadata.title}\n type=\"button\"\n >\n <FastForward\n className=\"slide-player__icon\"\n strokeWidth={2.25}\n />\n </button>\n <button\n aria-label={playerTexts.subtitleToggleAriaLabel}\n aria-keyshortcuts={subtitleShortcutMetadata.ariaKeyShortcuts}\n aria-pressed={isSubtitleEnabled}\n className=\"slide-player__action slide-player__action--subtitle\"\n onClick={onSubtitleToggle}\n title={subtitleShortcutMetadata.title}\n type=\"button\"\n >\n {isSubtitleEnabled ? (\n <Captions className=\"slide-player__icon\" strokeWidth={2.25} />\n ) : (\n <CaptionsOff\n className=\"slide-player__icon\"\n strokeWidth={2.25}\n />\n )}\n </button>\n {onFullscreen ? (\n <button\n aria-label={fullscreenAriaLabel}\n aria-keyshortcuts={\n fullscreenShortcutMetadata.ariaKeyShortcuts\n }\n className=\"slide-player__action slide-player__action--fullscreen\"\n onClick={onFullscreen}\n title={fullscreenShortcutMetadata.title}\n type=\"button\"\n >\n {isFullscreen ? (\n <ScanLine\n className=\"slide-player__icon\"\n strokeWidth={2.25}\n />\n ) : (\n <Maximize\n className=\"slide-player__icon\"\n strokeWidth={2.25}\n />\n )}\n </button>\n ) : null}\n </div>\n\n {customActionList.length > 0 ? (\n <>\n <div className=\"slide-player__separator\" />\n\n <div className=\"slide-player__group slide-player__group--custom-actions\">\n {customActionList.map((customAction, customActionIndex) => (\n <React.Fragment key={`custom-action-${customActionIndex}`}>\n {customAction}\n </React.Fragment>\n ))}\n </div>\n </>\n ) : null}\n </div>\n {slideProgress && slideProgress.totalSteps > 1 ? (\n <div\n aria-label={slideProgress.ariaLabel}\n className=\"slide-player__slide-progress\"\n role=\"navigation\"\n >\n {Array.from({ length: slideProgress.totalSteps }, (_, index) => (\n <button\n aria-current={\n index === slideProgress.currentIndex ? \"step\" : undefined\n }\n aria-label={`${slideProgress.ariaLabel} ${index + 1}`}\n className=\"slide-player__slide-progress-segment\"\n data-state={\n index < slideProgress.currentIndex\n ? \"completed\"\n : index === slideProgress.currentIndex\n ? \"current\"\n : \"upcoming\"\n }\n key={index}\n onClick={() => slideProgress.onNavigate?.(index)}\n type=\"button\"\n />\n ))}\n </div>\n ) : null}\n </>\n ) : null}\n </div>\n );\n};\n\nconst MemoizedPlayer = memo(Player);\n\nMemoizedPlayer.displayName = \"Player\";\n\nexport default MemoizedPlayer;\n"],"names":["audioPreloadElementCache","preloadAudioUrl","url","audio","hasCurrentSubtitleCueTracksCache","audioList","cache","audioItem","index","subtitleCues","createSubtitleCueTracksCache","subtitleCueLists","PauseIcon","jsxs","jsx","PlayIcon","PLAYER_SHORTCUT_LABELS","SUBTITLE_JUMP_AVAILABILITY_UPDATE_INTERVAL_MS","PLAYBACK_RESTORE_WAIT_TIMEOUT_MS","getShortcutTitle","label","shortcut","Player","className","currentAudioIndex","defaultPlaying","isPlaybackPaused","isAutoAdvanceEnabled","useAutoAdvanceToggle","onLoadingChange","onPlaybackPreferenceChange","onPlaybackStarted","onPlaybackTimeChange","onPlaybackCheckpoint","playbackRestoreRequest","onPlaybackRestoreComplete","onSubtitleToggle","onPrev","onNext","onSubtitleJump","canJumpToSubtitleTarget","onFullscreen","isFullscreen","mobileViewMode","DEFAULT_MOBILE_VIEW_MODE","settingsPortalContainer","onMobileViewModeChange","onEnded","onAutoAdvanceToggle","_deprecatedOnInteractionToggle","_deprecatedHasInteraction","isInteractionOpen","isSubtitleEnabled","prevDisabled","nextDisabled","showControls","onControlsPointerEnter","onControlsPointerLeave","slideProgress","enableKeyboardShortcuts","subtitleSeekRequest","customActions","customActionContext","locale","texts","onFocusCapture","onPointerDown","props","direction","getMarkdownFlowDirection","language","getMarkdownFlowLanguage","localKeyboardShortcutOwnerId","useId","keyboardShortcutContext","useContext","PlayerKeyboardShortcutContext","audioRef","useRef","shortcutDirection","readDirection","useResolvedDirection","isRtlNavigation","portalLanguage","useDetachedLanguage","previousInteractionOpenRef","audioSrcRef","currentAudioKeyRef","currentSegmentIndexRef","waitingSegmentIndexRef","currentAudioRef","currentAudioSegmentsRef","playbackPreferenceRef","wasPlayingBeforeExternalPauseRef","isLoadingRef","isPausedByUserRef","activeSourceTypeRef","preferredSourceTypeRef","isWaitingForSegmentRef","pendingAutoPlayRef","pendingSeekTimeRef","isSwitchingSegmentRef","playbackAnimationFrameRef","playbackTimeMsRef","updateSubtitleJumpAvailabilityRef","lastSubtitleJumpAvailabilityTimeMsRef","lastSubtitleJumpTargetRef","lastSubtitleSeekRequestIdRef","lastPlaybackRestoreRequestIdRef","lastPlaybackCheckpointAtRef","hasCompletedCurrentAudioRef","isResettingAudioRef","onPlaybackCheckpointRef","getCurrentPlaybackTimeMsRef","subtitleCueTracksCacheRef","playbackAccessModeRef","isPlaying","setIsPlaying","useState","isMobileMoreOpen","setIsMobileMoreOpen","subtitleJumpAvailability","setSubtitleJumpAvailability","keyboardShortcutOwnerId","shouldEnableKeyboardShortcuts","currentAudio","currentAudioUrl","currentAudioSegmentList","currentAudioSegmentCount","currentAudioSegments","useMemo","getSortedAudioSegments","subtitleCueTracksCache","subtitleCueTracks","customActionList","toPlayerCustomActionList","mobileVisibleActionCount","controlsStyle","playerTexts","getSlidePlayerTexts","currentAudioKey","isTogglePlaying","toggleAriaLabel","fullscreenAriaLabel","getShortcutMetadata","useCallback","shortcutText","ariaKey","subtitleShortcutMetadata","previousShortcutMetadata","previousSubtitleShortcutMetadata","playbackShortcutMetadata","nextShortcutMetadata","nextSubtitleShortcutMetadata","fullscreenShortcutMetadata","activateKeyboardShortcutOwner","activatePlayerKeyboardShortcutOwner","handleRootPointerDown","event","handleRootFocusCapture","useEffect","currentUrl","nextUrl","updateLoading","loading","reason","updatePlaybackPreference","playing","getNavigationContext","shouldKeepPlayingAfterNavigation","isAutoplayBlockedError","error","canStartPlaybackAutomatically","getSegmentSrc","audioData","getWaitingSegmentSeekTime","waitingSegmentIndex","totalDurationMs","segment","getSegmentStartTimeMs","segmentIndex","canSeekToAudioPlaybackTimeMs","timeMs","isPlaybackTimeCoveredBySegments","getSubtitleJumpTarget","currentTimeMs","options","target","getSubtitleCueJumpTarget","updateSubtitleJumpAvailability","force","normalizedCurrentTimeMs","nextAvailability","previousAvailability","getCurrentPlaybackTimeMs","audioElement","publishPlaybackTime","nextPlaybackTimeMs","shouldClearSubtitleCueJumpTarget","syncPlaybackTime","emitPlaybackCheckpoint","isComplete","audioKey","now","stopPlaybackTimeLoop","startPlaybackTimeLoop","updateFrame","resetAudio","tryPlayCurrentAudio","_reason","playPromise","startSegmentPlayback","nextAudioSrc","nextSeekTimeSeconds","shouldAutoResume","hasNewSrc","seekUrlPlayback","audioUrl","targetTimeSeconds","seekToPlaybackTimeMs","targetTimeMs","shouldResumePlayback","segmentSeekTarget","resolveSegmentSeekTarget","restorePlaybackTimeMs","jumpToSubtitleCue","didSeek","didJump","suppressPlayerControlsWakeAfterNavigation","finishAudioItem","finishUrlAudioIfSeekedToEnd","hasReachedAudioEnd","handleSegmentEnded","nextSegmentIndex","segments","nextSegment","activeAudio","hasFinal","resolvedSourceType","resolveAudioPlaybackSourceType","nextSeekTime","targetAudio","timeoutId","handleAudioPlay","handleAudioPause","handleAudioCanPlay","handleLoadedMetadata","handleAudioTimeUpdate","handleAudioLoadStart","handleAudioWaiting","handleAudioSeeking","handleAudioEnded","shouldFinishAsUrl","hasNextSegment","isFinalSegment","isStreamingAudio","handleAudioError","handleMobileViewModeChange","nextViewMode","togglePlayback","nextAutoAdvanceEnabled","registerPlayerKeyboardShortcutOwner","keyboardShortcutHandlers","keyboardShortcutHandlersRef","handleKeyDown","isActivePlayerKeyboardShortcutOwner","action","getPlayerKeyboardShortcutAction","shouldIgnorePlayerKeyboardShortcutEvent","handled","handler","cn","Fragment","MobilePlayerSettingsSheet","prevOpen","EllipsisVertical","Volume2","SkipBack","SkipForward","Rewind","FastForward","Captions","CaptionsOff","ScanLine","Maximize","customAction","customActionIndex","React","_","MemoizedPlayer","memo"],"mappings":"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"}
|
|
@@ -31,6 +31,7 @@ export interface SlidePlayerPlaybackCheckpoint {
|
|
|
31
31
|
export interface SlidePlayerProgress {
|
|
32
32
|
ariaLabel: string;
|
|
33
33
|
currentIndex: number;
|
|
34
|
+
onNavigate?: (index: number) => void;
|
|
34
35
|
totalSteps: number;
|
|
35
36
|
}
|
|
36
37
|
export interface SlidePlayerNavigationContext {
|
|
@@ -95,7 +96,7 @@ export type PlayerProps = Omit<React.ComponentProps<"div">, "onEnded"> & {
|
|
|
95
96
|
onControlsPointerEnter?: React.PointerEventHandler<HTMLDivElement>;
|
|
96
97
|
/** Fired when the pointer leaves the controls container to resume auto-hide. */
|
|
97
98
|
onControlsPointerLeave?: React.PointerEventHandler<HTMLDivElement>;
|
|
98
|
-
/**
|
|
99
|
+
/** Interactive navigation timeline for the generated slide sequence. */
|
|
99
100
|
slideProgress?: SlidePlayerProgress | null;
|
|
100
101
|
/**
|
|
101
102
|
* Enables document-level keyboard shortcuts for existing player actions.
|