@yetric/audioplayer 1.0.0-beta.1 → 1.1.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 +8 -8
- package/dist/{chunk-BN5MQE43.js → chunk-7KCRIJPH.js} +10 -4
- package/dist/{chunk-BN5MQE43.js.map → chunk-7KCRIJPH.js.map} +1 -1
- package/dist/index.cjs +9 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/react.cjs +13 -5
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +14 -6
- package/dist/react.js.map +1 -1
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Headless TypeScript audio player for modern browsers.
|
|
|
6
6
|
|
|
7
7
|
## Status
|
|
8
8
|
|
|
9
|
-
`1.
|
|
9
|
+
`1.1.0` is the current stable release.
|
|
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 `
|
|
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 `
|
|
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
|
-
- `
|
|
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
|
|
64
|
+
- React Native compatibility treated as a later adapter problem, not a 1.0 blocker
|
|
65
65
|
|
|
66
|
-
##
|
|
66
|
+
## 1.0 Goal
|
|
67
67
|
|
|
68
|
-
`1.0.0
|
|
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/
|
|
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
|
-
|
|
966
|
-
|
|
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
|
-
|
|
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-
|
|
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
|
-
|
|
994
|
-
|
|
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
|
-
|
|
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();
|