UNPKG

audio-hooks

Version:

A React hooks library for managing audio playback with advanced controls and features.

1 lines 30.7 kB
{"version":3,"sources":["/Users/dbl/Code/github/hey-lee/npmkits/audio-hooks/dist/react/index.cjs","../../src/react/index.ts","../../src/react/fns/index.ts"],"names":["__defProp","Object","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","getOwnPropertyNames","__hasOwnProp","prototype","hasOwnProperty","__export","target","all","name","get","enumerable","__copyProps","to","from","except","desc","key","call","__toCommonJS","mod","value","react_exports","AudioProvider","import_react3","MODE","useAudioList","module","exports","randomPlayingIndex","index","length","random","Math","floor","import_react","require","Shuffle","SingleOnce","SingleLoop","SequentialOnce","SequentialLoop","MODES","urls","onEnded","context","import_react2","useAudioContext","audioRef","useRef","audioPoolRef","sourceRef","gainNode","useGain","useState","playMode","setPlayMode","playingIndex","setPlayingIndex","audioUrls","setAudioList","playing","setPlaying","duration","setDuration","volume","setVolume","currentTime","setCurrentTime","playbackRate","setPlaybackRate","state","useMemo","audios","getAudio","url","available","current","find","a","ended","src","Audio","initAudio","useCallback","pause","disconnect","audio","crossOrigin","createMediaElementSource","connect","destination","updateTime","updateMetadata","onAudioEnded","play","nextIndex","getNextIndex","playTrack","push","onRateChange","controls","addEventListener","forEach","removeEventListener","err","console","warn","resume","error","getPrevIndex","isFromEndedEvent","playPrevTrack","playNextTrack","togglePlay","prev","next","seek","time","fastForward","ms","newTime","min","rewind","max","gain","setValueAtTime","nextPlayMode","_mode","currentIndex","indexOf","mode","rate","switchAudio"],"mappings":"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","sourcesContent":["\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/react/index.ts\nvar react_exports = {};\n__export(react_exports, {\n AudioProvider: () => import_react3.AudioProvider,\n MODE: () => MODE,\n useAudioList: () => useAudioList\n});\nmodule.exports = __toCommonJS(react_exports);\n\n// src/react/fns/index.ts\nvar randomPlayingIndex = (index, length) => {\n const random = Math.floor(Math.random() * (length - index + 1)) + index;\n if (random === index) {\n return randomPlayingIndex(index, length);\n }\n return random;\n};\n\n// src/react/index.ts\nvar import_react = require(\"react\");\nvar import_react2 = require(\"web-audio-hooks/react\");\nvar import_react3 = require(\"web-audio-hooks/react\");\nvar MODE = {\n Shuffle: `Shuffle`,\n SingleOnce: `SingleOnce`,\n SingleLoop: `SingleLoop`,\n SequentialOnce: `SequentialOnce`,\n SequentialLoop: `SequentialLoop`\n};\nvar MODES = [`Shuffle`, `SingleOnce`, `SingleLoop`, `SequentialOnce`, `SequentialLoop`];\nvar useAudioList = (urls, {\n onEnded\n} = {}) => {\n const context = (0, import_react2.useAudioContext)();\n const audioRef = (0, import_react.useRef)(null);\n const audioPoolRef = (0, import_react.useRef)([]);\n const sourceRef = (0, import_react.useRef)(null);\n const gainNode = (0, import_react2.useGain)(0.5);\n const [playMode, setPlayMode] = (0, import_react.useState)(MODE.SequentialOnce);\n const [playingIndex, setPlayingIndex] = (0, import_react.useState)(-1);\n const [audioUrls, setAudioList] = (0, import_react.useState)(urls);\n const [playing, setPlaying] = (0, import_react.useState)(false);\n const [duration, setDuration] = (0, import_react.useState)(0);\n const [volume, setVolume] = (0, import_react.useState)(0.5);\n const [currentTime, setCurrentTime] = (0, import_react.useState)(0);\n const [playbackRate, setPlaybackRate] = (0, import_react.useState)(1);\n const state = (0, import_react.useMemo)(() => ({\n audios: audioUrls,\n volume,\n playing,\n duration,\n currentTime,\n playbackRate,\n playMode,\n playingIndex\n }), [\n audioUrls,\n volume,\n playing,\n duration,\n currentTime,\n playbackRate,\n playMode,\n playingIndex\n ]);\n const getAudio = (url) => {\n const available = audioPoolRef.current.find((a) => a.ended);\n if (available && url) {\n available.src = url;\n return available;\n }\n return new Audio(url);\n };\n const initAudio = (0, import_react.useCallback)(\n (url) => {\n if (!context || !url || !gainNode) return;\n if (sourceRef.current) {\n audioRef.current?.pause();\n sourceRef.current.disconnect();\n }\n audioRef.current = getAudio(url);\n const audio = audioRef.current;\n audio.playbackRate = playbackRate;\n audio.crossOrigin = `anonymous`;\n sourceRef.current = context.createMediaElementSource(audio);\n sourceRef.current.connect(gainNode);\n gainNode.connect(context.destination);\n const updateTime = () => {\n setCurrentTime(audio.currentTime);\n };\n const updateMetadata = () => {\n setDuration(audio.duration);\n };\n const onAudioEnded = () => {\n onEnded?.();\n if (playMode === `SingleLoop`) {\n audio.currentTime = 0;\n audio.play();\n } else if (playMode === `SingleOnce`) {\n setPlaying(false);\n audioRef.current?.pause();\n } else {\n const nextIndex = getNextIndex(true);\n if (nextIndex !== -1) {\n playTrack(nextIndex);\n } else if (playMode === `SequentialOnce`) {\n setPlaying(false);\n audioRef.current?.pause();\n }\n }\n audioPoolRef.current.push(audio);\n };\n const onRateChange = () => {\n controls.setPlaybackRate(audio.playbackRate);\n };\n audio.addEventListener(`ratechange`, onRateChange);\n audio.addEventListener(`timeupdate`, updateTime);\n audio.addEventListener(`loadedmetadata`, updateMetadata);\n audio.addEventListener(`ended`, onAudioEnded);\n return () => {\n audio.pause();\n audioPoolRef.current.forEach((a) => a.pause());\n audioPoolRef.current = [];\n sourceRef.current?.disconnect();\n audio.removeEventListener(`ratechange`, onRateChange);\n audio.removeEventListener(`timeupdate`, updateTime);\n audio.removeEventListener(`loadedmetadata`, updateMetadata);\n audio.removeEventListener(`ended`, onAudioEnded);\n };\n },\n [context, gainNode, playbackRate, playMode]\n );\n const playTrack = (0, import_react.useCallback)(async (index) => {\n if (index < 0 || index >= audioUrls.length) {\n console.warn(`Invalid index: ${index}`);\n if (playMode === `SequentialOnce`) {\n setPlaying(false);\n audioRef.current?.pause();\n }\n return;\n }\n setPlayingIndex(index);\n setPlaying(false);\n initAudio(audioUrls[index]);\n try {\n if (context?.state === `suspended`) {\n await context.resume();\n }\n await audioRef.current?.play();\n setPlaying(true);\n } catch (err) {\n console.error(`\\u64AD\\u653E\\u5931\\u8D25:`, err);\n }\n }, [context, audioUrls, initAudio, playMode]);\n const getPrevIndex = () => {\n if (audioUrls.length === 0) return -1;\n if (playMode === `Shuffle`) {\n return randomPlayingIndex(playingIndex, audioUrls.length);\n }\n if (playingIndex <= 0) {\n return audioUrls.length - 1;\n }\n return playingIndex - 1;\n };\n const getNextIndex = (isFromEndedEvent = false) => {\n if (audioUrls.length === 0) return -1;\n if (audioUrls.length > 0 && playingIndex === -1) {\n return 0;\n }\n if (playMode === `Shuffle`) {\n return randomPlayingIndex(playingIndex, audioUrls.length);\n }\n if (playMode === `SingleOnce`) {\n return -1;\n }\n if (playingIndex >= audioUrls.length - 1) {\n if (playMode === `SequentialLoop`) {\n return 0;\n } else if (playMode === `SequentialOnce` && isFromEndedEvent) {\n return -1;\n }\n }\n return playingIndex + 1;\n };\n const playPrevTrack = () => {\n playTrack(getPrevIndex());\n };\n const playNextTrack = () => {\n playTrack(getNextIndex());\n };\n const controls = {\n play: async () => {\n if (audioRef.current) {\n await audioRef.current.play();\n setPlaying(true);\n } else {\n if (audioUrls.length > 0) {\n playTrack(0);\n }\n }\n },\n pause: () => {\n audioRef.current?.pause();\n setPlaying(false);\n },\n togglePlay: () => {\n playing ? controls.pause() : controls.play();\n },\n playTrack,\n setAudioList,\n prev: playPrevTrack,\n next: playNextTrack,\n seek: (time) => {\n if (audioRef.current) {\n audioRef.current.currentTime = time;\n }\n },\n fastForward: (ms = 5e3) => {\n if (audioRef.current) {\n const newTime = Math.min(audioRef.current.currentTime + ms / 1e3, audioRef.current.duration || 0);\n audioRef.current.currentTime = newTime;\n }\n },\n rewind: (ms = 5e3) => {\n if (audioRef.current) {\n const newTime = Math.max(audioRef.current.currentTime - ms / 1e3, 0);\n audioRef.current.currentTime = newTime;\n }\n },\n setVolume: (volume2) => {\n setVolume(volume2);\n if (gainNode) {\n gainNode.gain.setValueAtTime(volume2, context?.currentTime || 0);\n }\n },\n nextPlayMode: (_mode) => {\n const currentIndex = MODES.indexOf(playMode);\n const nextIndex = (currentIndex + 1) % MODES.length;\n const mode = _mode || MODES[nextIndex];\n setPlayMode(mode);\n },\n setPlaybackRate: (rate) => {\n rate = Math.min(Math.max(rate, 0.5), 3);\n setPlaybackRate(rate);\n if (audioRef.current) {\n audioRef.current.playbackRate = rate;\n }\n },\n switchAudio: setPlayingIndex\n };\n return {\n state,\n controls\n };\n};\n// Annotate the CommonJS export names for ESM import in node:\n0 && (module.exports = {\n AudioProvider,\n MODE,\n useAudioList\n});\n","\nimport { randomPlayingIndex } from './fns'\nimport { useState, useRef, useCallback, useMemo } from 'react'\nimport { useGain, useAudioContext } from 'web-audio-hooks/react'\n\nexport { AudioProvider } from 'web-audio-hooks/react'\n\n/**\n * Represents the playback mode for audio tracks\n * @typedef {('Shuffle' | 'SingleOnce' | 'SingleLoop' | 'SequentialOnce' | 'SequentialLoop')} PlayMode\n * - 'Shuffle' - Shuffle playback mode\n * - 'SingleLoop' - Repeat One playback mode\n * - 'SingleOnce' - Play current track once then stop\n * - 'SequentialOnce' - Play all tracks once then stop\n * - 'SequentialLoop' - Repeat All playback mode\n */\n\nexport const MODE: Record<PlayMode, PlayMode> = {\n Shuffle: `Shuffle`,\n SingleOnce: `SingleOnce`,\n SingleLoop: `SingleLoop`,\n SequentialOnce: `SequentialOnce`,\n SequentialLoop: `SequentialLoop`,\n}\nconst MODES = [`Shuffle`, `SingleOnce`, `SingleLoop`, `SequentialOnce`, `SequentialLoop`] as const\n\ntype PlayMode = (typeof MODES)[number]\n\n/**\n * AudioControls interface for audio playback functionality\n */\nexport interface AudioControls {\n /** Start playing the current audio track */\n play: () => void\n /** Pause the current audio track */\n pause: () => void\n /** Toggle play between play and pause */\n togglePlay: () => void\n /** Skip to next track based on current play mode */\n next: () => void\n /** Go to previous track based on current play mode */\n prev: () => void\n /**\n * Seek to specific time in current track\n * @param time - Target time in seconds\n */\n seek: (time: number) => void\n /**\n * Fast forward by specified milliseconds\n * @param ms - Number of milliseconds to fast forward (default: 5000)\n */\n fastForward: (ms?: number) => void\n /**\n * Rewind by specified milliseconds\n * @param ms - Number of milliseconds to rewind (default: 5000)\n */\n rewind: (ms?: number) => void\n /**\n * Set audio volume\n * @param volume - Volume level between 0 and 1\n */\n setVolume: (volume: number) => void\n /**\n * Change playback mode\n * @param mode - Optional specific play mode to set, cycles through modes if not provided\n */\n nextPlayMode: (mode?: PlayMode) => void\n /**\n * Play specific track by index\n * @param index - Index of track in playlist\n */\n playTrack: (index: number) => void\n /**\n * Set playback speed\n * @param rate - Playback rate between 0.5 and 3.0\n */\n setPlaybackRate: (rate: number) => void\n /**\n * Set the list of audio URLs\n * @param urls - Array of URLs for audio tracks\n */\n setAudioList: (urls: string[]) => void\n /**\n * Switch to a specific track in the playlist without playing it\n * @param index - Index of track to switch to\n */\n switchAudio: (index: number) => void\n}\n/**\n * State interface for audio playback functionality\n */\nexport interface AudioState {\n audios: string[]\n /** Whether audio is currently playing */\n playing: boolean\n /** Index of currently playing track in playlist */\n playingIndex: number\n /** Current playback position in seconds */\n currentTime: number\n /** Total duration of current track in seconds */\n duration: number\n /** Current volume level between 0 and 1 */\n volume: number\n /** Current playback speed between 0.5 and 3.0 */\n playbackRate: number\n /** Current playback mode (sequential/shuffle/loop) */\n playMode: PlayMode\n}\n\ninterface AudioEvents {\n onEnded?: () => void\n}\n\nexport type AudioOptions = AudioEvents\n\n/**\n * Return type for useAudioList hook\n * @property state - Current state of audio playback including playing status, time, volume etc\n * @property controls - Methods to control audio playback like play, pause, seek etc\n * @property setAudioList - Function to update the list of audio URLs\n */\nexport type UseAudioListReturn = {\n state: AudioState\n controls: AudioControls\n}\n\n/**\n * React hook for managing a list of audio tracks with playback controls\n * @param urls - Array of URLs for audio tracks to be played\n * @returns Object containing playback state, controls, and URL setter\n * @example\n * ```tsx\n * const { state, controls, setAudioList } = useAudioList([\n * 'audio1.mp3',\n * 'audio2.mp3'\n * ])\n * ```\n */\nexport const useAudioList = (urls: string[], {\n onEnded,\n}: AudioOptions = {}): UseAudioListReturn => {\n const context = useAudioContext()\n const audioRef = useRef<HTMLAudioElement | null>(null)\n const audioPoolRef = useRef<HTMLAudioElement[]>([])\n const sourceRef = useRef<MediaElementAudioSourceNode | null>(null)\n const gainNode = useGain(0.5)\n const [playMode, setPlayMode] = useState<AudioState['playMode']>(MODE.SequentialOnce)\n const [playingIndex, setPlayingIndex] = useState<AudioState['playingIndex']>(-1)\n\n const [audioUrls, setAudioList] = useState(urls)\n const [playing, setPlaying] = useState<AudioState['playing']>(false)\n const [duration, setDuration] = useState<AudioState['duration']>(0)\n const [volume, setVolume] = useState<AudioState['volume']>(0.5)\n const [currentTime, setCurrentTime] = useState<AudioState['currentTime']>(0)\n const [playbackRate, setPlaybackRate] = useState<AudioState['playbackRate']>(1)\n\n const state: AudioState = useMemo(() => ({\n audios: audioUrls,\n volume,\n playing,\n duration,\n currentTime,\n playbackRate,\n playMode,\n playingIndex,\n }), [\n audioUrls,\n volume,\n playing,\n duration,\n currentTime,\n playbackRate,\n playMode,\n playingIndex,\n ])\n\n const getAudio = (url?: string) => {\n const available = audioPoolRef.current.find((a) => a.ended)\n if (available && url) {\n available.src = url\n return available\n }\n return new Audio(url)\n }\n\n const initAudio = useCallback(\n (url: string) => {\n if (!context || !url || !gainNode) return\n if (sourceRef.current) {\n audioRef.current?.pause()\n sourceRef.current.disconnect()\n }\n\n audioRef.current = getAudio(url)\n const audio = audioRef.current\n audio.playbackRate = playbackRate\n audio.crossOrigin = `anonymous`\n\n sourceRef.current = context.createMediaElementSource(audio)\n sourceRef.current.connect(gainNode)\n gainNode.connect(context.destination)\n\n const updateTime = () => {\n setCurrentTime(audio.currentTime)\n }\n\n const updateMetadata = () => {\n setDuration(audio.duration)\n }\n\n const onAudioEnded = () => {\n onEnded?.()\n if (playMode === `SingleLoop`) {\n audio.currentTime = 0\n audio.play()\n } else if (playMode === `SingleOnce`) {\n setPlaying(false)\n audioRef.current?.pause()\n } else { // SequentialLoop, Shuffle, and SequentialOnce\n const nextIndex = getNextIndex(true) // Pass true to indicate 'Once' modes\n if (nextIndex !== -1) {\n playTrack(nextIndex)\n } else if (playMode === `SequentialOnce`) { // If no next track in SequentialOnce, stop\n setPlaying(false)\n audioRef.current?.pause()\n }\n }\n audioPoolRef.current.push(audio)\n }\n\n const onRateChange = () => {\n controls.setPlaybackRate(audio.playbackRate)\n }\n\n audio.addEventListener(`ratechange`, onRateChange)\n audio.addEventListener(`timeupdate`, updateTime)\n audio.addEventListener(`loadedmetadata`, updateMetadata)\n audio.addEventListener(`ended`, onAudioEnded)\n\n return () => {\n audio.pause()\n audioPoolRef.current.forEach(a => a.pause())\n audioPoolRef.current = []\n sourceRef.current?.disconnect()\n audio.removeEventListener(`ratechange`, onRateChange)\n audio.removeEventListener(`timeupdate`, updateTime)\n audio.removeEventListener(`loadedmetadata`, updateMetadata)\n audio.removeEventListener(`ended`, onAudioEnded)\n }\n },\n [context, gainNode, playbackRate, playMode]\n )\n\n const playTrack = useCallback(async (index: number) => {\n if (index < 0 || index >= audioUrls.length) {\n console.warn(`Invalid index: ${index}`)\n // If the index is invalid (e.g., end of SequentialOnce playlist), stop playing\n if (playMode === `SequentialOnce`) {\n setPlaying(false)\n audioRef.current?.pause()\n }\n return\n }\n\n setPlayingIndex(index)\n\n setPlaying(false)\n initAudio(audioUrls[index])\n\n try {\n if (context?.state === `suspended`) {\n await context.resume()\n }\n await audioRef.current?.play()\n setPlaying(true)\n } catch (err) {\n console.error(`播放失败:`, err)\n }\n\n }, [context, audioUrls, initAudio, playMode])\n\n const getPrevIndex = () => {\n if (audioUrls.length === 0) return -1\n if (playMode === `Shuffle`) {\n return randomPlayingIndex(playingIndex, audioUrls.length)\n }\n if (playingIndex <= 0) {\n return audioUrls.length - 1\n }\n return playingIndex - 1\n }\n\n // Add `isFromEndedEvent` to handle 'Once' modes\n const getNextIndex = (isFromEndedEvent = false) => {\n if (audioUrls.length === 0) return -1\n if (audioUrls.length > 0 && playingIndex === -1) {\n return 0\n }\n if (playMode === `Shuffle`) {\n return randomPlayingIndex(playingIndex, audioUrls.length)\n }\n\n if (playMode === `SingleOnce`) {\n return -1 // No next track for `SingleOnce`\n }\n\n // For `SequentialOnce` and `SequentialLoop`\n if (playingIndex >= (audioUrls.length - 1)) {\n if (playMode === `SequentialLoop`) {\n return 0 // Loop back to the beginning\n } else if (playMode === `SequentialOnce` && isFromEndedEvent) {\n return -1 // Stop if at the end of SequentialOnce and triggered by onEnded\n }\n }\n\n return playingIndex + 1\n }\n\n const playPrevTrack = () => {\n playTrack(getPrevIndex())\n }\n\n const playNextTrack = () => {\n playTrack(getNextIndex())\n }\n\n const controls: AudioControls = {\n play: async () => {\n if (audioRef.current) {\n await audioRef.current.play()\n setPlaying(true)\n } else {\n if (audioUrls.length > 0) {\n playTrack(0)\n }\n }\n },\n pause: () => {\n audioRef.current?.pause()\n setPlaying(false)\n },\n togglePlay: () => {\n playing ? controls.pause() : controls.play()\n },\n playTrack,\n setAudioList,\n prev: playPrevTrack,\n next: playNextTrack,\n seek: (time: number) => {\n if (audioRef.current) {\n audioRef.current.currentTime = time\n }\n },\n fastForward: (ms: number = 5000) => {\n if (audioRef.current) {\n const newTime = Math.min(audioRef.current.currentTime + ms / 1000, audioRef.current.duration || 0)\n audioRef.current.currentTime = newTime\n }\n },\n rewind: (ms: number = 5000) => {\n if (audioRef.current) {\n const newTime = Math.max(audioRef.current.currentTime - ms / 1000, 0)\n audioRef.current.currentTime = newTime\n }\n },\n setVolume: (volume: number) => {\n setVolume(volume)\n if (gainNode) {\n gainNode.gain.setValueAtTime(volume, context?.currentTime || 0)\n }\n },\n nextPlayMode: (_mode?: PlayMode) => {\n const currentIndex = MODES.indexOf(playMode)\n const nextIndex = (currentIndex + 1) % MODES.length\n const mode = _mode || MODES[nextIndex]\n setPlayMode(mode)\n },\n setPlaybackRate: (rate: number) => {\n rate = Math.min(Math.max(rate, 0.5), 3.0)\n setPlaybackRate(rate)\n if (audioRef.current) {\n audioRef.current.playbackRate = rate\n }\n },\n switchAudio: setPlayingIndex\n }\n\n return {\n state,\n controls,\n }\n}\n","\n/**\n * Generates a random index between the given index and length (inclusive)\n * If the generated random number equals the input index, recursively generates a new one\n * \n * @param index - The starting index (minimum value)\n * @param length - The maximum length (maximum value)\n * @returns A random number between index and length, excluding the input index\n */\nexport const randomPlayingIndex = (index: number, length: number): number => {\n const random = Math.floor(Math.random() * (length - index + 1)) + index\n if (random === index) {\n return randomPlayingIndex(index, length)\n }\n return random\n}"]}