@yetric/audioplayer 1.0.0-beta.1 → 1.0.0

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/README.md CHANGED
@@ -6,7 +6,7 @@ Headless TypeScript audio player for modern browsers.
6
6
 
7
7
  ## Status
8
8
 
9
- `1.0.0-beta.1` is the current intended npm beta release line.
9
+ `1.0.0` is the current stable release line.
10
10
 
11
11
  Recommended current focus:
12
12
 
@@ -52,20 +52,20 @@ The first milestone is not "generic media player." It is "good enough to replace
52
52
  - Browser-first, using `HTMLAudioElement` as the primary engine
53
53
  - Headless core API, so React/Angular/Web Components/vanilla JS can all use the same package
54
54
  - Imperative instance API first: `const player = createAudioPlayer()`
55
- - Queue management lives inside the player instance for `beta.1`
55
+ - Queue management lives inside the player instance for `1.0`
56
56
  - Persistence is opt-in, with `localStorage` as the first storage adapter
57
- - `load()` accepts one flat audio source object in `beta.1`
57
+ - `load()` accepts one flat audio source object in `1.0`
58
58
  - `subscribe(state)` is the primary UI model, with typed events for side effects
59
59
  - Every source / queue item must have a stable caller-provided `id`
60
60
  - `play(...)` may auto-load the requested item instead of requiring a separate `load()`
61
- - `beta.1` is optimized for one active player instance per app/page
61
+ - `1.0` is optimized for one active player instance per app/page
62
62
  - When playback finishes without auto-advancing, the current item remains loaded with `status: "ended"`
63
63
  - Strong TypeScript types without making vanilla JS usage awkward
64
- - React Native compatibility treated as a later adapter problem, not a `beta` blocker
64
+ - React Native compatibility treated as a later adapter problem, not a 1.0 blocker
65
65
 
66
- ## Beta 1 Goal
66
+ ## 1.0 Goal
67
67
 
68
- `1.0.0-beta.1` is ready when `podcast-app` can use this package for:
68
+ `1.0.0` is ready when `podcast-app` can use this package for:
69
69
 
70
70
  - load / replace a source
71
71
  - play / pause
@@ -118,7 +118,7 @@ The public API should stay small. Extra behavior like persistence, progress ping
118
118
  ## Repo Docs
119
119
 
120
120
  - [`docs/ROADMAP.md`](./docs/ROADMAP.md)
121
- - [`docs/BETA_1_ISSUES.md`](./docs/BETA_1_ISSUES.md)
121
+ - [`docs/V1_ISSUES.md`](./docs/V1_ISSUES.md)
122
122
  - [`docs/API_CONTRACT.md`](./docs/API_CONTRACT.md)
123
123
  - [`docs/GETTING_STARTED.md`](./docs/GETTING_STARTED.md)
124
124
  - [`docs/CORE_GUIDE.md`](./docs/CORE_GUIDE.md)
@@ -962,16 +962,22 @@ var attachAudioPlayerPersistence = (player, options) => {
962
962
  }, saveIntervalMs);
963
963
  };
964
964
  const waitForRestoredSource = (sourceId) => new Promise((resolve) => {
965
- const unsubscribe = player.subscribe((state) => {
966
- if (state.currentSourceId !== sourceId) {
965
+ let settled = false;
966
+ let unsubscribe;
967
+ unsubscribe = player.subscribe((state) => {
968
+ if (settled || state.currentSourceId !== sourceId) {
967
969
  return;
968
970
  }
969
971
  if (state.status === "loading") {
970
972
  return;
971
973
  }
972
- unsubscribe();
974
+ settled = true;
975
+ unsubscribe?.();
973
976
  resolve();
974
977
  });
978
+ if (settled) {
979
+ unsubscribe();
980
+ }
975
981
  });
976
982
  const restore = async () => {
977
983
  const persisted = options.adapter.load();
@@ -1250,4 +1256,4 @@ export {
1250
1256
  attachAudioPlayerProgressReporter,
1251
1257
  attachAudioPlayerMediaSession
1252
1258
  };
1253
- //# sourceMappingURL=chunk-BN5MQE43.js.map
1259
+ //# sourceMappingURL=chunk-7KCRIJPH.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export type PlayerStatus =\n | \"idle\"\n | \"loading\"\n | \"ready\"\n | \"playing\"\n | \"paused\"\n | \"ended\"\n | \"error\";\n\nexport type RepeatMode = \"off\" | \"one\" | \"all\";\n\nexport type AudioPlayerEventName =\n | \"sourcechange\"\n | \"queuechange\"\n | \"play\"\n | \"pause\"\n | \"seeking\"\n | \"seeked\"\n | \"timeupdate\"\n | \"ratechange\"\n | \"volumechange\"\n | \"ended\"\n | \"error\"\n | \"destroy\";\n\nexport interface AudioSource {\n id: string;\n src: string;\n title?: string;\n artist?: string;\n artwork?: string;\n album?: string;\n durationHint?: number;\n}\n\nexport interface AudioPlayerErrorState {\n code:\n | \"LOAD_ERROR\"\n | \"PLAY_ERROR\"\n | \"SEEK_ERROR\"\n | \"INVALID_VOLUME\"\n | \"INVALID_RATE\"\n | \"INVALID_QUEUE_ITEM\"\n | \"NO_ACTIVE_SOURCE\"\n | \"UNSUPPORTED_ENVIRONMENT\"\n | \"UNKNOWN_ERROR\";\n message: string;\n}\n\nexport interface AudioPlayerRuntimeError extends AudioPlayerErrorState {\n cause?: unknown;\n}\n\nexport interface AudioPlayerProgressState {\n currentTime: number;\n duration: number;\n buffered: number;\n playedFraction: number;\n bufferedFraction: number;\n}\n\nexport interface AudioPlayerQueuePositionState {\n currentIndex: number;\n currentSourceId: string | null;\n length: number;\n hasNext: boolean;\n hasPrevious: boolean;\n repeatMode: RepeatMode;\n}\n\nexport interface AudioPlayerQueueState {\n items: AudioSource[];\n itemIds: string[];\n position: AudioPlayerQueuePositionState;\n}\n\nexport interface AudioPlayerState {\n status: PlayerStatus;\n currentSource: AudioSource | null;\n currentSourceId: string | null;\n currentTime: number;\n duration: number;\n buffered: number;\n progress: AudioPlayerProgressState;\n rate: number;\n volume: number;\n muted: boolean;\n queue: AudioPlayerQueueState;\n error: AudioPlayerErrorState | null;\n}\n\nexport interface AudioPlayerEventMap {\n sourcechange: { source: AudioSource | null; state: AudioPlayerState };\n queuechange: { queue: AudioPlayerQueueState; state: AudioPlayerState };\n play: { source: AudioSource | null; state: AudioPlayerState };\n pause: { source: AudioSource | null; state: AudioPlayerState };\n seeking: { from: number; to: number; state: AudioPlayerState };\n seeked: { currentTime: number; state: AudioPlayerState };\n timeupdate: { currentTime: number; duration: number; state: AudioPlayerState };\n ratechange: { rate: number; state: AudioPlayerState };\n volumechange: { volume: number; muted: boolean; state: AudioPlayerState };\n ended: { source: AudioSource | null; state: AudioPlayerState };\n error: { error: AudioPlayerRuntimeError; state: AudioPlayerState };\n destroy: { state: AudioPlayerState };\n}\n\nexport interface CreateAudioPlayerOptions {\n initialVolume?: number;\n initialRate?: number;\n initialMuted?: boolean;\n initialRepeatMode?: RepeatMode;\n}\n\nexport interface SetQueueOptions {\n startAtId?: string;\n autoplay?: boolean;\n}\n\nexport interface PreviousOptions {\n restartThresholdSeconds?: number;\n}\n\nexport interface PersistedPlayerState {\n version: 1;\n savedAt: number;\n currentSource: AudioSource | null;\n currentSourceId: string | null;\n currentTime: number;\n rate: number;\n volume: number;\n muted: boolean;\n queue: {\n items: AudioSource[];\n position: {\n currentIndex: number;\n currentSourceId: string | null;\n repeatMode: RepeatMode;\n };\n };\n}\n\nexport interface AudioPlayerPersistenceAdapter {\n load(): PersistedPlayerState | null;\n save(state: PersistedPlayerState): void;\n clear(): void;\n}\n\nexport interface AudioPlayerPersistenceOptions {\n adapter: AudioPlayerPersistenceAdapter;\n autoRestore?: boolean;\n maxAgeMs?: number;\n saveIntervalMs?: number;\n}\n\nexport interface AudioPlayerPersistenceController {\n restore(): Promise<PersistedPlayerState | null>;\n save(): void;\n clear(): void;\n destroy(): void;\n}\n\nexport interface AudioPlayerProgressSnapshot {\n source: AudioSource | null;\n sourceId: string | null;\n currentTime: number;\n duration: number;\n playedFraction: number;\n status: PlayerStatus;\n queue: AudioPlayerQueuePositionState;\n}\n\nexport interface AudioPlayerProgressReporterOptions {\n intervalMs?: number;\n onReport: (snapshot: AudioPlayerProgressSnapshot) => void;\n}\n\nexport interface AudioPlayerProgressReporterController {\n report(): void;\n destroy(): void;\n}\n\nexport interface AudioPlayerMediaSessionOptions {\n artworkSizes?: number[];\n seekOffsetSeconds?: number;\n}\n\nexport interface AudioPlayerMediaSessionController {\n sync(): void;\n destroy(): void;\n}\n\nexport type AudioPlayerEventListener<K extends AudioPlayerEventName> = (\n event: AudioPlayerEventMap[K],\n) => void;\n\nexport interface AudioPlayer {\n getState(): AudioPlayerState;\n subscribe(listener: (state: AudioPlayerState) => void): () => void;\n on<K extends AudioPlayerEventName>(\n eventName: K,\n listener: AudioPlayerEventListener<K>,\n ): () => void;\n\n load(source: AudioSource): Promise<void>;\n play(source?: AudioSource): Promise<void>;\n pause(): void;\n toggle(): Promise<void>;\n unload(): void;\n seek(time: number): void;\n setRate(rate: number): void;\n setVolume(volume: number): void;\n setMuted(muted: boolean): void;\n\n setQueue(items: AudioSource[], options?: SetQueueOptions): Promise<void>;\n appendToQueue(items: AudioSource[]): void;\n removeFromQueue(id: string): void;\n clearQueue(): void;\n next(): Promise<void>;\n previous(options?: PreviousOptions): Promise<void>;\n setRepeatMode(mode: RepeatMode): void;\n\n destroy(): void;\n}\n\nconst DEFAULT_PREVIOUS_RESTART_THRESHOLD_SECONDS = 5;\nconst DEFAULT_PERSISTENCE_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000;\nconst DEFAULT_PERSISTENCE_SAVE_INTERVAL_MS = 5000;\nconst DEFAULT_PROGRESS_REPORT_INTERVAL_MS = 5000;\nconst DEFAULT_MEDIA_SESSION_ARTWORK_SIZES = [96, 128, 192, 256, 384, 512];\nconst DEFAULT_MEDIA_SESSION_SEEK_OFFSET_SECONDS = 10;\n\ntype AudioEngineEventName =\n | \"loadedmetadata\"\n | \"timeupdate\"\n | \"progress\"\n | \"play\"\n | \"pause\"\n | \"seeked\"\n | \"ratechange\"\n | \"volumechange\"\n | \"ended\"\n | \"error\";\n\ninterface AudioEngineSnapshot {\n currentTime: number;\n duration: number;\n buffered: number;\n rate: number;\n volume: number;\n muted: boolean;\n}\n\ninterface AudioEngine {\n readonly available: boolean;\n getSnapshot(durationHint?: number): AudioEngineSnapshot;\n getRuntimeError(): unknown;\n on(eventName: AudioEngineEventName, listener: EventListener): () => void;\n setSource(src: string): void;\n clearSource(): void;\n load(): void;\n play(): Promise<void>;\n pause(): void;\n setCurrentTime(time: number): void;\n setPlaybackRate(rate: number): void;\n setVolume(volume: number): void;\n setMuted(muted: boolean): void;\n destroy(): void;\n}\n\nconst createInitialState = (\n options: CreateAudioPlayerOptions,\n): AudioPlayerState => ({\n status: \"idle\",\n currentSource: null,\n currentSourceId: null,\n currentTime: 0,\n duration: 0,\n buffered: 0,\n progress: {\n currentTime: 0,\n duration: 0,\n buffered: 0,\n playedFraction: 0,\n bufferedFraction: 0,\n },\n rate: options.initialRate ?? 1,\n volume: options.initialVolume ?? 1,\n muted: options.initialMuted ?? false,\n queue: {\n items: [],\n itemIds: [],\n position: {\n currentIndex: -1,\n currentSourceId: null,\n length: 0,\n repeatMode: options.initialRepeatMode ?? \"off\",\n hasNext: false,\n hasPrevious: false,\n },\n },\n error: null,\n});\n\nconst createPlayerError = (\n code: AudioPlayerRuntimeError[\"code\"],\n message: string,\n cause?: unknown,\n): AudioPlayerRuntimeError => ({\n code,\n message,\n cause,\n});\n\nconst isRuntimePlayerError = (\n value: unknown,\n): value is AudioPlayerRuntimeError =>\n !!value &&\n typeof value === \"object\" &&\n \"code\" in value &&\n \"message\" in value;\n\nconst normalizePlayerError = (\n fallbackCode: AudioPlayerRuntimeError[\"code\"],\n fallbackMessage: string,\n cause: unknown,\n): AudioPlayerRuntimeError =>\n isRuntimePlayerError(cause)\n ? cause\n : createPlayerError(fallbackCode, fallbackMessage, cause);\n\nconst assertStableSource = (source: AudioSource): void => {\n if (!source.id || !source.src) {\n throw createPlayerError(\n \"INVALID_QUEUE_ITEM\",\n \"AudioSource requires stable id and src.\",\n );\n }\n};\n\nconst isFiniteNumber = (value: number): boolean =>\n Number.isFinite(value) && !Number.isNaN(value);\n\nconst safeDuration = (audio: HTMLAudioElement | null, hint?: number): number => {\n const duration = audio?.duration;\n return duration !== undefined && isFiniteNumber(duration) ? duration : hint ?? 0;\n};\n\nconst safeBuffered = (audio: HTMLAudioElement | null): number => {\n if (!audio || audio.buffered.length === 0) {\n return 0;\n }\n\n try {\n return audio.buffered.end(audio.buffered.length - 1);\n } catch {\n return 0;\n }\n};\n\nconst cloneQueueState = (state: AudioPlayerState): AudioPlayerQueueState => ({\n items: [...state.queue.items],\n itemIds: [...state.queue.itemIds],\n position: {\n ...state.queue.position,\n },\n});\n\nconst updateQueueFlags = (state: AudioPlayerState): AudioPlayerState => {\n const { items, position } = state.queue;\n const { currentIndex, repeatMode } = position;\n const lastIndex = items.length - 1;\n const hasItems = items.length > 0;\n const hasNext =\n !hasItems || currentIndex < 0\n ? false\n : repeatMode === \"all\"\n ? items.length > 0\n : currentIndex < lastIndex;\n const hasPrevious =\n !hasItems || currentIndex < 0\n ? false\n : repeatMode === \"all\"\n ? items.length > 0\n : currentIndex > 0;\n\n return {\n ...state,\n queue: {\n ...state.queue,\n itemIds: items.map((item) => item.id),\n position: {\n ...position,\n currentSourceId: state.currentSource?.id ?? null,\n length: items.length,\n hasNext,\n hasPrevious,\n },\n },\n };\n};\n\nconst createAudioElement = (): HTMLAudioElement | null => {\n if (typeof Audio === \"undefined\") {\n return null;\n }\n\n return new Audio();\n};\n\nconst createUnavailableAudioEngine = (): AudioEngine => {\n const unavailableError = (): AudioPlayerRuntimeError =>\n createPlayerError(\n \"UNSUPPORTED_ENVIRONMENT\",\n \"HTMLAudioElement is not available in this environment.\",\n );\n\n return {\n available: false,\n getSnapshot(durationHint) {\n return {\n currentTime: 0,\n duration: durationHint ?? 0,\n buffered: 0,\n rate: 1,\n volume: 1,\n muted: false,\n };\n },\n getRuntimeError() {\n return unavailableError();\n },\n on() {\n return () => {};\n },\n setSource() {\n throw unavailableError();\n },\n clearSource() {\n throw unavailableError();\n },\n load() {\n throw unavailableError();\n },\n play() {\n throw unavailableError();\n },\n pause() {\n throw unavailableError();\n },\n setCurrentTime() {\n throw unavailableError();\n },\n setPlaybackRate() {\n throw unavailableError();\n },\n setVolume() {\n throw unavailableError();\n },\n setMuted() {\n throw unavailableError();\n },\n destroy() {},\n };\n};\n\nconst createHtmlAudioEngine = (): AudioEngine => {\n const audio = createAudioElement();\n if (!audio) {\n return createUnavailableAudioEngine();\n }\n\n audio.preload = \"metadata\";\n const clearSource = (): void => {\n const element = audio as HTMLAudioElement & {\n removeAttribute?: (name: string) => void;\n };\n if (typeof element.removeAttribute === \"function\") {\n element.removeAttribute(\"src\");\n return;\n }\n\n audio.src = \"\";\n };\n\n return {\n available: true,\n getSnapshot(durationHint) {\n return {\n currentTime: audio.currentTime,\n duration: safeDuration(audio, durationHint),\n buffered: safeBuffered(audio),\n rate: audio.playbackRate,\n volume: audio.volume,\n muted: audio.muted,\n };\n },\n getRuntimeError() {\n return audio.error;\n },\n on(eventName, listener) {\n audio.addEventListener(eventName, listener);\n return () => {\n audio.removeEventListener(eventName, listener);\n };\n },\n setSource(src) {\n audio.src = src;\n },\n clearSource() {\n clearSource();\n },\n load() {\n audio.load();\n },\n play() {\n return audio.play();\n },\n pause() {\n audio.pause();\n },\n setCurrentTime(time) {\n audio.currentTime = time;\n },\n setPlaybackRate(rate) {\n audio.playbackRate = rate;\n },\n setVolume(volume) {\n audio.volume = volume;\n },\n setMuted(muted) {\n audio.muted = muted;\n },\n destroy() {\n audio.pause();\n clearSource();\n audio.load();\n },\n };\n};\n\nconst isBrowserStorageAvailable = (): boolean =>\n typeof window !== \"undefined\" && typeof window.localStorage !== \"undefined\";\n\nconst isPersistedPlayerState = (value: unknown): value is PersistedPlayerState => {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n\n const candidate = value as Partial<PersistedPlayerState>;\n return (\n candidate.version === 1 &&\n typeof candidate.savedAt === \"number\" &&\n \"currentSource\" in candidate &&\n typeof candidate.currentTime === \"number\" &&\n typeof candidate.rate === \"number\" &&\n typeof candidate.volume === \"number\" &&\n typeof candidate.muted === \"boolean\" &&\n !!candidate.queue &&\n Array.isArray(candidate.queue.items) &&\n !!candidate.queue.position\n );\n};\n\nconst toPersistedPlayerState = (state: AudioPlayerState): PersistedPlayerState => ({\n version: 1,\n savedAt: Date.now(),\n currentSource: state.currentSource,\n currentSourceId: state.currentSourceId,\n currentTime: state.currentTime,\n rate: state.rate,\n volume: state.volume,\n muted: state.muted,\n queue: {\n items: [...state.queue.items],\n position: {\n currentIndex: state.queue.position.currentIndex,\n currentSourceId: state.queue.position.currentSourceId,\n repeatMode: state.queue.position.repeatMode,\n },\n },\n});\n\nconst toProgressSnapshot = (\n state: AudioPlayerState,\n): AudioPlayerProgressSnapshot => ({\n source: state.currentSource,\n sourceId: state.currentSourceId,\n currentTime: state.currentTime,\n duration: state.duration,\n playedFraction: state.progress.playedFraction,\n status: state.status,\n queue: {\n ...state.queue.position,\n },\n});\n\nconst hasMediaSession = (): boolean =>\n typeof navigator !== \"undefined\" && \"mediaSession\" in navigator;\n\nconst createMediaSessionArtwork = (\n source: AudioSource | null,\n sizes: number[],\n): MediaImage[] => {\n if (!source?.artwork) {\n return [];\n }\n\n return sizes.map((size) => ({\n src: source.artwork as string,\n sizes: `${size}x${size}`,\n }));\n};\n\nexport const createLocalStoragePersistenceAdapter = (\n key: string,\n): AudioPlayerPersistenceAdapter => ({\n load() {\n if (!isBrowserStorageAvailable()) {\n return null;\n }\n\n try {\n const raw = window.localStorage.getItem(key);\n if (!raw) {\n return null;\n }\n\n const parsed: unknown = JSON.parse(raw);\n return isPersistedPlayerState(parsed) ? parsed : null;\n } catch {\n return null;\n }\n },\n\n save(state) {\n if (!isBrowserStorageAvailable()) {\n return;\n }\n\n window.localStorage.setItem(key, JSON.stringify(state));\n },\n\n clear() {\n if (!isBrowserStorageAvailable()) {\n return;\n }\n\n window.localStorage.removeItem(key);\n },\n});\n\nexport const createAudioPlayer = (\n options: CreateAudioPlayerOptions = {},\n): AudioPlayer => {\n let state = updateQueueFlags(createInitialState(options));\n let destroyed = false;\n let shouldAutoplayAfterLoad = false;\n let suppressPauseEvent = false;\n\n const engine = createHtmlAudioEngine();\n const subscribers = new Set<(nextState: AudioPlayerState) => void>();\n const eventListeners: {\n [K in AudioPlayerEventName]: Set<AudioPlayerEventListener<K>>;\n } = {\n sourcechange: new Set(),\n queuechange: new Set(),\n play: new Set(),\n pause: new Set(),\n seeking: new Set(),\n seeked: new Set(),\n timeupdate: new Set(),\n ratechange: new Set(),\n volumechange: new Set(),\n ended: new Set(),\n error: new Set(),\n destroy: new Set(),\n };\n\n const getState = (): AudioPlayerState => state;\n\n const publishState = (): void => {\n for (const subscriber of subscribers) {\n subscriber(state);\n }\n };\n\n const emit = <K extends AudioPlayerEventName>(\n eventName: K,\n event: AudioPlayerEventMap[K],\n ): void => {\n for (const listener of eventListeners[eventName]) {\n listener(event);\n }\n };\n\n const setState = (\n updater: (currentState: AudioPlayerState) => AudioPlayerState,\n ): AudioPlayerState => {\n state = updateQueueFlags(updater(state));\n publishState();\n return state;\n };\n\n const setError = (error: AudioPlayerRuntimeError): void => {\n shouldAutoplayAfterLoad = false;\n const nextState = setState((currentState) => ({\n ...currentState,\n status: \"error\",\n error: {\n code: error.code,\n message: error.message,\n },\n }));\n emit(\"error\", { error, state: nextState });\n };\n\n const clearError = (): void => {\n if (!state.error) {\n return;\n }\n\n setState((currentState) => ({\n ...currentState,\n error: null,\n }));\n };\n\n const syncAudioSnapshot = (\n statusOverride?: PlayerStatus,\n ): AudioPlayerState => {\n const snapshot = engine.getSnapshot(state.currentSource?.durationHint);\n const currentTime = snapshot.currentTime;\n const duration = snapshot.duration;\n const buffered = snapshot.buffered;\n const playedFraction =\n duration > 0 ? Math.min(1, Math.max(0, currentTime / duration)) : 0;\n const bufferedFraction =\n duration > 0 ? Math.min(1, Math.max(0, buffered / duration)) : 0;\n\n const nextState = setState((currentState) => ({\n ...currentState,\n currentSourceId: currentState.currentSource?.id ?? null,\n currentTime,\n duration,\n buffered,\n progress: {\n currentTime,\n duration,\n buffered,\n playedFraction,\n bufferedFraction,\n },\n rate: snapshot.rate,\n volume: snapshot.volume,\n muted: snapshot.muted,\n status: statusOverride ?? currentState.status,\n error:\n statusOverride === \"error\" ? currentState.error : null,\n }));\n\n return nextState;\n };\n\n const findQueueIndexById = (id: string | null | undefined): number =>\n id ? state.queue.items.findIndex((item) => item.id === id) : -1;\n\n const resolveNextQueueIndex = (\n mode: \"manual\" | \"ended\",\n ): number | null => {\n const { items, position } = state.queue;\n const { currentIndex, repeatMode } = position;\n\n if (items.length === 0 || currentIndex < 0) {\n return null;\n }\n\n if (repeatMode === \"one\") {\n return currentIndex;\n }\n\n if (currentIndex < items.length - 1) {\n return currentIndex + 1;\n }\n\n if (repeatMode === \"all\") {\n return 0;\n }\n\n return mode === \"ended\" ? -1 : null;\n };\n\n const resolvePreviousQueueIndex = (): number | null => {\n const { items, position } = state.queue;\n const { currentIndex, repeatMode } = position;\n\n if (items.length === 0 || currentIndex < 0) {\n return null;\n }\n\n if (currentIndex > 0) {\n return currentIndex - 1;\n }\n\n if (repeatMode === \"all\") {\n return items.length - 1;\n }\n\n return null;\n };\n\n const updateCurrentSource = (\n source: AudioSource | null,\n nextStatus: PlayerStatus,\n ): AudioPlayerState => {\n const queueIndex = findQueueIndexById(source?.id);\n const nextState = setState((currentState) => ({\n ...currentState,\n currentSource: source,\n currentSourceId: source?.id ?? null,\n currentTime: 0,\n duration: source?.durationHint ?? 0,\n buffered: 0,\n progress: {\n currentTime: 0,\n duration: source?.durationHint ?? 0,\n buffered: 0,\n playedFraction: 0,\n bufferedFraction: 0,\n },\n status: nextStatus,\n error: null,\n queue: {\n ...currentState.queue,\n position: {\n ...currentState.queue.position,\n currentIndex: queueIndex,\n currentSourceId: source?.id ?? null,\n },\n },\n }));\n emit(\"sourcechange\", { source, state: nextState });\n return nextState;\n };\n\n const setQueueState = (\n items: AudioSource[],\n currentIndex: number,\n ): AudioPlayerState =>\n setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n items,\n position: {\n ...currentState.queue.position,\n currentIndex,\n },\n },\n }));\n\n const emitQueueChange = (nextState: AudioPlayerState): void => {\n emit(\"queuechange\", { queue: cloneQueueState(nextState), state: nextState });\n };\n\n const attachSourceToAudio = (\n source: AudioSource,\n autoplayAfterLoad: boolean,\n ): void => {\n shouldAutoplayAfterLoad = autoplayAfterLoad;\n suppressPauseEvent = true;\n try {\n engine.pause();\n } finally {\n suppressPauseEvent = false;\n }\n engine.setSource(source.src);\n engine.setCurrentTime(0);\n engine.setPlaybackRate(state.rate);\n engine.setVolume(state.volume);\n engine.setMuted(state.muted);\n engine.load();\n };\n\n const loadInternal = async (\n source: AudioSource,\n autoplayAfterLoad = false,\n ): Promise<void> => {\n assertStableSource(source);\n updateCurrentSource(source, \"loading\");\n attachSourceToAudio(source, autoplayAfterLoad);\n };\n\n const selectQueueIndex = async (\n index: number,\n autoplayAfterLoad = false,\n ): Promise<AudioSource | null> => {\n const item = state.queue.items[index] ?? null;\n if (!item) {\n return null;\n }\n\n await loadInternal(item, autoplayAfterLoad);\n const nextState = setQueueState(state.queue.items, index);\n emitQueueChange(nextState);\n return item;\n };\n\n const playLoadedAudio = async (): Promise<void> => {\n try {\n await engine.play();\n } catch (cause) {\n setError(createPlayerError(\"PLAY_ERROR\", \"Failed to start playback.\", cause));\n }\n };\n\n const handlePlaybackEnded = async (): Promise<void> => {\n if (destroyed) {\n return;\n }\n\n if (state.queue.items.length > 0 && state.queue.position.currentIndex >= 0) {\n const nextIndex = resolveNextQueueIndex(\"ended\");\n if (nextIndex === -1 || nextIndex === null) {\n const endedState = syncAudioSnapshot(\"ended\");\n emit(\"ended\", { source: endedState.currentSource, state: endedState });\n return;\n }\n\n await selectQueueIndex(nextIndex, true);\n return;\n }\n\n const endedState = syncAudioSnapshot(\"ended\");\n emit(\"ended\", { source: endedState.currentSource, state: endedState });\n };\n\n const detachEngineListeners = [\n engine.on(\"loadedmetadata\", () => {\n if (destroyed || !state.currentSource) {\n return;\n }\n\n syncAudioSnapshot(\"ready\");\n if (shouldAutoplayAfterLoad) {\n shouldAutoplayAfterLoad = false;\n void playLoadedAudio();\n }\n }),\n engine.on(\"timeupdate\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot(\n state.status === \"ended\" ? \"playing\" : undefined,\n );\n emit(\"timeupdate\", {\n currentTime: nextState.currentTime,\n duration: nextState.duration,\n state: nextState,\n });\n }),\n engine.on(\"progress\", () => {\n if (!destroyed) {\n syncAudioSnapshot();\n }\n }),\n engine.on(\"play\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot(\"playing\");\n emit(\"play\", { source: nextState.currentSource, state: nextState });\n }),\n engine.on(\"pause\", () => {\n if (destroyed || suppressPauseEvent) {\n return;\n }\n\n const nextStatus =\n state.status === \"ended\" ? \"ended\" : state.currentSource ? \"paused\" : \"idle\";\n const nextState = syncAudioSnapshot(nextStatus);\n emit(\"pause\", { source: nextState.currentSource, state: nextState });\n }),\n engine.on(\"seeked\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot();\n emit(\"seeked\", { currentTime: nextState.currentTime, state: nextState });\n emit(\"timeupdate\", {\n currentTime: nextState.currentTime,\n duration: nextState.duration,\n state: nextState,\n });\n }),\n engine.on(\"ratechange\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot();\n emit(\"ratechange\", { rate: nextState.rate, state: nextState });\n }),\n engine.on(\"volumechange\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot();\n emit(\"volumechange\", {\n volume: nextState.volume,\n muted: nextState.muted,\n state: nextState,\n });\n }),\n engine.on(\"ended\", () => {\n void handlePlaybackEnded();\n }),\n engine.on(\"error\", () => {\n if (destroyed) {\n return;\n }\n\n setError(\n createPlayerError(\n \"LOAD_ERROR\",\n \"Audio element reported a playback error.\",\n engine.getRuntimeError(),\n ),\n );\n }),\n ];\n\n return {\n getState,\n\n subscribe(listener) {\n subscribers.add(listener);\n listener(state);\n return () => {\n subscribers.delete(listener);\n };\n },\n\n on(eventName, listener) {\n eventListeners[eventName].add(\n listener as AudioPlayerEventListener<typeof eventName>,\n );\n return () => {\n eventListeners[eventName].delete(\n listener as AudioPlayerEventListener<typeof eventName>,\n );\n };\n },\n\n async load(source) {\n try {\n await loadInternal(source);\n } catch (cause) {\n setError(\n normalizePlayerError(\"LOAD_ERROR\", \"Failed to load source.\", cause),\n );\n }\n },\n\n async play(source) {\n try {\n if (source) {\n await loadInternal(source, true);\n return;\n }\n\n if (!state.currentSource) {\n setError(\n createPlayerError(\n \"NO_ACTIVE_SOURCE\",\n \"Cannot play without an active source.\",\n ),\n );\n return;\n }\n\n if (state.status === \"loading\") {\n shouldAutoplayAfterLoad = true;\n return;\n }\n\n await playLoadedAudio();\n } catch (cause) {\n setError(normalizePlayerError(\"PLAY_ERROR\", \"Failed to start playback.\", cause));\n }\n },\n\n pause() {\n if (!engine.available) {\n return;\n }\n\n shouldAutoplayAfterLoad = false;\n engine.pause();\n },\n\n async toggle() {\n if (state.status === \"playing\") {\n this.pause();\n return;\n }\n\n await this.play();\n },\n\n unload() {\n shouldAutoplayAfterLoad = false;\n\n if (engine.available) {\n suppressPauseEvent = true;\n try {\n engine.pause();\n } finally {\n suppressPauseEvent = false;\n }\n engine.clearSource();\n engine.load();\n }\n\n const nextState = updateCurrentSource(null, \"idle\");\n emitQueueChange(nextState);\n },\n\n seek(time) {\n if (!state.currentSource) {\n setError(\n createPlayerError(\"SEEK_ERROR\", \"Cannot seek without an active source.\"),\n );\n return;\n }\n\n const max = engine.getSnapshot(state.currentSource.durationHint).duration;\n const normalized = Math.max(\n 0,\n max > 0 ? Math.min(time, max) : (isFiniteNumber(time) ? time : 0),\n );\n emit(\"seeking\", { from: state.currentTime, to: normalized, state });\n\n try {\n engine.setCurrentTime(normalized);\n } catch (cause) {\n setError(normalizePlayerError(\"SEEK_ERROR\", \"Failed to seek audio.\", cause));\n }\n },\n\n setRate(rate) {\n if (!engine.available) {\n setError(\n createPlayerError(\"INVALID_RATE\", \"Audio element is unavailable.\"),\n );\n return;\n }\n\n if (!isFiniteNumber(rate) || rate <= 0) {\n setError(\n createPlayerError(\"INVALID_RATE\", \"Playback rate must be greater than 0.\"),\n );\n return;\n }\n\n engine.setPlaybackRate(rate);\n clearError();\n syncAudioSnapshot();\n },\n\n setVolume(volume) {\n if (!engine.available) {\n setError(\n createPlayerError(\"INVALID_VOLUME\", \"Audio element is unavailable.\"),\n );\n return;\n }\n\n if (!isFiniteNumber(volume) || volume < 0 || volume > 1) {\n setError(\n createPlayerError(\"INVALID_VOLUME\", \"Volume must be between 0 and 1.\"),\n );\n return;\n }\n\n engine.setVolume(volume);\n clearError();\n syncAudioSnapshot();\n },\n\n setMuted(muted) {\n if (!engine.available) {\n return;\n }\n\n engine.setMuted(muted);\n clearError();\n syncAudioSnapshot();\n },\n\n async setQueue(items, queueOptions = {}) {\n try {\n for (const item of items) {\n assertStableSource(item);\n }\n\n const startIndex =\n queueOptions.startAtId === undefined\n ? items.length > 0\n ? 0\n : -1\n : items.findIndex((item) => item.id === queueOptions.startAtId);\n\n if (queueOptions.startAtId && startIndex < 0) {\n throw createPlayerError(\n \"INVALID_QUEUE_ITEM\",\n `Queue start item ${queueOptions.startAtId} was not found.`,\n );\n }\n\n const nextState = setState((currentState) => ({\n ...currentState,\n currentSource: startIndex >= 0 ? items[startIndex] ?? null : null,\n currentSourceId: startIndex >= 0 ? (items[startIndex]?.id ?? null) : null,\n currentTime: 0,\n duration: startIndex >= 0 ? (items[startIndex]?.durationHint ?? 0) : 0,\n buffered: 0,\n progress: {\n currentTime: 0,\n duration: startIndex >= 0 ? (items[startIndex]?.durationHint ?? 0) : 0,\n buffered: 0,\n playedFraction: 0,\n bufferedFraction: 0,\n },\n status: startIndex >= 0 ? \"ready\" : \"idle\",\n error: null,\n queue: {\n ...currentState.queue,\n items: [...items],\n position: {\n ...currentState.queue.position,\n currentIndex: startIndex,\n currentSourceId:\n startIndex >= 0 ? (items[startIndex]?.id ?? null) : null,\n },\n },\n }));\n\n emitQueueChange(nextState);\n emit(\"sourcechange\", {\n source: nextState.currentSource,\n state: nextState,\n });\n\n if (nextState.currentSource) {\n await loadInternal(nextState.currentSource, queueOptions.autoplay === true);\n const syncedState = setQueueState(items, startIndex);\n emitQueueChange(syncedState);\n } else if (engine.available) {\n shouldAutoplayAfterLoad = false;\n suppressPauseEvent = true;\n engine.pause();\n suppressPauseEvent = false;\n engine.clearSource();\n engine.load();\n }\n } catch (cause) {\n setError(\n normalizePlayerError(\n \"INVALID_QUEUE_ITEM\",\n \"Failed to set queue.\",\n cause,\n ),\n );\n }\n },\n\n appendToQueue(items) {\n try {\n for (const item of items) {\n assertStableSource(item);\n }\n\n const nextState = setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n items: [...currentState.queue.items, ...items],\n },\n }));\n emitQueueChange(nextState);\n } catch (cause) {\n setError(\n normalizePlayerError(\n \"INVALID_QUEUE_ITEM\",\n \"Failed to append queue items.\",\n cause,\n ),\n );\n }\n },\n\n removeFromQueue(id) {\n const nextItems = state.queue.items.filter((item) => item.id !== id);\n const nextIndex = nextItems.findIndex(\n (item) => item.id === state.currentSource?.id,\n );\n\n const nextState = setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n items: nextItems,\n position: {\n ...currentState.queue.position,\n currentIndex: nextIndex,\n currentSourceId: nextIndex >= 0 ? (nextItems[nextIndex]?.id ?? null) : null,\n },\n },\n }));\n\n emitQueueChange(nextState);\n },\n\n clearQueue() {\n const nextState = setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n items: [],\n position: {\n ...currentState.queue.position,\n currentIndex: -1,\n currentSourceId: null,\n },\n },\n }));\n\n emitQueueChange(nextState);\n },\n\n async next() {\n const nextIndex = resolveNextQueueIndex(\"manual\");\n if (nextIndex === null) {\n return;\n }\n\n await selectQueueIndex(nextIndex, true);\n },\n\n async previous(previousOptions = {}) {\n if (!state.currentSource) {\n return;\n }\n\n const threshold =\n previousOptions.restartThresholdSeconds ??\n DEFAULT_PREVIOUS_RESTART_THRESHOLD_SECONDS;\n\n if (state.currentTime > threshold) {\n this.seek(0);\n return;\n }\n\n const previousIndex = resolvePreviousQueueIndex();\n if (previousIndex === null) {\n this.seek(0);\n return;\n }\n\n await selectQueueIndex(previousIndex, true);\n },\n\n setRepeatMode(mode) {\n const nextState = setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n position: {\n ...currentState.queue.position,\n repeatMode: mode,\n },\n },\n }));\n emitQueueChange(nextState);\n },\n\n destroy() {\n if (destroyed) {\n return;\n }\n\n destroyed = true;\n shouldAutoplayAfterLoad = false;\n for (const detach of detachEngineListeners) {\n detach();\n }\n suppressPauseEvent = true;\n engine.destroy();\n suppressPauseEvent = false;\n\n const nextState = setState(() => createInitialState(options));\n emit(\"destroy\", { state: nextState });\n subscribers.clear();\n for (const eventName of Object.keys(eventListeners) as AudioPlayerEventName[]) {\n eventListeners[eventName].clear();\n }\n },\n };\n};\n\nexport const attachAudioPlayerPersistence = (\n player: AudioPlayer,\n options: AudioPlayerPersistenceOptions,\n): AudioPlayerPersistenceController => {\n const maxAgeMs = options.maxAgeMs ?? DEFAULT_PERSISTENCE_MAX_AGE_MS;\n const saveIntervalMs =\n options.saveIntervalMs ?? DEFAULT_PERSISTENCE_SAVE_INTERVAL_MS;\n let destroyed = false;\n let playIntervalId: ReturnType<typeof setInterval> | null = null;\n\n const save = (): void => {\n if (destroyed) {\n return;\n }\n\n const state = player.getState();\n if (!state.currentSource) {\n options.adapter.clear();\n return;\n }\n\n options.adapter.save(toPersistedPlayerState(state));\n };\n\n const clear = (): void => {\n options.adapter.clear();\n };\n\n const stopPlayInterval = (): void => {\n if (playIntervalId !== null) {\n clearInterval(playIntervalId);\n playIntervalId = null;\n }\n };\n\n const startPlayInterval = (): void => {\n if (playIntervalId !== null) {\n return;\n }\n\n playIntervalId = setInterval(() => {\n save();\n }, saveIntervalMs);\n };\n\n const waitForRestoredSource = (sourceId: string): Promise<void> =>\n new Promise((resolve) => {\n const unsubscribe = player.subscribe((state) => {\n if (state.currentSourceId !== sourceId) {\n return;\n }\n\n if (state.status === \"loading\") {\n return;\n }\n\n unsubscribe();\n resolve();\n });\n });\n\n const restore = async (): Promise<PersistedPlayerState | null> => {\n const persisted = options.adapter.load();\n if (!persisted) {\n return null;\n }\n\n if (Date.now() - persisted.savedAt > maxAgeMs) {\n options.adapter.clear();\n return null;\n }\n\n player.setRepeatMode(persisted.queue.position.repeatMode);\n player.setVolume(persisted.volume);\n player.setMuted(persisted.muted);\n player.setRate(persisted.rate);\n\n if (persisted.queue.items.length > 0) {\n await player.setQueue(persisted.queue.items, {\n startAtId: persisted.queue.position.currentSourceId ?? undefined,\n });\n } else if (persisted.currentSource) {\n await player.load(persisted.currentSource);\n } else {\n return persisted;\n }\n\n if (persisted.currentSourceId) {\n await waitForRestoredSource(persisted.currentSourceId);\n }\n\n if (persisted.currentTime > 0) {\n player.seek(persisted.currentTime);\n }\n\n return persisted;\n };\n\n const stateUnsubscribe = player.subscribe((state) => {\n if (state.status === \"playing\") {\n startPlayInterval();\n return;\n }\n\n stopPlayInterval();\n });\n\n const pauseUnsubscribe = player.on(\"pause\", () => {\n save();\n });\n const endedUnsubscribe = player.on(\"ended\", () => {\n save();\n });\n const sourceUnsubscribe = player.on(\"sourcechange\", () => {\n save();\n });\n const queueUnsubscribe = player.on(\"queuechange\", () => {\n save();\n });\n const rateUnsubscribe = player.on(\"ratechange\", () => {\n save();\n });\n const volumeUnsubscribe = player.on(\"volumechange\", () => {\n save();\n });\n\n const beforeUnloadHandler = (): void => {\n save();\n };\n\n const visibilityHandler = (): void => {\n if (typeof document === \"undefined\") {\n return;\n }\n\n if (document.visibilityState === \"hidden\") {\n save();\n }\n };\n\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"beforeunload\", beforeUnloadHandler);\n }\n\n if (typeof document !== \"undefined\") {\n document.addEventListener(\"visibilitychange\", visibilityHandler);\n }\n\n if (options.autoRestore !== false) {\n void restore();\n }\n\n return {\n restore,\n save,\n clear,\n destroy() {\n destroyed = true;\n stopPlayInterval();\n stateUnsubscribe();\n pauseUnsubscribe();\n endedUnsubscribe();\n sourceUnsubscribe();\n queueUnsubscribe();\n rateUnsubscribe();\n volumeUnsubscribe();\n\n if (typeof window !== \"undefined\") {\n window.removeEventListener(\"beforeunload\", beforeUnloadHandler);\n }\n\n if (typeof document !== \"undefined\") {\n document.removeEventListener(\"visibilitychange\", visibilityHandler);\n }\n },\n };\n};\n\nexport const attachAudioPlayerProgressReporter = (\n player: AudioPlayer,\n options: AudioPlayerProgressReporterOptions,\n): AudioPlayerProgressReporterController => {\n const intervalMs = options.intervalMs ?? DEFAULT_PROGRESS_REPORT_INTERVAL_MS;\n let destroyed = false;\n let intervalId: ReturnType<typeof setInterval> | null = null;\n\n const report = (): void => {\n if (destroyed) {\n return;\n }\n\n const state = player.getState();\n if (!state.currentSource) {\n return;\n }\n\n options.onReport(toProgressSnapshot(state));\n };\n\n const stopInterval = (): void => {\n if (intervalId !== null) {\n clearInterval(intervalId);\n intervalId = null;\n }\n };\n\n const startInterval = (): void => {\n if (intervalId !== null) {\n return;\n }\n\n intervalId = setInterval(() => {\n report();\n }, intervalMs);\n };\n\n const stateUnsubscribe = player.subscribe((state) => {\n if (state.status === \"playing\") {\n startInterval();\n return;\n }\n\n stopInterval();\n });\n\n const pauseUnsubscribe = player.on(\"pause\", () => {\n report();\n });\n const endedUnsubscribe = player.on(\"ended\", () => {\n report();\n });\n const seekedUnsubscribe = player.on(\"seeked\", () => {\n report();\n });\n const sourceUnsubscribe = player.on(\"sourcechange\", () => {\n report();\n });\n\n return {\n report,\n destroy() {\n destroyed = true;\n stopInterval();\n stateUnsubscribe();\n pauseUnsubscribe();\n endedUnsubscribe();\n seekedUnsubscribe();\n sourceUnsubscribe();\n },\n };\n};\n\nexport const attachAudioPlayerMediaSession = (\n player: AudioPlayer,\n options: AudioPlayerMediaSessionOptions = {},\n): AudioPlayerMediaSessionController => {\n if (!hasMediaSession()) {\n return {\n sync() {},\n destroy() {},\n };\n }\n\n const artworkSizes =\n options.artworkSizes ?? DEFAULT_MEDIA_SESSION_ARTWORK_SIZES;\n const seekOffsetSeconds =\n options.seekOffsetSeconds ?? DEFAULT_MEDIA_SESSION_SEEK_OFFSET_SECONDS;\n let destroyed = false;\n\n const sync = (): void => {\n if (destroyed || !hasMediaSession()) {\n return;\n }\n\n const state = player.getState();\n const source = state.currentSource;\n\n navigator.mediaSession.metadata = source\n ? new MediaMetadata({\n title: source.title ?? \"\",\n artist: source.artist ?? \"\",\n album: source.album ?? \"\",\n artwork: createMediaSessionArtwork(source, artworkSizes),\n })\n : null;\n\n navigator.mediaSession.playbackState =\n state.status === \"playing\"\n ? \"playing\"\n : state.currentSource\n ? \"paused\"\n : \"none\";\n\n if (state.currentSource && state.duration > 0) {\n try {\n navigator.mediaSession.setPositionState({\n duration: state.duration,\n playbackRate: state.rate,\n position: Math.min(state.currentTime, state.duration),\n });\n } catch {\n // Ignore unsupported position state implementations.\n }\n } else {\n try {\n navigator.mediaSession.setPositionState();\n } catch {\n // Ignore unsupported position state implementations.\n }\n }\n };\n\n const setActionHandler = (\n action: MediaSessionAction,\n handler: MediaSessionActionHandler | null,\n ): void => {\n try {\n navigator.mediaSession.setActionHandler(action, handler);\n } catch {\n // Ignore unsupported actions.\n }\n };\n\n setActionHandler(\"play\", () => {\n void player.play();\n });\n setActionHandler(\"pause\", () => {\n player.pause();\n });\n setActionHandler(\"seekbackward\", () => {\n const state = player.getState();\n player.seek(Math.max(0, state.currentTime - seekOffsetSeconds));\n });\n setActionHandler(\"seekforward\", () => {\n const state = player.getState();\n const max = state.duration > 0 ? state.duration : state.currentTime + seekOffsetSeconds;\n player.seek(Math.min(max, state.currentTime + seekOffsetSeconds));\n });\n setActionHandler(\"previoustrack\", () => {\n void player.previous();\n });\n setActionHandler(\"nexttrack\", () => {\n void player.next();\n });\n setActionHandler(\"seekto\", (details) => {\n if (details.seekTime === undefined) {\n return;\n }\n\n player.seek(details.seekTime);\n });\n setActionHandler(\"stop\", () => {\n player.pause();\n });\n\n const stateUnsubscribe = player.subscribe(() => {\n sync();\n });\n\n sync();\n\n return {\n sync,\n destroy() {\n destroyed = true;\n stateUnsubscribe();\n if (!hasMediaSession()) {\n return;\n }\n\n const actions: MediaSessionAction[] = [\n \"play\",\n \"pause\",\n \"seekbackward\",\n \"seekforward\",\n \"previoustrack\",\n \"nexttrack\",\n \"seekto\",\n \"stop\",\n ];\n\n for (const action of actions) {\n setActionHandler(action, null);\n }\n\n navigator.mediaSession.metadata = null;\n navigator.mediaSession.playbackState = \"none\";\n try {\n navigator.mediaSession.setPositionState();\n } catch {\n // Ignore unsupported position state implementations.\n }\n },\n };\n};\n"],"mappings":"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","names":["endedState"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export type PlayerStatus =\n | \"idle\"\n | \"loading\"\n | \"ready\"\n | \"playing\"\n | \"paused\"\n | \"ended\"\n | \"error\";\n\nexport type RepeatMode = \"off\" | \"one\" | \"all\";\n\nexport type AudioPlayerEventName =\n | \"sourcechange\"\n | \"queuechange\"\n | \"play\"\n | \"pause\"\n | \"seeking\"\n | \"seeked\"\n | \"timeupdate\"\n | \"ratechange\"\n | \"volumechange\"\n | \"ended\"\n | \"error\"\n | \"destroy\";\n\nexport interface AudioSource {\n id: string;\n src: string;\n title?: string;\n artist?: string;\n artwork?: string;\n album?: string;\n durationHint?: number;\n}\n\nexport interface AudioPlayerErrorState {\n code:\n | \"LOAD_ERROR\"\n | \"PLAY_ERROR\"\n | \"SEEK_ERROR\"\n | \"INVALID_VOLUME\"\n | \"INVALID_RATE\"\n | \"INVALID_QUEUE_ITEM\"\n | \"NO_ACTIVE_SOURCE\"\n | \"UNSUPPORTED_ENVIRONMENT\"\n | \"UNKNOWN_ERROR\";\n message: string;\n}\n\nexport interface AudioPlayerRuntimeError extends AudioPlayerErrorState {\n cause?: unknown;\n}\n\nexport interface AudioPlayerProgressState {\n currentTime: number;\n duration: number;\n buffered: number;\n playedFraction: number;\n bufferedFraction: number;\n}\n\nexport interface AudioPlayerQueuePositionState {\n currentIndex: number;\n currentSourceId: string | null;\n length: number;\n hasNext: boolean;\n hasPrevious: boolean;\n repeatMode: RepeatMode;\n}\n\nexport interface AudioPlayerQueueState {\n items: AudioSource[];\n itemIds: string[];\n position: AudioPlayerQueuePositionState;\n}\n\nexport interface AudioPlayerState {\n status: PlayerStatus;\n currentSource: AudioSource | null;\n currentSourceId: string | null;\n currentTime: number;\n duration: number;\n buffered: number;\n progress: AudioPlayerProgressState;\n rate: number;\n volume: number;\n muted: boolean;\n queue: AudioPlayerQueueState;\n error: AudioPlayerErrorState | null;\n}\n\nexport interface AudioPlayerEventMap {\n sourcechange: { source: AudioSource | null; state: AudioPlayerState };\n queuechange: { queue: AudioPlayerQueueState; state: AudioPlayerState };\n play: { source: AudioSource | null; state: AudioPlayerState };\n pause: { source: AudioSource | null; state: AudioPlayerState };\n seeking: { from: number; to: number; state: AudioPlayerState };\n seeked: { currentTime: number; state: AudioPlayerState };\n timeupdate: { currentTime: number; duration: number; state: AudioPlayerState };\n ratechange: { rate: number; state: AudioPlayerState };\n volumechange: { volume: number; muted: boolean; state: AudioPlayerState };\n ended: { source: AudioSource | null; state: AudioPlayerState };\n error: { error: AudioPlayerRuntimeError; state: AudioPlayerState };\n destroy: { state: AudioPlayerState };\n}\n\nexport interface CreateAudioPlayerOptions {\n initialVolume?: number;\n initialRate?: number;\n initialMuted?: boolean;\n initialRepeatMode?: RepeatMode;\n}\n\nexport interface SetQueueOptions {\n startAtId?: string;\n autoplay?: boolean;\n}\n\nexport interface PreviousOptions {\n restartThresholdSeconds?: number;\n}\n\nexport interface PersistedPlayerState {\n version: 1;\n savedAt: number;\n currentSource: AudioSource | null;\n currentSourceId: string | null;\n currentTime: number;\n rate: number;\n volume: number;\n muted: boolean;\n queue: {\n items: AudioSource[];\n position: {\n currentIndex: number;\n currentSourceId: string | null;\n repeatMode: RepeatMode;\n };\n };\n}\n\nexport interface AudioPlayerPersistenceAdapter {\n load(): PersistedPlayerState | null;\n save(state: PersistedPlayerState): void;\n clear(): void;\n}\n\nexport interface AudioPlayerPersistenceOptions {\n adapter: AudioPlayerPersistenceAdapter;\n autoRestore?: boolean;\n maxAgeMs?: number;\n saveIntervalMs?: number;\n}\n\nexport interface AudioPlayerPersistenceController {\n restore(): Promise<PersistedPlayerState | null>;\n save(): void;\n clear(): void;\n destroy(): void;\n}\n\nexport interface AudioPlayerProgressSnapshot {\n source: AudioSource | null;\n sourceId: string | null;\n currentTime: number;\n duration: number;\n playedFraction: number;\n status: PlayerStatus;\n queue: AudioPlayerQueuePositionState;\n}\n\nexport interface AudioPlayerProgressReporterOptions {\n intervalMs?: number;\n onReport: (snapshot: AudioPlayerProgressSnapshot) => void;\n}\n\nexport interface AudioPlayerProgressReporterController {\n report(): void;\n destroy(): void;\n}\n\nexport interface AudioPlayerMediaSessionOptions {\n artworkSizes?: number[];\n seekOffsetSeconds?: number;\n}\n\nexport interface AudioPlayerMediaSessionController {\n sync(): void;\n destroy(): void;\n}\n\nexport type AudioPlayerEventListener<K extends AudioPlayerEventName> = (\n event: AudioPlayerEventMap[K],\n) => void;\n\nexport interface AudioPlayer {\n getState(): AudioPlayerState;\n subscribe(listener: (state: AudioPlayerState) => void): () => void;\n on<K extends AudioPlayerEventName>(\n eventName: K,\n listener: AudioPlayerEventListener<K>,\n ): () => void;\n\n load(source: AudioSource): Promise<void>;\n play(source?: AudioSource): Promise<void>;\n pause(): void;\n toggle(): Promise<void>;\n unload(): void;\n seek(time: number): void;\n setRate(rate: number): void;\n setVolume(volume: number): void;\n setMuted(muted: boolean): void;\n\n setQueue(items: AudioSource[], options?: SetQueueOptions): Promise<void>;\n appendToQueue(items: AudioSource[]): void;\n removeFromQueue(id: string): void;\n clearQueue(): void;\n next(): Promise<void>;\n previous(options?: PreviousOptions): Promise<void>;\n setRepeatMode(mode: RepeatMode): void;\n\n destroy(): void;\n}\n\nconst DEFAULT_PREVIOUS_RESTART_THRESHOLD_SECONDS = 5;\nconst DEFAULT_PERSISTENCE_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000;\nconst DEFAULT_PERSISTENCE_SAVE_INTERVAL_MS = 5000;\nconst DEFAULT_PROGRESS_REPORT_INTERVAL_MS = 5000;\nconst DEFAULT_MEDIA_SESSION_ARTWORK_SIZES = [96, 128, 192, 256, 384, 512];\nconst DEFAULT_MEDIA_SESSION_SEEK_OFFSET_SECONDS = 10;\n\ntype AudioEngineEventName =\n | \"loadedmetadata\"\n | \"timeupdate\"\n | \"progress\"\n | \"play\"\n | \"pause\"\n | \"seeked\"\n | \"ratechange\"\n | \"volumechange\"\n | \"ended\"\n | \"error\";\n\ninterface AudioEngineSnapshot {\n currentTime: number;\n duration: number;\n buffered: number;\n rate: number;\n volume: number;\n muted: boolean;\n}\n\ninterface AudioEngine {\n readonly available: boolean;\n getSnapshot(durationHint?: number): AudioEngineSnapshot;\n getRuntimeError(): unknown;\n on(eventName: AudioEngineEventName, listener: EventListener): () => void;\n setSource(src: string): void;\n clearSource(): void;\n load(): void;\n play(): Promise<void>;\n pause(): void;\n setCurrentTime(time: number): void;\n setPlaybackRate(rate: number): void;\n setVolume(volume: number): void;\n setMuted(muted: boolean): void;\n destroy(): void;\n}\n\nconst createInitialState = (\n options: CreateAudioPlayerOptions,\n): AudioPlayerState => ({\n status: \"idle\",\n currentSource: null,\n currentSourceId: null,\n currentTime: 0,\n duration: 0,\n buffered: 0,\n progress: {\n currentTime: 0,\n duration: 0,\n buffered: 0,\n playedFraction: 0,\n bufferedFraction: 0,\n },\n rate: options.initialRate ?? 1,\n volume: options.initialVolume ?? 1,\n muted: options.initialMuted ?? false,\n queue: {\n items: [],\n itemIds: [],\n position: {\n currentIndex: -1,\n currentSourceId: null,\n length: 0,\n repeatMode: options.initialRepeatMode ?? \"off\",\n hasNext: false,\n hasPrevious: false,\n },\n },\n error: null,\n});\n\nconst createPlayerError = (\n code: AudioPlayerRuntimeError[\"code\"],\n message: string,\n cause?: unknown,\n): AudioPlayerRuntimeError => ({\n code,\n message,\n cause,\n});\n\nconst isRuntimePlayerError = (\n value: unknown,\n): value is AudioPlayerRuntimeError =>\n !!value &&\n typeof value === \"object\" &&\n \"code\" in value &&\n \"message\" in value;\n\nconst normalizePlayerError = (\n fallbackCode: AudioPlayerRuntimeError[\"code\"],\n fallbackMessage: string,\n cause: unknown,\n): AudioPlayerRuntimeError =>\n isRuntimePlayerError(cause)\n ? cause\n : createPlayerError(fallbackCode, fallbackMessage, cause);\n\nconst assertStableSource = (source: AudioSource): void => {\n if (!source.id || !source.src) {\n throw createPlayerError(\n \"INVALID_QUEUE_ITEM\",\n \"AudioSource requires stable id and src.\",\n );\n }\n};\n\nconst isFiniteNumber = (value: number): boolean =>\n Number.isFinite(value) && !Number.isNaN(value);\n\nconst safeDuration = (audio: HTMLAudioElement | null, hint?: number): number => {\n const duration = audio?.duration;\n return duration !== undefined && isFiniteNumber(duration) ? duration : hint ?? 0;\n};\n\nconst safeBuffered = (audio: HTMLAudioElement | null): number => {\n if (!audio || audio.buffered.length === 0) {\n return 0;\n }\n\n try {\n return audio.buffered.end(audio.buffered.length - 1);\n } catch {\n return 0;\n }\n};\n\nconst cloneQueueState = (state: AudioPlayerState): AudioPlayerQueueState => ({\n items: [...state.queue.items],\n itemIds: [...state.queue.itemIds],\n position: {\n ...state.queue.position,\n },\n});\n\nconst updateQueueFlags = (state: AudioPlayerState): AudioPlayerState => {\n const { items, position } = state.queue;\n const { currentIndex, repeatMode } = position;\n const lastIndex = items.length - 1;\n const hasItems = items.length > 0;\n const hasNext =\n !hasItems || currentIndex < 0\n ? false\n : repeatMode === \"all\"\n ? items.length > 0\n : currentIndex < lastIndex;\n const hasPrevious =\n !hasItems || currentIndex < 0\n ? false\n : repeatMode === \"all\"\n ? items.length > 0\n : currentIndex > 0;\n\n return {\n ...state,\n queue: {\n ...state.queue,\n itemIds: items.map((item) => item.id),\n position: {\n ...position,\n currentSourceId: state.currentSource?.id ?? null,\n length: items.length,\n hasNext,\n hasPrevious,\n },\n },\n };\n};\n\nconst createAudioElement = (): HTMLAudioElement | null => {\n if (typeof Audio === \"undefined\") {\n return null;\n }\n\n return new Audio();\n};\n\nconst createUnavailableAudioEngine = (): AudioEngine => {\n const unavailableError = (): AudioPlayerRuntimeError =>\n createPlayerError(\n \"UNSUPPORTED_ENVIRONMENT\",\n \"HTMLAudioElement is not available in this environment.\",\n );\n\n return {\n available: false,\n getSnapshot(durationHint) {\n return {\n currentTime: 0,\n duration: durationHint ?? 0,\n buffered: 0,\n rate: 1,\n volume: 1,\n muted: false,\n };\n },\n getRuntimeError() {\n return unavailableError();\n },\n on() {\n return () => {};\n },\n setSource() {\n throw unavailableError();\n },\n clearSource() {\n throw unavailableError();\n },\n load() {\n throw unavailableError();\n },\n play() {\n throw unavailableError();\n },\n pause() {\n throw unavailableError();\n },\n setCurrentTime() {\n throw unavailableError();\n },\n setPlaybackRate() {\n throw unavailableError();\n },\n setVolume() {\n throw unavailableError();\n },\n setMuted() {\n throw unavailableError();\n },\n destroy() {},\n };\n};\n\nconst createHtmlAudioEngine = (): AudioEngine => {\n const audio = createAudioElement();\n if (!audio) {\n return createUnavailableAudioEngine();\n }\n\n audio.preload = \"metadata\";\n const clearSource = (): void => {\n const element = audio as HTMLAudioElement & {\n removeAttribute?: (name: string) => void;\n };\n if (typeof element.removeAttribute === \"function\") {\n element.removeAttribute(\"src\");\n return;\n }\n\n audio.src = \"\";\n };\n\n return {\n available: true,\n getSnapshot(durationHint) {\n return {\n currentTime: audio.currentTime,\n duration: safeDuration(audio, durationHint),\n buffered: safeBuffered(audio),\n rate: audio.playbackRate,\n volume: audio.volume,\n muted: audio.muted,\n };\n },\n getRuntimeError() {\n return audio.error;\n },\n on(eventName, listener) {\n audio.addEventListener(eventName, listener);\n return () => {\n audio.removeEventListener(eventName, listener);\n };\n },\n setSource(src) {\n audio.src = src;\n },\n clearSource() {\n clearSource();\n },\n load() {\n audio.load();\n },\n play() {\n return audio.play();\n },\n pause() {\n audio.pause();\n },\n setCurrentTime(time) {\n audio.currentTime = time;\n },\n setPlaybackRate(rate) {\n audio.playbackRate = rate;\n },\n setVolume(volume) {\n audio.volume = volume;\n },\n setMuted(muted) {\n audio.muted = muted;\n },\n destroy() {\n audio.pause();\n clearSource();\n audio.load();\n },\n };\n};\n\nconst isBrowserStorageAvailable = (): boolean =>\n typeof window !== \"undefined\" && typeof window.localStorage !== \"undefined\";\n\nconst isPersistedPlayerState = (value: unknown): value is PersistedPlayerState => {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n\n const candidate = value as Partial<PersistedPlayerState>;\n return (\n candidate.version === 1 &&\n typeof candidate.savedAt === \"number\" &&\n \"currentSource\" in candidate &&\n typeof candidate.currentTime === \"number\" &&\n typeof candidate.rate === \"number\" &&\n typeof candidate.volume === \"number\" &&\n typeof candidate.muted === \"boolean\" &&\n !!candidate.queue &&\n Array.isArray(candidate.queue.items) &&\n !!candidate.queue.position\n );\n};\n\nconst toPersistedPlayerState = (state: AudioPlayerState): PersistedPlayerState => ({\n version: 1,\n savedAt: Date.now(),\n currentSource: state.currentSource,\n currentSourceId: state.currentSourceId,\n currentTime: state.currentTime,\n rate: state.rate,\n volume: state.volume,\n muted: state.muted,\n queue: {\n items: [...state.queue.items],\n position: {\n currentIndex: state.queue.position.currentIndex,\n currentSourceId: state.queue.position.currentSourceId,\n repeatMode: state.queue.position.repeatMode,\n },\n },\n});\n\nconst toProgressSnapshot = (\n state: AudioPlayerState,\n): AudioPlayerProgressSnapshot => ({\n source: state.currentSource,\n sourceId: state.currentSourceId,\n currentTime: state.currentTime,\n duration: state.duration,\n playedFraction: state.progress.playedFraction,\n status: state.status,\n queue: {\n ...state.queue.position,\n },\n});\n\nconst hasMediaSession = (): boolean =>\n typeof navigator !== \"undefined\" && \"mediaSession\" in navigator;\n\nconst createMediaSessionArtwork = (\n source: AudioSource | null,\n sizes: number[],\n): MediaImage[] => {\n if (!source?.artwork) {\n return [];\n }\n\n return sizes.map((size) => ({\n src: source.artwork as string,\n sizes: `${size}x${size}`,\n }));\n};\n\nexport const createLocalStoragePersistenceAdapter = (\n key: string,\n): AudioPlayerPersistenceAdapter => ({\n load() {\n if (!isBrowserStorageAvailable()) {\n return null;\n }\n\n try {\n const raw = window.localStorage.getItem(key);\n if (!raw) {\n return null;\n }\n\n const parsed: unknown = JSON.parse(raw);\n return isPersistedPlayerState(parsed) ? parsed : null;\n } catch {\n return null;\n }\n },\n\n save(state) {\n if (!isBrowserStorageAvailable()) {\n return;\n }\n\n window.localStorage.setItem(key, JSON.stringify(state));\n },\n\n clear() {\n if (!isBrowserStorageAvailable()) {\n return;\n }\n\n window.localStorage.removeItem(key);\n },\n});\n\nexport const createAudioPlayer = (\n options: CreateAudioPlayerOptions = {},\n): AudioPlayer => {\n let state = updateQueueFlags(createInitialState(options));\n let destroyed = false;\n let shouldAutoplayAfterLoad = false;\n let suppressPauseEvent = false;\n\n const engine = createHtmlAudioEngine();\n const subscribers = new Set<(nextState: AudioPlayerState) => void>();\n const eventListeners: {\n [K in AudioPlayerEventName]: Set<AudioPlayerEventListener<K>>;\n } = {\n sourcechange: new Set(),\n queuechange: new Set(),\n play: new Set(),\n pause: new Set(),\n seeking: new Set(),\n seeked: new Set(),\n timeupdate: new Set(),\n ratechange: new Set(),\n volumechange: new Set(),\n ended: new Set(),\n error: new Set(),\n destroy: new Set(),\n };\n\n const getState = (): AudioPlayerState => state;\n\n const publishState = (): void => {\n for (const subscriber of subscribers) {\n subscriber(state);\n }\n };\n\n const emit = <K extends AudioPlayerEventName>(\n eventName: K,\n event: AudioPlayerEventMap[K],\n ): void => {\n for (const listener of eventListeners[eventName]) {\n listener(event);\n }\n };\n\n const setState = (\n updater: (currentState: AudioPlayerState) => AudioPlayerState,\n ): AudioPlayerState => {\n state = updateQueueFlags(updater(state));\n publishState();\n return state;\n };\n\n const setError = (error: AudioPlayerRuntimeError): void => {\n shouldAutoplayAfterLoad = false;\n const nextState = setState((currentState) => ({\n ...currentState,\n status: \"error\",\n error: {\n code: error.code,\n message: error.message,\n },\n }));\n emit(\"error\", { error, state: nextState });\n };\n\n const clearError = (): void => {\n if (!state.error) {\n return;\n }\n\n setState((currentState) => ({\n ...currentState,\n error: null,\n }));\n };\n\n const syncAudioSnapshot = (\n statusOverride?: PlayerStatus,\n ): AudioPlayerState => {\n const snapshot = engine.getSnapshot(state.currentSource?.durationHint);\n const currentTime = snapshot.currentTime;\n const duration = snapshot.duration;\n const buffered = snapshot.buffered;\n const playedFraction =\n duration > 0 ? Math.min(1, Math.max(0, currentTime / duration)) : 0;\n const bufferedFraction =\n duration > 0 ? Math.min(1, Math.max(0, buffered / duration)) : 0;\n\n const nextState = setState((currentState) => ({\n ...currentState,\n currentSourceId: currentState.currentSource?.id ?? null,\n currentTime,\n duration,\n buffered,\n progress: {\n currentTime,\n duration,\n buffered,\n playedFraction,\n bufferedFraction,\n },\n rate: snapshot.rate,\n volume: snapshot.volume,\n muted: snapshot.muted,\n status: statusOverride ?? currentState.status,\n error:\n statusOverride === \"error\" ? currentState.error : null,\n }));\n\n return nextState;\n };\n\n const findQueueIndexById = (id: string | null | undefined): number =>\n id ? state.queue.items.findIndex((item) => item.id === id) : -1;\n\n const resolveNextQueueIndex = (\n mode: \"manual\" | \"ended\",\n ): number | null => {\n const { items, position } = state.queue;\n const { currentIndex, repeatMode } = position;\n\n if (items.length === 0 || currentIndex < 0) {\n return null;\n }\n\n if (repeatMode === \"one\") {\n return currentIndex;\n }\n\n if (currentIndex < items.length - 1) {\n return currentIndex + 1;\n }\n\n if (repeatMode === \"all\") {\n return 0;\n }\n\n return mode === \"ended\" ? -1 : null;\n };\n\n const resolvePreviousQueueIndex = (): number | null => {\n const { items, position } = state.queue;\n const { currentIndex, repeatMode } = position;\n\n if (items.length === 0 || currentIndex < 0) {\n return null;\n }\n\n if (currentIndex > 0) {\n return currentIndex - 1;\n }\n\n if (repeatMode === \"all\") {\n return items.length - 1;\n }\n\n return null;\n };\n\n const updateCurrentSource = (\n source: AudioSource | null,\n nextStatus: PlayerStatus,\n ): AudioPlayerState => {\n const queueIndex = findQueueIndexById(source?.id);\n const nextState = setState((currentState) => ({\n ...currentState,\n currentSource: source,\n currentSourceId: source?.id ?? null,\n currentTime: 0,\n duration: source?.durationHint ?? 0,\n buffered: 0,\n progress: {\n currentTime: 0,\n duration: source?.durationHint ?? 0,\n buffered: 0,\n playedFraction: 0,\n bufferedFraction: 0,\n },\n status: nextStatus,\n error: null,\n queue: {\n ...currentState.queue,\n position: {\n ...currentState.queue.position,\n currentIndex: queueIndex,\n currentSourceId: source?.id ?? null,\n },\n },\n }));\n emit(\"sourcechange\", { source, state: nextState });\n return nextState;\n };\n\n const setQueueState = (\n items: AudioSource[],\n currentIndex: number,\n ): AudioPlayerState =>\n setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n items,\n position: {\n ...currentState.queue.position,\n currentIndex,\n },\n },\n }));\n\n const emitQueueChange = (nextState: AudioPlayerState): void => {\n emit(\"queuechange\", { queue: cloneQueueState(nextState), state: nextState });\n };\n\n const attachSourceToAudio = (\n source: AudioSource,\n autoplayAfterLoad: boolean,\n ): void => {\n shouldAutoplayAfterLoad = autoplayAfterLoad;\n suppressPauseEvent = true;\n try {\n engine.pause();\n } finally {\n suppressPauseEvent = false;\n }\n engine.setSource(source.src);\n engine.setCurrentTime(0);\n engine.setPlaybackRate(state.rate);\n engine.setVolume(state.volume);\n engine.setMuted(state.muted);\n engine.load();\n };\n\n const loadInternal = async (\n source: AudioSource,\n autoplayAfterLoad = false,\n ): Promise<void> => {\n assertStableSource(source);\n updateCurrentSource(source, \"loading\");\n attachSourceToAudio(source, autoplayAfterLoad);\n };\n\n const selectQueueIndex = async (\n index: number,\n autoplayAfterLoad = false,\n ): Promise<AudioSource | null> => {\n const item = state.queue.items[index] ?? null;\n if (!item) {\n return null;\n }\n\n await loadInternal(item, autoplayAfterLoad);\n const nextState = setQueueState(state.queue.items, index);\n emitQueueChange(nextState);\n return item;\n };\n\n const playLoadedAudio = async (): Promise<void> => {\n try {\n await engine.play();\n } catch (cause) {\n setError(createPlayerError(\"PLAY_ERROR\", \"Failed to start playback.\", cause));\n }\n };\n\n const handlePlaybackEnded = async (): Promise<void> => {\n if (destroyed) {\n return;\n }\n\n if (state.queue.items.length > 0 && state.queue.position.currentIndex >= 0) {\n const nextIndex = resolveNextQueueIndex(\"ended\");\n if (nextIndex === -1 || nextIndex === null) {\n const endedState = syncAudioSnapshot(\"ended\");\n emit(\"ended\", { source: endedState.currentSource, state: endedState });\n return;\n }\n\n await selectQueueIndex(nextIndex, true);\n return;\n }\n\n const endedState = syncAudioSnapshot(\"ended\");\n emit(\"ended\", { source: endedState.currentSource, state: endedState });\n };\n\n const detachEngineListeners = [\n engine.on(\"loadedmetadata\", () => {\n if (destroyed || !state.currentSource) {\n return;\n }\n\n syncAudioSnapshot(\"ready\");\n if (shouldAutoplayAfterLoad) {\n shouldAutoplayAfterLoad = false;\n void playLoadedAudio();\n }\n }),\n engine.on(\"timeupdate\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot(\n state.status === \"ended\" ? \"playing\" : undefined,\n );\n emit(\"timeupdate\", {\n currentTime: nextState.currentTime,\n duration: nextState.duration,\n state: nextState,\n });\n }),\n engine.on(\"progress\", () => {\n if (!destroyed) {\n syncAudioSnapshot();\n }\n }),\n engine.on(\"play\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot(\"playing\");\n emit(\"play\", { source: nextState.currentSource, state: nextState });\n }),\n engine.on(\"pause\", () => {\n if (destroyed || suppressPauseEvent) {\n return;\n }\n\n const nextStatus =\n state.status === \"ended\" ? \"ended\" : state.currentSource ? \"paused\" : \"idle\";\n const nextState = syncAudioSnapshot(nextStatus);\n emit(\"pause\", { source: nextState.currentSource, state: nextState });\n }),\n engine.on(\"seeked\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot();\n emit(\"seeked\", { currentTime: nextState.currentTime, state: nextState });\n emit(\"timeupdate\", {\n currentTime: nextState.currentTime,\n duration: nextState.duration,\n state: nextState,\n });\n }),\n engine.on(\"ratechange\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot();\n emit(\"ratechange\", { rate: nextState.rate, state: nextState });\n }),\n engine.on(\"volumechange\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot();\n emit(\"volumechange\", {\n volume: nextState.volume,\n muted: nextState.muted,\n state: nextState,\n });\n }),\n engine.on(\"ended\", () => {\n void handlePlaybackEnded();\n }),\n engine.on(\"error\", () => {\n if (destroyed) {\n return;\n }\n\n setError(\n createPlayerError(\n \"LOAD_ERROR\",\n \"Audio element reported a playback error.\",\n engine.getRuntimeError(),\n ),\n );\n }),\n ];\n\n return {\n getState,\n\n subscribe(listener) {\n subscribers.add(listener);\n listener(state);\n return () => {\n subscribers.delete(listener);\n };\n },\n\n on(eventName, listener) {\n eventListeners[eventName].add(\n listener as AudioPlayerEventListener<typeof eventName>,\n );\n return () => {\n eventListeners[eventName].delete(\n listener as AudioPlayerEventListener<typeof eventName>,\n );\n };\n },\n\n async load(source) {\n try {\n await loadInternal(source);\n } catch (cause) {\n setError(\n normalizePlayerError(\"LOAD_ERROR\", \"Failed to load source.\", cause),\n );\n }\n },\n\n async play(source) {\n try {\n if (source) {\n await loadInternal(source, true);\n return;\n }\n\n if (!state.currentSource) {\n setError(\n createPlayerError(\n \"NO_ACTIVE_SOURCE\",\n \"Cannot play without an active source.\",\n ),\n );\n return;\n }\n\n if (state.status === \"loading\") {\n shouldAutoplayAfterLoad = true;\n return;\n }\n\n await playLoadedAudio();\n } catch (cause) {\n setError(normalizePlayerError(\"PLAY_ERROR\", \"Failed to start playback.\", cause));\n }\n },\n\n pause() {\n if (!engine.available) {\n return;\n }\n\n shouldAutoplayAfterLoad = false;\n engine.pause();\n },\n\n async toggle() {\n if (state.status === \"playing\") {\n this.pause();\n return;\n }\n\n await this.play();\n },\n\n unload() {\n shouldAutoplayAfterLoad = false;\n\n if (engine.available) {\n suppressPauseEvent = true;\n try {\n engine.pause();\n } finally {\n suppressPauseEvent = false;\n }\n engine.clearSource();\n engine.load();\n }\n\n const nextState = updateCurrentSource(null, \"idle\");\n emitQueueChange(nextState);\n },\n\n seek(time) {\n if (!state.currentSource) {\n setError(\n createPlayerError(\"SEEK_ERROR\", \"Cannot seek without an active source.\"),\n );\n return;\n }\n\n const max = engine.getSnapshot(state.currentSource.durationHint).duration;\n const normalized = Math.max(\n 0,\n max > 0 ? Math.min(time, max) : (isFiniteNumber(time) ? time : 0),\n );\n emit(\"seeking\", { from: state.currentTime, to: normalized, state });\n\n try {\n engine.setCurrentTime(normalized);\n } catch (cause) {\n setError(normalizePlayerError(\"SEEK_ERROR\", \"Failed to seek audio.\", cause));\n }\n },\n\n setRate(rate) {\n if (!engine.available) {\n setError(\n createPlayerError(\"INVALID_RATE\", \"Audio element is unavailable.\"),\n );\n return;\n }\n\n if (!isFiniteNumber(rate) || rate <= 0) {\n setError(\n createPlayerError(\"INVALID_RATE\", \"Playback rate must be greater than 0.\"),\n );\n return;\n }\n\n engine.setPlaybackRate(rate);\n clearError();\n syncAudioSnapshot();\n },\n\n setVolume(volume) {\n if (!engine.available) {\n setError(\n createPlayerError(\"INVALID_VOLUME\", \"Audio element is unavailable.\"),\n );\n return;\n }\n\n if (!isFiniteNumber(volume) || volume < 0 || volume > 1) {\n setError(\n createPlayerError(\"INVALID_VOLUME\", \"Volume must be between 0 and 1.\"),\n );\n return;\n }\n\n engine.setVolume(volume);\n clearError();\n syncAudioSnapshot();\n },\n\n setMuted(muted) {\n if (!engine.available) {\n return;\n }\n\n engine.setMuted(muted);\n clearError();\n syncAudioSnapshot();\n },\n\n async setQueue(items, queueOptions = {}) {\n try {\n for (const item of items) {\n assertStableSource(item);\n }\n\n const startIndex =\n queueOptions.startAtId === undefined\n ? items.length > 0\n ? 0\n : -1\n : items.findIndex((item) => item.id === queueOptions.startAtId);\n\n if (queueOptions.startAtId && startIndex < 0) {\n throw createPlayerError(\n \"INVALID_QUEUE_ITEM\",\n `Queue start item ${queueOptions.startAtId} was not found.`,\n );\n }\n\n const nextState = setState((currentState) => ({\n ...currentState,\n currentSource: startIndex >= 0 ? items[startIndex] ?? null : null,\n currentSourceId: startIndex >= 0 ? (items[startIndex]?.id ?? null) : null,\n currentTime: 0,\n duration: startIndex >= 0 ? (items[startIndex]?.durationHint ?? 0) : 0,\n buffered: 0,\n progress: {\n currentTime: 0,\n duration: startIndex >= 0 ? (items[startIndex]?.durationHint ?? 0) : 0,\n buffered: 0,\n playedFraction: 0,\n bufferedFraction: 0,\n },\n status: startIndex >= 0 ? \"ready\" : \"idle\",\n error: null,\n queue: {\n ...currentState.queue,\n items: [...items],\n position: {\n ...currentState.queue.position,\n currentIndex: startIndex,\n currentSourceId:\n startIndex >= 0 ? (items[startIndex]?.id ?? null) : null,\n },\n },\n }));\n\n emitQueueChange(nextState);\n emit(\"sourcechange\", {\n source: nextState.currentSource,\n state: nextState,\n });\n\n if (nextState.currentSource) {\n await loadInternal(nextState.currentSource, queueOptions.autoplay === true);\n const syncedState = setQueueState(items, startIndex);\n emitQueueChange(syncedState);\n } else if (engine.available) {\n shouldAutoplayAfterLoad = false;\n suppressPauseEvent = true;\n engine.pause();\n suppressPauseEvent = false;\n engine.clearSource();\n engine.load();\n }\n } catch (cause) {\n setError(\n normalizePlayerError(\n \"INVALID_QUEUE_ITEM\",\n \"Failed to set queue.\",\n cause,\n ),\n );\n }\n },\n\n appendToQueue(items) {\n try {\n for (const item of items) {\n assertStableSource(item);\n }\n\n const nextState = setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n items: [...currentState.queue.items, ...items],\n },\n }));\n emitQueueChange(nextState);\n } catch (cause) {\n setError(\n normalizePlayerError(\n \"INVALID_QUEUE_ITEM\",\n \"Failed to append queue items.\",\n cause,\n ),\n );\n }\n },\n\n removeFromQueue(id) {\n const nextItems = state.queue.items.filter((item) => item.id !== id);\n const nextIndex = nextItems.findIndex(\n (item) => item.id === state.currentSource?.id,\n );\n\n const nextState = setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n items: nextItems,\n position: {\n ...currentState.queue.position,\n currentIndex: nextIndex,\n currentSourceId: nextIndex >= 0 ? (nextItems[nextIndex]?.id ?? null) : null,\n },\n },\n }));\n\n emitQueueChange(nextState);\n },\n\n clearQueue() {\n const nextState = setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n items: [],\n position: {\n ...currentState.queue.position,\n currentIndex: -1,\n currentSourceId: null,\n },\n },\n }));\n\n emitQueueChange(nextState);\n },\n\n async next() {\n const nextIndex = resolveNextQueueIndex(\"manual\");\n if (nextIndex === null) {\n return;\n }\n\n await selectQueueIndex(nextIndex, true);\n },\n\n async previous(previousOptions = {}) {\n if (!state.currentSource) {\n return;\n }\n\n const threshold =\n previousOptions.restartThresholdSeconds ??\n DEFAULT_PREVIOUS_RESTART_THRESHOLD_SECONDS;\n\n if (state.currentTime > threshold) {\n this.seek(0);\n return;\n }\n\n const previousIndex = resolvePreviousQueueIndex();\n if (previousIndex === null) {\n this.seek(0);\n return;\n }\n\n await selectQueueIndex(previousIndex, true);\n },\n\n setRepeatMode(mode) {\n const nextState = setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n position: {\n ...currentState.queue.position,\n repeatMode: mode,\n },\n },\n }));\n emitQueueChange(nextState);\n },\n\n destroy() {\n if (destroyed) {\n return;\n }\n\n destroyed = true;\n shouldAutoplayAfterLoad = false;\n for (const detach of detachEngineListeners) {\n detach();\n }\n suppressPauseEvent = true;\n engine.destroy();\n suppressPauseEvent = false;\n\n const nextState = setState(() => createInitialState(options));\n emit(\"destroy\", { state: nextState });\n subscribers.clear();\n for (const eventName of Object.keys(eventListeners) as AudioPlayerEventName[]) {\n eventListeners[eventName].clear();\n }\n },\n };\n};\n\nexport const attachAudioPlayerPersistence = (\n player: AudioPlayer,\n options: AudioPlayerPersistenceOptions,\n): AudioPlayerPersistenceController => {\n const maxAgeMs = options.maxAgeMs ?? DEFAULT_PERSISTENCE_MAX_AGE_MS;\n const saveIntervalMs =\n options.saveIntervalMs ?? DEFAULT_PERSISTENCE_SAVE_INTERVAL_MS;\n let destroyed = false;\n let playIntervalId: ReturnType<typeof setInterval> | null = null;\n\n const save = (): void => {\n if (destroyed) {\n return;\n }\n\n const state = player.getState();\n if (!state.currentSource) {\n options.adapter.clear();\n return;\n }\n\n options.adapter.save(toPersistedPlayerState(state));\n };\n\n const clear = (): void => {\n options.adapter.clear();\n };\n\n const stopPlayInterval = (): void => {\n if (playIntervalId !== null) {\n clearInterval(playIntervalId);\n playIntervalId = null;\n }\n };\n\n const startPlayInterval = (): void => {\n if (playIntervalId !== null) {\n return;\n }\n\n playIntervalId = setInterval(() => {\n save();\n }, saveIntervalMs);\n };\n\n const waitForRestoredSource = (sourceId: string): Promise<void> =>\n new Promise((resolve) => {\n let settled = false;\n let unsubscribe: (() => void) | undefined;\n unsubscribe = player.subscribe((state) => {\n if (settled || state.currentSourceId !== sourceId) {\n return;\n }\n\n if (state.status === \"loading\") {\n return;\n }\n\n settled = true;\n unsubscribe?.();\n resolve();\n });\n\n // subscribe emits synchronously, so the source may already be settled\n if (settled) {\n unsubscribe();\n }\n });\n\n const restore = async (): Promise<PersistedPlayerState | null> => {\n const persisted = options.adapter.load();\n if (!persisted) {\n return null;\n }\n\n if (Date.now() - persisted.savedAt > maxAgeMs) {\n options.adapter.clear();\n return null;\n }\n\n player.setRepeatMode(persisted.queue.position.repeatMode);\n player.setVolume(persisted.volume);\n player.setMuted(persisted.muted);\n player.setRate(persisted.rate);\n\n if (persisted.queue.items.length > 0) {\n await player.setQueue(persisted.queue.items, {\n startAtId: persisted.queue.position.currentSourceId ?? undefined,\n });\n } else if (persisted.currentSource) {\n await player.load(persisted.currentSource);\n } else {\n return persisted;\n }\n\n if (persisted.currentSourceId) {\n await waitForRestoredSource(persisted.currentSourceId);\n }\n\n if (persisted.currentTime > 0) {\n player.seek(persisted.currentTime);\n }\n\n return persisted;\n };\n\n const stateUnsubscribe = player.subscribe((state) => {\n if (state.status === \"playing\") {\n startPlayInterval();\n return;\n }\n\n stopPlayInterval();\n });\n\n const pauseUnsubscribe = player.on(\"pause\", () => {\n save();\n });\n const endedUnsubscribe = player.on(\"ended\", () => {\n save();\n });\n const sourceUnsubscribe = player.on(\"sourcechange\", () => {\n save();\n });\n const queueUnsubscribe = player.on(\"queuechange\", () => {\n save();\n });\n const rateUnsubscribe = player.on(\"ratechange\", () => {\n save();\n });\n const volumeUnsubscribe = player.on(\"volumechange\", () => {\n save();\n });\n\n const beforeUnloadHandler = (): void => {\n save();\n };\n\n const visibilityHandler = (): void => {\n if (typeof document === \"undefined\") {\n return;\n }\n\n if (document.visibilityState === \"hidden\") {\n save();\n }\n };\n\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"beforeunload\", beforeUnloadHandler);\n }\n\n if (typeof document !== \"undefined\") {\n document.addEventListener(\"visibilitychange\", visibilityHandler);\n }\n\n if (options.autoRestore !== false) {\n void restore();\n }\n\n return {\n restore,\n save,\n clear,\n destroy() {\n destroyed = true;\n stopPlayInterval();\n stateUnsubscribe();\n pauseUnsubscribe();\n endedUnsubscribe();\n sourceUnsubscribe();\n queueUnsubscribe();\n rateUnsubscribe();\n volumeUnsubscribe();\n\n if (typeof window !== \"undefined\") {\n window.removeEventListener(\"beforeunload\", beforeUnloadHandler);\n }\n\n if (typeof document !== \"undefined\") {\n document.removeEventListener(\"visibilitychange\", visibilityHandler);\n }\n },\n };\n};\n\nexport const attachAudioPlayerProgressReporter = (\n player: AudioPlayer,\n options: AudioPlayerProgressReporterOptions,\n): AudioPlayerProgressReporterController => {\n const intervalMs = options.intervalMs ?? DEFAULT_PROGRESS_REPORT_INTERVAL_MS;\n let destroyed = false;\n let intervalId: ReturnType<typeof setInterval> | null = null;\n\n const report = (): void => {\n if (destroyed) {\n return;\n }\n\n const state = player.getState();\n if (!state.currentSource) {\n return;\n }\n\n options.onReport(toProgressSnapshot(state));\n };\n\n const stopInterval = (): void => {\n if (intervalId !== null) {\n clearInterval(intervalId);\n intervalId = null;\n }\n };\n\n const startInterval = (): void => {\n if (intervalId !== null) {\n return;\n }\n\n intervalId = setInterval(() => {\n report();\n }, intervalMs);\n };\n\n const stateUnsubscribe = player.subscribe((state) => {\n if (state.status === \"playing\") {\n startInterval();\n return;\n }\n\n stopInterval();\n });\n\n const pauseUnsubscribe = player.on(\"pause\", () => {\n report();\n });\n const endedUnsubscribe = player.on(\"ended\", () => {\n report();\n });\n const seekedUnsubscribe = player.on(\"seeked\", () => {\n report();\n });\n const sourceUnsubscribe = player.on(\"sourcechange\", () => {\n report();\n });\n\n return {\n report,\n destroy() {\n destroyed = true;\n stopInterval();\n stateUnsubscribe();\n pauseUnsubscribe();\n endedUnsubscribe();\n seekedUnsubscribe();\n sourceUnsubscribe();\n },\n };\n};\n\nexport const attachAudioPlayerMediaSession = (\n player: AudioPlayer,\n options: AudioPlayerMediaSessionOptions = {},\n): AudioPlayerMediaSessionController => {\n if (!hasMediaSession()) {\n return {\n sync() {},\n destroy() {},\n };\n }\n\n const artworkSizes =\n options.artworkSizes ?? DEFAULT_MEDIA_SESSION_ARTWORK_SIZES;\n const seekOffsetSeconds =\n options.seekOffsetSeconds ?? DEFAULT_MEDIA_SESSION_SEEK_OFFSET_SECONDS;\n let destroyed = false;\n\n const sync = (): void => {\n if (destroyed || !hasMediaSession()) {\n return;\n }\n\n const state = player.getState();\n const source = state.currentSource;\n\n navigator.mediaSession.metadata = source\n ? new MediaMetadata({\n title: source.title ?? \"\",\n artist: source.artist ?? \"\",\n album: source.album ?? \"\",\n artwork: createMediaSessionArtwork(source, artworkSizes),\n })\n : null;\n\n navigator.mediaSession.playbackState =\n state.status === \"playing\"\n ? \"playing\"\n : state.currentSource\n ? \"paused\"\n : \"none\";\n\n if (state.currentSource && state.duration > 0) {\n try {\n navigator.mediaSession.setPositionState({\n duration: state.duration,\n playbackRate: state.rate,\n position: Math.min(state.currentTime, state.duration),\n });\n } catch {\n // Ignore unsupported position state implementations.\n }\n } else {\n try {\n navigator.mediaSession.setPositionState();\n } catch {\n // Ignore unsupported position state implementations.\n }\n }\n };\n\n const setActionHandler = (\n action: MediaSessionAction,\n handler: MediaSessionActionHandler | null,\n ): void => {\n try {\n navigator.mediaSession.setActionHandler(action, handler);\n } catch {\n // Ignore unsupported actions.\n }\n };\n\n setActionHandler(\"play\", () => {\n void player.play();\n });\n setActionHandler(\"pause\", () => {\n player.pause();\n });\n setActionHandler(\"seekbackward\", () => {\n const state = player.getState();\n player.seek(Math.max(0, state.currentTime - seekOffsetSeconds));\n });\n setActionHandler(\"seekforward\", () => {\n const state = player.getState();\n const max = state.duration > 0 ? state.duration : state.currentTime + seekOffsetSeconds;\n player.seek(Math.min(max, state.currentTime + seekOffsetSeconds));\n });\n setActionHandler(\"previoustrack\", () => {\n void player.previous();\n });\n setActionHandler(\"nexttrack\", () => {\n void player.next();\n });\n setActionHandler(\"seekto\", (details) => {\n if (details.seekTime === undefined) {\n return;\n }\n\n player.seek(details.seekTime);\n });\n setActionHandler(\"stop\", () => {\n player.pause();\n });\n\n const stateUnsubscribe = player.subscribe(() => {\n sync();\n });\n\n sync();\n\n return {\n sync,\n destroy() {\n destroyed = true;\n stateUnsubscribe();\n if (!hasMediaSession()) {\n return;\n }\n\n const actions: MediaSessionAction[] = [\n \"play\",\n \"pause\",\n \"seekbackward\",\n \"seekforward\",\n \"previoustrack\",\n \"nexttrack\",\n \"seekto\",\n \"stop\",\n ];\n\n for (const action of actions) {\n setActionHandler(action, null);\n }\n\n navigator.mediaSession.metadata = null;\n navigator.mediaSession.playbackState = \"none\";\n try {\n navigator.mediaSession.setPositionState();\n } catch {\n // Ignore unsupported position state implementations.\n }\n },\n };\n};\n"],"mappings":"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","names":["endedState"]}
package/dist/index.cjs CHANGED
@@ -990,16 +990,22 @@ var attachAudioPlayerPersistence = (player, options) => {
990
990
  }, saveIntervalMs);
991
991
  };
992
992
  const waitForRestoredSource = (sourceId) => new Promise((resolve) => {
993
- const unsubscribe = player.subscribe((state) => {
994
- if (state.currentSourceId !== sourceId) {
993
+ let settled = false;
994
+ let unsubscribe;
995
+ unsubscribe = player.subscribe((state) => {
996
+ if (settled || state.currentSourceId !== sourceId) {
995
997
  return;
996
998
  }
997
999
  if (state.status === "loading") {
998
1000
  return;
999
1001
  }
1000
- unsubscribe();
1002
+ settled = true;
1003
+ unsubscribe?.();
1001
1004
  resolve();
1002
1005
  });
1006
+ if (settled) {
1007
+ unsubscribe();
1008
+ }
1003
1009
  });
1004
1010
  const restore = async () => {
1005
1011
  const persisted = options.adapter.load();
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export type PlayerStatus =\n | \"idle\"\n | \"loading\"\n | \"ready\"\n | \"playing\"\n | \"paused\"\n | \"ended\"\n | \"error\";\n\nexport type RepeatMode = \"off\" | \"one\" | \"all\";\n\nexport type AudioPlayerEventName =\n | \"sourcechange\"\n | \"queuechange\"\n | \"play\"\n | \"pause\"\n | \"seeking\"\n | \"seeked\"\n | \"timeupdate\"\n | \"ratechange\"\n | \"volumechange\"\n | \"ended\"\n | \"error\"\n | \"destroy\";\n\nexport interface AudioSource {\n id: string;\n src: string;\n title?: string;\n artist?: string;\n artwork?: string;\n album?: string;\n durationHint?: number;\n}\n\nexport interface AudioPlayerErrorState {\n code:\n | \"LOAD_ERROR\"\n | \"PLAY_ERROR\"\n | \"SEEK_ERROR\"\n | \"INVALID_VOLUME\"\n | \"INVALID_RATE\"\n | \"INVALID_QUEUE_ITEM\"\n | \"NO_ACTIVE_SOURCE\"\n | \"UNSUPPORTED_ENVIRONMENT\"\n | \"UNKNOWN_ERROR\";\n message: string;\n}\n\nexport interface AudioPlayerRuntimeError extends AudioPlayerErrorState {\n cause?: unknown;\n}\n\nexport interface AudioPlayerProgressState {\n currentTime: number;\n duration: number;\n buffered: number;\n playedFraction: number;\n bufferedFraction: number;\n}\n\nexport interface AudioPlayerQueuePositionState {\n currentIndex: number;\n currentSourceId: string | null;\n length: number;\n hasNext: boolean;\n hasPrevious: boolean;\n repeatMode: RepeatMode;\n}\n\nexport interface AudioPlayerQueueState {\n items: AudioSource[];\n itemIds: string[];\n position: AudioPlayerQueuePositionState;\n}\n\nexport interface AudioPlayerState {\n status: PlayerStatus;\n currentSource: AudioSource | null;\n currentSourceId: string | null;\n currentTime: number;\n duration: number;\n buffered: number;\n progress: AudioPlayerProgressState;\n rate: number;\n volume: number;\n muted: boolean;\n queue: AudioPlayerQueueState;\n error: AudioPlayerErrorState | null;\n}\n\nexport interface AudioPlayerEventMap {\n sourcechange: { source: AudioSource | null; state: AudioPlayerState };\n queuechange: { queue: AudioPlayerQueueState; state: AudioPlayerState };\n play: { source: AudioSource | null; state: AudioPlayerState };\n pause: { source: AudioSource | null; state: AudioPlayerState };\n seeking: { from: number; to: number; state: AudioPlayerState };\n seeked: { currentTime: number; state: AudioPlayerState };\n timeupdate: { currentTime: number; duration: number; state: AudioPlayerState };\n ratechange: { rate: number; state: AudioPlayerState };\n volumechange: { volume: number; muted: boolean; state: AudioPlayerState };\n ended: { source: AudioSource | null; state: AudioPlayerState };\n error: { error: AudioPlayerRuntimeError; state: AudioPlayerState };\n destroy: { state: AudioPlayerState };\n}\n\nexport interface CreateAudioPlayerOptions {\n initialVolume?: number;\n initialRate?: number;\n initialMuted?: boolean;\n initialRepeatMode?: RepeatMode;\n}\n\nexport interface SetQueueOptions {\n startAtId?: string;\n autoplay?: boolean;\n}\n\nexport interface PreviousOptions {\n restartThresholdSeconds?: number;\n}\n\nexport interface PersistedPlayerState {\n version: 1;\n savedAt: number;\n currentSource: AudioSource | null;\n currentSourceId: string | null;\n currentTime: number;\n rate: number;\n volume: number;\n muted: boolean;\n queue: {\n items: AudioSource[];\n position: {\n currentIndex: number;\n currentSourceId: string | null;\n repeatMode: RepeatMode;\n };\n };\n}\n\nexport interface AudioPlayerPersistenceAdapter {\n load(): PersistedPlayerState | null;\n save(state: PersistedPlayerState): void;\n clear(): void;\n}\n\nexport interface AudioPlayerPersistenceOptions {\n adapter: AudioPlayerPersistenceAdapter;\n autoRestore?: boolean;\n maxAgeMs?: number;\n saveIntervalMs?: number;\n}\n\nexport interface AudioPlayerPersistenceController {\n restore(): Promise<PersistedPlayerState | null>;\n save(): void;\n clear(): void;\n destroy(): void;\n}\n\nexport interface AudioPlayerProgressSnapshot {\n source: AudioSource | null;\n sourceId: string | null;\n currentTime: number;\n duration: number;\n playedFraction: number;\n status: PlayerStatus;\n queue: AudioPlayerQueuePositionState;\n}\n\nexport interface AudioPlayerProgressReporterOptions {\n intervalMs?: number;\n onReport: (snapshot: AudioPlayerProgressSnapshot) => void;\n}\n\nexport interface AudioPlayerProgressReporterController {\n report(): void;\n destroy(): void;\n}\n\nexport interface AudioPlayerMediaSessionOptions {\n artworkSizes?: number[];\n seekOffsetSeconds?: number;\n}\n\nexport interface AudioPlayerMediaSessionController {\n sync(): void;\n destroy(): void;\n}\n\nexport type AudioPlayerEventListener<K extends AudioPlayerEventName> = (\n event: AudioPlayerEventMap[K],\n) => void;\n\nexport interface AudioPlayer {\n getState(): AudioPlayerState;\n subscribe(listener: (state: AudioPlayerState) => void): () => void;\n on<K extends AudioPlayerEventName>(\n eventName: K,\n listener: AudioPlayerEventListener<K>,\n ): () => void;\n\n load(source: AudioSource): Promise<void>;\n play(source?: AudioSource): Promise<void>;\n pause(): void;\n toggle(): Promise<void>;\n unload(): void;\n seek(time: number): void;\n setRate(rate: number): void;\n setVolume(volume: number): void;\n setMuted(muted: boolean): void;\n\n setQueue(items: AudioSource[], options?: SetQueueOptions): Promise<void>;\n appendToQueue(items: AudioSource[]): void;\n removeFromQueue(id: string): void;\n clearQueue(): void;\n next(): Promise<void>;\n previous(options?: PreviousOptions): Promise<void>;\n setRepeatMode(mode: RepeatMode): void;\n\n destroy(): void;\n}\n\nconst DEFAULT_PREVIOUS_RESTART_THRESHOLD_SECONDS = 5;\nconst DEFAULT_PERSISTENCE_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000;\nconst DEFAULT_PERSISTENCE_SAVE_INTERVAL_MS = 5000;\nconst DEFAULT_PROGRESS_REPORT_INTERVAL_MS = 5000;\nconst DEFAULT_MEDIA_SESSION_ARTWORK_SIZES = [96, 128, 192, 256, 384, 512];\nconst DEFAULT_MEDIA_SESSION_SEEK_OFFSET_SECONDS = 10;\n\ntype AudioEngineEventName =\n | \"loadedmetadata\"\n | \"timeupdate\"\n | \"progress\"\n | \"play\"\n | \"pause\"\n | \"seeked\"\n | \"ratechange\"\n | \"volumechange\"\n | \"ended\"\n | \"error\";\n\ninterface AudioEngineSnapshot {\n currentTime: number;\n duration: number;\n buffered: number;\n rate: number;\n volume: number;\n muted: boolean;\n}\n\ninterface AudioEngine {\n readonly available: boolean;\n getSnapshot(durationHint?: number): AudioEngineSnapshot;\n getRuntimeError(): unknown;\n on(eventName: AudioEngineEventName, listener: EventListener): () => void;\n setSource(src: string): void;\n clearSource(): void;\n load(): void;\n play(): Promise<void>;\n pause(): void;\n setCurrentTime(time: number): void;\n setPlaybackRate(rate: number): void;\n setVolume(volume: number): void;\n setMuted(muted: boolean): void;\n destroy(): void;\n}\n\nconst createInitialState = (\n options: CreateAudioPlayerOptions,\n): AudioPlayerState => ({\n status: \"idle\",\n currentSource: null,\n currentSourceId: null,\n currentTime: 0,\n duration: 0,\n buffered: 0,\n progress: {\n currentTime: 0,\n duration: 0,\n buffered: 0,\n playedFraction: 0,\n bufferedFraction: 0,\n },\n rate: options.initialRate ?? 1,\n volume: options.initialVolume ?? 1,\n muted: options.initialMuted ?? false,\n queue: {\n items: [],\n itemIds: [],\n position: {\n currentIndex: -1,\n currentSourceId: null,\n length: 0,\n repeatMode: options.initialRepeatMode ?? \"off\",\n hasNext: false,\n hasPrevious: false,\n },\n },\n error: null,\n});\n\nconst createPlayerError = (\n code: AudioPlayerRuntimeError[\"code\"],\n message: string,\n cause?: unknown,\n): AudioPlayerRuntimeError => ({\n code,\n message,\n cause,\n});\n\nconst isRuntimePlayerError = (\n value: unknown,\n): value is AudioPlayerRuntimeError =>\n !!value &&\n typeof value === \"object\" &&\n \"code\" in value &&\n \"message\" in value;\n\nconst normalizePlayerError = (\n fallbackCode: AudioPlayerRuntimeError[\"code\"],\n fallbackMessage: string,\n cause: unknown,\n): AudioPlayerRuntimeError =>\n isRuntimePlayerError(cause)\n ? cause\n : createPlayerError(fallbackCode, fallbackMessage, cause);\n\nconst assertStableSource = (source: AudioSource): void => {\n if (!source.id || !source.src) {\n throw createPlayerError(\n \"INVALID_QUEUE_ITEM\",\n \"AudioSource requires stable id and src.\",\n );\n }\n};\n\nconst isFiniteNumber = (value: number): boolean =>\n Number.isFinite(value) && !Number.isNaN(value);\n\nconst safeDuration = (audio: HTMLAudioElement | null, hint?: number): number => {\n const duration = audio?.duration;\n return duration !== undefined && isFiniteNumber(duration) ? duration : hint ?? 0;\n};\n\nconst safeBuffered = (audio: HTMLAudioElement | null): number => {\n if (!audio || audio.buffered.length === 0) {\n return 0;\n }\n\n try {\n return audio.buffered.end(audio.buffered.length - 1);\n } catch {\n return 0;\n }\n};\n\nconst cloneQueueState = (state: AudioPlayerState): AudioPlayerQueueState => ({\n items: [...state.queue.items],\n itemIds: [...state.queue.itemIds],\n position: {\n ...state.queue.position,\n },\n});\n\nconst updateQueueFlags = (state: AudioPlayerState): AudioPlayerState => {\n const { items, position } = state.queue;\n const { currentIndex, repeatMode } = position;\n const lastIndex = items.length - 1;\n const hasItems = items.length > 0;\n const hasNext =\n !hasItems || currentIndex < 0\n ? false\n : repeatMode === \"all\"\n ? items.length > 0\n : currentIndex < lastIndex;\n const hasPrevious =\n !hasItems || currentIndex < 0\n ? false\n : repeatMode === \"all\"\n ? items.length > 0\n : currentIndex > 0;\n\n return {\n ...state,\n queue: {\n ...state.queue,\n itemIds: items.map((item) => item.id),\n position: {\n ...position,\n currentSourceId: state.currentSource?.id ?? null,\n length: items.length,\n hasNext,\n hasPrevious,\n },\n },\n };\n};\n\nconst createAudioElement = (): HTMLAudioElement | null => {\n if (typeof Audio === \"undefined\") {\n return null;\n }\n\n return new Audio();\n};\n\nconst createUnavailableAudioEngine = (): AudioEngine => {\n const unavailableError = (): AudioPlayerRuntimeError =>\n createPlayerError(\n \"UNSUPPORTED_ENVIRONMENT\",\n \"HTMLAudioElement is not available in this environment.\",\n );\n\n return {\n available: false,\n getSnapshot(durationHint) {\n return {\n currentTime: 0,\n duration: durationHint ?? 0,\n buffered: 0,\n rate: 1,\n volume: 1,\n muted: false,\n };\n },\n getRuntimeError() {\n return unavailableError();\n },\n on() {\n return () => {};\n },\n setSource() {\n throw unavailableError();\n },\n clearSource() {\n throw unavailableError();\n },\n load() {\n throw unavailableError();\n },\n play() {\n throw unavailableError();\n },\n pause() {\n throw unavailableError();\n },\n setCurrentTime() {\n throw unavailableError();\n },\n setPlaybackRate() {\n throw unavailableError();\n },\n setVolume() {\n throw unavailableError();\n },\n setMuted() {\n throw unavailableError();\n },\n destroy() {},\n };\n};\n\nconst createHtmlAudioEngine = (): AudioEngine => {\n const audio = createAudioElement();\n if (!audio) {\n return createUnavailableAudioEngine();\n }\n\n audio.preload = \"metadata\";\n const clearSource = (): void => {\n const element = audio as HTMLAudioElement & {\n removeAttribute?: (name: string) => void;\n };\n if (typeof element.removeAttribute === \"function\") {\n element.removeAttribute(\"src\");\n return;\n }\n\n audio.src = \"\";\n };\n\n return {\n available: true,\n getSnapshot(durationHint) {\n return {\n currentTime: audio.currentTime,\n duration: safeDuration(audio, durationHint),\n buffered: safeBuffered(audio),\n rate: audio.playbackRate,\n volume: audio.volume,\n muted: audio.muted,\n };\n },\n getRuntimeError() {\n return audio.error;\n },\n on(eventName, listener) {\n audio.addEventListener(eventName, listener);\n return () => {\n audio.removeEventListener(eventName, listener);\n };\n },\n setSource(src) {\n audio.src = src;\n },\n clearSource() {\n clearSource();\n },\n load() {\n audio.load();\n },\n play() {\n return audio.play();\n },\n pause() {\n audio.pause();\n },\n setCurrentTime(time) {\n audio.currentTime = time;\n },\n setPlaybackRate(rate) {\n audio.playbackRate = rate;\n },\n setVolume(volume) {\n audio.volume = volume;\n },\n setMuted(muted) {\n audio.muted = muted;\n },\n destroy() {\n audio.pause();\n clearSource();\n audio.load();\n },\n };\n};\n\nconst isBrowserStorageAvailable = (): boolean =>\n typeof window !== \"undefined\" && typeof window.localStorage !== \"undefined\";\n\nconst isPersistedPlayerState = (value: unknown): value is PersistedPlayerState => {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n\n const candidate = value as Partial<PersistedPlayerState>;\n return (\n candidate.version === 1 &&\n typeof candidate.savedAt === \"number\" &&\n \"currentSource\" in candidate &&\n typeof candidate.currentTime === \"number\" &&\n typeof candidate.rate === \"number\" &&\n typeof candidate.volume === \"number\" &&\n typeof candidate.muted === \"boolean\" &&\n !!candidate.queue &&\n Array.isArray(candidate.queue.items) &&\n !!candidate.queue.position\n );\n};\n\nconst toPersistedPlayerState = (state: AudioPlayerState): PersistedPlayerState => ({\n version: 1,\n savedAt: Date.now(),\n currentSource: state.currentSource,\n currentSourceId: state.currentSourceId,\n currentTime: state.currentTime,\n rate: state.rate,\n volume: state.volume,\n muted: state.muted,\n queue: {\n items: [...state.queue.items],\n position: {\n currentIndex: state.queue.position.currentIndex,\n currentSourceId: state.queue.position.currentSourceId,\n repeatMode: state.queue.position.repeatMode,\n },\n },\n});\n\nconst toProgressSnapshot = (\n state: AudioPlayerState,\n): AudioPlayerProgressSnapshot => ({\n source: state.currentSource,\n sourceId: state.currentSourceId,\n currentTime: state.currentTime,\n duration: state.duration,\n playedFraction: state.progress.playedFraction,\n status: state.status,\n queue: {\n ...state.queue.position,\n },\n});\n\nconst hasMediaSession = (): boolean =>\n typeof navigator !== \"undefined\" && \"mediaSession\" in navigator;\n\nconst createMediaSessionArtwork = (\n source: AudioSource | null,\n sizes: number[],\n): MediaImage[] => {\n if (!source?.artwork) {\n return [];\n }\n\n return sizes.map((size) => ({\n src: source.artwork as string,\n sizes: `${size}x${size}`,\n }));\n};\n\nexport const createLocalStoragePersistenceAdapter = (\n key: string,\n): AudioPlayerPersistenceAdapter => ({\n load() {\n if (!isBrowserStorageAvailable()) {\n return null;\n }\n\n try {\n const raw = window.localStorage.getItem(key);\n if (!raw) {\n return null;\n }\n\n const parsed: unknown = JSON.parse(raw);\n return isPersistedPlayerState(parsed) ? parsed : null;\n } catch {\n return null;\n }\n },\n\n save(state) {\n if (!isBrowserStorageAvailable()) {\n return;\n }\n\n window.localStorage.setItem(key, JSON.stringify(state));\n },\n\n clear() {\n if (!isBrowserStorageAvailable()) {\n return;\n }\n\n window.localStorage.removeItem(key);\n },\n});\n\nexport const createAudioPlayer = (\n options: CreateAudioPlayerOptions = {},\n): AudioPlayer => {\n let state = updateQueueFlags(createInitialState(options));\n let destroyed = false;\n let shouldAutoplayAfterLoad = false;\n let suppressPauseEvent = false;\n\n const engine = createHtmlAudioEngine();\n const subscribers = new Set<(nextState: AudioPlayerState) => void>();\n const eventListeners: {\n [K in AudioPlayerEventName]: Set<AudioPlayerEventListener<K>>;\n } = {\n sourcechange: new Set(),\n queuechange: new Set(),\n play: new Set(),\n pause: new Set(),\n seeking: new Set(),\n seeked: new Set(),\n timeupdate: new Set(),\n ratechange: new Set(),\n volumechange: new Set(),\n ended: new Set(),\n error: new Set(),\n destroy: new Set(),\n };\n\n const getState = (): AudioPlayerState => state;\n\n const publishState = (): void => {\n for (const subscriber of subscribers) {\n subscriber(state);\n }\n };\n\n const emit = <K extends AudioPlayerEventName>(\n eventName: K,\n event: AudioPlayerEventMap[K],\n ): void => {\n for (const listener of eventListeners[eventName]) {\n listener(event);\n }\n };\n\n const setState = (\n updater: (currentState: AudioPlayerState) => AudioPlayerState,\n ): AudioPlayerState => {\n state = updateQueueFlags(updater(state));\n publishState();\n return state;\n };\n\n const setError = (error: AudioPlayerRuntimeError): void => {\n shouldAutoplayAfterLoad = false;\n const nextState = setState((currentState) => ({\n ...currentState,\n status: \"error\",\n error: {\n code: error.code,\n message: error.message,\n },\n }));\n emit(\"error\", { error, state: nextState });\n };\n\n const clearError = (): void => {\n if (!state.error) {\n return;\n }\n\n setState((currentState) => ({\n ...currentState,\n error: null,\n }));\n };\n\n const syncAudioSnapshot = (\n statusOverride?: PlayerStatus,\n ): AudioPlayerState => {\n const snapshot = engine.getSnapshot(state.currentSource?.durationHint);\n const currentTime = snapshot.currentTime;\n const duration = snapshot.duration;\n const buffered = snapshot.buffered;\n const playedFraction =\n duration > 0 ? Math.min(1, Math.max(0, currentTime / duration)) : 0;\n const bufferedFraction =\n duration > 0 ? Math.min(1, Math.max(0, buffered / duration)) : 0;\n\n const nextState = setState((currentState) => ({\n ...currentState,\n currentSourceId: currentState.currentSource?.id ?? null,\n currentTime,\n duration,\n buffered,\n progress: {\n currentTime,\n duration,\n buffered,\n playedFraction,\n bufferedFraction,\n },\n rate: snapshot.rate,\n volume: snapshot.volume,\n muted: snapshot.muted,\n status: statusOverride ?? currentState.status,\n error:\n statusOverride === \"error\" ? currentState.error : null,\n }));\n\n return nextState;\n };\n\n const findQueueIndexById = (id: string | null | undefined): number =>\n id ? state.queue.items.findIndex((item) => item.id === id) : -1;\n\n const resolveNextQueueIndex = (\n mode: \"manual\" | \"ended\",\n ): number | null => {\n const { items, position } = state.queue;\n const { currentIndex, repeatMode } = position;\n\n if (items.length === 0 || currentIndex < 0) {\n return null;\n }\n\n if (repeatMode === \"one\") {\n return currentIndex;\n }\n\n if (currentIndex < items.length - 1) {\n return currentIndex + 1;\n }\n\n if (repeatMode === \"all\") {\n return 0;\n }\n\n return mode === \"ended\" ? -1 : null;\n };\n\n const resolvePreviousQueueIndex = (): number | null => {\n const { items, position } = state.queue;\n const { currentIndex, repeatMode } = position;\n\n if (items.length === 0 || currentIndex < 0) {\n return null;\n }\n\n if (currentIndex > 0) {\n return currentIndex - 1;\n }\n\n if (repeatMode === \"all\") {\n return items.length - 1;\n }\n\n return null;\n };\n\n const updateCurrentSource = (\n source: AudioSource | null,\n nextStatus: PlayerStatus,\n ): AudioPlayerState => {\n const queueIndex = findQueueIndexById(source?.id);\n const nextState = setState((currentState) => ({\n ...currentState,\n currentSource: source,\n currentSourceId: source?.id ?? null,\n currentTime: 0,\n duration: source?.durationHint ?? 0,\n buffered: 0,\n progress: {\n currentTime: 0,\n duration: source?.durationHint ?? 0,\n buffered: 0,\n playedFraction: 0,\n bufferedFraction: 0,\n },\n status: nextStatus,\n error: null,\n queue: {\n ...currentState.queue,\n position: {\n ...currentState.queue.position,\n currentIndex: queueIndex,\n currentSourceId: source?.id ?? null,\n },\n },\n }));\n emit(\"sourcechange\", { source, state: nextState });\n return nextState;\n };\n\n const setQueueState = (\n items: AudioSource[],\n currentIndex: number,\n ): AudioPlayerState =>\n setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n items,\n position: {\n ...currentState.queue.position,\n currentIndex,\n },\n },\n }));\n\n const emitQueueChange = (nextState: AudioPlayerState): void => {\n emit(\"queuechange\", { queue: cloneQueueState(nextState), state: nextState });\n };\n\n const attachSourceToAudio = (\n source: AudioSource,\n autoplayAfterLoad: boolean,\n ): void => {\n shouldAutoplayAfterLoad = autoplayAfterLoad;\n suppressPauseEvent = true;\n try {\n engine.pause();\n } finally {\n suppressPauseEvent = false;\n }\n engine.setSource(source.src);\n engine.setCurrentTime(0);\n engine.setPlaybackRate(state.rate);\n engine.setVolume(state.volume);\n engine.setMuted(state.muted);\n engine.load();\n };\n\n const loadInternal = async (\n source: AudioSource,\n autoplayAfterLoad = false,\n ): Promise<void> => {\n assertStableSource(source);\n updateCurrentSource(source, \"loading\");\n attachSourceToAudio(source, autoplayAfterLoad);\n };\n\n const selectQueueIndex = async (\n index: number,\n autoplayAfterLoad = false,\n ): Promise<AudioSource | null> => {\n const item = state.queue.items[index] ?? null;\n if (!item) {\n return null;\n }\n\n await loadInternal(item, autoplayAfterLoad);\n const nextState = setQueueState(state.queue.items, index);\n emitQueueChange(nextState);\n return item;\n };\n\n const playLoadedAudio = async (): Promise<void> => {\n try {\n await engine.play();\n } catch (cause) {\n setError(createPlayerError(\"PLAY_ERROR\", \"Failed to start playback.\", cause));\n }\n };\n\n const handlePlaybackEnded = async (): Promise<void> => {\n if (destroyed) {\n return;\n }\n\n if (state.queue.items.length > 0 && state.queue.position.currentIndex >= 0) {\n const nextIndex = resolveNextQueueIndex(\"ended\");\n if (nextIndex === -1 || nextIndex === null) {\n const endedState = syncAudioSnapshot(\"ended\");\n emit(\"ended\", { source: endedState.currentSource, state: endedState });\n return;\n }\n\n await selectQueueIndex(nextIndex, true);\n return;\n }\n\n const endedState = syncAudioSnapshot(\"ended\");\n emit(\"ended\", { source: endedState.currentSource, state: endedState });\n };\n\n const detachEngineListeners = [\n engine.on(\"loadedmetadata\", () => {\n if (destroyed || !state.currentSource) {\n return;\n }\n\n syncAudioSnapshot(\"ready\");\n if (shouldAutoplayAfterLoad) {\n shouldAutoplayAfterLoad = false;\n void playLoadedAudio();\n }\n }),\n engine.on(\"timeupdate\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot(\n state.status === \"ended\" ? \"playing\" : undefined,\n );\n emit(\"timeupdate\", {\n currentTime: nextState.currentTime,\n duration: nextState.duration,\n state: nextState,\n });\n }),\n engine.on(\"progress\", () => {\n if (!destroyed) {\n syncAudioSnapshot();\n }\n }),\n engine.on(\"play\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot(\"playing\");\n emit(\"play\", { source: nextState.currentSource, state: nextState });\n }),\n engine.on(\"pause\", () => {\n if (destroyed || suppressPauseEvent) {\n return;\n }\n\n const nextStatus =\n state.status === \"ended\" ? \"ended\" : state.currentSource ? \"paused\" : \"idle\";\n const nextState = syncAudioSnapshot(nextStatus);\n emit(\"pause\", { source: nextState.currentSource, state: nextState });\n }),\n engine.on(\"seeked\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot();\n emit(\"seeked\", { currentTime: nextState.currentTime, state: nextState });\n emit(\"timeupdate\", {\n currentTime: nextState.currentTime,\n duration: nextState.duration,\n state: nextState,\n });\n }),\n engine.on(\"ratechange\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot();\n emit(\"ratechange\", { rate: nextState.rate, state: nextState });\n }),\n engine.on(\"volumechange\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot();\n emit(\"volumechange\", {\n volume: nextState.volume,\n muted: nextState.muted,\n state: nextState,\n });\n }),\n engine.on(\"ended\", () => {\n void handlePlaybackEnded();\n }),\n engine.on(\"error\", () => {\n if (destroyed) {\n return;\n }\n\n setError(\n createPlayerError(\n \"LOAD_ERROR\",\n \"Audio element reported a playback error.\",\n engine.getRuntimeError(),\n ),\n );\n }),\n ];\n\n return {\n getState,\n\n subscribe(listener) {\n subscribers.add(listener);\n listener(state);\n return () => {\n subscribers.delete(listener);\n };\n },\n\n on(eventName, listener) {\n eventListeners[eventName].add(\n listener as AudioPlayerEventListener<typeof eventName>,\n );\n return () => {\n eventListeners[eventName].delete(\n listener as AudioPlayerEventListener<typeof eventName>,\n );\n };\n },\n\n async load(source) {\n try {\n await loadInternal(source);\n } catch (cause) {\n setError(\n normalizePlayerError(\"LOAD_ERROR\", \"Failed to load source.\", cause),\n );\n }\n },\n\n async play(source) {\n try {\n if (source) {\n await loadInternal(source, true);\n return;\n }\n\n if (!state.currentSource) {\n setError(\n createPlayerError(\n \"NO_ACTIVE_SOURCE\",\n \"Cannot play without an active source.\",\n ),\n );\n return;\n }\n\n if (state.status === \"loading\") {\n shouldAutoplayAfterLoad = true;\n return;\n }\n\n await playLoadedAudio();\n } catch (cause) {\n setError(normalizePlayerError(\"PLAY_ERROR\", \"Failed to start playback.\", cause));\n }\n },\n\n pause() {\n if (!engine.available) {\n return;\n }\n\n shouldAutoplayAfterLoad = false;\n engine.pause();\n },\n\n async toggle() {\n if (state.status === \"playing\") {\n this.pause();\n return;\n }\n\n await this.play();\n },\n\n unload() {\n shouldAutoplayAfterLoad = false;\n\n if (engine.available) {\n suppressPauseEvent = true;\n try {\n engine.pause();\n } finally {\n suppressPauseEvent = false;\n }\n engine.clearSource();\n engine.load();\n }\n\n const nextState = updateCurrentSource(null, \"idle\");\n emitQueueChange(nextState);\n },\n\n seek(time) {\n if (!state.currentSource) {\n setError(\n createPlayerError(\"SEEK_ERROR\", \"Cannot seek without an active source.\"),\n );\n return;\n }\n\n const max = engine.getSnapshot(state.currentSource.durationHint).duration;\n const normalized = Math.max(\n 0,\n max > 0 ? Math.min(time, max) : (isFiniteNumber(time) ? time : 0),\n );\n emit(\"seeking\", { from: state.currentTime, to: normalized, state });\n\n try {\n engine.setCurrentTime(normalized);\n } catch (cause) {\n setError(normalizePlayerError(\"SEEK_ERROR\", \"Failed to seek audio.\", cause));\n }\n },\n\n setRate(rate) {\n if (!engine.available) {\n setError(\n createPlayerError(\"INVALID_RATE\", \"Audio element is unavailable.\"),\n );\n return;\n }\n\n if (!isFiniteNumber(rate) || rate <= 0) {\n setError(\n createPlayerError(\"INVALID_RATE\", \"Playback rate must be greater than 0.\"),\n );\n return;\n }\n\n engine.setPlaybackRate(rate);\n clearError();\n syncAudioSnapshot();\n },\n\n setVolume(volume) {\n if (!engine.available) {\n setError(\n createPlayerError(\"INVALID_VOLUME\", \"Audio element is unavailable.\"),\n );\n return;\n }\n\n if (!isFiniteNumber(volume) || volume < 0 || volume > 1) {\n setError(\n createPlayerError(\"INVALID_VOLUME\", \"Volume must be between 0 and 1.\"),\n );\n return;\n }\n\n engine.setVolume(volume);\n clearError();\n syncAudioSnapshot();\n },\n\n setMuted(muted) {\n if (!engine.available) {\n return;\n }\n\n engine.setMuted(muted);\n clearError();\n syncAudioSnapshot();\n },\n\n async setQueue(items, queueOptions = {}) {\n try {\n for (const item of items) {\n assertStableSource(item);\n }\n\n const startIndex =\n queueOptions.startAtId === undefined\n ? items.length > 0\n ? 0\n : -1\n : items.findIndex((item) => item.id === queueOptions.startAtId);\n\n if (queueOptions.startAtId && startIndex < 0) {\n throw createPlayerError(\n \"INVALID_QUEUE_ITEM\",\n `Queue start item ${queueOptions.startAtId} was not found.`,\n );\n }\n\n const nextState = setState((currentState) => ({\n ...currentState,\n currentSource: startIndex >= 0 ? items[startIndex] ?? null : null,\n currentSourceId: startIndex >= 0 ? (items[startIndex]?.id ?? null) : null,\n currentTime: 0,\n duration: startIndex >= 0 ? (items[startIndex]?.durationHint ?? 0) : 0,\n buffered: 0,\n progress: {\n currentTime: 0,\n duration: startIndex >= 0 ? (items[startIndex]?.durationHint ?? 0) : 0,\n buffered: 0,\n playedFraction: 0,\n bufferedFraction: 0,\n },\n status: startIndex >= 0 ? \"ready\" : \"idle\",\n error: null,\n queue: {\n ...currentState.queue,\n items: [...items],\n position: {\n ...currentState.queue.position,\n currentIndex: startIndex,\n currentSourceId:\n startIndex >= 0 ? (items[startIndex]?.id ?? null) : null,\n },\n },\n }));\n\n emitQueueChange(nextState);\n emit(\"sourcechange\", {\n source: nextState.currentSource,\n state: nextState,\n });\n\n if (nextState.currentSource) {\n await loadInternal(nextState.currentSource, queueOptions.autoplay === true);\n const syncedState = setQueueState(items, startIndex);\n emitQueueChange(syncedState);\n } else if (engine.available) {\n shouldAutoplayAfterLoad = false;\n suppressPauseEvent = true;\n engine.pause();\n suppressPauseEvent = false;\n engine.clearSource();\n engine.load();\n }\n } catch (cause) {\n setError(\n normalizePlayerError(\n \"INVALID_QUEUE_ITEM\",\n \"Failed to set queue.\",\n cause,\n ),\n );\n }\n },\n\n appendToQueue(items) {\n try {\n for (const item of items) {\n assertStableSource(item);\n }\n\n const nextState = setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n items: [...currentState.queue.items, ...items],\n },\n }));\n emitQueueChange(nextState);\n } catch (cause) {\n setError(\n normalizePlayerError(\n \"INVALID_QUEUE_ITEM\",\n \"Failed to append queue items.\",\n cause,\n ),\n );\n }\n },\n\n removeFromQueue(id) {\n const nextItems = state.queue.items.filter((item) => item.id !== id);\n const nextIndex = nextItems.findIndex(\n (item) => item.id === state.currentSource?.id,\n );\n\n const nextState = setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n items: nextItems,\n position: {\n ...currentState.queue.position,\n currentIndex: nextIndex,\n currentSourceId: nextIndex >= 0 ? (nextItems[nextIndex]?.id ?? null) : null,\n },\n },\n }));\n\n emitQueueChange(nextState);\n },\n\n clearQueue() {\n const nextState = setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n items: [],\n position: {\n ...currentState.queue.position,\n currentIndex: -1,\n currentSourceId: null,\n },\n },\n }));\n\n emitQueueChange(nextState);\n },\n\n async next() {\n const nextIndex = resolveNextQueueIndex(\"manual\");\n if (nextIndex === null) {\n return;\n }\n\n await selectQueueIndex(nextIndex, true);\n },\n\n async previous(previousOptions = {}) {\n if (!state.currentSource) {\n return;\n }\n\n const threshold =\n previousOptions.restartThresholdSeconds ??\n DEFAULT_PREVIOUS_RESTART_THRESHOLD_SECONDS;\n\n if (state.currentTime > threshold) {\n this.seek(0);\n return;\n }\n\n const previousIndex = resolvePreviousQueueIndex();\n if (previousIndex === null) {\n this.seek(0);\n return;\n }\n\n await selectQueueIndex(previousIndex, true);\n },\n\n setRepeatMode(mode) {\n const nextState = setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n position: {\n ...currentState.queue.position,\n repeatMode: mode,\n },\n },\n }));\n emitQueueChange(nextState);\n },\n\n destroy() {\n if (destroyed) {\n return;\n }\n\n destroyed = true;\n shouldAutoplayAfterLoad = false;\n for (const detach of detachEngineListeners) {\n detach();\n }\n suppressPauseEvent = true;\n engine.destroy();\n suppressPauseEvent = false;\n\n const nextState = setState(() => createInitialState(options));\n emit(\"destroy\", { state: nextState });\n subscribers.clear();\n for (const eventName of Object.keys(eventListeners) as AudioPlayerEventName[]) {\n eventListeners[eventName].clear();\n }\n },\n };\n};\n\nexport const attachAudioPlayerPersistence = (\n player: AudioPlayer,\n options: AudioPlayerPersistenceOptions,\n): AudioPlayerPersistenceController => {\n const maxAgeMs = options.maxAgeMs ?? DEFAULT_PERSISTENCE_MAX_AGE_MS;\n const saveIntervalMs =\n options.saveIntervalMs ?? DEFAULT_PERSISTENCE_SAVE_INTERVAL_MS;\n let destroyed = false;\n let playIntervalId: ReturnType<typeof setInterval> | null = null;\n\n const save = (): void => {\n if (destroyed) {\n return;\n }\n\n const state = player.getState();\n if (!state.currentSource) {\n options.adapter.clear();\n return;\n }\n\n options.adapter.save(toPersistedPlayerState(state));\n };\n\n const clear = (): void => {\n options.adapter.clear();\n };\n\n const stopPlayInterval = (): void => {\n if (playIntervalId !== null) {\n clearInterval(playIntervalId);\n playIntervalId = null;\n }\n };\n\n const startPlayInterval = (): void => {\n if (playIntervalId !== null) {\n return;\n }\n\n playIntervalId = setInterval(() => {\n save();\n }, saveIntervalMs);\n };\n\n const waitForRestoredSource = (sourceId: string): Promise<void> =>\n new Promise((resolve) => {\n const unsubscribe = player.subscribe((state) => {\n if (state.currentSourceId !== sourceId) {\n return;\n }\n\n if (state.status === \"loading\") {\n return;\n }\n\n unsubscribe();\n resolve();\n });\n });\n\n const restore = async (): Promise<PersistedPlayerState | null> => {\n const persisted = options.adapter.load();\n if (!persisted) {\n return null;\n }\n\n if (Date.now() - persisted.savedAt > maxAgeMs) {\n options.adapter.clear();\n return null;\n }\n\n player.setRepeatMode(persisted.queue.position.repeatMode);\n player.setVolume(persisted.volume);\n player.setMuted(persisted.muted);\n player.setRate(persisted.rate);\n\n if (persisted.queue.items.length > 0) {\n await player.setQueue(persisted.queue.items, {\n startAtId: persisted.queue.position.currentSourceId ?? undefined,\n });\n } else if (persisted.currentSource) {\n await player.load(persisted.currentSource);\n } else {\n return persisted;\n }\n\n if (persisted.currentSourceId) {\n await waitForRestoredSource(persisted.currentSourceId);\n }\n\n if (persisted.currentTime > 0) {\n player.seek(persisted.currentTime);\n }\n\n return persisted;\n };\n\n const stateUnsubscribe = player.subscribe((state) => {\n if (state.status === \"playing\") {\n startPlayInterval();\n return;\n }\n\n stopPlayInterval();\n });\n\n const pauseUnsubscribe = player.on(\"pause\", () => {\n save();\n });\n const endedUnsubscribe = player.on(\"ended\", () => {\n save();\n });\n const sourceUnsubscribe = player.on(\"sourcechange\", () => {\n save();\n });\n const queueUnsubscribe = player.on(\"queuechange\", () => {\n save();\n });\n const rateUnsubscribe = player.on(\"ratechange\", () => {\n save();\n });\n const volumeUnsubscribe = player.on(\"volumechange\", () => {\n save();\n });\n\n const beforeUnloadHandler = (): void => {\n save();\n };\n\n const visibilityHandler = (): void => {\n if (typeof document === \"undefined\") {\n return;\n }\n\n if (document.visibilityState === \"hidden\") {\n save();\n }\n };\n\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"beforeunload\", beforeUnloadHandler);\n }\n\n if (typeof document !== \"undefined\") {\n document.addEventListener(\"visibilitychange\", visibilityHandler);\n }\n\n if (options.autoRestore !== false) {\n void restore();\n }\n\n return {\n restore,\n save,\n clear,\n destroy() {\n destroyed = true;\n stopPlayInterval();\n stateUnsubscribe();\n pauseUnsubscribe();\n endedUnsubscribe();\n sourceUnsubscribe();\n queueUnsubscribe();\n rateUnsubscribe();\n volumeUnsubscribe();\n\n if (typeof window !== \"undefined\") {\n window.removeEventListener(\"beforeunload\", beforeUnloadHandler);\n }\n\n if (typeof document !== \"undefined\") {\n document.removeEventListener(\"visibilitychange\", visibilityHandler);\n }\n },\n };\n};\n\nexport const attachAudioPlayerProgressReporter = (\n player: AudioPlayer,\n options: AudioPlayerProgressReporterOptions,\n): AudioPlayerProgressReporterController => {\n const intervalMs = options.intervalMs ?? DEFAULT_PROGRESS_REPORT_INTERVAL_MS;\n let destroyed = false;\n let intervalId: ReturnType<typeof setInterval> | null = null;\n\n const report = (): void => {\n if (destroyed) {\n return;\n }\n\n const state = player.getState();\n if (!state.currentSource) {\n return;\n }\n\n options.onReport(toProgressSnapshot(state));\n };\n\n const stopInterval = (): void => {\n if (intervalId !== null) {\n clearInterval(intervalId);\n intervalId = null;\n }\n };\n\n const startInterval = (): void => {\n if (intervalId !== null) {\n return;\n }\n\n intervalId = setInterval(() => {\n report();\n }, intervalMs);\n };\n\n const stateUnsubscribe = player.subscribe((state) => {\n if (state.status === \"playing\") {\n startInterval();\n return;\n }\n\n stopInterval();\n });\n\n const pauseUnsubscribe = player.on(\"pause\", () => {\n report();\n });\n const endedUnsubscribe = player.on(\"ended\", () => {\n report();\n });\n const seekedUnsubscribe = player.on(\"seeked\", () => {\n report();\n });\n const sourceUnsubscribe = player.on(\"sourcechange\", () => {\n report();\n });\n\n return {\n report,\n destroy() {\n destroyed = true;\n stopInterval();\n stateUnsubscribe();\n pauseUnsubscribe();\n endedUnsubscribe();\n seekedUnsubscribe();\n sourceUnsubscribe();\n },\n };\n};\n\nexport const attachAudioPlayerMediaSession = (\n player: AudioPlayer,\n options: AudioPlayerMediaSessionOptions = {},\n): AudioPlayerMediaSessionController => {\n if (!hasMediaSession()) {\n return {\n sync() {},\n destroy() {},\n };\n }\n\n const artworkSizes =\n options.artworkSizes ?? DEFAULT_MEDIA_SESSION_ARTWORK_SIZES;\n const seekOffsetSeconds =\n options.seekOffsetSeconds ?? DEFAULT_MEDIA_SESSION_SEEK_OFFSET_SECONDS;\n let destroyed = false;\n\n const sync = (): void => {\n if (destroyed || !hasMediaSession()) {\n return;\n }\n\n const state = player.getState();\n const source = state.currentSource;\n\n navigator.mediaSession.metadata = source\n ? new MediaMetadata({\n title: source.title ?? \"\",\n artist: source.artist ?? \"\",\n album: source.album ?? \"\",\n artwork: createMediaSessionArtwork(source, artworkSizes),\n })\n : null;\n\n navigator.mediaSession.playbackState =\n state.status === \"playing\"\n ? \"playing\"\n : state.currentSource\n ? \"paused\"\n : \"none\";\n\n if (state.currentSource && state.duration > 0) {\n try {\n navigator.mediaSession.setPositionState({\n duration: state.duration,\n playbackRate: state.rate,\n position: Math.min(state.currentTime, state.duration),\n });\n } catch {\n // Ignore unsupported position state implementations.\n }\n } else {\n try {\n navigator.mediaSession.setPositionState();\n } catch {\n // Ignore unsupported position state implementations.\n }\n }\n };\n\n const setActionHandler = (\n action: MediaSessionAction,\n handler: MediaSessionActionHandler | null,\n ): void => {\n try {\n navigator.mediaSession.setActionHandler(action, handler);\n } catch {\n // Ignore unsupported actions.\n }\n };\n\n setActionHandler(\"play\", () => {\n void player.play();\n });\n setActionHandler(\"pause\", () => {\n player.pause();\n });\n setActionHandler(\"seekbackward\", () => {\n const state = player.getState();\n player.seek(Math.max(0, state.currentTime - seekOffsetSeconds));\n });\n setActionHandler(\"seekforward\", () => {\n const state = player.getState();\n const max = state.duration > 0 ? state.duration : state.currentTime + seekOffsetSeconds;\n player.seek(Math.min(max, state.currentTime + seekOffsetSeconds));\n });\n setActionHandler(\"previoustrack\", () => {\n void player.previous();\n });\n setActionHandler(\"nexttrack\", () => {\n void player.next();\n });\n setActionHandler(\"seekto\", (details) => {\n if (details.seekTime === undefined) {\n return;\n }\n\n player.seek(details.seekTime);\n });\n setActionHandler(\"stop\", () => {\n player.pause();\n });\n\n const stateUnsubscribe = player.subscribe(() => {\n sync();\n });\n\n sync();\n\n return {\n sync,\n destroy() {\n destroyed = true;\n stateUnsubscribe();\n if (!hasMediaSession()) {\n return;\n }\n\n const actions: MediaSessionAction[] = [\n \"play\",\n \"pause\",\n \"seekbackward\",\n \"seekforward\",\n \"previoustrack\",\n \"nexttrack\",\n \"seekto\",\n \"stop\",\n ];\n\n for (const action of actions) {\n setActionHandler(action, null);\n }\n\n navigator.mediaSession.metadata = null;\n navigator.mediaSession.playbackState = \"none\";\n try {\n navigator.mediaSession.setPositionState();\n } catch {\n // Ignore unsupported position state implementations.\n }\n },\n };\n};\n"],"mappings":"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","names":["endedState"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export type PlayerStatus =\n | \"idle\"\n | \"loading\"\n | \"ready\"\n | \"playing\"\n | \"paused\"\n | \"ended\"\n | \"error\";\n\nexport type RepeatMode = \"off\" | \"one\" | \"all\";\n\nexport type AudioPlayerEventName =\n | \"sourcechange\"\n | \"queuechange\"\n | \"play\"\n | \"pause\"\n | \"seeking\"\n | \"seeked\"\n | \"timeupdate\"\n | \"ratechange\"\n | \"volumechange\"\n | \"ended\"\n | \"error\"\n | \"destroy\";\n\nexport interface AudioSource {\n id: string;\n src: string;\n title?: string;\n artist?: string;\n artwork?: string;\n album?: string;\n durationHint?: number;\n}\n\nexport interface AudioPlayerErrorState {\n code:\n | \"LOAD_ERROR\"\n | \"PLAY_ERROR\"\n | \"SEEK_ERROR\"\n | \"INVALID_VOLUME\"\n | \"INVALID_RATE\"\n | \"INVALID_QUEUE_ITEM\"\n | \"NO_ACTIVE_SOURCE\"\n | \"UNSUPPORTED_ENVIRONMENT\"\n | \"UNKNOWN_ERROR\";\n message: string;\n}\n\nexport interface AudioPlayerRuntimeError extends AudioPlayerErrorState {\n cause?: unknown;\n}\n\nexport interface AudioPlayerProgressState {\n currentTime: number;\n duration: number;\n buffered: number;\n playedFraction: number;\n bufferedFraction: number;\n}\n\nexport interface AudioPlayerQueuePositionState {\n currentIndex: number;\n currentSourceId: string | null;\n length: number;\n hasNext: boolean;\n hasPrevious: boolean;\n repeatMode: RepeatMode;\n}\n\nexport interface AudioPlayerQueueState {\n items: AudioSource[];\n itemIds: string[];\n position: AudioPlayerQueuePositionState;\n}\n\nexport interface AudioPlayerState {\n status: PlayerStatus;\n currentSource: AudioSource | null;\n currentSourceId: string | null;\n currentTime: number;\n duration: number;\n buffered: number;\n progress: AudioPlayerProgressState;\n rate: number;\n volume: number;\n muted: boolean;\n queue: AudioPlayerQueueState;\n error: AudioPlayerErrorState | null;\n}\n\nexport interface AudioPlayerEventMap {\n sourcechange: { source: AudioSource | null; state: AudioPlayerState };\n queuechange: { queue: AudioPlayerQueueState; state: AudioPlayerState };\n play: { source: AudioSource | null; state: AudioPlayerState };\n pause: { source: AudioSource | null; state: AudioPlayerState };\n seeking: { from: number; to: number; state: AudioPlayerState };\n seeked: { currentTime: number; state: AudioPlayerState };\n timeupdate: { currentTime: number; duration: number; state: AudioPlayerState };\n ratechange: { rate: number; state: AudioPlayerState };\n volumechange: { volume: number; muted: boolean; state: AudioPlayerState };\n ended: { source: AudioSource | null; state: AudioPlayerState };\n error: { error: AudioPlayerRuntimeError; state: AudioPlayerState };\n destroy: { state: AudioPlayerState };\n}\n\nexport interface CreateAudioPlayerOptions {\n initialVolume?: number;\n initialRate?: number;\n initialMuted?: boolean;\n initialRepeatMode?: RepeatMode;\n}\n\nexport interface SetQueueOptions {\n startAtId?: string;\n autoplay?: boolean;\n}\n\nexport interface PreviousOptions {\n restartThresholdSeconds?: number;\n}\n\nexport interface PersistedPlayerState {\n version: 1;\n savedAt: number;\n currentSource: AudioSource | null;\n currentSourceId: string | null;\n currentTime: number;\n rate: number;\n volume: number;\n muted: boolean;\n queue: {\n items: AudioSource[];\n position: {\n currentIndex: number;\n currentSourceId: string | null;\n repeatMode: RepeatMode;\n };\n };\n}\n\nexport interface AudioPlayerPersistenceAdapter {\n load(): PersistedPlayerState | null;\n save(state: PersistedPlayerState): void;\n clear(): void;\n}\n\nexport interface AudioPlayerPersistenceOptions {\n adapter: AudioPlayerPersistenceAdapter;\n autoRestore?: boolean;\n maxAgeMs?: number;\n saveIntervalMs?: number;\n}\n\nexport interface AudioPlayerPersistenceController {\n restore(): Promise<PersistedPlayerState | null>;\n save(): void;\n clear(): void;\n destroy(): void;\n}\n\nexport interface AudioPlayerProgressSnapshot {\n source: AudioSource | null;\n sourceId: string | null;\n currentTime: number;\n duration: number;\n playedFraction: number;\n status: PlayerStatus;\n queue: AudioPlayerQueuePositionState;\n}\n\nexport interface AudioPlayerProgressReporterOptions {\n intervalMs?: number;\n onReport: (snapshot: AudioPlayerProgressSnapshot) => void;\n}\n\nexport interface AudioPlayerProgressReporterController {\n report(): void;\n destroy(): void;\n}\n\nexport interface AudioPlayerMediaSessionOptions {\n artworkSizes?: number[];\n seekOffsetSeconds?: number;\n}\n\nexport interface AudioPlayerMediaSessionController {\n sync(): void;\n destroy(): void;\n}\n\nexport type AudioPlayerEventListener<K extends AudioPlayerEventName> = (\n event: AudioPlayerEventMap[K],\n) => void;\n\nexport interface AudioPlayer {\n getState(): AudioPlayerState;\n subscribe(listener: (state: AudioPlayerState) => void): () => void;\n on<K extends AudioPlayerEventName>(\n eventName: K,\n listener: AudioPlayerEventListener<K>,\n ): () => void;\n\n load(source: AudioSource): Promise<void>;\n play(source?: AudioSource): Promise<void>;\n pause(): void;\n toggle(): Promise<void>;\n unload(): void;\n seek(time: number): void;\n setRate(rate: number): void;\n setVolume(volume: number): void;\n setMuted(muted: boolean): void;\n\n setQueue(items: AudioSource[], options?: SetQueueOptions): Promise<void>;\n appendToQueue(items: AudioSource[]): void;\n removeFromQueue(id: string): void;\n clearQueue(): void;\n next(): Promise<void>;\n previous(options?: PreviousOptions): Promise<void>;\n setRepeatMode(mode: RepeatMode): void;\n\n destroy(): void;\n}\n\nconst DEFAULT_PREVIOUS_RESTART_THRESHOLD_SECONDS = 5;\nconst DEFAULT_PERSISTENCE_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000;\nconst DEFAULT_PERSISTENCE_SAVE_INTERVAL_MS = 5000;\nconst DEFAULT_PROGRESS_REPORT_INTERVAL_MS = 5000;\nconst DEFAULT_MEDIA_SESSION_ARTWORK_SIZES = [96, 128, 192, 256, 384, 512];\nconst DEFAULT_MEDIA_SESSION_SEEK_OFFSET_SECONDS = 10;\n\ntype AudioEngineEventName =\n | \"loadedmetadata\"\n | \"timeupdate\"\n | \"progress\"\n | \"play\"\n | \"pause\"\n | \"seeked\"\n | \"ratechange\"\n | \"volumechange\"\n | \"ended\"\n | \"error\";\n\ninterface AudioEngineSnapshot {\n currentTime: number;\n duration: number;\n buffered: number;\n rate: number;\n volume: number;\n muted: boolean;\n}\n\ninterface AudioEngine {\n readonly available: boolean;\n getSnapshot(durationHint?: number): AudioEngineSnapshot;\n getRuntimeError(): unknown;\n on(eventName: AudioEngineEventName, listener: EventListener): () => void;\n setSource(src: string): void;\n clearSource(): void;\n load(): void;\n play(): Promise<void>;\n pause(): void;\n setCurrentTime(time: number): void;\n setPlaybackRate(rate: number): void;\n setVolume(volume: number): void;\n setMuted(muted: boolean): void;\n destroy(): void;\n}\n\nconst createInitialState = (\n options: CreateAudioPlayerOptions,\n): AudioPlayerState => ({\n status: \"idle\",\n currentSource: null,\n currentSourceId: null,\n currentTime: 0,\n duration: 0,\n buffered: 0,\n progress: {\n currentTime: 0,\n duration: 0,\n buffered: 0,\n playedFraction: 0,\n bufferedFraction: 0,\n },\n rate: options.initialRate ?? 1,\n volume: options.initialVolume ?? 1,\n muted: options.initialMuted ?? false,\n queue: {\n items: [],\n itemIds: [],\n position: {\n currentIndex: -1,\n currentSourceId: null,\n length: 0,\n repeatMode: options.initialRepeatMode ?? \"off\",\n hasNext: false,\n hasPrevious: false,\n },\n },\n error: null,\n});\n\nconst createPlayerError = (\n code: AudioPlayerRuntimeError[\"code\"],\n message: string,\n cause?: unknown,\n): AudioPlayerRuntimeError => ({\n code,\n message,\n cause,\n});\n\nconst isRuntimePlayerError = (\n value: unknown,\n): value is AudioPlayerRuntimeError =>\n !!value &&\n typeof value === \"object\" &&\n \"code\" in value &&\n \"message\" in value;\n\nconst normalizePlayerError = (\n fallbackCode: AudioPlayerRuntimeError[\"code\"],\n fallbackMessage: string,\n cause: unknown,\n): AudioPlayerRuntimeError =>\n isRuntimePlayerError(cause)\n ? cause\n : createPlayerError(fallbackCode, fallbackMessage, cause);\n\nconst assertStableSource = (source: AudioSource): void => {\n if (!source.id || !source.src) {\n throw createPlayerError(\n \"INVALID_QUEUE_ITEM\",\n \"AudioSource requires stable id and src.\",\n );\n }\n};\n\nconst isFiniteNumber = (value: number): boolean =>\n Number.isFinite(value) && !Number.isNaN(value);\n\nconst safeDuration = (audio: HTMLAudioElement | null, hint?: number): number => {\n const duration = audio?.duration;\n return duration !== undefined && isFiniteNumber(duration) ? duration : hint ?? 0;\n};\n\nconst safeBuffered = (audio: HTMLAudioElement | null): number => {\n if (!audio || audio.buffered.length === 0) {\n return 0;\n }\n\n try {\n return audio.buffered.end(audio.buffered.length - 1);\n } catch {\n return 0;\n }\n};\n\nconst cloneQueueState = (state: AudioPlayerState): AudioPlayerQueueState => ({\n items: [...state.queue.items],\n itemIds: [...state.queue.itemIds],\n position: {\n ...state.queue.position,\n },\n});\n\nconst updateQueueFlags = (state: AudioPlayerState): AudioPlayerState => {\n const { items, position } = state.queue;\n const { currentIndex, repeatMode } = position;\n const lastIndex = items.length - 1;\n const hasItems = items.length > 0;\n const hasNext =\n !hasItems || currentIndex < 0\n ? false\n : repeatMode === \"all\"\n ? items.length > 0\n : currentIndex < lastIndex;\n const hasPrevious =\n !hasItems || currentIndex < 0\n ? false\n : repeatMode === \"all\"\n ? items.length > 0\n : currentIndex > 0;\n\n return {\n ...state,\n queue: {\n ...state.queue,\n itemIds: items.map((item) => item.id),\n position: {\n ...position,\n currentSourceId: state.currentSource?.id ?? null,\n length: items.length,\n hasNext,\n hasPrevious,\n },\n },\n };\n};\n\nconst createAudioElement = (): HTMLAudioElement | null => {\n if (typeof Audio === \"undefined\") {\n return null;\n }\n\n return new Audio();\n};\n\nconst createUnavailableAudioEngine = (): AudioEngine => {\n const unavailableError = (): AudioPlayerRuntimeError =>\n createPlayerError(\n \"UNSUPPORTED_ENVIRONMENT\",\n \"HTMLAudioElement is not available in this environment.\",\n );\n\n return {\n available: false,\n getSnapshot(durationHint) {\n return {\n currentTime: 0,\n duration: durationHint ?? 0,\n buffered: 0,\n rate: 1,\n volume: 1,\n muted: false,\n };\n },\n getRuntimeError() {\n return unavailableError();\n },\n on() {\n return () => {};\n },\n setSource() {\n throw unavailableError();\n },\n clearSource() {\n throw unavailableError();\n },\n load() {\n throw unavailableError();\n },\n play() {\n throw unavailableError();\n },\n pause() {\n throw unavailableError();\n },\n setCurrentTime() {\n throw unavailableError();\n },\n setPlaybackRate() {\n throw unavailableError();\n },\n setVolume() {\n throw unavailableError();\n },\n setMuted() {\n throw unavailableError();\n },\n destroy() {},\n };\n};\n\nconst createHtmlAudioEngine = (): AudioEngine => {\n const audio = createAudioElement();\n if (!audio) {\n return createUnavailableAudioEngine();\n }\n\n audio.preload = \"metadata\";\n const clearSource = (): void => {\n const element = audio as HTMLAudioElement & {\n removeAttribute?: (name: string) => void;\n };\n if (typeof element.removeAttribute === \"function\") {\n element.removeAttribute(\"src\");\n return;\n }\n\n audio.src = \"\";\n };\n\n return {\n available: true,\n getSnapshot(durationHint) {\n return {\n currentTime: audio.currentTime,\n duration: safeDuration(audio, durationHint),\n buffered: safeBuffered(audio),\n rate: audio.playbackRate,\n volume: audio.volume,\n muted: audio.muted,\n };\n },\n getRuntimeError() {\n return audio.error;\n },\n on(eventName, listener) {\n audio.addEventListener(eventName, listener);\n return () => {\n audio.removeEventListener(eventName, listener);\n };\n },\n setSource(src) {\n audio.src = src;\n },\n clearSource() {\n clearSource();\n },\n load() {\n audio.load();\n },\n play() {\n return audio.play();\n },\n pause() {\n audio.pause();\n },\n setCurrentTime(time) {\n audio.currentTime = time;\n },\n setPlaybackRate(rate) {\n audio.playbackRate = rate;\n },\n setVolume(volume) {\n audio.volume = volume;\n },\n setMuted(muted) {\n audio.muted = muted;\n },\n destroy() {\n audio.pause();\n clearSource();\n audio.load();\n },\n };\n};\n\nconst isBrowserStorageAvailable = (): boolean =>\n typeof window !== \"undefined\" && typeof window.localStorage !== \"undefined\";\n\nconst isPersistedPlayerState = (value: unknown): value is PersistedPlayerState => {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n\n const candidate = value as Partial<PersistedPlayerState>;\n return (\n candidate.version === 1 &&\n typeof candidate.savedAt === \"number\" &&\n \"currentSource\" in candidate &&\n typeof candidate.currentTime === \"number\" &&\n typeof candidate.rate === \"number\" &&\n typeof candidate.volume === \"number\" &&\n typeof candidate.muted === \"boolean\" &&\n !!candidate.queue &&\n Array.isArray(candidate.queue.items) &&\n !!candidate.queue.position\n );\n};\n\nconst toPersistedPlayerState = (state: AudioPlayerState): PersistedPlayerState => ({\n version: 1,\n savedAt: Date.now(),\n currentSource: state.currentSource,\n currentSourceId: state.currentSourceId,\n currentTime: state.currentTime,\n rate: state.rate,\n volume: state.volume,\n muted: state.muted,\n queue: {\n items: [...state.queue.items],\n position: {\n currentIndex: state.queue.position.currentIndex,\n currentSourceId: state.queue.position.currentSourceId,\n repeatMode: state.queue.position.repeatMode,\n },\n },\n});\n\nconst toProgressSnapshot = (\n state: AudioPlayerState,\n): AudioPlayerProgressSnapshot => ({\n source: state.currentSource,\n sourceId: state.currentSourceId,\n currentTime: state.currentTime,\n duration: state.duration,\n playedFraction: state.progress.playedFraction,\n status: state.status,\n queue: {\n ...state.queue.position,\n },\n});\n\nconst hasMediaSession = (): boolean =>\n typeof navigator !== \"undefined\" && \"mediaSession\" in navigator;\n\nconst createMediaSessionArtwork = (\n source: AudioSource | null,\n sizes: number[],\n): MediaImage[] => {\n if (!source?.artwork) {\n return [];\n }\n\n return sizes.map((size) => ({\n src: source.artwork as string,\n sizes: `${size}x${size}`,\n }));\n};\n\nexport const createLocalStoragePersistenceAdapter = (\n key: string,\n): AudioPlayerPersistenceAdapter => ({\n load() {\n if (!isBrowserStorageAvailable()) {\n return null;\n }\n\n try {\n const raw = window.localStorage.getItem(key);\n if (!raw) {\n return null;\n }\n\n const parsed: unknown = JSON.parse(raw);\n return isPersistedPlayerState(parsed) ? parsed : null;\n } catch {\n return null;\n }\n },\n\n save(state) {\n if (!isBrowserStorageAvailable()) {\n return;\n }\n\n window.localStorage.setItem(key, JSON.stringify(state));\n },\n\n clear() {\n if (!isBrowserStorageAvailable()) {\n return;\n }\n\n window.localStorage.removeItem(key);\n },\n});\n\nexport const createAudioPlayer = (\n options: CreateAudioPlayerOptions = {},\n): AudioPlayer => {\n let state = updateQueueFlags(createInitialState(options));\n let destroyed = false;\n let shouldAutoplayAfterLoad = false;\n let suppressPauseEvent = false;\n\n const engine = createHtmlAudioEngine();\n const subscribers = new Set<(nextState: AudioPlayerState) => void>();\n const eventListeners: {\n [K in AudioPlayerEventName]: Set<AudioPlayerEventListener<K>>;\n } = {\n sourcechange: new Set(),\n queuechange: new Set(),\n play: new Set(),\n pause: new Set(),\n seeking: new Set(),\n seeked: new Set(),\n timeupdate: new Set(),\n ratechange: new Set(),\n volumechange: new Set(),\n ended: new Set(),\n error: new Set(),\n destroy: new Set(),\n };\n\n const getState = (): AudioPlayerState => state;\n\n const publishState = (): void => {\n for (const subscriber of subscribers) {\n subscriber(state);\n }\n };\n\n const emit = <K extends AudioPlayerEventName>(\n eventName: K,\n event: AudioPlayerEventMap[K],\n ): void => {\n for (const listener of eventListeners[eventName]) {\n listener(event);\n }\n };\n\n const setState = (\n updater: (currentState: AudioPlayerState) => AudioPlayerState,\n ): AudioPlayerState => {\n state = updateQueueFlags(updater(state));\n publishState();\n return state;\n };\n\n const setError = (error: AudioPlayerRuntimeError): void => {\n shouldAutoplayAfterLoad = false;\n const nextState = setState((currentState) => ({\n ...currentState,\n status: \"error\",\n error: {\n code: error.code,\n message: error.message,\n },\n }));\n emit(\"error\", { error, state: nextState });\n };\n\n const clearError = (): void => {\n if (!state.error) {\n return;\n }\n\n setState((currentState) => ({\n ...currentState,\n error: null,\n }));\n };\n\n const syncAudioSnapshot = (\n statusOverride?: PlayerStatus,\n ): AudioPlayerState => {\n const snapshot = engine.getSnapshot(state.currentSource?.durationHint);\n const currentTime = snapshot.currentTime;\n const duration = snapshot.duration;\n const buffered = snapshot.buffered;\n const playedFraction =\n duration > 0 ? Math.min(1, Math.max(0, currentTime / duration)) : 0;\n const bufferedFraction =\n duration > 0 ? Math.min(1, Math.max(0, buffered / duration)) : 0;\n\n const nextState = setState((currentState) => ({\n ...currentState,\n currentSourceId: currentState.currentSource?.id ?? null,\n currentTime,\n duration,\n buffered,\n progress: {\n currentTime,\n duration,\n buffered,\n playedFraction,\n bufferedFraction,\n },\n rate: snapshot.rate,\n volume: snapshot.volume,\n muted: snapshot.muted,\n status: statusOverride ?? currentState.status,\n error:\n statusOverride === \"error\" ? currentState.error : null,\n }));\n\n return nextState;\n };\n\n const findQueueIndexById = (id: string | null | undefined): number =>\n id ? state.queue.items.findIndex((item) => item.id === id) : -1;\n\n const resolveNextQueueIndex = (\n mode: \"manual\" | \"ended\",\n ): number | null => {\n const { items, position } = state.queue;\n const { currentIndex, repeatMode } = position;\n\n if (items.length === 0 || currentIndex < 0) {\n return null;\n }\n\n if (repeatMode === \"one\") {\n return currentIndex;\n }\n\n if (currentIndex < items.length - 1) {\n return currentIndex + 1;\n }\n\n if (repeatMode === \"all\") {\n return 0;\n }\n\n return mode === \"ended\" ? -1 : null;\n };\n\n const resolvePreviousQueueIndex = (): number | null => {\n const { items, position } = state.queue;\n const { currentIndex, repeatMode } = position;\n\n if (items.length === 0 || currentIndex < 0) {\n return null;\n }\n\n if (currentIndex > 0) {\n return currentIndex - 1;\n }\n\n if (repeatMode === \"all\") {\n return items.length - 1;\n }\n\n return null;\n };\n\n const updateCurrentSource = (\n source: AudioSource | null,\n nextStatus: PlayerStatus,\n ): AudioPlayerState => {\n const queueIndex = findQueueIndexById(source?.id);\n const nextState = setState((currentState) => ({\n ...currentState,\n currentSource: source,\n currentSourceId: source?.id ?? null,\n currentTime: 0,\n duration: source?.durationHint ?? 0,\n buffered: 0,\n progress: {\n currentTime: 0,\n duration: source?.durationHint ?? 0,\n buffered: 0,\n playedFraction: 0,\n bufferedFraction: 0,\n },\n status: nextStatus,\n error: null,\n queue: {\n ...currentState.queue,\n position: {\n ...currentState.queue.position,\n currentIndex: queueIndex,\n currentSourceId: source?.id ?? null,\n },\n },\n }));\n emit(\"sourcechange\", { source, state: nextState });\n return nextState;\n };\n\n const setQueueState = (\n items: AudioSource[],\n currentIndex: number,\n ): AudioPlayerState =>\n setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n items,\n position: {\n ...currentState.queue.position,\n currentIndex,\n },\n },\n }));\n\n const emitQueueChange = (nextState: AudioPlayerState): void => {\n emit(\"queuechange\", { queue: cloneQueueState(nextState), state: nextState });\n };\n\n const attachSourceToAudio = (\n source: AudioSource,\n autoplayAfterLoad: boolean,\n ): void => {\n shouldAutoplayAfterLoad = autoplayAfterLoad;\n suppressPauseEvent = true;\n try {\n engine.pause();\n } finally {\n suppressPauseEvent = false;\n }\n engine.setSource(source.src);\n engine.setCurrentTime(0);\n engine.setPlaybackRate(state.rate);\n engine.setVolume(state.volume);\n engine.setMuted(state.muted);\n engine.load();\n };\n\n const loadInternal = async (\n source: AudioSource,\n autoplayAfterLoad = false,\n ): Promise<void> => {\n assertStableSource(source);\n updateCurrentSource(source, \"loading\");\n attachSourceToAudio(source, autoplayAfterLoad);\n };\n\n const selectQueueIndex = async (\n index: number,\n autoplayAfterLoad = false,\n ): Promise<AudioSource | null> => {\n const item = state.queue.items[index] ?? null;\n if (!item) {\n return null;\n }\n\n await loadInternal(item, autoplayAfterLoad);\n const nextState = setQueueState(state.queue.items, index);\n emitQueueChange(nextState);\n return item;\n };\n\n const playLoadedAudio = async (): Promise<void> => {\n try {\n await engine.play();\n } catch (cause) {\n setError(createPlayerError(\"PLAY_ERROR\", \"Failed to start playback.\", cause));\n }\n };\n\n const handlePlaybackEnded = async (): Promise<void> => {\n if (destroyed) {\n return;\n }\n\n if (state.queue.items.length > 0 && state.queue.position.currentIndex >= 0) {\n const nextIndex = resolveNextQueueIndex(\"ended\");\n if (nextIndex === -1 || nextIndex === null) {\n const endedState = syncAudioSnapshot(\"ended\");\n emit(\"ended\", { source: endedState.currentSource, state: endedState });\n return;\n }\n\n await selectQueueIndex(nextIndex, true);\n return;\n }\n\n const endedState = syncAudioSnapshot(\"ended\");\n emit(\"ended\", { source: endedState.currentSource, state: endedState });\n };\n\n const detachEngineListeners = [\n engine.on(\"loadedmetadata\", () => {\n if (destroyed || !state.currentSource) {\n return;\n }\n\n syncAudioSnapshot(\"ready\");\n if (shouldAutoplayAfterLoad) {\n shouldAutoplayAfterLoad = false;\n void playLoadedAudio();\n }\n }),\n engine.on(\"timeupdate\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot(\n state.status === \"ended\" ? \"playing\" : undefined,\n );\n emit(\"timeupdate\", {\n currentTime: nextState.currentTime,\n duration: nextState.duration,\n state: nextState,\n });\n }),\n engine.on(\"progress\", () => {\n if (!destroyed) {\n syncAudioSnapshot();\n }\n }),\n engine.on(\"play\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot(\"playing\");\n emit(\"play\", { source: nextState.currentSource, state: nextState });\n }),\n engine.on(\"pause\", () => {\n if (destroyed || suppressPauseEvent) {\n return;\n }\n\n const nextStatus =\n state.status === \"ended\" ? \"ended\" : state.currentSource ? \"paused\" : \"idle\";\n const nextState = syncAudioSnapshot(nextStatus);\n emit(\"pause\", { source: nextState.currentSource, state: nextState });\n }),\n engine.on(\"seeked\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot();\n emit(\"seeked\", { currentTime: nextState.currentTime, state: nextState });\n emit(\"timeupdate\", {\n currentTime: nextState.currentTime,\n duration: nextState.duration,\n state: nextState,\n });\n }),\n engine.on(\"ratechange\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot();\n emit(\"ratechange\", { rate: nextState.rate, state: nextState });\n }),\n engine.on(\"volumechange\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot();\n emit(\"volumechange\", {\n volume: nextState.volume,\n muted: nextState.muted,\n state: nextState,\n });\n }),\n engine.on(\"ended\", () => {\n void handlePlaybackEnded();\n }),\n engine.on(\"error\", () => {\n if (destroyed) {\n return;\n }\n\n setError(\n createPlayerError(\n \"LOAD_ERROR\",\n \"Audio element reported a playback error.\",\n engine.getRuntimeError(),\n ),\n );\n }),\n ];\n\n return {\n getState,\n\n subscribe(listener) {\n subscribers.add(listener);\n listener(state);\n return () => {\n subscribers.delete(listener);\n };\n },\n\n on(eventName, listener) {\n eventListeners[eventName].add(\n listener as AudioPlayerEventListener<typeof eventName>,\n );\n return () => {\n eventListeners[eventName].delete(\n listener as AudioPlayerEventListener<typeof eventName>,\n );\n };\n },\n\n async load(source) {\n try {\n await loadInternal(source);\n } catch (cause) {\n setError(\n normalizePlayerError(\"LOAD_ERROR\", \"Failed to load source.\", cause),\n );\n }\n },\n\n async play(source) {\n try {\n if (source) {\n await loadInternal(source, true);\n return;\n }\n\n if (!state.currentSource) {\n setError(\n createPlayerError(\n \"NO_ACTIVE_SOURCE\",\n \"Cannot play without an active source.\",\n ),\n );\n return;\n }\n\n if (state.status === \"loading\") {\n shouldAutoplayAfterLoad = true;\n return;\n }\n\n await playLoadedAudio();\n } catch (cause) {\n setError(normalizePlayerError(\"PLAY_ERROR\", \"Failed to start playback.\", cause));\n }\n },\n\n pause() {\n if (!engine.available) {\n return;\n }\n\n shouldAutoplayAfterLoad = false;\n engine.pause();\n },\n\n async toggle() {\n if (state.status === \"playing\") {\n this.pause();\n return;\n }\n\n await this.play();\n },\n\n unload() {\n shouldAutoplayAfterLoad = false;\n\n if (engine.available) {\n suppressPauseEvent = true;\n try {\n engine.pause();\n } finally {\n suppressPauseEvent = false;\n }\n engine.clearSource();\n engine.load();\n }\n\n const nextState = updateCurrentSource(null, \"idle\");\n emitQueueChange(nextState);\n },\n\n seek(time) {\n if (!state.currentSource) {\n setError(\n createPlayerError(\"SEEK_ERROR\", \"Cannot seek without an active source.\"),\n );\n return;\n }\n\n const max = engine.getSnapshot(state.currentSource.durationHint).duration;\n const normalized = Math.max(\n 0,\n max > 0 ? Math.min(time, max) : (isFiniteNumber(time) ? time : 0),\n );\n emit(\"seeking\", { from: state.currentTime, to: normalized, state });\n\n try {\n engine.setCurrentTime(normalized);\n } catch (cause) {\n setError(normalizePlayerError(\"SEEK_ERROR\", \"Failed to seek audio.\", cause));\n }\n },\n\n setRate(rate) {\n if (!engine.available) {\n setError(\n createPlayerError(\"INVALID_RATE\", \"Audio element is unavailable.\"),\n );\n return;\n }\n\n if (!isFiniteNumber(rate) || rate <= 0) {\n setError(\n createPlayerError(\"INVALID_RATE\", \"Playback rate must be greater than 0.\"),\n );\n return;\n }\n\n engine.setPlaybackRate(rate);\n clearError();\n syncAudioSnapshot();\n },\n\n setVolume(volume) {\n if (!engine.available) {\n setError(\n createPlayerError(\"INVALID_VOLUME\", \"Audio element is unavailable.\"),\n );\n return;\n }\n\n if (!isFiniteNumber(volume) || volume < 0 || volume > 1) {\n setError(\n createPlayerError(\"INVALID_VOLUME\", \"Volume must be between 0 and 1.\"),\n );\n return;\n }\n\n engine.setVolume(volume);\n clearError();\n syncAudioSnapshot();\n },\n\n setMuted(muted) {\n if (!engine.available) {\n return;\n }\n\n engine.setMuted(muted);\n clearError();\n syncAudioSnapshot();\n },\n\n async setQueue(items, queueOptions = {}) {\n try {\n for (const item of items) {\n assertStableSource(item);\n }\n\n const startIndex =\n queueOptions.startAtId === undefined\n ? items.length > 0\n ? 0\n : -1\n : items.findIndex((item) => item.id === queueOptions.startAtId);\n\n if (queueOptions.startAtId && startIndex < 0) {\n throw createPlayerError(\n \"INVALID_QUEUE_ITEM\",\n `Queue start item ${queueOptions.startAtId} was not found.`,\n );\n }\n\n const nextState = setState((currentState) => ({\n ...currentState,\n currentSource: startIndex >= 0 ? items[startIndex] ?? null : null,\n currentSourceId: startIndex >= 0 ? (items[startIndex]?.id ?? null) : null,\n currentTime: 0,\n duration: startIndex >= 0 ? (items[startIndex]?.durationHint ?? 0) : 0,\n buffered: 0,\n progress: {\n currentTime: 0,\n duration: startIndex >= 0 ? (items[startIndex]?.durationHint ?? 0) : 0,\n buffered: 0,\n playedFraction: 0,\n bufferedFraction: 0,\n },\n status: startIndex >= 0 ? \"ready\" : \"idle\",\n error: null,\n queue: {\n ...currentState.queue,\n items: [...items],\n position: {\n ...currentState.queue.position,\n currentIndex: startIndex,\n currentSourceId:\n startIndex >= 0 ? (items[startIndex]?.id ?? null) : null,\n },\n },\n }));\n\n emitQueueChange(nextState);\n emit(\"sourcechange\", {\n source: nextState.currentSource,\n state: nextState,\n });\n\n if (nextState.currentSource) {\n await loadInternal(nextState.currentSource, queueOptions.autoplay === true);\n const syncedState = setQueueState(items, startIndex);\n emitQueueChange(syncedState);\n } else if (engine.available) {\n shouldAutoplayAfterLoad = false;\n suppressPauseEvent = true;\n engine.pause();\n suppressPauseEvent = false;\n engine.clearSource();\n engine.load();\n }\n } catch (cause) {\n setError(\n normalizePlayerError(\n \"INVALID_QUEUE_ITEM\",\n \"Failed to set queue.\",\n cause,\n ),\n );\n }\n },\n\n appendToQueue(items) {\n try {\n for (const item of items) {\n assertStableSource(item);\n }\n\n const nextState = setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n items: [...currentState.queue.items, ...items],\n },\n }));\n emitQueueChange(nextState);\n } catch (cause) {\n setError(\n normalizePlayerError(\n \"INVALID_QUEUE_ITEM\",\n \"Failed to append queue items.\",\n cause,\n ),\n );\n }\n },\n\n removeFromQueue(id) {\n const nextItems = state.queue.items.filter((item) => item.id !== id);\n const nextIndex = nextItems.findIndex(\n (item) => item.id === state.currentSource?.id,\n );\n\n const nextState = setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n items: nextItems,\n position: {\n ...currentState.queue.position,\n currentIndex: nextIndex,\n currentSourceId: nextIndex >= 0 ? (nextItems[nextIndex]?.id ?? null) : null,\n },\n },\n }));\n\n emitQueueChange(nextState);\n },\n\n clearQueue() {\n const nextState = setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n items: [],\n position: {\n ...currentState.queue.position,\n currentIndex: -1,\n currentSourceId: null,\n },\n },\n }));\n\n emitQueueChange(nextState);\n },\n\n async next() {\n const nextIndex = resolveNextQueueIndex(\"manual\");\n if (nextIndex === null) {\n return;\n }\n\n await selectQueueIndex(nextIndex, true);\n },\n\n async previous(previousOptions = {}) {\n if (!state.currentSource) {\n return;\n }\n\n const threshold =\n previousOptions.restartThresholdSeconds ??\n DEFAULT_PREVIOUS_RESTART_THRESHOLD_SECONDS;\n\n if (state.currentTime > threshold) {\n this.seek(0);\n return;\n }\n\n const previousIndex = resolvePreviousQueueIndex();\n if (previousIndex === null) {\n this.seek(0);\n return;\n }\n\n await selectQueueIndex(previousIndex, true);\n },\n\n setRepeatMode(mode) {\n const nextState = setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n position: {\n ...currentState.queue.position,\n repeatMode: mode,\n },\n },\n }));\n emitQueueChange(nextState);\n },\n\n destroy() {\n if (destroyed) {\n return;\n }\n\n destroyed = true;\n shouldAutoplayAfterLoad = false;\n for (const detach of detachEngineListeners) {\n detach();\n }\n suppressPauseEvent = true;\n engine.destroy();\n suppressPauseEvent = false;\n\n const nextState = setState(() => createInitialState(options));\n emit(\"destroy\", { state: nextState });\n subscribers.clear();\n for (const eventName of Object.keys(eventListeners) as AudioPlayerEventName[]) {\n eventListeners[eventName].clear();\n }\n },\n };\n};\n\nexport const attachAudioPlayerPersistence = (\n player: AudioPlayer,\n options: AudioPlayerPersistenceOptions,\n): AudioPlayerPersistenceController => {\n const maxAgeMs = options.maxAgeMs ?? DEFAULT_PERSISTENCE_MAX_AGE_MS;\n const saveIntervalMs =\n options.saveIntervalMs ?? DEFAULT_PERSISTENCE_SAVE_INTERVAL_MS;\n let destroyed = false;\n let playIntervalId: ReturnType<typeof setInterval> | null = null;\n\n const save = (): void => {\n if (destroyed) {\n return;\n }\n\n const state = player.getState();\n if (!state.currentSource) {\n options.adapter.clear();\n return;\n }\n\n options.adapter.save(toPersistedPlayerState(state));\n };\n\n const clear = (): void => {\n options.adapter.clear();\n };\n\n const stopPlayInterval = (): void => {\n if (playIntervalId !== null) {\n clearInterval(playIntervalId);\n playIntervalId = null;\n }\n };\n\n const startPlayInterval = (): void => {\n if (playIntervalId !== null) {\n return;\n }\n\n playIntervalId = setInterval(() => {\n save();\n }, saveIntervalMs);\n };\n\n const waitForRestoredSource = (sourceId: string): Promise<void> =>\n new Promise((resolve) => {\n let settled = false;\n let unsubscribe: (() => void) | undefined;\n unsubscribe = player.subscribe((state) => {\n if (settled || state.currentSourceId !== sourceId) {\n return;\n }\n\n if (state.status === \"loading\") {\n return;\n }\n\n settled = true;\n unsubscribe?.();\n resolve();\n });\n\n // subscribe emits synchronously, so the source may already be settled\n if (settled) {\n unsubscribe();\n }\n });\n\n const restore = async (): Promise<PersistedPlayerState | null> => {\n const persisted = options.adapter.load();\n if (!persisted) {\n return null;\n }\n\n if (Date.now() - persisted.savedAt > maxAgeMs) {\n options.adapter.clear();\n return null;\n }\n\n player.setRepeatMode(persisted.queue.position.repeatMode);\n player.setVolume(persisted.volume);\n player.setMuted(persisted.muted);\n player.setRate(persisted.rate);\n\n if (persisted.queue.items.length > 0) {\n await player.setQueue(persisted.queue.items, {\n startAtId: persisted.queue.position.currentSourceId ?? undefined,\n });\n } else if (persisted.currentSource) {\n await player.load(persisted.currentSource);\n } else {\n return persisted;\n }\n\n if (persisted.currentSourceId) {\n await waitForRestoredSource(persisted.currentSourceId);\n }\n\n if (persisted.currentTime > 0) {\n player.seek(persisted.currentTime);\n }\n\n return persisted;\n };\n\n const stateUnsubscribe = player.subscribe((state) => {\n if (state.status === \"playing\") {\n startPlayInterval();\n return;\n }\n\n stopPlayInterval();\n });\n\n const pauseUnsubscribe = player.on(\"pause\", () => {\n save();\n });\n const endedUnsubscribe = player.on(\"ended\", () => {\n save();\n });\n const sourceUnsubscribe = player.on(\"sourcechange\", () => {\n save();\n });\n const queueUnsubscribe = player.on(\"queuechange\", () => {\n save();\n });\n const rateUnsubscribe = player.on(\"ratechange\", () => {\n save();\n });\n const volumeUnsubscribe = player.on(\"volumechange\", () => {\n save();\n });\n\n const beforeUnloadHandler = (): void => {\n save();\n };\n\n const visibilityHandler = (): void => {\n if (typeof document === \"undefined\") {\n return;\n }\n\n if (document.visibilityState === \"hidden\") {\n save();\n }\n };\n\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"beforeunload\", beforeUnloadHandler);\n }\n\n if (typeof document !== \"undefined\") {\n document.addEventListener(\"visibilitychange\", visibilityHandler);\n }\n\n if (options.autoRestore !== false) {\n void restore();\n }\n\n return {\n restore,\n save,\n clear,\n destroy() {\n destroyed = true;\n stopPlayInterval();\n stateUnsubscribe();\n pauseUnsubscribe();\n endedUnsubscribe();\n sourceUnsubscribe();\n queueUnsubscribe();\n rateUnsubscribe();\n volumeUnsubscribe();\n\n if (typeof window !== \"undefined\") {\n window.removeEventListener(\"beforeunload\", beforeUnloadHandler);\n }\n\n if (typeof document !== \"undefined\") {\n document.removeEventListener(\"visibilitychange\", visibilityHandler);\n }\n },\n };\n};\n\nexport const attachAudioPlayerProgressReporter = (\n player: AudioPlayer,\n options: AudioPlayerProgressReporterOptions,\n): AudioPlayerProgressReporterController => {\n const intervalMs = options.intervalMs ?? DEFAULT_PROGRESS_REPORT_INTERVAL_MS;\n let destroyed = false;\n let intervalId: ReturnType<typeof setInterval> | null = null;\n\n const report = (): void => {\n if (destroyed) {\n return;\n }\n\n const state = player.getState();\n if (!state.currentSource) {\n return;\n }\n\n options.onReport(toProgressSnapshot(state));\n };\n\n const stopInterval = (): void => {\n if (intervalId !== null) {\n clearInterval(intervalId);\n intervalId = null;\n }\n };\n\n const startInterval = (): void => {\n if (intervalId !== null) {\n return;\n }\n\n intervalId = setInterval(() => {\n report();\n }, intervalMs);\n };\n\n const stateUnsubscribe = player.subscribe((state) => {\n if (state.status === \"playing\") {\n startInterval();\n return;\n }\n\n stopInterval();\n });\n\n const pauseUnsubscribe = player.on(\"pause\", () => {\n report();\n });\n const endedUnsubscribe = player.on(\"ended\", () => {\n report();\n });\n const seekedUnsubscribe = player.on(\"seeked\", () => {\n report();\n });\n const sourceUnsubscribe = player.on(\"sourcechange\", () => {\n report();\n });\n\n return {\n report,\n destroy() {\n destroyed = true;\n stopInterval();\n stateUnsubscribe();\n pauseUnsubscribe();\n endedUnsubscribe();\n seekedUnsubscribe();\n sourceUnsubscribe();\n },\n };\n};\n\nexport const attachAudioPlayerMediaSession = (\n player: AudioPlayer,\n options: AudioPlayerMediaSessionOptions = {},\n): AudioPlayerMediaSessionController => {\n if (!hasMediaSession()) {\n return {\n sync() {},\n destroy() {},\n };\n }\n\n const artworkSizes =\n options.artworkSizes ?? DEFAULT_MEDIA_SESSION_ARTWORK_SIZES;\n const seekOffsetSeconds =\n options.seekOffsetSeconds ?? DEFAULT_MEDIA_SESSION_SEEK_OFFSET_SECONDS;\n let destroyed = false;\n\n const sync = (): void => {\n if (destroyed || !hasMediaSession()) {\n return;\n }\n\n const state = player.getState();\n const source = state.currentSource;\n\n navigator.mediaSession.metadata = source\n ? new MediaMetadata({\n title: source.title ?? \"\",\n artist: source.artist ?? \"\",\n album: source.album ?? \"\",\n artwork: createMediaSessionArtwork(source, artworkSizes),\n })\n : null;\n\n navigator.mediaSession.playbackState =\n state.status === \"playing\"\n ? \"playing\"\n : state.currentSource\n ? \"paused\"\n : \"none\";\n\n if (state.currentSource && state.duration > 0) {\n try {\n navigator.mediaSession.setPositionState({\n duration: state.duration,\n playbackRate: state.rate,\n position: Math.min(state.currentTime, state.duration),\n });\n } catch {\n // Ignore unsupported position state implementations.\n }\n } else {\n try {\n navigator.mediaSession.setPositionState();\n } catch {\n // Ignore unsupported position state implementations.\n }\n }\n };\n\n const setActionHandler = (\n action: MediaSessionAction,\n handler: MediaSessionActionHandler | null,\n ): void => {\n try {\n navigator.mediaSession.setActionHandler(action, handler);\n } catch {\n // Ignore unsupported actions.\n }\n };\n\n setActionHandler(\"play\", () => {\n void player.play();\n });\n setActionHandler(\"pause\", () => {\n player.pause();\n });\n setActionHandler(\"seekbackward\", () => {\n const state = player.getState();\n player.seek(Math.max(0, state.currentTime - seekOffsetSeconds));\n });\n setActionHandler(\"seekforward\", () => {\n const state = player.getState();\n const max = state.duration > 0 ? state.duration : state.currentTime + seekOffsetSeconds;\n player.seek(Math.min(max, state.currentTime + seekOffsetSeconds));\n });\n setActionHandler(\"previoustrack\", () => {\n void player.previous();\n });\n setActionHandler(\"nexttrack\", () => {\n void player.next();\n });\n setActionHandler(\"seekto\", (details) => {\n if (details.seekTime === undefined) {\n return;\n }\n\n player.seek(details.seekTime);\n });\n setActionHandler(\"stop\", () => {\n player.pause();\n });\n\n const stateUnsubscribe = player.subscribe(() => {\n sync();\n });\n\n sync();\n\n return {\n sync,\n destroy() {\n destroyed = true;\n stateUnsubscribe();\n if (!hasMediaSession()) {\n return;\n }\n\n const actions: MediaSessionAction[] = [\n \"play\",\n \"pause\",\n \"seekbackward\",\n \"seekforward\",\n \"previoustrack\",\n \"nexttrack\",\n \"seekto\",\n \"stop\",\n ];\n\n for (const action of actions) {\n setActionHandler(action, null);\n }\n\n navigator.mediaSession.metadata = null;\n navigator.mediaSession.playbackState = \"none\";\n try {\n navigator.mediaSession.setPositionState();\n } catch {\n // Ignore unsupported position state implementations.\n }\n },\n };\n};\n"],"mappings":"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","names":["endedState"]}
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  attachAudioPlayerProgressReporter,
5
5
  createAudioPlayer,
6
6
  createLocalStoragePersistenceAdapter
7
- } from "./chunk-BN5MQE43.js";
7
+ } from "./chunk-7KCRIJPH.js";
8
8
  export {
9
9
  attachAudioPlayerMediaSession,
10
10
  attachAudioPlayerPersistence,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/react.tsx","../src/index.ts"],"sourcesContent":["import {\n createContext,\n type ReactNode,\n useContext,\n useEffect,\n useRef,\n useSyncExternalStore,\n} from \"react\";\nimport {\n createAudioPlayer,\n type AudioPlayer,\n type AudioPlayerState,\n type CreateAudioPlayerOptions,\n} from \"./index\";\n\nconst AudioPlayerContext = createContext<AudioPlayer | null>(null);\n\nexport interface AudioPlayerProviderProps {\n children: ReactNode;\n options?: CreateAudioPlayerOptions;\n player?: AudioPlayer;\n}\n\nexport const AudioPlayerProvider = ({\n children,\n options,\n player,\n}: AudioPlayerProviderProps) => {\n const playerRef = useRef<AudioPlayer | null>(player ?? null);\n\n if (playerRef.current === null) {\n playerRef.current = createAudioPlayer(options);\n }\n\n useEffect(() => {\n if (!player) {\n return () => {\n playerRef.current?.destroy();\n };\n }\n\n return undefined;\n }, [player]);\n\n return (\n <AudioPlayerContext.Provider value={playerRef.current}>\n {children}\n </AudioPlayerContext.Provider>\n );\n};\n\nexport const useAudioPlayer = (): AudioPlayer => {\n const player = useContext(AudioPlayerContext);\n\n if (!player) {\n throw new Error(\"useAudioPlayer must be used inside AudioPlayerProvider.\");\n }\n\n return player;\n};\n\nexport const useAudioPlayerState = (): AudioPlayerState => {\n const player = useAudioPlayer();\n\n return useSyncExternalStore(\n player.subscribe,\n player.getState,\n player.getState,\n );\n};\n","export type PlayerStatus =\n | \"idle\"\n | \"loading\"\n | \"ready\"\n | \"playing\"\n | \"paused\"\n | \"ended\"\n | \"error\";\n\nexport type RepeatMode = \"off\" | \"one\" | \"all\";\n\nexport type AudioPlayerEventName =\n | \"sourcechange\"\n | \"queuechange\"\n | \"play\"\n | \"pause\"\n | \"seeking\"\n | \"seeked\"\n | \"timeupdate\"\n | \"ratechange\"\n | \"volumechange\"\n | \"ended\"\n | \"error\"\n | \"destroy\";\n\nexport interface AudioSource {\n id: string;\n src: string;\n title?: string;\n artist?: string;\n artwork?: string;\n album?: string;\n durationHint?: number;\n}\n\nexport interface AudioPlayerErrorState {\n code:\n | \"LOAD_ERROR\"\n | \"PLAY_ERROR\"\n | \"SEEK_ERROR\"\n | \"INVALID_VOLUME\"\n | \"INVALID_RATE\"\n | \"INVALID_QUEUE_ITEM\"\n | \"NO_ACTIVE_SOURCE\"\n | \"UNSUPPORTED_ENVIRONMENT\"\n | \"UNKNOWN_ERROR\";\n message: string;\n}\n\nexport interface AudioPlayerRuntimeError extends AudioPlayerErrorState {\n cause?: unknown;\n}\n\nexport interface AudioPlayerProgressState {\n currentTime: number;\n duration: number;\n buffered: number;\n playedFraction: number;\n bufferedFraction: number;\n}\n\nexport interface AudioPlayerQueuePositionState {\n currentIndex: number;\n currentSourceId: string | null;\n length: number;\n hasNext: boolean;\n hasPrevious: boolean;\n repeatMode: RepeatMode;\n}\n\nexport interface AudioPlayerQueueState {\n items: AudioSource[];\n itemIds: string[];\n position: AudioPlayerQueuePositionState;\n}\n\nexport interface AudioPlayerState {\n status: PlayerStatus;\n currentSource: AudioSource | null;\n currentSourceId: string | null;\n currentTime: number;\n duration: number;\n buffered: number;\n progress: AudioPlayerProgressState;\n rate: number;\n volume: number;\n muted: boolean;\n queue: AudioPlayerQueueState;\n error: AudioPlayerErrorState | null;\n}\n\nexport interface AudioPlayerEventMap {\n sourcechange: { source: AudioSource | null; state: AudioPlayerState };\n queuechange: { queue: AudioPlayerQueueState; state: AudioPlayerState };\n play: { source: AudioSource | null; state: AudioPlayerState };\n pause: { source: AudioSource | null; state: AudioPlayerState };\n seeking: { from: number; to: number; state: AudioPlayerState };\n seeked: { currentTime: number; state: AudioPlayerState };\n timeupdate: { currentTime: number; duration: number; state: AudioPlayerState };\n ratechange: { rate: number; state: AudioPlayerState };\n volumechange: { volume: number; muted: boolean; state: AudioPlayerState };\n ended: { source: AudioSource | null; state: AudioPlayerState };\n error: { error: AudioPlayerRuntimeError; state: AudioPlayerState };\n destroy: { state: AudioPlayerState };\n}\n\nexport interface CreateAudioPlayerOptions {\n initialVolume?: number;\n initialRate?: number;\n initialMuted?: boolean;\n initialRepeatMode?: RepeatMode;\n}\n\nexport interface SetQueueOptions {\n startAtId?: string;\n autoplay?: boolean;\n}\n\nexport interface PreviousOptions {\n restartThresholdSeconds?: number;\n}\n\nexport interface PersistedPlayerState {\n version: 1;\n savedAt: number;\n currentSource: AudioSource | null;\n currentSourceId: string | null;\n currentTime: number;\n rate: number;\n volume: number;\n muted: boolean;\n queue: {\n items: AudioSource[];\n position: {\n currentIndex: number;\n currentSourceId: string | null;\n repeatMode: RepeatMode;\n };\n };\n}\n\nexport interface AudioPlayerPersistenceAdapter {\n load(): PersistedPlayerState | null;\n save(state: PersistedPlayerState): void;\n clear(): void;\n}\n\nexport interface AudioPlayerPersistenceOptions {\n adapter: AudioPlayerPersistenceAdapter;\n autoRestore?: boolean;\n maxAgeMs?: number;\n saveIntervalMs?: number;\n}\n\nexport interface AudioPlayerPersistenceController {\n restore(): Promise<PersistedPlayerState | null>;\n save(): void;\n clear(): void;\n destroy(): void;\n}\n\nexport interface AudioPlayerProgressSnapshot {\n source: AudioSource | null;\n sourceId: string | null;\n currentTime: number;\n duration: number;\n playedFraction: number;\n status: PlayerStatus;\n queue: AudioPlayerQueuePositionState;\n}\n\nexport interface AudioPlayerProgressReporterOptions {\n intervalMs?: number;\n onReport: (snapshot: AudioPlayerProgressSnapshot) => void;\n}\n\nexport interface AudioPlayerProgressReporterController {\n report(): void;\n destroy(): void;\n}\n\nexport interface AudioPlayerMediaSessionOptions {\n artworkSizes?: number[];\n seekOffsetSeconds?: number;\n}\n\nexport interface AudioPlayerMediaSessionController {\n sync(): void;\n destroy(): void;\n}\n\nexport type AudioPlayerEventListener<K extends AudioPlayerEventName> = (\n event: AudioPlayerEventMap[K],\n) => void;\n\nexport interface AudioPlayer {\n getState(): AudioPlayerState;\n subscribe(listener: (state: AudioPlayerState) => void): () => void;\n on<K extends AudioPlayerEventName>(\n eventName: K,\n listener: AudioPlayerEventListener<K>,\n ): () => void;\n\n load(source: AudioSource): Promise<void>;\n play(source?: AudioSource): Promise<void>;\n pause(): void;\n toggle(): Promise<void>;\n unload(): void;\n seek(time: number): void;\n setRate(rate: number): void;\n setVolume(volume: number): void;\n setMuted(muted: boolean): void;\n\n setQueue(items: AudioSource[], options?: SetQueueOptions): Promise<void>;\n appendToQueue(items: AudioSource[]): void;\n removeFromQueue(id: string): void;\n clearQueue(): void;\n next(): Promise<void>;\n previous(options?: PreviousOptions): Promise<void>;\n setRepeatMode(mode: RepeatMode): void;\n\n destroy(): void;\n}\n\nconst DEFAULT_PREVIOUS_RESTART_THRESHOLD_SECONDS = 5;\nconst DEFAULT_PERSISTENCE_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000;\nconst DEFAULT_PERSISTENCE_SAVE_INTERVAL_MS = 5000;\nconst DEFAULT_PROGRESS_REPORT_INTERVAL_MS = 5000;\nconst DEFAULT_MEDIA_SESSION_ARTWORK_SIZES = [96, 128, 192, 256, 384, 512];\nconst DEFAULT_MEDIA_SESSION_SEEK_OFFSET_SECONDS = 10;\n\ntype AudioEngineEventName =\n | \"loadedmetadata\"\n | \"timeupdate\"\n | \"progress\"\n | \"play\"\n | \"pause\"\n | \"seeked\"\n | \"ratechange\"\n | \"volumechange\"\n | \"ended\"\n | \"error\";\n\ninterface AudioEngineSnapshot {\n currentTime: number;\n duration: number;\n buffered: number;\n rate: number;\n volume: number;\n muted: boolean;\n}\n\ninterface AudioEngine {\n readonly available: boolean;\n getSnapshot(durationHint?: number): AudioEngineSnapshot;\n getRuntimeError(): unknown;\n on(eventName: AudioEngineEventName, listener: EventListener): () => void;\n setSource(src: string): void;\n clearSource(): void;\n load(): void;\n play(): Promise<void>;\n pause(): void;\n setCurrentTime(time: number): void;\n setPlaybackRate(rate: number): void;\n setVolume(volume: number): void;\n setMuted(muted: boolean): void;\n destroy(): void;\n}\n\nconst createInitialState = (\n options: CreateAudioPlayerOptions,\n): AudioPlayerState => ({\n status: \"idle\",\n currentSource: null,\n currentSourceId: null,\n currentTime: 0,\n duration: 0,\n buffered: 0,\n progress: {\n currentTime: 0,\n duration: 0,\n buffered: 0,\n playedFraction: 0,\n bufferedFraction: 0,\n },\n rate: options.initialRate ?? 1,\n volume: options.initialVolume ?? 1,\n muted: options.initialMuted ?? false,\n queue: {\n items: [],\n itemIds: [],\n position: {\n currentIndex: -1,\n currentSourceId: null,\n length: 0,\n repeatMode: options.initialRepeatMode ?? \"off\",\n hasNext: false,\n hasPrevious: false,\n },\n },\n error: null,\n});\n\nconst createPlayerError = (\n code: AudioPlayerRuntimeError[\"code\"],\n message: string,\n cause?: unknown,\n): AudioPlayerRuntimeError => ({\n code,\n message,\n cause,\n});\n\nconst isRuntimePlayerError = (\n value: unknown,\n): value is AudioPlayerRuntimeError =>\n !!value &&\n typeof value === \"object\" &&\n \"code\" in value &&\n \"message\" in value;\n\nconst normalizePlayerError = (\n fallbackCode: AudioPlayerRuntimeError[\"code\"],\n fallbackMessage: string,\n cause: unknown,\n): AudioPlayerRuntimeError =>\n isRuntimePlayerError(cause)\n ? cause\n : createPlayerError(fallbackCode, fallbackMessage, cause);\n\nconst assertStableSource = (source: AudioSource): void => {\n if (!source.id || !source.src) {\n throw createPlayerError(\n \"INVALID_QUEUE_ITEM\",\n \"AudioSource requires stable id and src.\",\n );\n }\n};\n\nconst isFiniteNumber = (value: number): boolean =>\n Number.isFinite(value) && !Number.isNaN(value);\n\nconst safeDuration = (audio: HTMLAudioElement | null, hint?: number): number => {\n const duration = audio?.duration;\n return duration !== undefined && isFiniteNumber(duration) ? duration : hint ?? 0;\n};\n\nconst safeBuffered = (audio: HTMLAudioElement | null): number => {\n if (!audio || audio.buffered.length === 0) {\n return 0;\n }\n\n try {\n return audio.buffered.end(audio.buffered.length - 1);\n } catch {\n return 0;\n }\n};\n\nconst cloneQueueState = (state: AudioPlayerState): AudioPlayerQueueState => ({\n items: [...state.queue.items],\n itemIds: [...state.queue.itemIds],\n position: {\n ...state.queue.position,\n },\n});\n\nconst updateQueueFlags = (state: AudioPlayerState): AudioPlayerState => {\n const { items, position } = state.queue;\n const { currentIndex, repeatMode } = position;\n const lastIndex = items.length - 1;\n const hasItems = items.length > 0;\n const hasNext =\n !hasItems || currentIndex < 0\n ? false\n : repeatMode === \"all\"\n ? items.length > 0\n : currentIndex < lastIndex;\n const hasPrevious =\n !hasItems || currentIndex < 0\n ? false\n : repeatMode === \"all\"\n ? items.length > 0\n : currentIndex > 0;\n\n return {\n ...state,\n queue: {\n ...state.queue,\n itemIds: items.map((item) => item.id),\n position: {\n ...position,\n currentSourceId: state.currentSource?.id ?? null,\n length: items.length,\n hasNext,\n hasPrevious,\n },\n },\n };\n};\n\nconst createAudioElement = (): HTMLAudioElement | null => {\n if (typeof Audio === \"undefined\") {\n return null;\n }\n\n return new Audio();\n};\n\nconst createUnavailableAudioEngine = (): AudioEngine => {\n const unavailableError = (): AudioPlayerRuntimeError =>\n createPlayerError(\n \"UNSUPPORTED_ENVIRONMENT\",\n \"HTMLAudioElement is not available in this environment.\",\n );\n\n return {\n available: false,\n getSnapshot(durationHint) {\n return {\n currentTime: 0,\n duration: durationHint ?? 0,\n buffered: 0,\n rate: 1,\n volume: 1,\n muted: false,\n };\n },\n getRuntimeError() {\n return unavailableError();\n },\n on() {\n return () => {};\n },\n setSource() {\n throw unavailableError();\n },\n clearSource() {\n throw unavailableError();\n },\n load() {\n throw unavailableError();\n },\n play() {\n throw unavailableError();\n },\n pause() {\n throw unavailableError();\n },\n setCurrentTime() {\n throw unavailableError();\n },\n setPlaybackRate() {\n throw unavailableError();\n },\n setVolume() {\n throw unavailableError();\n },\n setMuted() {\n throw unavailableError();\n },\n destroy() {},\n };\n};\n\nconst createHtmlAudioEngine = (): AudioEngine => {\n const audio = createAudioElement();\n if (!audio) {\n return createUnavailableAudioEngine();\n }\n\n audio.preload = \"metadata\";\n const clearSource = (): void => {\n const element = audio as HTMLAudioElement & {\n removeAttribute?: (name: string) => void;\n };\n if (typeof element.removeAttribute === \"function\") {\n element.removeAttribute(\"src\");\n return;\n }\n\n audio.src = \"\";\n };\n\n return {\n available: true,\n getSnapshot(durationHint) {\n return {\n currentTime: audio.currentTime,\n duration: safeDuration(audio, durationHint),\n buffered: safeBuffered(audio),\n rate: audio.playbackRate,\n volume: audio.volume,\n muted: audio.muted,\n };\n },\n getRuntimeError() {\n return audio.error;\n },\n on(eventName, listener) {\n audio.addEventListener(eventName, listener);\n return () => {\n audio.removeEventListener(eventName, listener);\n };\n },\n setSource(src) {\n audio.src = src;\n },\n clearSource() {\n clearSource();\n },\n load() {\n audio.load();\n },\n play() {\n return audio.play();\n },\n pause() {\n audio.pause();\n },\n setCurrentTime(time) {\n audio.currentTime = time;\n },\n setPlaybackRate(rate) {\n audio.playbackRate = rate;\n },\n setVolume(volume) {\n audio.volume = volume;\n },\n setMuted(muted) {\n audio.muted = muted;\n },\n destroy() {\n audio.pause();\n clearSource();\n audio.load();\n },\n };\n};\n\nconst isBrowserStorageAvailable = (): boolean =>\n typeof window !== \"undefined\" && typeof window.localStorage !== \"undefined\";\n\nconst isPersistedPlayerState = (value: unknown): value is PersistedPlayerState => {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n\n const candidate = value as Partial<PersistedPlayerState>;\n return (\n candidate.version === 1 &&\n typeof candidate.savedAt === \"number\" &&\n \"currentSource\" in candidate &&\n typeof candidate.currentTime === \"number\" &&\n typeof candidate.rate === \"number\" &&\n typeof candidate.volume === \"number\" &&\n typeof candidate.muted === \"boolean\" &&\n !!candidate.queue &&\n Array.isArray(candidate.queue.items) &&\n !!candidate.queue.position\n );\n};\n\nconst toPersistedPlayerState = (state: AudioPlayerState): PersistedPlayerState => ({\n version: 1,\n savedAt: Date.now(),\n currentSource: state.currentSource,\n currentSourceId: state.currentSourceId,\n currentTime: state.currentTime,\n rate: state.rate,\n volume: state.volume,\n muted: state.muted,\n queue: {\n items: [...state.queue.items],\n position: {\n currentIndex: state.queue.position.currentIndex,\n currentSourceId: state.queue.position.currentSourceId,\n repeatMode: state.queue.position.repeatMode,\n },\n },\n});\n\nconst toProgressSnapshot = (\n state: AudioPlayerState,\n): AudioPlayerProgressSnapshot => ({\n source: state.currentSource,\n sourceId: state.currentSourceId,\n currentTime: state.currentTime,\n duration: state.duration,\n playedFraction: state.progress.playedFraction,\n status: state.status,\n queue: {\n ...state.queue.position,\n },\n});\n\nconst hasMediaSession = (): boolean =>\n typeof navigator !== \"undefined\" && \"mediaSession\" in navigator;\n\nconst createMediaSessionArtwork = (\n source: AudioSource | null,\n sizes: number[],\n): MediaImage[] => {\n if (!source?.artwork) {\n return [];\n }\n\n return sizes.map((size) => ({\n src: source.artwork as string,\n sizes: `${size}x${size}`,\n }));\n};\n\nexport const createLocalStoragePersistenceAdapter = (\n key: string,\n): AudioPlayerPersistenceAdapter => ({\n load() {\n if (!isBrowserStorageAvailable()) {\n return null;\n }\n\n try {\n const raw = window.localStorage.getItem(key);\n if (!raw) {\n return null;\n }\n\n const parsed: unknown = JSON.parse(raw);\n return isPersistedPlayerState(parsed) ? parsed : null;\n } catch {\n return null;\n }\n },\n\n save(state) {\n if (!isBrowserStorageAvailable()) {\n return;\n }\n\n window.localStorage.setItem(key, JSON.stringify(state));\n },\n\n clear() {\n if (!isBrowserStorageAvailable()) {\n return;\n }\n\n window.localStorage.removeItem(key);\n },\n});\n\nexport const createAudioPlayer = (\n options: CreateAudioPlayerOptions = {},\n): AudioPlayer => {\n let state = updateQueueFlags(createInitialState(options));\n let destroyed = false;\n let shouldAutoplayAfterLoad = false;\n let suppressPauseEvent = false;\n\n const engine = createHtmlAudioEngine();\n const subscribers = new Set<(nextState: AudioPlayerState) => void>();\n const eventListeners: {\n [K in AudioPlayerEventName]: Set<AudioPlayerEventListener<K>>;\n } = {\n sourcechange: new Set(),\n queuechange: new Set(),\n play: new Set(),\n pause: new Set(),\n seeking: new Set(),\n seeked: new Set(),\n timeupdate: new Set(),\n ratechange: new Set(),\n volumechange: new Set(),\n ended: new Set(),\n error: new Set(),\n destroy: new Set(),\n };\n\n const getState = (): AudioPlayerState => state;\n\n const publishState = (): void => {\n for (const subscriber of subscribers) {\n subscriber(state);\n }\n };\n\n const emit = <K extends AudioPlayerEventName>(\n eventName: K,\n event: AudioPlayerEventMap[K],\n ): void => {\n for (const listener of eventListeners[eventName]) {\n listener(event);\n }\n };\n\n const setState = (\n updater: (currentState: AudioPlayerState) => AudioPlayerState,\n ): AudioPlayerState => {\n state = updateQueueFlags(updater(state));\n publishState();\n return state;\n };\n\n const setError = (error: AudioPlayerRuntimeError): void => {\n shouldAutoplayAfterLoad = false;\n const nextState = setState((currentState) => ({\n ...currentState,\n status: \"error\",\n error: {\n code: error.code,\n message: error.message,\n },\n }));\n emit(\"error\", { error, state: nextState });\n };\n\n const clearError = (): void => {\n if (!state.error) {\n return;\n }\n\n setState((currentState) => ({\n ...currentState,\n error: null,\n }));\n };\n\n const syncAudioSnapshot = (\n statusOverride?: PlayerStatus,\n ): AudioPlayerState => {\n const snapshot = engine.getSnapshot(state.currentSource?.durationHint);\n const currentTime = snapshot.currentTime;\n const duration = snapshot.duration;\n const buffered = snapshot.buffered;\n const playedFraction =\n duration > 0 ? Math.min(1, Math.max(0, currentTime / duration)) : 0;\n const bufferedFraction =\n duration > 0 ? Math.min(1, Math.max(0, buffered / duration)) : 0;\n\n const nextState = setState((currentState) => ({\n ...currentState,\n currentSourceId: currentState.currentSource?.id ?? null,\n currentTime,\n duration,\n buffered,\n progress: {\n currentTime,\n duration,\n buffered,\n playedFraction,\n bufferedFraction,\n },\n rate: snapshot.rate,\n volume: snapshot.volume,\n muted: snapshot.muted,\n status: statusOverride ?? currentState.status,\n error:\n statusOverride === \"error\" ? currentState.error : null,\n }));\n\n return nextState;\n };\n\n const findQueueIndexById = (id: string | null | undefined): number =>\n id ? state.queue.items.findIndex((item) => item.id === id) : -1;\n\n const resolveNextQueueIndex = (\n mode: \"manual\" | \"ended\",\n ): number | null => {\n const { items, position } = state.queue;\n const { currentIndex, repeatMode } = position;\n\n if (items.length === 0 || currentIndex < 0) {\n return null;\n }\n\n if (repeatMode === \"one\") {\n return currentIndex;\n }\n\n if (currentIndex < items.length - 1) {\n return currentIndex + 1;\n }\n\n if (repeatMode === \"all\") {\n return 0;\n }\n\n return mode === \"ended\" ? -1 : null;\n };\n\n const resolvePreviousQueueIndex = (): number | null => {\n const { items, position } = state.queue;\n const { currentIndex, repeatMode } = position;\n\n if (items.length === 0 || currentIndex < 0) {\n return null;\n }\n\n if (currentIndex > 0) {\n return currentIndex - 1;\n }\n\n if (repeatMode === \"all\") {\n return items.length - 1;\n }\n\n return null;\n };\n\n const updateCurrentSource = (\n source: AudioSource | null,\n nextStatus: PlayerStatus,\n ): AudioPlayerState => {\n const queueIndex = findQueueIndexById(source?.id);\n const nextState = setState((currentState) => ({\n ...currentState,\n currentSource: source,\n currentSourceId: source?.id ?? null,\n currentTime: 0,\n duration: source?.durationHint ?? 0,\n buffered: 0,\n progress: {\n currentTime: 0,\n duration: source?.durationHint ?? 0,\n buffered: 0,\n playedFraction: 0,\n bufferedFraction: 0,\n },\n status: nextStatus,\n error: null,\n queue: {\n ...currentState.queue,\n position: {\n ...currentState.queue.position,\n currentIndex: queueIndex,\n currentSourceId: source?.id ?? null,\n },\n },\n }));\n emit(\"sourcechange\", { source, state: nextState });\n return nextState;\n };\n\n const setQueueState = (\n items: AudioSource[],\n currentIndex: number,\n ): AudioPlayerState =>\n setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n items,\n position: {\n ...currentState.queue.position,\n currentIndex,\n },\n },\n }));\n\n const emitQueueChange = (nextState: AudioPlayerState): void => {\n emit(\"queuechange\", { queue: cloneQueueState(nextState), state: nextState });\n };\n\n const attachSourceToAudio = (\n source: AudioSource,\n autoplayAfterLoad: boolean,\n ): void => {\n shouldAutoplayAfterLoad = autoplayAfterLoad;\n suppressPauseEvent = true;\n try {\n engine.pause();\n } finally {\n suppressPauseEvent = false;\n }\n engine.setSource(source.src);\n engine.setCurrentTime(0);\n engine.setPlaybackRate(state.rate);\n engine.setVolume(state.volume);\n engine.setMuted(state.muted);\n engine.load();\n };\n\n const loadInternal = async (\n source: AudioSource,\n autoplayAfterLoad = false,\n ): Promise<void> => {\n assertStableSource(source);\n updateCurrentSource(source, \"loading\");\n attachSourceToAudio(source, autoplayAfterLoad);\n };\n\n const selectQueueIndex = async (\n index: number,\n autoplayAfterLoad = false,\n ): Promise<AudioSource | null> => {\n const item = state.queue.items[index] ?? null;\n if (!item) {\n return null;\n }\n\n await loadInternal(item, autoplayAfterLoad);\n const nextState = setQueueState(state.queue.items, index);\n emitQueueChange(nextState);\n return item;\n };\n\n const playLoadedAudio = async (): Promise<void> => {\n try {\n await engine.play();\n } catch (cause) {\n setError(createPlayerError(\"PLAY_ERROR\", \"Failed to start playback.\", cause));\n }\n };\n\n const handlePlaybackEnded = async (): Promise<void> => {\n if (destroyed) {\n return;\n }\n\n if (state.queue.items.length > 0 && state.queue.position.currentIndex >= 0) {\n const nextIndex = resolveNextQueueIndex(\"ended\");\n if (nextIndex === -1 || nextIndex === null) {\n const endedState = syncAudioSnapshot(\"ended\");\n emit(\"ended\", { source: endedState.currentSource, state: endedState });\n return;\n }\n\n await selectQueueIndex(nextIndex, true);\n return;\n }\n\n const endedState = syncAudioSnapshot(\"ended\");\n emit(\"ended\", { source: endedState.currentSource, state: endedState });\n };\n\n const detachEngineListeners = [\n engine.on(\"loadedmetadata\", () => {\n if (destroyed || !state.currentSource) {\n return;\n }\n\n syncAudioSnapshot(\"ready\");\n if (shouldAutoplayAfterLoad) {\n shouldAutoplayAfterLoad = false;\n void playLoadedAudio();\n }\n }),\n engine.on(\"timeupdate\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot(\n state.status === \"ended\" ? \"playing\" : undefined,\n );\n emit(\"timeupdate\", {\n currentTime: nextState.currentTime,\n duration: nextState.duration,\n state: nextState,\n });\n }),\n engine.on(\"progress\", () => {\n if (!destroyed) {\n syncAudioSnapshot();\n }\n }),\n engine.on(\"play\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot(\"playing\");\n emit(\"play\", { source: nextState.currentSource, state: nextState });\n }),\n engine.on(\"pause\", () => {\n if (destroyed || suppressPauseEvent) {\n return;\n }\n\n const nextStatus =\n state.status === \"ended\" ? \"ended\" : state.currentSource ? \"paused\" : \"idle\";\n const nextState = syncAudioSnapshot(nextStatus);\n emit(\"pause\", { source: nextState.currentSource, state: nextState });\n }),\n engine.on(\"seeked\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot();\n emit(\"seeked\", { currentTime: nextState.currentTime, state: nextState });\n emit(\"timeupdate\", {\n currentTime: nextState.currentTime,\n duration: nextState.duration,\n state: nextState,\n });\n }),\n engine.on(\"ratechange\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot();\n emit(\"ratechange\", { rate: nextState.rate, state: nextState });\n }),\n engine.on(\"volumechange\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot();\n emit(\"volumechange\", {\n volume: nextState.volume,\n muted: nextState.muted,\n state: nextState,\n });\n }),\n engine.on(\"ended\", () => {\n void handlePlaybackEnded();\n }),\n engine.on(\"error\", () => {\n if (destroyed) {\n return;\n }\n\n setError(\n createPlayerError(\n \"LOAD_ERROR\",\n \"Audio element reported a playback error.\",\n engine.getRuntimeError(),\n ),\n );\n }),\n ];\n\n return {\n getState,\n\n subscribe(listener) {\n subscribers.add(listener);\n listener(state);\n return () => {\n subscribers.delete(listener);\n };\n },\n\n on(eventName, listener) {\n eventListeners[eventName].add(\n listener as AudioPlayerEventListener<typeof eventName>,\n );\n return () => {\n eventListeners[eventName].delete(\n listener as AudioPlayerEventListener<typeof eventName>,\n );\n };\n },\n\n async load(source) {\n try {\n await loadInternal(source);\n } catch (cause) {\n setError(\n normalizePlayerError(\"LOAD_ERROR\", \"Failed to load source.\", cause),\n );\n }\n },\n\n async play(source) {\n try {\n if (source) {\n await loadInternal(source, true);\n return;\n }\n\n if (!state.currentSource) {\n setError(\n createPlayerError(\n \"NO_ACTIVE_SOURCE\",\n \"Cannot play without an active source.\",\n ),\n );\n return;\n }\n\n if (state.status === \"loading\") {\n shouldAutoplayAfterLoad = true;\n return;\n }\n\n await playLoadedAudio();\n } catch (cause) {\n setError(normalizePlayerError(\"PLAY_ERROR\", \"Failed to start playback.\", cause));\n }\n },\n\n pause() {\n if (!engine.available) {\n return;\n }\n\n shouldAutoplayAfterLoad = false;\n engine.pause();\n },\n\n async toggle() {\n if (state.status === \"playing\") {\n this.pause();\n return;\n }\n\n await this.play();\n },\n\n unload() {\n shouldAutoplayAfterLoad = false;\n\n if (engine.available) {\n suppressPauseEvent = true;\n try {\n engine.pause();\n } finally {\n suppressPauseEvent = false;\n }\n engine.clearSource();\n engine.load();\n }\n\n const nextState = updateCurrentSource(null, \"idle\");\n emitQueueChange(nextState);\n },\n\n seek(time) {\n if (!state.currentSource) {\n setError(\n createPlayerError(\"SEEK_ERROR\", \"Cannot seek without an active source.\"),\n );\n return;\n }\n\n const max = engine.getSnapshot(state.currentSource.durationHint).duration;\n const normalized = Math.max(\n 0,\n max > 0 ? Math.min(time, max) : (isFiniteNumber(time) ? time : 0),\n );\n emit(\"seeking\", { from: state.currentTime, to: normalized, state });\n\n try {\n engine.setCurrentTime(normalized);\n } catch (cause) {\n setError(normalizePlayerError(\"SEEK_ERROR\", \"Failed to seek audio.\", cause));\n }\n },\n\n setRate(rate) {\n if (!engine.available) {\n setError(\n createPlayerError(\"INVALID_RATE\", \"Audio element is unavailable.\"),\n );\n return;\n }\n\n if (!isFiniteNumber(rate) || rate <= 0) {\n setError(\n createPlayerError(\"INVALID_RATE\", \"Playback rate must be greater than 0.\"),\n );\n return;\n }\n\n engine.setPlaybackRate(rate);\n clearError();\n syncAudioSnapshot();\n },\n\n setVolume(volume) {\n if (!engine.available) {\n setError(\n createPlayerError(\"INVALID_VOLUME\", \"Audio element is unavailable.\"),\n );\n return;\n }\n\n if (!isFiniteNumber(volume) || volume < 0 || volume > 1) {\n setError(\n createPlayerError(\"INVALID_VOLUME\", \"Volume must be between 0 and 1.\"),\n );\n return;\n }\n\n engine.setVolume(volume);\n clearError();\n syncAudioSnapshot();\n },\n\n setMuted(muted) {\n if (!engine.available) {\n return;\n }\n\n engine.setMuted(muted);\n clearError();\n syncAudioSnapshot();\n },\n\n async setQueue(items, queueOptions = {}) {\n try {\n for (const item of items) {\n assertStableSource(item);\n }\n\n const startIndex =\n queueOptions.startAtId === undefined\n ? items.length > 0\n ? 0\n : -1\n : items.findIndex((item) => item.id === queueOptions.startAtId);\n\n if (queueOptions.startAtId && startIndex < 0) {\n throw createPlayerError(\n \"INVALID_QUEUE_ITEM\",\n `Queue start item ${queueOptions.startAtId} was not found.`,\n );\n }\n\n const nextState = setState((currentState) => ({\n ...currentState,\n currentSource: startIndex >= 0 ? items[startIndex] ?? null : null,\n currentSourceId: startIndex >= 0 ? (items[startIndex]?.id ?? null) : null,\n currentTime: 0,\n duration: startIndex >= 0 ? (items[startIndex]?.durationHint ?? 0) : 0,\n buffered: 0,\n progress: {\n currentTime: 0,\n duration: startIndex >= 0 ? (items[startIndex]?.durationHint ?? 0) : 0,\n buffered: 0,\n playedFraction: 0,\n bufferedFraction: 0,\n },\n status: startIndex >= 0 ? \"ready\" : \"idle\",\n error: null,\n queue: {\n ...currentState.queue,\n items: [...items],\n position: {\n ...currentState.queue.position,\n currentIndex: startIndex,\n currentSourceId:\n startIndex >= 0 ? (items[startIndex]?.id ?? null) : null,\n },\n },\n }));\n\n emitQueueChange(nextState);\n emit(\"sourcechange\", {\n source: nextState.currentSource,\n state: nextState,\n });\n\n if (nextState.currentSource) {\n await loadInternal(nextState.currentSource, queueOptions.autoplay === true);\n const syncedState = setQueueState(items, startIndex);\n emitQueueChange(syncedState);\n } else if (engine.available) {\n shouldAutoplayAfterLoad = false;\n suppressPauseEvent = true;\n engine.pause();\n suppressPauseEvent = false;\n engine.clearSource();\n engine.load();\n }\n } catch (cause) {\n setError(\n normalizePlayerError(\n \"INVALID_QUEUE_ITEM\",\n \"Failed to set queue.\",\n cause,\n ),\n );\n }\n },\n\n appendToQueue(items) {\n try {\n for (const item of items) {\n assertStableSource(item);\n }\n\n const nextState = setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n items: [...currentState.queue.items, ...items],\n },\n }));\n emitQueueChange(nextState);\n } catch (cause) {\n setError(\n normalizePlayerError(\n \"INVALID_QUEUE_ITEM\",\n \"Failed to append queue items.\",\n cause,\n ),\n );\n }\n },\n\n removeFromQueue(id) {\n const nextItems = state.queue.items.filter((item) => item.id !== id);\n const nextIndex = nextItems.findIndex(\n (item) => item.id === state.currentSource?.id,\n );\n\n const nextState = setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n items: nextItems,\n position: {\n ...currentState.queue.position,\n currentIndex: nextIndex,\n currentSourceId: nextIndex >= 0 ? (nextItems[nextIndex]?.id ?? null) : null,\n },\n },\n }));\n\n emitQueueChange(nextState);\n },\n\n clearQueue() {\n const nextState = setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n items: [],\n position: {\n ...currentState.queue.position,\n currentIndex: -1,\n currentSourceId: null,\n },\n },\n }));\n\n emitQueueChange(nextState);\n },\n\n async next() {\n const nextIndex = resolveNextQueueIndex(\"manual\");\n if (nextIndex === null) {\n return;\n }\n\n await selectQueueIndex(nextIndex, true);\n },\n\n async previous(previousOptions = {}) {\n if (!state.currentSource) {\n return;\n }\n\n const threshold =\n previousOptions.restartThresholdSeconds ??\n DEFAULT_PREVIOUS_RESTART_THRESHOLD_SECONDS;\n\n if (state.currentTime > threshold) {\n this.seek(0);\n return;\n }\n\n const previousIndex = resolvePreviousQueueIndex();\n if (previousIndex === null) {\n this.seek(0);\n return;\n }\n\n await selectQueueIndex(previousIndex, true);\n },\n\n setRepeatMode(mode) {\n const nextState = setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n position: {\n ...currentState.queue.position,\n repeatMode: mode,\n },\n },\n }));\n emitQueueChange(nextState);\n },\n\n destroy() {\n if (destroyed) {\n return;\n }\n\n destroyed = true;\n shouldAutoplayAfterLoad = false;\n for (const detach of detachEngineListeners) {\n detach();\n }\n suppressPauseEvent = true;\n engine.destroy();\n suppressPauseEvent = false;\n\n const nextState = setState(() => createInitialState(options));\n emit(\"destroy\", { state: nextState });\n subscribers.clear();\n for (const eventName of Object.keys(eventListeners) as AudioPlayerEventName[]) {\n eventListeners[eventName].clear();\n }\n },\n };\n};\n\nexport const attachAudioPlayerPersistence = (\n player: AudioPlayer,\n options: AudioPlayerPersistenceOptions,\n): AudioPlayerPersistenceController => {\n const maxAgeMs = options.maxAgeMs ?? DEFAULT_PERSISTENCE_MAX_AGE_MS;\n const saveIntervalMs =\n options.saveIntervalMs ?? DEFAULT_PERSISTENCE_SAVE_INTERVAL_MS;\n let destroyed = false;\n let playIntervalId: ReturnType<typeof setInterval> | null = null;\n\n const save = (): void => {\n if (destroyed) {\n return;\n }\n\n const state = player.getState();\n if (!state.currentSource) {\n options.adapter.clear();\n return;\n }\n\n options.adapter.save(toPersistedPlayerState(state));\n };\n\n const clear = (): void => {\n options.adapter.clear();\n };\n\n const stopPlayInterval = (): void => {\n if (playIntervalId !== null) {\n clearInterval(playIntervalId);\n playIntervalId = null;\n }\n };\n\n const startPlayInterval = (): void => {\n if (playIntervalId !== null) {\n return;\n }\n\n playIntervalId = setInterval(() => {\n save();\n }, saveIntervalMs);\n };\n\n const waitForRestoredSource = (sourceId: string): Promise<void> =>\n new Promise((resolve) => {\n const unsubscribe = player.subscribe((state) => {\n if (state.currentSourceId !== sourceId) {\n return;\n }\n\n if (state.status === \"loading\") {\n return;\n }\n\n unsubscribe();\n resolve();\n });\n });\n\n const restore = async (): Promise<PersistedPlayerState | null> => {\n const persisted = options.adapter.load();\n if (!persisted) {\n return null;\n }\n\n if (Date.now() - persisted.savedAt > maxAgeMs) {\n options.adapter.clear();\n return null;\n }\n\n player.setRepeatMode(persisted.queue.position.repeatMode);\n player.setVolume(persisted.volume);\n player.setMuted(persisted.muted);\n player.setRate(persisted.rate);\n\n if (persisted.queue.items.length > 0) {\n await player.setQueue(persisted.queue.items, {\n startAtId: persisted.queue.position.currentSourceId ?? undefined,\n });\n } else if (persisted.currentSource) {\n await player.load(persisted.currentSource);\n } else {\n return persisted;\n }\n\n if (persisted.currentSourceId) {\n await waitForRestoredSource(persisted.currentSourceId);\n }\n\n if (persisted.currentTime > 0) {\n player.seek(persisted.currentTime);\n }\n\n return persisted;\n };\n\n const stateUnsubscribe = player.subscribe((state) => {\n if (state.status === \"playing\") {\n startPlayInterval();\n return;\n }\n\n stopPlayInterval();\n });\n\n const pauseUnsubscribe = player.on(\"pause\", () => {\n save();\n });\n const endedUnsubscribe = player.on(\"ended\", () => {\n save();\n });\n const sourceUnsubscribe = player.on(\"sourcechange\", () => {\n save();\n });\n const queueUnsubscribe = player.on(\"queuechange\", () => {\n save();\n });\n const rateUnsubscribe = player.on(\"ratechange\", () => {\n save();\n });\n const volumeUnsubscribe = player.on(\"volumechange\", () => {\n save();\n });\n\n const beforeUnloadHandler = (): void => {\n save();\n };\n\n const visibilityHandler = (): void => {\n if (typeof document === \"undefined\") {\n return;\n }\n\n if (document.visibilityState === \"hidden\") {\n save();\n }\n };\n\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"beforeunload\", beforeUnloadHandler);\n }\n\n if (typeof document !== \"undefined\") {\n document.addEventListener(\"visibilitychange\", visibilityHandler);\n }\n\n if (options.autoRestore !== false) {\n void restore();\n }\n\n return {\n restore,\n save,\n clear,\n destroy() {\n destroyed = true;\n stopPlayInterval();\n stateUnsubscribe();\n pauseUnsubscribe();\n endedUnsubscribe();\n sourceUnsubscribe();\n queueUnsubscribe();\n rateUnsubscribe();\n volumeUnsubscribe();\n\n if (typeof window !== \"undefined\") {\n window.removeEventListener(\"beforeunload\", beforeUnloadHandler);\n }\n\n if (typeof document !== \"undefined\") {\n document.removeEventListener(\"visibilitychange\", visibilityHandler);\n }\n },\n };\n};\n\nexport const attachAudioPlayerProgressReporter = (\n player: AudioPlayer,\n options: AudioPlayerProgressReporterOptions,\n): AudioPlayerProgressReporterController => {\n const intervalMs = options.intervalMs ?? DEFAULT_PROGRESS_REPORT_INTERVAL_MS;\n let destroyed = false;\n let intervalId: ReturnType<typeof setInterval> | null = null;\n\n const report = (): void => {\n if (destroyed) {\n return;\n }\n\n const state = player.getState();\n if (!state.currentSource) {\n return;\n }\n\n options.onReport(toProgressSnapshot(state));\n };\n\n const stopInterval = (): void => {\n if (intervalId !== null) {\n clearInterval(intervalId);\n intervalId = null;\n }\n };\n\n const startInterval = (): void => {\n if (intervalId !== null) {\n return;\n }\n\n intervalId = setInterval(() => {\n report();\n }, intervalMs);\n };\n\n const stateUnsubscribe = player.subscribe((state) => {\n if (state.status === \"playing\") {\n startInterval();\n return;\n }\n\n stopInterval();\n });\n\n const pauseUnsubscribe = player.on(\"pause\", () => {\n report();\n });\n const endedUnsubscribe = player.on(\"ended\", () => {\n report();\n });\n const seekedUnsubscribe = player.on(\"seeked\", () => {\n report();\n });\n const sourceUnsubscribe = player.on(\"sourcechange\", () => {\n report();\n });\n\n return {\n report,\n destroy() {\n destroyed = true;\n stopInterval();\n stateUnsubscribe();\n pauseUnsubscribe();\n endedUnsubscribe();\n seekedUnsubscribe();\n sourceUnsubscribe();\n },\n };\n};\n\nexport const attachAudioPlayerMediaSession = (\n player: AudioPlayer,\n options: AudioPlayerMediaSessionOptions = {},\n): AudioPlayerMediaSessionController => {\n if (!hasMediaSession()) {\n return {\n sync() {},\n destroy() {},\n };\n }\n\n const artworkSizes =\n options.artworkSizes ?? DEFAULT_MEDIA_SESSION_ARTWORK_SIZES;\n const seekOffsetSeconds =\n options.seekOffsetSeconds ?? DEFAULT_MEDIA_SESSION_SEEK_OFFSET_SECONDS;\n let destroyed = false;\n\n const sync = (): void => {\n if (destroyed || !hasMediaSession()) {\n return;\n }\n\n const state = player.getState();\n const source = state.currentSource;\n\n navigator.mediaSession.metadata = source\n ? new MediaMetadata({\n title: source.title ?? \"\",\n artist: source.artist ?? \"\",\n album: source.album ?? \"\",\n artwork: createMediaSessionArtwork(source, artworkSizes),\n })\n : null;\n\n navigator.mediaSession.playbackState =\n state.status === \"playing\"\n ? \"playing\"\n : state.currentSource\n ? \"paused\"\n : \"none\";\n\n if (state.currentSource && state.duration > 0) {\n try {\n navigator.mediaSession.setPositionState({\n duration: state.duration,\n playbackRate: state.rate,\n position: Math.min(state.currentTime, state.duration),\n });\n } catch {\n // Ignore unsupported position state implementations.\n }\n } else {\n try {\n navigator.mediaSession.setPositionState();\n } catch {\n // Ignore unsupported position state implementations.\n }\n }\n };\n\n const setActionHandler = (\n action: MediaSessionAction,\n handler: MediaSessionActionHandler | null,\n ): void => {\n try {\n navigator.mediaSession.setActionHandler(action, handler);\n } catch {\n // Ignore unsupported actions.\n }\n };\n\n setActionHandler(\"play\", () => {\n void player.play();\n });\n setActionHandler(\"pause\", () => {\n player.pause();\n });\n setActionHandler(\"seekbackward\", () => {\n const state = player.getState();\n player.seek(Math.max(0, state.currentTime - seekOffsetSeconds));\n });\n setActionHandler(\"seekforward\", () => {\n const state = player.getState();\n const max = state.duration > 0 ? state.duration : state.currentTime + seekOffsetSeconds;\n player.seek(Math.min(max, state.currentTime + seekOffsetSeconds));\n });\n setActionHandler(\"previoustrack\", () => {\n void player.previous();\n });\n setActionHandler(\"nexttrack\", () => {\n void player.next();\n });\n setActionHandler(\"seekto\", (details) => {\n if (details.seekTime === undefined) {\n return;\n }\n\n player.seek(details.seekTime);\n });\n setActionHandler(\"stop\", () => {\n player.pause();\n });\n\n const stateUnsubscribe = player.subscribe(() => {\n sync();\n });\n\n sync();\n\n return {\n sync,\n destroy() {\n destroyed = true;\n stateUnsubscribe();\n if (!hasMediaSession()) {\n return;\n }\n\n const actions: MediaSessionAction[] = [\n \"play\",\n \"pause\",\n \"seekbackward\",\n \"seekforward\",\n \"previoustrack\",\n \"nexttrack\",\n \"seekto\",\n \"stop\",\n ];\n\n for (const action of actions) {\n setActionHandler(action, null);\n }\n\n navigator.mediaSession.metadata = null;\n navigator.mediaSession.playbackState = \"none\";\n try {\n navigator.mediaSession.setPositionState();\n } catch {\n // Ignore unsupported position state implementations.\n }\n },\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAOO;;;ACyNP,IAAM,6CAA6C;AACnD,IAAM,iCAAiC,KAAK,KAAK,KAAK,KAAK;AA4C3D,IAAM,qBAAqB,CACzB,aACsB;AAAA,EACtB,QAAQ;AAAA,EACR,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,aAAa;AAAA,EACb,UAAU;AAAA,EACV,UAAU;AAAA,EACV,UAAU;AAAA,IACR,aAAa;AAAA,IACb,UAAU;AAAA,IACV,UAAU;AAAA,IACV,gBAAgB;AAAA,IAChB,kBAAkB;AAAA,EACpB;AAAA,EACA,MAAM,QAAQ,eAAe;AAAA,EAC7B,QAAQ,QAAQ,iBAAiB;AAAA,EACjC,OAAO,QAAQ,gBAAgB;AAAA,EAC/B,OAAO;AAAA,IACL,OAAO,CAAC;AAAA,IACR,SAAS,CAAC;AAAA,IACV,UAAU;AAAA,MACR,cAAc;AAAA,MACd,iBAAiB;AAAA,MACjB,QAAQ;AAAA,MACR,YAAY,QAAQ,qBAAqB;AAAA,MACzC,SAAS;AAAA,MACT,aAAa;AAAA,IACf;AAAA,EACF;AAAA,EACA,OAAO;AACT;AAEA,IAAM,oBAAoB,CACxB,MACA,SACA,WAC6B;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,uBAAuB,CAC3B,UAEA,CAAC,CAAC,SACF,OAAO,UAAU,YACjB,UAAU,SACV,aAAa;AAEf,IAAM,uBAAuB,CAC3B,cACA,iBACA,UAEA,qBAAqB,KAAK,IACtB,QACA,kBAAkB,cAAc,iBAAiB,KAAK;AAE5D,IAAM,qBAAqB,CAAC,WAA8B;AACxD,MAAI,CAAC,OAAO,MAAM,CAAC,OAAO,KAAK;AAC7B,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAM,iBAAiB,CAAC,UACtB,OAAO,SAAS,KAAK,KAAK,CAAC,OAAO,MAAM,KAAK;AAE/C,IAAM,eAAe,CAAC,OAAgC,SAA0B;AAC9E,QAAM,WAAW,OAAO;AACxB,SAAO,aAAa,UAAa,eAAe,QAAQ,IAAI,WAAW,QAAQ;AACjF;AAEA,IAAM,eAAe,CAAC,UAA2C;AAC/D,MAAI,CAAC,SAAS,MAAM,SAAS,WAAW,GAAG;AACzC,WAAO;AAAA,EACT;AAEA,MAAI;AACF,WAAO,MAAM,SAAS,IAAI,MAAM,SAAS,SAAS,CAAC;AAAA,EACrD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,IAAM,kBAAkB,CAAC,WAAoD;AAAA,EAC3E,OAAO,CAAC,GAAG,MAAM,MAAM,KAAK;AAAA,EAC5B,SAAS,CAAC,GAAG,MAAM,MAAM,OAAO;AAAA,EAChC,UAAU;AAAA,IACR,GAAG,MAAM,MAAM;AAAA,EACjB;AACF;AAEA,IAAM,mBAAmB,CAAC,UAA8C;AACtE,QAAM,EAAE,OAAO,SAAS,IAAI,MAAM;AAClC,QAAM,EAAE,cAAc,WAAW,IAAI;AACrC,QAAM,YAAY,MAAM,SAAS;AACjC,QAAM,WAAW,MAAM,SAAS;AAChC,QAAM,UACJ,CAAC,YAAY,eAAe,IACxB,QACA,eAAe,QACb,MAAM,SAAS,IACf,eAAe;AACvB,QAAM,cACJ,CAAC,YAAY,eAAe,IACxB,QACA,eAAe,QACb,MAAM,SAAS,IACf,eAAe;AAEvB,SAAO;AAAA,IACL,GAAG;AAAA,IACH,OAAO;AAAA,MACL,GAAG,MAAM;AAAA,MACT,SAAS,MAAM,IAAI,CAAC,SAAS,KAAK,EAAE;AAAA,MACpC,UAAU;AAAA,QACR,GAAG;AAAA,QACH,iBAAiB,MAAM,eAAe,MAAM;AAAA,QAC5C,QAAQ,MAAM;AAAA,QACd;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAM,qBAAqB,MAA+B;AACxD,MAAI,OAAO,UAAU,aAAa;AAChC,WAAO;AAAA,EACT;AAEA,SAAO,IAAI,MAAM;AACnB;AAEA,IAAM,+BAA+B,MAAmB;AACtD,QAAM,mBAAmB,MACvB;AAAA,IACE;AAAA,IACA;AAAA,EACF;AAEF,SAAO;AAAA,IACL,WAAW;AAAA,IACX,YAAY,cAAc;AACxB,aAAO;AAAA,QACL,aAAa;AAAA,QACb,UAAU,gBAAgB;AAAA,QAC1B,UAAU;AAAA,QACV,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,kBAAkB;AAChB,aAAO,iBAAiB;AAAA,IAC1B;AAAA,IACA,KAAK;AACH,aAAO,MAAM;AAAA,MAAC;AAAA,IAChB;AAAA,IACA,YAAY;AACV,YAAM,iBAAiB;AAAA,IACzB;AAAA,IACA,cAAc;AACZ,YAAM,iBAAiB;AAAA,IACzB;AAAA,IACA,OAAO;AACL,YAAM,iBAAiB;AAAA,IACzB;AAAA,IACA,OAAO;AACL,YAAM,iBAAiB;AAAA,IACzB;AAAA,IACA,QAAQ;AACN,YAAM,iBAAiB;AAAA,IACzB;AAAA,IACA,iBAAiB;AACf,YAAM,iBAAiB;AAAA,IACzB;AAAA,IACA,kBAAkB;AAChB,YAAM,iBAAiB;AAAA,IACzB;AAAA,IACA,YAAY;AACV,YAAM,iBAAiB;AAAA,IACzB;AAAA,IACA,WAAW;AACT,YAAM,iBAAiB;AAAA,IACzB;AAAA,IACA,UAAU;AAAA,IAAC;AAAA,EACb;AACF;AAEA,IAAM,wBAAwB,MAAmB;AAC/C,QAAM,QAAQ,mBAAmB;AACjC,MAAI,CAAC,OAAO;AACV,WAAO,6BAA6B;AAAA,EACtC;AAEA,QAAM,UAAU;AAChB,QAAM,cAAc,MAAY;AAC9B,UAAM,UAAU;AAGhB,QAAI,OAAO,QAAQ,oBAAoB,YAAY;AACjD,cAAQ,gBAAgB,KAAK;AAC7B;AAAA,IACF;AAEA,UAAM,MAAM;AAAA,EACd;AAEA,SAAO;AAAA,IACL,WAAW;AAAA,IACX,YAAY,cAAc;AACxB,aAAO;AAAA,QACL,aAAa,MAAM;AAAA,QACnB,UAAU,aAAa,OAAO,YAAY;AAAA,QAC1C,UAAU,aAAa,KAAK;AAAA,QAC5B,MAAM,MAAM;AAAA,QACZ,QAAQ,MAAM;AAAA,QACd,OAAO,MAAM;AAAA,MACf;AAAA,IACF;AAAA,IACA,kBAAkB;AAChB,aAAO,MAAM;AAAA,IACf;AAAA,IACA,GAAG,WAAW,UAAU;AACtB,YAAM,iBAAiB,WAAW,QAAQ;AAC1C,aAAO,MAAM;AACX,cAAM,oBAAoB,WAAW,QAAQ;AAAA,MAC/C;AAAA,IACF;AAAA,IACA,UAAU,KAAK;AACb,YAAM,MAAM;AAAA,IACd;AAAA,IACA,cAAc;AACZ,kBAAY;AAAA,IACd;AAAA,IACA,OAAO;AACL,YAAM,KAAK;AAAA,IACb;AAAA,IACA,OAAO;AACL,aAAO,MAAM,KAAK;AAAA,IACpB;AAAA,IACA,QAAQ;AACN,YAAM,MAAM;AAAA,IACd;AAAA,IACA,eAAe,MAAM;AACnB,YAAM,cAAc;AAAA,IACtB;AAAA,IACA,gBAAgB,MAAM;AACpB,YAAM,eAAe;AAAA,IACvB;AAAA,IACA,UAAU,QAAQ;AAChB,YAAM,SAAS;AAAA,IACjB;AAAA,IACA,SAAS,OAAO;AACd,YAAM,QAAQ;AAAA,IAChB;AAAA,IACA,UAAU;AACR,YAAM,MAAM;AACZ,kBAAY;AACZ,YAAM,KAAK;AAAA,IACb;AAAA,EACF;AACF;AAiHO,IAAM,oBAAoB,CAC/B,UAAoC,CAAC,MACrB;AAChB,MAAI,QAAQ,iBAAiB,mBAAmB,OAAO,CAAC;AACxD,MAAI,YAAY;AAChB,MAAI,0BAA0B;AAC9B,MAAI,qBAAqB;AAEzB,QAAM,SAAS,sBAAsB;AACrC,QAAM,cAAc,oBAAI,IAA2C;AACnE,QAAM,iBAEF;AAAA,IACF,cAAc,oBAAI,IAAI;AAAA,IACtB,aAAa,oBAAI,IAAI;AAAA,IACrB,MAAM,oBAAI,IAAI;AAAA,IACd,OAAO,oBAAI,IAAI;AAAA,IACf,SAAS,oBAAI,IAAI;AAAA,IACjB,QAAQ,oBAAI,IAAI;AAAA,IAChB,YAAY,oBAAI,IAAI;AAAA,IACpB,YAAY,oBAAI,IAAI;AAAA,IACpB,cAAc,oBAAI,IAAI;AAAA,IACtB,OAAO,oBAAI,IAAI;AAAA,IACf,OAAO,oBAAI,IAAI;AAAA,IACf,SAAS,oBAAI,IAAI;AAAA,EACnB;AAEA,QAAM,WAAW,MAAwB;AAEzC,QAAM,eAAe,MAAY;AAC/B,eAAW,cAAc,aAAa;AACpC,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF;AAEA,QAAM,OAAO,CACX,WACA,UACS;AACT,eAAW,YAAY,eAAe,SAAS,GAAG;AAChD,eAAS,KAAK;AAAA,IAChB;AAAA,EACF;AAEA,QAAM,WAAW,CACf,YACqB;AACrB,YAAQ,iBAAiB,QAAQ,KAAK,CAAC;AACvC,iBAAa;AACb,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,CAAC,UAAyC;AACzD,8BAA0B;AAC1B,UAAM,YAAY,SAAS,CAAC,kBAAkB;AAAA,MAC5C,GAAG;AAAA,MACH,QAAQ;AAAA,MACR,OAAO;AAAA,QACL,MAAM,MAAM;AAAA,QACZ,SAAS,MAAM;AAAA,MACjB;AAAA,IACF,EAAE;AACF,SAAK,SAAS,EAAE,OAAO,OAAO,UAAU,CAAC;AAAA,EAC3C;AAEA,QAAM,aAAa,MAAY;AAC7B,QAAI,CAAC,MAAM,OAAO;AAChB;AAAA,IACF;AAEA,aAAS,CAAC,kBAAkB;AAAA,MAC1B,GAAG;AAAA,MACH,OAAO;AAAA,IACT,EAAE;AAAA,EACJ;AAEA,QAAM,oBAAoB,CACxB,mBACqB;AACrB,UAAM,WAAW,OAAO,YAAY,MAAM,eAAe,YAAY;AACrE,UAAM,cAAc,SAAS;AAC7B,UAAM,WAAW,SAAS;AAC1B,UAAM,WAAW,SAAS;AAC1B,UAAM,iBACJ,WAAW,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,cAAc,QAAQ,CAAC,IAAI;AACpE,UAAM,mBACJ,WAAW,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,WAAW,QAAQ,CAAC,IAAI;AAEjE,UAAM,YAAY,SAAS,CAAC,kBAAkB;AAAA,MAC5C,GAAG;AAAA,MACH,iBAAiB,aAAa,eAAe,MAAM;AAAA,MACnD;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,MAAM,SAAS;AAAA,MACf,QAAQ,SAAS;AAAA,MACjB,OAAO,SAAS;AAAA,MAChB,QAAQ,kBAAkB,aAAa;AAAA,MACvC,OACE,mBAAmB,UAAU,aAAa,QAAQ;AAAA,IACtD,EAAE;AAEF,WAAO;AAAA,EACT;AAEA,QAAM,qBAAqB,CAAC,OAC1B,KAAK,MAAM,MAAM,MAAM,UAAU,CAAC,SAAS,KAAK,OAAO,EAAE,IAAI;AAE/D,QAAM,wBAAwB,CAC5B,SACkB;AAClB,UAAM,EAAE,OAAO,SAAS,IAAI,MAAM;AAClC,UAAM,EAAE,cAAc,WAAW,IAAI;AAErC,QAAI,MAAM,WAAW,KAAK,eAAe,GAAG;AAC1C,aAAO;AAAA,IACT;AAEA,QAAI,eAAe,OAAO;AACxB,aAAO;AAAA,IACT;AAEA,QAAI,eAAe,MAAM,SAAS,GAAG;AACnC,aAAO,eAAe;AAAA,IACxB;AAEA,QAAI,eAAe,OAAO;AACxB,aAAO;AAAA,IACT;AAEA,WAAO,SAAS,UAAU,KAAK;AAAA,EACjC;AAEA,QAAM,4BAA4B,MAAqB;AACrD,UAAM,EAAE,OAAO,SAAS,IAAI,MAAM;AAClC,UAAM,EAAE,cAAc,WAAW,IAAI;AAErC,QAAI,MAAM,WAAW,KAAK,eAAe,GAAG;AAC1C,aAAO;AAAA,IACT;AAEA,QAAI,eAAe,GAAG;AACpB,aAAO,eAAe;AAAA,IACxB;AAEA,QAAI,eAAe,OAAO;AACxB,aAAO,MAAM,SAAS;AAAA,IACxB;AAEA,WAAO;AAAA,EACT;AAEA,QAAM,sBAAsB,CAC1B,QACA,eACqB;AACrB,UAAM,aAAa,mBAAmB,QAAQ,EAAE;AAChD,UAAM,YAAY,SAAS,CAAC,kBAAkB;AAAA,MAC5C,GAAG;AAAA,MACH,eAAe;AAAA,MACf,iBAAiB,QAAQ,MAAM;AAAA,MAC/B,aAAa;AAAA,MACb,UAAU,QAAQ,gBAAgB;AAAA,MAClC,UAAU;AAAA,MACV,UAAU;AAAA,QACR,aAAa;AAAA,QACb,UAAU,QAAQ,gBAAgB;AAAA,QAClC,UAAU;AAAA,QACV,gBAAgB;AAAA,QAChB,kBAAkB;AAAA,MACpB;AAAA,MACA,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,OAAO;AAAA,QACL,GAAG,aAAa;AAAA,QAChB,UAAU;AAAA,UACR,GAAG,aAAa,MAAM;AAAA,UACtB,cAAc;AAAA,UACd,iBAAiB,QAAQ,MAAM;AAAA,QACjC;AAAA,MACF;AAAA,IACF,EAAE;AACF,SAAK,gBAAgB,EAAE,QAAQ,OAAO,UAAU,CAAC;AACjD,WAAO;AAAA,EACT;AAEA,QAAM,gBAAgB,CACpB,OACA,iBAEA,SAAS,CAAC,kBAAkB;AAAA,IAC1B,GAAG;AAAA,IACH,OAAO;AAAA,MACL,GAAG,aAAa;AAAA,MAChB;AAAA,MACA,UAAU;AAAA,QACR,GAAG,aAAa,MAAM;AAAA,QACtB;AAAA,MACF;AAAA,IACF;AAAA,EACF,EAAE;AAEJ,QAAM,kBAAkB,CAAC,cAAsC;AAC7D,SAAK,eAAe,EAAE,OAAO,gBAAgB,SAAS,GAAG,OAAO,UAAU,CAAC;AAAA,EAC7E;AAEA,QAAM,sBAAsB,CAC1B,QACA,sBACS;AACT,8BAA0B;AAC1B,yBAAqB;AACrB,QAAI;AACF,aAAO,MAAM;AAAA,IACf,UAAE;AACA,2BAAqB;AAAA,IACvB;AACA,WAAO,UAAU,OAAO,GAAG;AAC3B,WAAO,eAAe,CAAC;AACvB,WAAO,gBAAgB,MAAM,IAAI;AACjC,WAAO,UAAU,MAAM,MAAM;AAC7B,WAAO,SAAS,MAAM,KAAK;AAC3B,WAAO,KAAK;AAAA,EACd;AAEA,QAAM,eAAe,OACnB,QACA,oBAAoB,UACF;AAClB,uBAAmB,MAAM;AACzB,wBAAoB,QAAQ,SAAS;AACrC,wBAAoB,QAAQ,iBAAiB;AAAA,EAC/C;AAEA,QAAM,mBAAmB,OACvB,OACA,oBAAoB,UACY;AAChC,UAAM,OAAO,MAAM,MAAM,MAAM,KAAK,KAAK;AACzC,QAAI,CAAC,MAAM;AACT,aAAO;AAAA,IACT;AAEA,UAAM,aAAa,MAAM,iBAAiB;AAC1C,UAAM,YAAY,cAAc,MAAM,MAAM,OAAO,KAAK;AACxD,oBAAgB,SAAS;AACzB,WAAO;AAAA,EACT;AAEA,QAAM,kBAAkB,YAA2B;AACjD,QAAI;AACF,YAAM,OAAO,KAAK;AAAA,IACpB,SAAS,OAAO;AACd,eAAS,kBAAkB,cAAc,6BAA6B,KAAK,CAAC;AAAA,IAC9E;AAAA,EACF;AAEA,QAAM,sBAAsB,YAA2B;AACrD,QAAI,WAAW;AACb;AAAA,IACF;AAEA,QAAI,MAAM,MAAM,MAAM,SAAS,KAAK,MAAM,MAAM,SAAS,gBAAgB,GAAG;AAC1E,YAAM,YAAY,sBAAsB,OAAO;AAC/C,UAAI,cAAc,MAAM,cAAc,MAAM;AAC1C,cAAMA,cAAa,kBAAkB,OAAO;AAC5C,aAAK,SAAS,EAAE,QAAQA,YAAW,eAAe,OAAOA,YAAW,CAAC;AACrE;AAAA,MACF;AAEA,YAAM,iBAAiB,WAAW,IAAI;AACtC;AAAA,IACF;AAEA,UAAM,aAAa,kBAAkB,OAAO;AAC5C,SAAK,SAAS,EAAE,QAAQ,WAAW,eAAe,OAAO,WAAW,CAAC;AAAA,EACvE;AAEA,QAAM,wBAAwB;AAAA,IAC5B,OAAO,GAAG,kBAAkB,MAAM;AAChC,UAAI,aAAa,CAAC,MAAM,eAAe;AACrC;AAAA,MACF;AAEA,wBAAkB,OAAO;AACzB,UAAI,yBAAyB;AAC3B,kCAA0B;AAC1B,aAAK,gBAAgB;AAAA,MACvB;AAAA,IACF,CAAC;AAAA,IACD,OAAO,GAAG,cAAc,MAAM;AAC5B,UAAI,WAAW;AACb;AAAA,MACF;AAEA,YAAM,YAAY;AAAA,QAChB,MAAM,WAAW,UAAU,YAAY;AAAA,MACzC;AACA,WAAK,cAAc;AAAA,QACjB,aAAa,UAAU;AAAA,QACvB,UAAU,UAAU;AAAA,QACpB,OAAO;AAAA,MACT,CAAC;AAAA,IACH,CAAC;AAAA,IACD,OAAO,GAAG,YAAY,MAAM;AAC1B,UAAI,CAAC,WAAW;AACd,0BAAkB;AAAA,MACpB;AAAA,IACF,CAAC;AAAA,IACD,OAAO,GAAG,QAAQ,MAAM;AACtB,UAAI,WAAW;AACb;AAAA,MACF;AAEA,YAAM,YAAY,kBAAkB,SAAS;AAC7C,WAAK,QAAQ,EAAE,QAAQ,UAAU,eAAe,OAAO,UAAU,CAAC;AAAA,IACpE,CAAC;AAAA,IACD,OAAO,GAAG,SAAS,MAAM;AACvB,UAAI,aAAa,oBAAoB;AACnC;AAAA,MACF;AAEA,YAAM,aACJ,MAAM,WAAW,UAAU,UAAU,MAAM,gBAAgB,WAAW;AACxE,YAAM,YAAY,kBAAkB,UAAU;AAC9C,WAAK,SAAS,EAAE,QAAQ,UAAU,eAAe,OAAO,UAAU,CAAC;AAAA,IACrE,CAAC;AAAA,IACD,OAAO,GAAG,UAAU,MAAM;AACxB,UAAI,WAAW;AACb;AAAA,MACF;AAEA,YAAM,YAAY,kBAAkB;AACpC,WAAK,UAAU,EAAE,aAAa,UAAU,aAAa,OAAO,UAAU,CAAC;AACvE,WAAK,cAAc;AAAA,QACjB,aAAa,UAAU;AAAA,QACvB,UAAU,UAAU;AAAA,QACpB,OAAO;AAAA,MACT,CAAC;AAAA,IACH,CAAC;AAAA,IACD,OAAO,GAAG,cAAc,MAAM;AAC5B,UAAI,WAAW;AACb;AAAA,MACF;AAEA,YAAM,YAAY,kBAAkB;AACpC,WAAK,cAAc,EAAE,MAAM,UAAU,MAAM,OAAO,UAAU,CAAC;AAAA,IAC/D,CAAC;AAAA,IACD,OAAO,GAAG,gBAAgB,MAAM;AAC9B,UAAI,WAAW;AACb;AAAA,MACF;AAEA,YAAM,YAAY,kBAAkB;AACpC,WAAK,gBAAgB;AAAA,QACnB,QAAQ,UAAU;AAAA,QAClB,OAAO,UAAU;AAAA,QACjB,OAAO;AAAA,MACT,CAAC;AAAA,IACH,CAAC;AAAA,IACD,OAAO,GAAG,SAAS,MAAM;AACvB,WAAK,oBAAoB;AAAA,IAC3B,CAAC;AAAA,IACD,OAAO,GAAG,SAAS,MAAM;AACvB,UAAI,WAAW;AACb;AAAA,MACF;AAEA;AAAA,QACE;AAAA,UACE;AAAA,UACA;AAAA,UACA,OAAO,gBAAgB;AAAA,QACzB;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL;AAAA,IAEA,UAAU,UAAU;AAClB,kBAAY,IAAI,QAAQ;AACxB,eAAS,KAAK;AACd,aAAO,MAAM;AACX,oBAAY,OAAO,QAAQ;AAAA,MAC7B;AAAA,IACF;AAAA,IAEA,GAAG,WAAW,UAAU;AACtB,qBAAe,SAAS,EAAE;AAAA,QACxB;AAAA,MACF;AACA,aAAO,MAAM;AACX,uBAAe,SAAS,EAAE;AAAA,UACxB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IAEA,MAAM,KAAK,QAAQ;AACjB,UAAI;AACF,cAAM,aAAa,MAAM;AAAA,MAC3B,SAAS,OAAO;AACd;AAAA,UACE,qBAAqB,cAAc,0BAA0B,KAAK;AAAA,QACpE;AAAA,MACF;AAAA,IACF;AAAA,IAEA,MAAM,KAAK,QAAQ;AACjB,UAAI;AACF,YAAI,QAAQ;AACV,gBAAM,aAAa,QAAQ,IAAI;AAC/B;AAAA,QACF;AAEA,YAAI,CAAC,MAAM,eAAe;AACxB;AAAA,YACE;AAAA,cACE;AAAA,cACA;AAAA,YACF;AAAA,UACF;AACA;AAAA,QACF;AAEA,YAAI,MAAM,WAAW,WAAW;AAC9B,oCAA0B;AAC1B;AAAA,QACF;AAEA,cAAM,gBAAgB;AAAA,MACxB,SAAS,OAAO;AACd,iBAAS,qBAAqB,cAAc,6BAA6B,KAAK,CAAC;AAAA,MACjF;AAAA,IACF;AAAA,IAEA,QAAQ;AACN,UAAI,CAAC,OAAO,WAAW;AACrB;AAAA,MACF;AAEA,gCAA0B;AAC1B,aAAO,MAAM;AAAA,IACf;AAAA,IAEA,MAAM,SAAS;AACb,UAAI,MAAM,WAAW,WAAW;AAC9B,aAAK,MAAM;AACX;AAAA,MACF;AAEA,YAAM,KAAK,KAAK;AAAA,IAClB;AAAA,IAEA,SAAS;AACP,gCAA0B;AAE1B,UAAI,OAAO,WAAW;AACpB,6BAAqB;AACrB,YAAI;AACF,iBAAO,MAAM;AAAA,QACf,UAAE;AACA,+BAAqB;AAAA,QACvB;AACA,eAAO,YAAY;AACnB,eAAO,KAAK;AAAA,MACd;AAEA,YAAM,YAAY,oBAAoB,MAAM,MAAM;AAClD,sBAAgB,SAAS;AAAA,IAC3B;AAAA,IAEA,KAAK,MAAM;AACT,UAAI,CAAC,MAAM,eAAe;AACxB;AAAA,UACE,kBAAkB,cAAc,uCAAuC;AAAA,QACzE;AACA;AAAA,MACF;AAEA,YAAM,MAAM,OAAO,YAAY,MAAM,cAAc,YAAY,EAAE;AACjE,YAAM,aAAa,KAAK;AAAA,QACtB;AAAA,QACA,MAAM,IAAI,KAAK,IAAI,MAAM,GAAG,IAAK,eAAe,IAAI,IAAI,OAAO;AAAA,MACjE;AACA,WAAK,WAAW,EAAE,MAAM,MAAM,aAAa,IAAI,YAAY,MAAM,CAAC;AAElE,UAAI;AACF,eAAO,eAAe,UAAU;AAAA,MAClC,SAAS,OAAO;AACd,iBAAS,qBAAqB,cAAc,yBAAyB,KAAK,CAAC;AAAA,MAC7E;AAAA,IACF;AAAA,IAEA,QAAQ,MAAM;AACZ,UAAI,CAAC,OAAO,WAAW;AACrB;AAAA,UACE,kBAAkB,gBAAgB,+BAA+B;AAAA,QACnE;AACA;AAAA,MACF;AAEA,UAAI,CAAC,eAAe,IAAI,KAAK,QAAQ,GAAG;AACtC;AAAA,UACE,kBAAkB,gBAAgB,uCAAuC;AAAA,QAC3E;AACA;AAAA,MACF;AAEA,aAAO,gBAAgB,IAAI;AAC3B,iBAAW;AACX,wBAAkB;AAAA,IACpB;AAAA,IAEA,UAAU,QAAQ;AAChB,UAAI,CAAC,OAAO,WAAW;AACrB;AAAA,UACE,kBAAkB,kBAAkB,+BAA+B;AAAA,QACrE;AACA;AAAA,MACF;AAEA,UAAI,CAAC,eAAe,MAAM,KAAK,SAAS,KAAK,SAAS,GAAG;AACvD;AAAA,UACE,kBAAkB,kBAAkB,iCAAiC;AAAA,QACvE;AACA;AAAA,MACF;AAEA,aAAO,UAAU,MAAM;AACvB,iBAAW;AACX,wBAAkB;AAAA,IACpB;AAAA,IAEA,SAAS,OAAO;AACd,UAAI,CAAC,OAAO,WAAW;AACrB;AAAA,MACF;AAEA,aAAO,SAAS,KAAK;AACrB,iBAAW;AACX,wBAAkB;AAAA,IACpB;AAAA,IAEA,MAAM,SAAS,OAAO,eAAe,CAAC,GAAG;AACvC,UAAI;AACF,mBAAW,QAAQ,OAAO;AACxB,6BAAmB,IAAI;AAAA,QACzB;AAEA,cAAM,aACJ,aAAa,cAAc,SACvB,MAAM,SAAS,IACb,IACA,KACF,MAAM,UAAU,CAAC,SAAS,KAAK,OAAO,aAAa,SAAS;AAElE,YAAI,aAAa,aAAa,aAAa,GAAG;AAC5C,gBAAM;AAAA,YACJ;AAAA,YACA,oBAAoB,aAAa,SAAS;AAAA,UAC5C;AAAA,QACF;AAEA,cAAM,YAAY,SAAS,CAAC,kBAAkB;AAAA,UAC5C,GAAG;AAAA,UACH,eAAe,cAAc,IAAI,MAAM,UAAU,KAAK,OAAO;AAAA,UAC7D,iBAAiB,cAAc,IAAK,MAAM,UAAU,GAAG,MAAM,OAAQ;AAAA,UACrE,aAAa;AAAA,UACb,UAAU,cAAc,IAAK,MAAM,UAAU,GAAG,gBAAgB,IAAK;AAAA,UACrE,UAAU;AAAA,UACV,UAAU;AAAA,YACR,aAAa;AAAA,YACb,UAAU,cAAc,IAAK,MAAM,UAAU,GAAG,gBAAgB,IAAK;AAAA,YACrE,UAAU;AAAA,YACV,gBAAgB;AAAA,YAChB,kBAAkB;AAAA,UACpB;AAAA,UACA,QAAQ,cAAc,IAAI,UAAU;AAAA,UACpC,OAAO;AAAA,UACP,OAAO;AAAA,YACL,GAAG,aAAa;AAAA,YAChB,OAAO,CAAC,GAAG,KAAK;AAAA,YAChB,UAAU;AAAA,cACR,GAAG,aAAa,MAAM;AAAA,cACtB,cAAc;AAAA,cACd,iBACE,cAAc,IAAK,MAAM,UAAU,GAAG,MAAM,OAAQ;AAAA,YACxD;AAAA,UACF;AAAA,QACF,EAAE;AAEF,wBAAgB,SAAS;AACzB,aAAK,gBAAgB;AAAA,UACnB,QAAQ,UAAU;AAAA,UAClB,OAAO;AAAA,QACT,CAAC;AAED,YAAI,UAAU,eAAe;AAC3B,gBAAM,aAAa,UAAU,eAAe,aAAa,aAAa,IAAI;AAC1E,gBAAM,cAAc,cAAc,OAAO,UAAU;AACnD,0BAAgB,WAAW;AAAA,QAC7B,WAAW,OAAO,WAAW;AAC3B,oCAA0B;AAC1B,+BAAqB;AACrB,iBAAO,MAAM;AACb,+BAAqB;AACrB,iBAAO,YAAY;AACnB,iBAAO,KAAK;AAAA,QACd;AAAA,MACF,SAAS,OAAO;AACd;AAAA,UACE;AAAA,YACE;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IAEA,cAAc,OAAO;AACnB,UAAI;AACF,mBAAW,QAAQ,OAAO;AACxB,6BAAmB,IAAI;AAAA,QACzB;AAEA,cAAM,YAAY,SAAS,CAAC,kBAAkB;AAAA,UAC5C,GAAG;AAAA,UACH,OAAO;AAAA,YACL,GAAG,aAAa;AAAA,YAChB,OAAO,CAAC,GAAG,aAAa,MAAM,OAAO,GAAG,KAAK;AAAA,UAC/C;AAAA,QACF,EAAE;AACF,wBAAgB,SAAS;AAAA,MAC3B,SAAS,OAAO;AACd;AAAA,UACE;AAAA,YACE;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IAEA,gBAAgB,IAAI;AAClB,YAAM,YAAY,MAAM,MAAM,MAAM,OAAO,CAAC,SAAS,KAAK,OAAO,EAAE;AACnE,YAAM,YAAY,UAAU;AAAA,QAC1B,CAAC,SAAS,KAAK,OAAO,MAAM,eAAe;AAAA,MAC7C;AAEA,YAAM,YAAY,SAAS,CAAC,kBAAkB;AAAA,QAC5C,GAAG;AAAA,QACH,OAAO;AAAA,UACL,GAAG,aAAa;AAAA,UAChB,OAAO;AAAA,UACP,UAAU;AAAA,YACR,GAAG,aAAa,MAAM;AAAA,YACtB,cAAc;AAAA,YACd,iBAAiB,aAAa,IAAK,UAAU,SAAS,GAAG,MAAM,OAAQ;AAAA,UACzE;AAAA,QACF;AAAA,MACF,EAAE;AAEF,sBAAgB,SAAS;AAAA,IAC3B;AAAA,IAEA,aAAa;AACX,YAAM,YAAY,SAAS,CAAC,kBAAkB;AAAA,QAC5C,GAAG;AAAA,QACH,OAAO;AAAA,UACL,GAAG,aAAa;AAAA,UAChB,OAAO,CAAC;AAAA,UACR,UAAU;AAAA,YACR,GAAG,aAAa,MAAM;AAAA,YACtB,cAAc;AAAA,YACd,iBAAiB;AAAA,UACnB;AAAA,QACF;AAAA,MACF,EAAE;AAEF,sBAAgB,SAAS;AAAA,IAC3B;AAAA,IAEA,MAAM,OAAO;AACX,YAAM,YAAY,sBAAsB,QAAQ;AAChD,UAAI,cAAc,MAAM;AACtB;AAAA,MACF;AAEA,YAAM,iBAAiB,WAAW,IAAI;AAAA,IACxC;AAAA,IAEA,MAAM,SAAS,kBAAkB,CAAC,GAAG;AACnC,UAAI,CAAC,MAAM,eAAe;AACxB;AAAA,MACF;AAEA,YAAM,YACJ,gBAAgB,2BAChB;AAEF,UAAI,MAAM,cAAc,WAAW;AACjC,aAAK,KAAK,CAAC;AACX;AAAA,MACF;AAEA,YAAM,gBAAgB,0BAA0B;AAChD,UAAI,kBAAkB,MAAM;AAC1B,aAAK,KAAK,CAAC;AACX;AAAA,MACF;AAEA,YAAM,iBAAiB,eAAe,IAAI;AAAA,IAC5C;AAAA,IAEA,cAAc,MAAM;AAClB,YAAM,YAAY,SAAS,CAAC,kBAAkB;AAAA,QAC5C,GAAG;AAAA,QACH,OAAO;AAAA,UACL,GAAG,aAAa;AAAA,UAChB,UAAU;AAAA,YACR,GAAG,aAAa,MAAM;AAAA,YACtB,YAAY;AAAA,UACd;AAAA,QACF;AAAA,MACF,EAAE;AACF,sBAAgB,SAAS;AAAA,IAC3B;AAAA,IAEA,UAAU;AACR,UAAI,WAAW;AACb;AAAA,MACF;AAEA,kBAAY;AACZ,gCAA0B;AAC1B,iBAAW,UAAU,uBAAuB;AAC1C,eAAO;AAAA,MACT;AACA,2BAAqB;AACrB,aAAO,QAAQ;AACf,2BAAqB;AAErB,YAAM,YAAY,SAAS,MAAM,mBAAmB,OAAO,CAAC;AAC5D,WAAK,WAAW,EAAE,OAAO,UAAU,CAAC;AACpC,kBAAY,MAAM;AAClB,iBAAW,aAAa,OAAO,KAAK,cAAc,GAA6B;AAC7E,uBAAe,SAAS,EAAE,MAAM;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AACF;;;ADx1CI;AA9BJ,IAAM,yBAAqB,4BAAkC,IAAI;AAQ1D,IAAM,sBAAsB,CAAC;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AACF,MAAgC;AAC9B,QAAM,gBAAY,qBAA2B,UAAU,IAAI;AAE3D,MAAI,UAAU,YAAY,MAAM;AAC9B,cAAU,UAAU,kBAAkB,OAAO;AAAA,EAC/C;AAEA,8BAAU,MAAM;AACd,QAAI,CAAC,QAAQ;AACX,aAAO,MAAM;AACX,kBAAU,SAAS,QAAQ;AAAA,MAC7B;AAAA,IACF;AAEA,WAAO;AAAA,EACT,GAAG,CAAC,MAAM,CAAC;AAEX,SACE,4CAAC,mBAAmB,UAAnB,EAA4B,OAAO,UAAU,SAC3C,UACH;AAEJ;AAEO,IAAM,iBAAiB,MAAmB;AAC/C,QAAM,aAAS,yBAAW,kBAAkB;AAE5C,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AAEA,SAAO;AACT;AAEO,IAAM,sBAAsB,MAAwB;AACzD,QAAM,SAAS,eAAe;AAE9B,aAAO;AAAA,IACL,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,EACT;AACF;","names":["endedState"]}
1
+ {"version":3,"sources":["../src/react.tsx","../src/index.ts"],"sourcesContent":["import {\n createContext,\n type ReactNode,\n useContext,\n useEffect,\n useRef,\n useSyncExternalStore,\n} from \"react\";\nimport {\n createAudioPlayer,\n type AudioPlayer,\n type AudioPlayerState,\n type CreateAudioPlayerOptions,\n} from \"./index\";\n\nconst AudioPlayerContext = createContext<AudioPlayer | null>(null);\n\nexport interface AudioPlayerProviderProps {\n children: ReactNode;\n options?: CreateAudioPlayerOptions;\n player?: AudioPlayer;\n}\n\nexport const AudioPlayerProvider = ({\n children,\n options,\n player,\n}: AudioPlayerProviderProps) => {\n const playerRef = useRef<AudioPlayer | null>(player ?? null);\n\n if (playerRef.current === null) {\n playerRef.current = createAudioPlayer(options);\n }\n\n useEffect(() => {\n if (!player) {\n return () => {\n playerRef.current?.destroy();\n };\n }\n\n return undefined;\n }, [player]);\n\n return (\n <AudioPlayerContext.Provider value={playerRef.current}>\n {children}\n </AudioPlayerContext.Provider>\n );\n};\n\nexport const useAudioPlayer = (): AudioPlayer => {\n const player = useContext(AudioPlayerContext);\n\n if (!player) {\n throw new Error(\"useAudioPlayer must be used inside AudioPlayerProvider.\");\n }\n\n return player;\n};\n\nexport const useAudioPlayerState = (): AudioPlayerState => {\n const player = useAudioPlayer();\n\n return useSyncExternalStore(\n player.subscribe,\n player.getState,\n player.getState,\n );\n};\n","export type PlayerStatus =\n | \"idle\"\n | \"loading\"\n | \"ready\"\n | \"playing\"\n | \"paused\"\n | \"ended\"\n | \"error\";\n\nexport type RepeatMode = \"off\" | \"one\" | \"all\";\n\nexport type AudioPlayerEventName =\n | \"sourcechange\"\n | \"queuechange\"\n | \"play\"\n | \"pause\"\n | \"seeking\"\n | \"seeked\"\n | \"timeupdate\"\n | \"ratechange\"\n | \"volumechange\"\n | \"ended\"\n | \"error\"\n | \"destroy\";\n\nexport interface AudioSource {\n id: string;\n src: string;\n title?: string;\n artist?: string;\n artwork?: string;\n album?: string;\n durationHint?: number;\n}\n\nexport interface AudioPlayerErrorState {\n code:\n | \"LOAD_ERROR\"\n | \"PLAY_ERROR\"\n | \"SEEK_ERROR\"\n | \"INVALID_VOLUME\"\n | \"INVALID_RATE\"\n | \"INVALID_QUEUE_ITEM\"\n | \"NO_ACTIVE_SOURCE\"\n | \"UNSUPPORTED_ENVIRONMENT\"\n | \"UNKNOWN_ERROR\";\n message: string;\n}\n\nexport interface AudioPlayerRuntimeError extends AudioPlayerErrorState {\n cause?: unknown;\n}\n\nexport interface AudioPlayerProgressState {\n currentTime: number;\n duration: number;\n buffered: number;\n playedFraction: number;\n bufferedFraction: number;\n}\n\nexport interface AudioPlayerQueuePositionState {\n currentIndex: number;\n currentSourceId: string | null;\n length: number;\n hasNext: boolean;\n hasPrevious: boolean;\n repeatMode: RepeatMode;\n}\n\nexport interface AudioPlayerQueueState {\n items: AudioSource[];\n itemIds: string[];\n position: AudioPlayerQueuePositionState;\n}\n\nexport interface AudioPlayerState {\n status: PlayerStatus;\n currentSource: AudioSource | null;\n currentSourceId: string | null;\n currentTime: number;\n duration: number;\n buffered: number;\n progress: AudioPlayerProgressState;\n rate: number;\n volume: number;\n muted: boolean;\n queue: AudioPlayerQueueState;\n error: AudioPlayerErrorState | null;\n}\n\nexport interface AudioPlayerEventMap {\n sourcechange: { source: AudioSource | null; state: AudioPlayerState };\n queuechange: { queue: AudioPlayerQueueState; state: AudioPlayerState };\n play: { source: AudioSource | null; state: AudioPlayerState };\n pause: { source: AudioSource | null; state: AudioPlayerState };\n seeking: { from: number; to: number; state: AudioPlayerState };\n seeked: { currentTime: number; state: AudioPlayerState };\n timeupdate: { currentTime: number; duration: number; state: AudioPlayerState };\n ratechange: { rate: number; state: AudioPlayerState };\n volumechange: { volume: number; muted: boolean; state: AudioPlayerState };\n ended: { source: AudioSource | null; state: AudioPlayerState };\n error: { error: AudioPlayerRuntimeError; state: AudioPlayerState };\n destroy: { state: AudioPlayerState };\n}\n\nexport interface CreateAudioPlayerOptions {\n initialVolume?: number;\n initialRate?: number;\n initialMuted?: boolean;\n initialRepeatMode?: RepeatMode;\n}\n\nexport interface SetQueueOptions {\n startAtId?: string;\n autoplay?: boolean;\n}\n\nexport interface PreviousOptions {\n restartThresholdSeconds?: number;\n}\n\nexport interface PersistedPlayerState {\n version: 1;\n savedAt: number;\n currentSource: AudioSource | null;\n currentSourceId: string | null;\n currentTime: number;\n rate: number;\n volume: number;\n muted: boolean;\n queue: {\n items: AudioSource[];\n position: {\n currentIndex: number;\n currentSourceId: string | null;\n repeatMode: RepeatMode;\n };\n };\n}\n\nexport interface AudioPlayerPersistenceAdapter {\n load(): PersistedPlayerState | null;\n save(state: PersistedPlayerState): void;\n clear(): void;\n}\n\nexport interface AudioPlayerPersistenceOptions {\n adapter: AudioPlayerPersistenceAdapter;\n autoRestore?: boolean;\n maxAgeMs?: number;\n saveIntervalMs?: number;\n}\n\nexport interface AudioPlayerPersistenceController {\n restore(): Promise<PersistedPlayerState | null>;\n save(): void;\n clear(): void;\n destroy(): void;\n}\n\nexport interface AudioPlayerProgressSnapshot {\n source: AudioSource | null;\n sourceId: string | null;\n currentTime: number;\n duration: number;\n playedFraction: number;\n status: PlayerStatus;\n queue: AudioPlayerQueuePositionState;\n}\n\nexport interface AudioPlayerProgressReporterOptions {\n intervalMs?: number;\n onReport: (snapshot: AudioPlayerProgressSnapshot) => void;\n}\n\nexport interface AudioPlayerProgressReporterController {\n report(): void;\n destroy(): void;\n}\n\nexport interface AudioPlayerMediaSessionOptions {\n artworkSizes?: number[];\n seekOffsetSeconds?: number;\n}\n\nexport interface AudioPlayerMediaSessionController {\n sync(): void;\n destroy(): void;\n}\n\nexport type AudioPlayerEventListener<K extends AudioPlayerEventName> = (\n event: AudioPlayerEventMap[K],\n) => void;\n\nexport interface AudioPlayer {\n getState(): AudioPlayerState;\n subscribe(listener: (state: AudioPlayerState) => void): () => void;\n on<K extends AudioPlayerEventName>(\n eventName: K,\n listener: AudioPlayerEventListener<K>,\n ): () => void;\n\n load(source: AudioSource): Promise<void>;\n play(source?: AudioSource): Promise<void>;\n pause(): void;\n toggle(): Promise<void>;\n unload(): void;\n seek(time: number): void;\n setRate(rate: number): void;\n setVolume(volume: number): void;\n setMuted(muted: boolean): void;\n\n setQueue(items: AudioSource[], options?: SetQueueOptions): Promise<void>;\n appendToQueue(items: AudioSource[]): void;\n removeFromQueue(id: string): void;\n clearQueue(): void;\n next(): Promise<void>;\n previous(options?: PreviousOptions): Promise<void>;\n setRepeatMode(mode: RepeatMode): void;\n\n destroy(): void;\n}\n\nconst DEFAULT_PREVIOUS_RESTART_THRESHOLD_SECONDS = 5;\nconst DEFAULT_PERSISTENCE_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000;\nconst DEFAULT_PERSISTENCE_SAVE_INTERVAL_MS = 5000;\nconst DEFAULT_PROGRESS_REPORT_INTERVAL_MS = 5000;\nconst DEFAULT_MEDIA_SESSION_ARTWORK_SIZES = [96, 128, 192, 256, 384, 512];\nconst DEFAULT_MEDIA_SESSION_SEEK_OFFSET_SECONDS = 10;\n\ntype AudioEngineEventName =\n | \"loadedmetadata\"\n | \"timeupdate\"\n | \"progress\"\n | \"play\"\n | \"pause\"\n | \"seeked\"\n | \"ratechange\"\n | \"volumechange\"\n | \"ended\"\n | \"error\";\n\ninterface AudioEngineSnapshot {\n currentTime: number;\n duration: number;\n buffered: number;\n rate: number;\n volume: number;\n muted: boolean;\n}\n\ninterface AudioEngine {\n readonly available: boolean;\n getSnapshot(durationHint?: number): AudioEngineSnapshot;\n getRuntimeError(): unknown;\n on(eventName: AudioEngineEventName, listener: EventListener): () => void;\n setSource(src: string): void;\n clearSource(): void;\n load(): void;\n play(): Promise<void>;\n pause(): void;\n setCurrentTime(time: number): void;\n setPlaybackRate(rate: number): void;\n setVolume(volume: number): void;\n setMuted(muted: boolean): void;\n destroy(): void;\n}\n\nconst createInitialState = (\n options: CreateAudioPlayerOptions,\n): AudioPlayerState => ({\n status: \"idle\",\n currentSource: null,\n currentSourceId: null,\n currentTime: 0,\n duration: 0,\n buffered: 0,\n progress: {\n currentTime: 0,\n duration: 0,\n buffered: 0,\n playedFraction: 0,\n bufferedFraction: 0,\n },\n rate: options.initialRate ?? 1,\n volume: options.initialVolume ?? 1,\n muted: options.initialMuted ?? false,\n queue: {\n items: [],\n itemIds: [],\n position: {\n currentIndex: -1,\n currentSourceId: null,\n length: 0,\n repeatMode: options.initialRepeatMode ?? \"off\",\n hasNext: false,\n hasPrevious: false,\n },\n },\n error: null,\n});\n\nconst createPlayerError = (\n code: AudioPlayerRuntimeError[\"code\"],\n message: string,\n cause?: unknown,\n): AudioPlayerRuntimeError => ({\n code,\n message,\n cause,\n});\n\nconst isRuntimePlayerError = (\n value: unknown,\n): value is AudioPlayerRuntimeError =>\n !!value &&\n typeof value === \"object\" &&\n \"code\" in value &&\n \"message\" in value;\n\nconst normalizePlayerError = (\n fallbackCode: AudioPlayerRuntimeError[\"code\"],\n fallbackMessage: string,\n cause: unknown,\n): AudioPlayerRuntimeError =>\n isRuntimePlayerError(cause)\n ? cause\n : createPlayerError(fallbackCode, fallbackMessage, cause);\n\nconst assertStableSource = (source: AudioSource): void => {\n if (!source.id || !source.src) {\n throw createPlayerError(\n \"INVALID_QUEUE_ITEM\",\n \"AudioSource requires stable id and src.\",\n );\n }\n};\n\nconst isFiniteNumber = (value: number): boolean =>\n Number.isFinite(value) && !Number.isNaN(value);\n\nconst safeDuration = (audio: HTMLAudioElement | null, hint?: number): number => {\n const duration = audio?.duration;\n return duration !== undefined && isFiniteNumber(duration) ? duration : hint ?? 0;\n};\n\nconst safeBuffered = (audio: HTMLAudioElement | null): number => {\n if (!audio || audio.buffered.length === 0) {\n return 0;\n }\n\n try {\n return audio.buffered.end(audio.buffered.length - 1);\n } catch {\n return 0;\n }\n};\n\nconst cloneQueueState = (state: AudioPlayerState): AudioPlayerQueueState => ({\n items: [...state.queue.items],\n itemIds: [...state.queue.itemIds],\n position: {\n ...state.queue.position,\n },\n});\n\nconst updateQueueFlags = (state: AudioPlayerState): AudioPlayerState => {\n const { items, position } = state.queue;\n const { currentIndex, repeatMode } = position;\n const lastIndex = items.length - 1;\n const hasItems = items.length > 0;\n const hasNext =\n !hasItems || currentIndex < 0\n ? false\n : repeatMode === \"all\"\n ? items.length > 0\n : currentIndex < lastIndex;\n const hasPrevious =\n !hasItems || currentIndex < 0\n ? false\n : repeatMode === \"all\"\n ? items.length > 0\n : currentIndex > 0;\n\n return {\n ...state,\n queue: {\n ...state.queue,\n itemIds: items.map((item) => item.id),\n position: {\n ...position,\n currentSourceId: state.currentSource?.id ?? null,\n length: items.length,\n hasNext,\n hasPrevious,\n },\n },\n };\n};\n\nconst createAudioElement = (): HTMLAudioElement | null => {\n if (typeof Audio === \"undefined\") {\n return null;\n }\n\n return new Audio();\n};\n\nconst createUnavailableAudioEngine = (): AudioEngine => {\n const unavailableError = (): AudioPlayerRuntimeError =>\n createPlayerError(\n \"UNSUPPORTED_ENVIRONMENT\",\n \"HTMLAudioElement is not available in this environment.\",\n );\n\n return {\n available: false,\n getSnapshot(durationHint) {\n return {\n currentTime: 0,\n duration: durationHint ?? 0,\n buffered: 0,\n rate: 1,\n volume: 1,\n muted: false,\n };\n },\n getRuntimeError() {\n return unavailableError();\n },\n on() {\n return () => {};\n },\n setSource() {\n throw unavailableError();\n },\n clearSource() {\n throw unavailableError();\n },\n load() {\n throw unavailableError();\n },\n play() {\n throw unavailableError();\n },\n pause() {\n throw unavailableError();\n },\n setCurrentTime() {\n throw unavailableError();\n },\n setPlaybackRate() {\n throw unavailableError();\n },\n setVolume() {\n throw unavailableError();\n },\n setMuted() {\n throw unavailableError();\n },\n destroy() {},\n };\n};\n\nconst createHtmlAudioEngine = (): AudioEngine => {\n const audio = createAudioElement();\n if (!audio) {\n return createUnavailableAudioEngine();\n }\n\n audio.preload = \"metadata\";\n const clearSource = (): void => {\n const element = audio as HTMLAudioElement & {\n removeAttribute?: (name: string) => void;\n };\n if (typeof element.removeAttribute === \"function\") {\n element.removeAttribute(\"src\");\n return;\n }\n\n audio.src = \"\";\n };\n\n return {\n available: true,\n getSnapshot(durationHint) {\n return {\n currentTime: audio.currentTime,\n duration: safeDuration(audio, durationHint),\n buffered: safeBuffered(audio),\n rate: audio.playbackRate,\n volume: audio.volume,\n muted: audio.muted,\n };\n },\n getRuntimeError() {\n return audio.error;\n },\n on(eventName, listener) {\n audio.addEventListener(eventName, listener);\n return () => {\n audio.removeEventListener(eventName, listener);\n };\n },\n setSource(src) {\n audio.src = src;\n },\n clearSource() {\n clearSource();\n },\n load() {\n audio.load();\n },\n play() {\n return audio.play();\n },\n pause() {\n audio.pause();\n },\n setCurrentTime(time) {\n audio.currentTime = time;\n },\n setPlaybackRate(rate) {\n audio.playbackRate = rate;\n },\n setVolume(volume) {\n audio.volume = volume;\n },\n setMuted(muted) {\n audio.muted = muted;\n },\n destroy() {\n audio.pause();\n clearSource();\n audio.load();\n },\n };\n};\n\nconst isBrowserStorageAvailable = (): boolean =>\n typeof window !== \"undefined\" && typeof window.localStorage !== \"undefined\";\n\nconst isPersistedPlayerState = (value: unknown): value is PersistedPlayerState => {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n\n const candidate = value as Partial<PersistedPlayerState>;\n return (\n candidate.version === 1 &&\n typeof candidate.savedAt === \"number\" &&\n \"currentSource\" in candidate &&\n typeof candidate.currentTime === \"number\" &&\n typeof candidate.rate === \"number\" &&\n typeof candidate.volume === \"number\" &&\n typeof candidate.muted === \"boolean\" &&\n !!candidate.queue &&\n Array.isArray(candidate.queue.items) &&\n !!candidate.queue.position\n );\n};\n\nconst toPersistedPlayerState = (state: AudioPlayerState): PersistedPlayerState => ({\n version: 1,\n savedAt: Date.now(),\n currentSource: state.currentSource,\n currentSourceId: state.currentSourceId,\n currentTime: state.currentTime,\n rate: state.rate,\n volume: state.volume,\n muted: state.muted,\n queue: {\n items: [...state.queue.items],\n position: {\n currentIndex: state.queue.position.currentIndex,\n currentSourceId: state.queue.position.currentSourceId,\n repeatMode: state.queue.position.repeatMode,\n },\n },\n});\n\nconst toProgressSnapshot = (\n state: AudioPlayerState,\n): AudioPlayerProgressSnapshot => ({\n source: state.currentSource,\n sourceId: state.currentSourceId,\n currentTime: state.currentTime,\n duration: state.duration,\n playedFraction: state.progress.playedFraction,\n status: state.status,\n queue: {\n ...state.queue.position,\n },\n});\n\nconst hasMediaSession = (): boolean =>\n typeof navigator !== \"undefined\" && \"mediaSession\" in navigator;\n\nconst createMediaSessionArtwork = (\n source: AudioSource | null,\n sizes: number[],\n): MediaImage[] => {\n if (!source?.artwork) {\n return [];\n }\n\n return sizes.map((size) => ({\n src: source.artwork as string,\n sizes: `${size}x${size}`,\n }));\n};\n\nexport const createLocalStoragePersistenceAdapter = (\n key: string,\n): AudioPlayerPersistenceAdapter => ({\n load() {\n if (!isBrowserStorageAvailable()) {\n return null;\n }\n\n try {\n const raw = window.localStorage.getItem(key);\n if (!raw) {\n return null;\n }\n\n const parsed: unknown = JSON.parse(raw);\n return isPersistedPlayerState(parsed) ? parsed : null;\n } catch {\n return null;\n }\n },\n\n save(state) {\n if (!isBrowserStorageAvailable()) {\n return;\n }\n\n window.localStorage.setItem(key, JSON.stringify(state));\n },\n\n clear() {\n if (!isBrowserStorageAvailable()) {\n return;\n }\n\n window.localStorage.removeItem(key);\n },\n});\n\nexport const createAudioPlayer = (\n options: CreateAudioPlayerOptions = {},\n): AudioPlayer => {\n let state = updateQueueFlags(createInitialState(options));\n let destroyed = false;\n let shouldAutoplayAfterLoad = false;\n let suppressPauseEvent = false;\n\n const engine = createHtmlAudioEngine();\n const subscribers = new Set<(nextState: AudioPlayerState) => void>();\n const eventListeners: {\n [K in AudioPlayerEventName]: Set<AudioPlayerEventListener<K>>;\n } = {\n sourcechange: new Set(),\n queuechange: new Set(),\n play: new Set(),\n pause: new Set(),\n seeking: new Set(),\n seeked: new Set(),\n timeupdate: new Set(),\n ratechange: new Set(),\n volumechange: new Set(),\n ended: new Set(),\n error: new Set(),\n destroy: new Set(),\n };\n\n const getState = (): AudioPlayerState => state;\n\n const publishState = (): void => {\n for (const subscriber of subscribers) {\n subscriber(state);\n }\n };\n\n const emit = <K extends AudioPlayerEventName>(\n eventName: K,\n event: AudioPlayerEventMap[K],\n ): void => {\n for (const listener of eventListeners[eventName]) {\n listener(event);\n }\n };\n\n const setState = (\n updater: (currentState: AudioPlayerState) => AudioPlayerState,\n ): AudioPlayerState => {\n state = updateQueueFlags(updater(state));\n publishState();\n return state;\n };\n\n const setError = (error: AudioPlayerRuntimeError): void => {\n shouldAutoplayAfterLoad = false;\n const nextState = setState((currentState) => ({\n ...currentState,\n status: \"error\",\n error: {\n code: error.code,\n message: error.message,\n },\n }));\n emit(\"error\", { error, state: nextState });\n };\n\n const clearError = (): void => {\n if (!state.error) {\n return;\n }\n\n setState((currentState) => ({\n ...currentState,\n error: null,\n }));\n };\n\n const syncAudioSnapshot = (\n statusOverride?: PlayerStatus,\n ): AudioPlayerState => {\n const snapshot = engine.getSnapshot(state.currentSource?.durationHint);\n const currentTime = snapshot.currentTime;\n const duration = snapshot.duration;\n const buffered = snapshot.buffered;\n const playedFraction =\n duration > 0 ? Math.min(1, Math.max(0, currentTime / duration)) : 0;\n const bufferedFraction =\n duration > 0 ? Math.min(1, Math.max(0, buffered / duration)) : 0;\n\n const nextState = setState((currentState) => ({\n ...currentState,\n currentSourceId: currentState.currentSource?.id ?? null,\n currentTime,\n duration,\n buffered,\n progress: {\n currentTime,\n duration,\n buffered,\n playedFraction,\n bufferedFraction,\n },\n rate: snapshot.rate,\n volume: snapshot.volume,\n muted: snapshot.muted,\n status: statusOverride ?? currentState.status,\n error:\n statusOverride === \"error\" ? currentState.error : null,\n }));\n\n return nextState;\n };\n\n const findQueueIndexById = (id: string | null | undefined): number =>\n id ? state.queue.items.findIndex((item) => item.id === id) : -1;\n\n const resolveNextQueueIndex = (\n mode: \"manual\" | \"ended\",\n ): number | null => {\n const { items, position } = state.queue;\n const { currentIndex, repeatMode } = position;\n\n if (items.length === 0 || currentIndex < 0) {\n return null;\n }\n\n if (repeatMode === \"one\") {\n return currentIndex;\n }\n\n if (currentIndex < items.length - 1) {\n return currentIndex + 1;\n }\n\n if (repeatMode === \"all\") {\n return 0;\n }\n\n return mode === \"ended\" ? -1 : null;\n };\n\n const resolvePreviousQueueIndex = (): number | null => {\n const { items, position } = state.queue;\n const { currentIndex, repeatMode } = position;\n\n if (items.length === 0 || currentIndex < 0) {\n return null;\n }\n\n if (currentIndex > 0) {\n return currentIndex - 1;\n }\n\n if (repeatMode === \"all\") {\n return items.length - 1;\n }\n\n return null;\n };\n\n const updateCurrentSource = (\n source: AudioSource | null,\n nextStatus: PlayerStatus,\n ): AudioPlayerState => {\n const queueIndex = findQueueIndexById(source?.id);\n const nextState = setState((currentState) => ({\n ...currentState,\n currentSource: source,\n currentSourceId: source?.id ?? null,\n currentTime: 0,\n duration: source?.durationHint ?? 0,\n buffered: 0,\n progress: {\n currentTime: 0,\n duration: source?.durationHint ?? 0,\n buffered: 0,\n playedFraction: 0,\n bufferedFraction: 0,\n },\n status: nextStatus,\n error: null,\n queue: {\n ...currentState.queue,\n position: {\n ...currentState.queue.position,\n currentIndex: queueIndex,\n currentSourceId: source?.id ?? null,\n },\n },\n }));\n emit(\"sourcechange\", { source, state: nextState });\n return nextState;\n };\n\n const setQueueState = (\n items: AudioSource[],\n currentIndex: number,\n ): AudioPlayerState =>\n setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n items,\n position: {\n ...currentState.queue.position,\n currentIndex,\n },\n },\n }));\n\n const emitQueueChange = (nextState: AudioPlayerState): void => {\n emit(\"queuechange\", { queue: cloneQueueState(nextState), state: nextState });\n };\n\n const attachSourceToAudio = (\n source: AudioSource,\n autoplayAfterLoad: boolean,\n ): void => {\n shouldAutoplayAfterLoad = autoplayAfterLoad;\n suppressPauseEvent = true;\n try {\n engine.pause();\n } finally {\n suppressPauseEvent = false;\n }\n engine.setSource(source.src);\n engine.setCurrentTime(0);\n engine.setPlaybackRate(state.rate);\n engine.setVolume(state.volume);\n engine.setMuted(state.muted);\n engine.load();\n };\n\n const loadInternal = async (\n source: AudioSource,\n autoplayAfterLoad = false,\n ): Promise<void> => {\n assertStableSource(source);\n updateCurrentSource(source, \"loading\");\n attachSourceToAudio(source, autoplayAfterLoad);\n };\n\n const selectQueueIndex = async (\n index: number,\n autoplayAfterLoad = false,\n ): Promise<AudioSource | null> => {\n const item = state.queue.items[index] ?? null;\n if (!item) {\n return null;\n }\n\n await loadInternal(item, autoplayAfterLoad);\n const nextState = setQueueState(state.queue.items, index);\n emitQueueChange(nextState);\n return item;\n };\n\n const playLoadedAudio = async (): Promise<void> => {\n try {\n await engine.play();\n } catch (cause) {\n setError(createPlayerError(\"PLAY_ERROR\", \"Failed to start playback.\", cause));\n }\n };\n\n const handlePlaybackEnded = async (): Promise<void> => {\n if (destroyed) {\n return;\n }\n\n if (state.queue.items.length > 0 && state.queue.position.currentIndex >= 0) {\n const nextIndex = resolveNextQueueIndex(\"ended\");\n if (nextIndex === -1 || nextIndex === null) {\n const endedState = syncAudioSnapshot(\"ended\");\n emit(\"ended\", { source: endedState.currentSource, state: endedState });\n return;\n }\n\n await selectQueueIndex(nextIndex, true);\n return;\n }\n\n const endedState = syncAudioSnapshot(\"ended\");\n emit(\"ended\", { source: endedState.currentSource, state: endedState });\n };\n\n const detachEngineListeners = [\n engine.on(\"loadedmetadata\", () => {\n if (destroyed || !state.currentSource) {\n return;\n }\n\n syncAudioSnapshot(\"ready\");\n if (shouldAutoplayAfterLoad) {\n shouldAutoplayAfterLoad = false;\n void playLoadedAudio();\n }\n }),\n engine.on(\"timeupdate\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot(\n state.status === \"ended\" ? \"playing\" : undefined,\n );\n emit(\"timeupdate\", {\n currentTime: nextState.currentTime,\n duration: nextState.duration,\n state: nextState,\n });\n }),\n engine.on(\"progress\", () => {\n if (!destroyed) {\n syncAudioSnapshot();\n }\n }),\n engine.on(\"play\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot(\"playing\");\n emit(\"play\", { source: nextState.currentSource, state: nextState });\n }),\n engine.on(\"pause\", () => {\n if (destroyed || suppressPauseEvent) {\n return;\n }\n\n const nextStatus =\n state.status === \"ended\" ? \"ended\" : state.currentSource ? \"paused\" : \"idle\";\n const nextState = syncAudioSnapshot(nextStatus);\n emit(\"pause\", { source: nextState.currentSource, state: nextState });\n }),\n engine.on(\"seeked\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot();\n emit(\"seeked\", { currentTime: nextState.currentTime, state: nextState });\n emit(\"timeupdate\", {\n currentTime: nextState.currentTime,\n duration: nextState.duration,\n state: nextState,\n });\n }),\n engine.on(\"ratechange\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot();\n emit(\"ratechange\", { rate: nextState.rate, state: nextState });\n }),\n engine.on(\"volumechange\", () => {\n if (destroyed) {\n return;\n }\n\n const nextState = syncAudioSnapshot();\n emit(\"volumechange\", {\n volume: nextState.volume,\n muted: nextState.muted,\n state: nextState,\n });\n }),\n engine.on(\"ended\", () => {\n void handlePlaybackEnded();\n }),\n engine.on(\"error\", () => {\n if (destroyed) {\n return;\n }\n\n setError(\n createPlayerError(\n \"LOAD_ERROR\",\n \"Audio element reported a playback error.\",\n engine.getRuntimeError(),\n ),\n );\n }),\n ];\n\n return {\n getState,\n\n subscribe(listener) {\n subscribers.add(listener);\n listener(state);\n return () => {\n subscribers.delete(listener);\n };\n },\n\n on(eventName, listener) {\n eventListeners[eventName].add(\n listener as AudioPlayerEventListener<typeof eventName>,\n );\n return () => {\n eventListeners[eventName].delete(\n listener as AudioPlayerEventListener<typeof eventName>,\n );\n };\n },\n\n async load(source) {\n try {\n await loadInternal(source);\n } catch (cause) {\n setError(\n normalizePlayerError(\"LOAD_ERROR\", \"Failed to load source.\", cause),\n );\n }\n },\n\n async play(source) {\n try {\n if (source) {\n await loadInternal(source, true);\n return;\n }\n\n if (!state.currentSource) {\n setError(\n createPlayerError(\n \"NO_ACTIVE_SOURCE\",\n \"Cannot play without an active source.\",\n ),\n );\n return;\n }\n\n if (state.status === \"loading\") {\n shouldAutoplayAfterLoad = true;\n return;\n }\n\n await playLoadedAudio();\n } catch (cause) {\n setError(normalizePlayerError(\"PLAY_ERROR\", \"Failed to start playback.\", cause));\n }\n },\n\n pause() {\n if (!engine.available) {\n return;\n }\n\n shouldAutoplayAfterLoad = false;\n engine.pause();\n },\n\n async toggle() {\n if (state.status === \"playing\") {\n this.pause();\n return;\n }\n\n await this.play();\n },\n\n unload() {\n shouldAutoplayAfterLoad = false;\n\n if (engine.available) {\n suppressPauseEvent = true;\n try {\n engine.pause();\n } finally {\n suppressPauseEvent = false;\n }\n engine.clearSource();\n engine.load();\n }\n\n const nextState = updateCurrentSource(null, \"idle\");\n emitQueueChange(nextState);\n },\n\n seek(time) {\n if (!state.currentSource) {\n setError(\n createPlayerError(\"SEEK_ERROR\", \"Cannot seek without an active source.\"),\n );\n return;\n }\n\n const max = engine.getSnapshot(state.currentSource.durationHint).duration;\n const normalized = Math.max(\n 0,\n max > 0 ? Math.min(time, max) : (isFiniteNumber(time) ? time : 0),\n );\n emit(\"seeking\", { from: state.currentTime, to: normalized, state });\n\n try {\n engine.setCurrentTime(normalized);\n } catch (cause) {\n setError(normalizePlayerError(\"SEEK_ERROR\", \"Failed to seek audio.\", cause));\n }\n },\n\n setRate(rate) {\n if (!engine.available) {\n setError(\n createPlayerError(\"INVALID_RATE\", \"Audio element is unavailable.\"),\n );\n return;\n }\n\n if (!isFiniteNumber(rate) || rate <= 0) {\n setError(\n createPlayerError(\"INVALID_RATE\", \"Playback rate must be greater than 0.\"),\n );\n return;\n }\n\n engine.setPlaybackRate(rate);\n clearError();\n syncAudioSnapshot();\n },\n\n setVolume(volume) {\n if (!engine.available) {\n setError(\n createPlayerError(\"INVALID_VOLUME\", \"Audio element is unavailable.\"),\n );\n return;\n }\n\n if (!isFiniteNumber(volume) || volume < 0 || volume > 1) {\n setError(\n createPlayerError(\"INVALID_VOLUME\", \"Volume must be between 0 and 1.\"),\n );\n return;\n }\n\n engine.setVolume(volume);\n clearError();\n syncAudioSnapshot();\n },\n\n setMuted(muted) {\n if (!engine.available) {\n return;\n }\n\n engine.setMuted(muted);\n clearError();\n syncAudioSnapshot();\n },\n\n async setQueue(items, queueOptions = {}) {\n try {\n for (const item of items) {\n assertStableSource(item);\n }\n\n const startIndex =\n queueOptions.startAtId === undefined\n ? items.length > 0\n ? 0\n : -1\n : items.findIndex((item) => item.id === queueOptions.startAtId);\n\n if (queueOptions.startAtId && startIndex < 0) {\n throw createPlayerError(\n \"INVALID_QUEUE_ITEM\",\n `Queue start item ${queueOptions.startAtId} was not found.`,\n );\n }\n\n const nextState = setState((currentState) => ({\n ...currentState,\n currentSource: startIndex >= 0 ? items[startIndex] ?? null : null,\n currentSourceId: startIndex >= 0 ? (items[startIndex]?.id ?? null) : null,\n currentTime: 0,\n duration: startIndex >= 0 ? (items[startIndex]?.durationHint ?? 0) : 0,\n buffered: 0,\n progress: {\n currentTime: 0,\n duration: startIndex >= 0 ? (items[startIndex]?.durationHint ?? 0) : 0,\n buffered: 0,\n playedFraction: 0,\n bufferedFraction: 0,\n },\n status: startIndex >= 0 ? \"ready\" : \"idle\",\n error: null,\n queue: {\n ...currentState.queue,\n items: [...items],\n position: {\n ...currentState.queue.position,\n currentIndex: startIndex,\n currentSourceId:\n startIndex >= 0 ? (items[startIndex]?.id ?? null) : null,\n },\n },\n }));\n\n emitQueueChange(nextState);\n emit(\"sourcechange\", {\n source: nextState.currentSource,\n state: nextState,\n });\n\n if (nextState.currentSource) {\n await loadInternal(nextState.currentSource, queueOptions.autoplay === true);\n const syncedState = setQueueState(items, startIndex);\n emitQueueChange(syncedState);\n } else if (engine.available) {\n shouldAutoplayAfterLoad = false;\n suppressPauseEvent = true;\n engine.pause();\n suppressPauseEvent = false;\n engine.clearSource();\n engine.load();\n }\n } catch (cause) {\n setError(\n normalizePlayerError(\n \"INVALID_QUEUE_ITEM\",\n \"Failed to set queue.\",\n cause,\n ),\n );\n }\n },\n\n appendToQueue(items) {\n try {\n for (const item of items) {\n assertStableSource(item);\n }\n\n const nextState = setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n items: [...currentState.queue.items, ...items],\n },\n }));\n emitQueueChange(nextState);\n } catch (cause) {\n setError(\n normalizePlayerError(\n \"INVALID_QUEUE_ITEM\",\n \"Failed to append queue items.\",\n cause,\n ),\n );\n }\n },\n\n removeFromQueue(id) {\n const nextItems = state.queue.items.filter((item) => item.id !== id);\n const nextIndex = nextItems.findIndex(\n (item) => item.id === state.currentSource?.id,\n );\n\n const nextState = setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n items: nextItems,\n position: {\n ...currentState.queue.position,\n currentIndex: nextIndex,\n currentSourceId: nextIndex >= 0 ? (nextItems[nextIndex]?.id ?? null) : null,\n },\n },\n }));\n\n emitQueueChange(nextState);\n },\n\n clearQueue() {\n const nextState = setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n items: [],\n position: {\n ...currentState.queue.position,\n currentIndex: -1,\n currentSourceId: null,\n },\n },\n }));\n\n emitQueueChange(nextState);\n },\n\n async next() {\n const nextIndex = resolveNextQueueIndex(\"manual\");\n if (nextIndex === null) {\n return;\n }\n\n await selectQueueIndex(nextIndex, true);\n },\n\n async previous(previousOptions = {}) {\n if (!state.currentSource) {\n return;\n }\n\n const threshold =\n previousOptions.restartThresholdSeconds ??\n DEFAULT_PREVIOUS_RESTART_THRESHOLD_SECONDS;\n\n if (state.currentTime > threshold) {\n this.seek(0);\n return;\n }\n\n const previousIndex = resolvePreviousQueueIndex();\n if (previousIndex === null) {\n this.seek(0);\n return;\n }\n\n await selectQueueIndex(previousIndex, true);\n },\n\n setRepeatMode(mode) {\n const nextState = setState((currentState) => ({\n ...currentState,\n queue: {\n ...currentState.queue,\n position: {\n ...currentState.queue.position,\n repeatMode: mode,\n },\n },\n }));\n emitQueueChange(nextState);\n },\n\n destroy() {\n if (destroyed) {\n return;\n }\n\n destroyed = true;\n shouldAutoplayAfterLoad = false;\n for (const detach of detachEngineListeners) {\n detach();\n }\n suppressPauseEvent = true;\n engine.destroy();\n suppressPauseEvent = false;\n\n const nextState = setState(() => createInitialState(options));\n emit(\"destroy\", { state: nextState });\n subscribers.clear();\n for (const eventName of Object.keys(eventListeners) as AudioPlayerEventName[]) {\n eventListeners[eventName].clear();\n }\n },\n };\n};\n\nexport const attachAudioPlayerPersistence = (\n player: AudioPlayer,\n options: AudioPlayerPersistenceOptions,\n): AudioPlayerPersistenceController => {\n const maxAgeMs = options.maxAgeMs ?? DEFAULT_PERSISTENCE_MAX_AGE_MS;\n const saveIntervalMs =\n options.saveIntervalMs ?? DEFAULT_PERSISTENCE_SAVE_INTERVAL_MS;\n let destroyed = false;\n let playIntervalId: ReturnType<typeof setInterval> | null = null;\n\n const save = (): void => {\n if (destroyed) {\n return;\n }\n\n const state = player.getState();\n if (!state.currentSource) {\n options.adapter.clear();\n return;\n }\n\n options.adapter.save(toPersistedPlayerState(state));\n };\n\n const clear = (): void => {\n options.adapter.clear();\n };\n\n const stopPlayInterval = (): void => {\n if (playIntervalId !== null) {\n clearInterval(playIntervalId);\n playIntervalId = null;\n }\n };\n\n const startPlayInterval = (): void => {\n if (playIntervalId !== null) {\n return;\n }\n\n playIntervalId = setInterval(() => {\n save();\n }, saveIntervalMs);\n };\n\n const waitForRestoredSource = (sourceId: string): Promise<void> =>\n new Promise((resolve) => {\n let settled = false;\n let unsubscribe: (() => void) | undefined;\n unsubscribe = player.subscribe((state) => {\n if (settled || state.currentSourceId !== sourceId) {\n return;\n }\n\n if (state.status === \"loading\") {\n return;\n }\n\n settled = true;\n unsubscribe?.();\n resolve();\n });\n\n // subscribe emits synchronously, so the source may already be settled\n if (settled) {\n unsubscribe();\n }\n });\n\n const restore = async (): Promise<PersistedPlayerState | null> => {\n const persisted = options.adapter.load();\n if (!persisted) {\n return null;\n }\n\n if (Date.now() - persisted.savedAt > maxAgeMs) {\n options.adapter.clear();\n return null;\n }\n\n player.setRepeatMode(persisted.queue.position.repeatMode);\n player.setVolume(persisted.volume);\n player.setMuted(persisted.muted);\n player.setRate(persisted.rate);\n\n if (persisted.queue.items.length > 0) {\n await player.setQueue(persisted.queue.items, {\n startAtId: persisted.queue.position.currentSourceId ?? undefined,\n });\n } else if (persisted.currentSource) {\n await player.load(persisted.currentSource);\n } else {\n return persisted;\n }\n\n if (persisted.currentSourceId) {\n await waitForRestoredSource(persisted.currentSourceId);\n }\n\n if (persisted.currentTime > 0) {\n player.seek(persisted.currentTime);\n }\n\n return persisted;\n };\n\n const stateUnsubscribe = player.subscribe((state) => {\n if (state.status === \"playing\") {\n startPlayInterval();\n return;\n }\n\n stopPlayInterval();\n });\n\n const pauseUnsubscribe = player.on(\"pause\", () => {\n save();\n });\n const endedUnsubscribe = player.on(\"ended\", () => {\n save();\n });\n const sourceUnsubscribe = player.on(\"sourcechange\", () => {\n save();\n });\n const queueUnsubscribe = player.on(\"queuechange\", () => {\n save();\n });\n const rateUnsubscribe = player.on(\"ratechange\", () => {\n save();\n });\n const volumeUnsubscribe = player.on(\"volumechange\", () => {\n save();\n });\n\n const beforeUnloadHandler = (): void => {\n save();\n };\n\n const visibilityHandler = (): void => {\n if (typeof document === \"undefined\") {\n return;\n }\n\n if (document.visibilityState === \"hidden\") {\n save();\n }\n };\n\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"beforeunload\", beforeUnloadHandler);\n }\n\n if (typeof document !== \"undefined\") {\n document.addEventListener(\"visibilitychange\", visibilityHandler);\n }\n\n if (options.autoRestore !== false) {\n void restore();\n }\n\n return {\n restore,\n save,\n clear,\n destroy() {\n destroyed = true;\n stopPlayInterval();\n stateUnsubscribe();\n pauseUnsubscribe();\n endedUnsubscribe();\n sourceUnsubscribe();\n queueUnsubscribe();\n rateUnsubscribe();\n volumeUnsubscribe();\n\n if (typeof window !== \"undefined\") {\n window.removeEventListener(\"beforeunload\", beforeUnloadHandler);\n }\n\n if (typeof document !== \"undefined\") {\n document.removeEventListener(\"visibilitychange\", visibilityHandler);\n }\n },\n };\n};\n\nexport const attachAudioPlayerProgressReporter = (\n player: AudioPlayer,\n options: AudioPlayerProgressReporterOptions,\n): AudioPlayerProgressReporterController => {\n const intervalMs = options.intervalMs ?? DEFAULT_PROGRESS_REPORT_INTERVAL_MS;\n let destroyed = false;\n let intervalId: ReturnType<typeof setInterval> | null = null;\n\n const report = (): void => {\n if (destroyed) {\n return;\n }\n\n const state = player.getState();\n if (!state.currentSource) {\n return;\n }\n\n options.onReport(toProgressSnapshot(state));\n };\n\n const stopInterval = (): void => {\n if (intervalId !== null) {\n clearInterval(intervalId);\n intervalId = null;\n }\n };\n\n const startInterval = (): void => {\n if (intervalId !== null) {\n return;\n }\n\n intervalId = setInterval(() => {\n report();\n }, intervalMs);\n };\n\n const stateUnsubscribe = player.subscribe((state) => {\n if (state.status === \"playing\") {\n startInterval();\n return;\n }\n\n stopInterval();\n });\n\n const pauseUnsubscribe = player.on(\"pause\", () => {\n report();\n });\n const endedUnsubscribe = player.on(\"ended\", () => {\n report();\n });\n const seekedUnsubscribe = player.on(\"seeked\", () => {\n report();\n });\n const sourceUnsubscribe = player.on(\"sourcechange\", () => {\n report();\n });\n\n return {\n report,\n destroy() {\n destroyed = true;\n stopInterval();\n stateUnsubscribe();\n pauseUnsubscribe();\n endedUnsubscribe();\n seekedUnsubscribe();\n sourceUnsubscribe();\n },\n };\n};\n\nexport const attachAudioPlayerMediaSession = (\n player: AudioPlayer,\n options: AudioPlayerMediaSessionOptions = {},\n): AudioPlayerMediaSessionController => {\n if (!hasMediaSession()) {\n return {\n sync() {},\n destroy() {},\n };\n }\n\n const artworkSizes =\n options.artworkSizes ?? DEFAULT_MEDIA_SESSION_ARTWORK_SIZES;\n const seekOffsetSeconds =\n options.seekOffsetSeconds ?? DEFAULT_MEDIA_SESSION_SEEK_OFFSET_SECONDS;\n let destroyed = false;\n\n const sync = (): void => {\n if (destroyed || !hasMediaSession()) {\n return;\n }\n\n const state = player.getState();\n const source = state.currentSource;\n\n navigator.mediaSession.metadata = source\n ? new MediaMetadata({\n title: source.title ?? \"\",\n artist: source.artist ?? \"\",\n album: source.album ?? \"\",\n artwork: createMediaSessionArtwork(source, artworkSizes),\n })\n : null;\n\n navigator.mediaSession.playbackState =\n state.status === \"playing\"\n ? \"playing\"\n : state.currentSource\n ? \"paused\"\n : \"none\";\n\n if (state.currentSource && state.duration > 0) {\n try {\n navigator.mediaSession.setPositionState({\n duration: state.duration,\n playbackRate: state.rate,\n position: Math.min(state.currentTime, state.duration),\n });\n } catch {\n // Ignore unsupported position state implementations.\n }\n } else {\n try {\n navigator.mediaSession.setPositionState();\n } catch {\n // Ignore unsupported position state implementations.\n }\n }\n };\n\n const setActionHandler = (\n action: MediaSessionAction,\n handler: MediaSessionActionHandler | null,\n ): void => {\n try {\n navigator.mediaSession.setActionHandler(action, handler);\n } catch {\n // Ignore unsupported actions.\n }\n };\n\n setActionHandler(\"play\", () => {\n void player.play();\n });\n setActionHandler(\"pause\", () => {\n player.pause();\n });\n setActionHandler(\"seekbackward\", () => {\n const state = player.getState();\n player.seek(Math.max(0, state.currentTime - seekOffsetSeconds));\n });\n setActionHandler(\"seekforward\", () => {\n const state = player.getState();\n const max = state.duration > 0 ? state.duration : state.currentTime + seekOffsetSeconds;\n player.seek(Math.min(max, state.currentTime + seekOffsetSeconds));\n });\n setActionHandler(\"previoustrack\", () => {\n void player.previous();\n });\n setActionHandler(\"nexttrack\", () => {\n void player.next();\n });\n setActionHandler(\"seekto\", (details) => {\n if (details.seekTime === undefined) {\n return;\n }\n\n player.seek(details.seekTime);\n });\n setActionHandler(\"stop\", () => {\n player.pause();\n });\n\n const stateUnsubscribe = player.subscribe(() => {\n sync();\n });\n\n sync();\n\n return {\n sync,\n destroy() {\n destroyed = true;\n stateUnsubscribe();\n if (!hasMediaSession()) {\n return;\n }\n\n const actions: MediaSessionAction[] = [\n \"play\",\n \"pause\",\n \"seekbackward\",\n \"seekforward\",\n \"previoustrack\",\n \"nexttrack\",\n \"seekto\",\n \"stop\",\n ];\n\n for (const action of actions) {\n setActionHandler(action, null);\n }\n\n navigator.mediaSession.metadata = null;\n navigator.mediaSession.playbackState = \"none\";\n try {\n navigator.mediaSession.setPositionState();\n } catch {\n // Ignore unsupported position state implementations.\n }\n },\n };\n};\n"],"mappings":"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","names":["endedState"]}
package/dist/react.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createAudioPlayer
3
- } from "./chunk-BN5MQE43.js";
3
+ } from "./chunk-7KCRIJPH.js";
4
4
 
5
5
  // src/react.tsx
6
6
  import {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yetric/audioplayer",
3
- "version": "1.0.0-beta.1",
3
+ "version": "1.0.0",
4
4
  "description": "Headless TypeScript audio player library for modern browsers.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -74,7 +74,7 @@
74
74
  "tsup": "^8.5.1",
75
75
  "typescript": "^6.0.2",
76
76
  "vite": "^8.0.3",
77
- "vitest": "^4.1.2"
77
+ "vitest": "^4.1.4"
78
78
  },
79
79
  "peerDependencies": {
80
80
  "react": ">=18"