@lucaismyname/ginger 0.0.13 → 0.0.15
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 +80 -2
- package/dist/{GingerSplitContexts-4YZ-OJ9V.js → GingerSplitContexts-BzBExb95.js} +22 -21
- package/dist/GingerSplitContexts-BzBExb95.js.map +1 -0
- package/dist/GingerSplitContexts-C7puo0M7.cjs +2 -0
- package/dist/GingerSplitContexts-C7puo0M7.cjs.map +1 -0
- package/dist/analyzer/liveAudioGraph.d.ts +14 -0
- package/dist/analyzer/liveAudioGraph.d.ts.map +1 -0
- package/dist/analyzer/useGingerLiveAnalyzer.d.ts +21 -0
- package/dist/analyzer/useGingerLiveAnalyzer.d.ts.map +1 -0
- package/dist/audio/GingerPlayer.d.ts.map +1 -1
- package/dist/audio/GingerPlayer.test.d.ts +2 -0
- package/dist/audio/GingerPlayer.test.d.ts.map +1 -0
- package/dist/client.cjs +1 -1
- package/dist/client.js +21 -18
- package/dist/context/GingerContext.d.ts +2 -1
- package/dist/context/GingerContext.d.ts.map +1 -1
- package/dist/context/GingerProvider.d.ts.map +1 -1
- package/dist/context/GingerSplitContexts.d.ts +2 -1
- package/dist/context/GingerSplitContexts.d.ts.map +1 -1
- package/dist/core/playbackReducer.d.ts.map +1 -1
- package/dist/core/queue.d.ts.map +1 -1
- package/dist/experimental-gapless/index.cjs +1 -1
- package/dist/experimental-gapless/index.js +1 -1
- package/dist/ginger-BTPRqWHs.js +1621 -0
- package/dist/ginger-BTPRqWHs.js.map +1 -0
- package/dist/ginger-BiI69vrn.cjs +2 -0
- package/dist/ginger-BiI69vrn.cjs.map +1 -0
- package/dist/hooks/hooks.test.d.ts +2 -0
- package/dist/hooks/hooks.test.d.ts.map +1 -0
- package/dist/hooks/useGinger.d.ts +1 -0
- package/dist/hooks/useGinger.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -18
- package/dist/internal/fft.d.ts +7 -0
- package/dist/internal/fft.d.ts.map +1 -0
- package/dist/internal/fft.test.d.ts +2 -0
- package/dist/internal/fft.test.d.ts.map +1 -0
- package/dist/media/useMediaSession.d.ts.map +1 -1
- package/dist/media/useMediaSession.test.d.ts +2 -0
- package/dist/media/useMediaSession.test.d.ts.map +1 -0
- package/dist/testing/helpers.d.ts +21 -0
- package/dist/testing/helpers.d.ts.map +1 -0
- package/dist/testing/index.cjs +19 -19
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.ts +2 -7
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +33 -4
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/renderGinger.d.ts +8 -0
- package/dist/testing/renderGinger.d.ts.map +1 -0
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/useSeekDrag-Br1V0Vao.js +290 -0
- package/dist/useSeekDrag-Br1V0Vao.js.map +1 -0
- package/dist/useSeekDrag-aS7uk26h.cjs +2 -0
- package/dist/useSeekDrag-aS7uk26h.cjs.map +1 -0
- package/dist/waveform/analyzeAudioFile.d.ts +31 -0
- package/dist/waveform/analyzeAudioFile.d.ts.map +1 -0
- package/dist/waveform/analyzeAudioFile.test.d.ts +2 -0
- package/dist/waveform/analyzeAudioFile.test.d.ts.map +1 -0
- package/dist/waveform/index.cjs +1 -1
- package/dist/waveform/index.cjs.map +1 -1
- package/dist/waveform/index.d.ts +4 -0
- package/dist/waveform/index.d.ts.map +1 -1
- package/dist/waveform/index.js +207 -23
- package/dist/waveform/index.js.map +1 -1
- package/dist/waveform/useAudioFileAnalysis.d.ts +8 -0
- package/dist/waveform/useAudioFileAnalysis.d.ts.map +1 -0
- package/package.json +4 -1
- package/dist/GingerSplitContexts-4YZ-OJ9V.js.map +0 -1
- package/dist/GingerSplitContexts-Bze1Bqe2.cjs +0 -2
- package/dist/GingerSplitContexts-Bze1Bqe2.cjs.map +0 -1
- package/dist/ginger-DYoHDn8T.cjs +0 -2
- package/dist/ginger-DYoHDn8T.cjs.map +0 -1
- package/dist/ginger-Dntdd6zH.js +0 -1599
- package/dist/ginger-Dntdd6zH.js.map +0 -1
- package/dist/useSeekDrag-DBzoym0-.cjs +0 -2
- package/dist/useSeekDrag-DBzoym0-.cjs.map +0 -1
- package/dist/useSeekDrag-jLsYA-uG.js +0 -174
- package/dist/useSeekDrag-jLsYA-uG.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../../src/waveform/useAudioPeaks.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\nexport type UseAudioPeaksState = {\n peaks: number[];\n isLoading: boolean;\n error: string | null;\n};\n\nexport function useAudioPeaks(fileUrl: string | null | undefined, buckets = 64): UseAudioPeaksState {\n const [state, setState] = useState<UseAudioPeaksState>({\n peaks: [],\n isLoading: false,\n error: null,\n });\n\n useEffect(() => {\n if (!fileUrl) {\n setState({ peaks: [], isLoading: false, error: null });\n return;\n }\n let cancelled = false;\n setState((prev) => ({ ...prev, isLoading: true, error: null }));\n void (async () => {\n try {\n const response = await fetch(fileUrl);\n if (!response.ok) throw new Error(`Fetch failed: ${response.status} ${response.statusText}`);\n const buffer = await response.arrayBuffer();\n const audioContext = new AudioContext();\n const audioBuffer = await audioContext.decodeAudioData(buffer);\n const channel = audioBuffer.getChannelData(0);\n const step = Math.max(1, Math.floor(channel.length / buckets));\n const peaks: number[] = [];\n for (let i = 0; i < buckets; i += 1) {\n let max = 0;\n const start = i * step;\n const end = Math.min(channel.length, start + step);\n for (let j = start; j < end; j += 1) {\n max = Math.max(max, Math.abs(channel[j] ?? 0));\n }\n peaks.push(max);\n }\n await audioContext.close();\n if (!cancelled) {\n setState({ peaks, isLoading: false, error: null });\n }\n } catch (error) {\n if (!cancelled) {\n setState({\n peaks: [],\n isLoading: false,\n error: error instanceof Error ? error.message : \"Failed to decode peaks\",\n });\n }\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, [buckets, fileUrl]);\n\n return state;\n}\n"],"names":["useAudioPeaks","fileUrl","buckets","state","setState","useState","useEffect","cancelled","prev","response","buffer","audioContext","channel","step","peaks","i","max","start","end","j","error"],"mappings":"yGAQO,SAASA,EAAcC,EAAoCC,EAAU,GAAwB,CAClG,KAAM,CAACC,EAAOC,CAAQ,EAAIC,WAA6B,CACrD,MAAO,CAAA,EACP,UAAW,GACX,MAAO,IAAA,CACR,EAEDC,OAAAA,EAAAA,UAAU,IAAM,CACd,GAAI,CAACL,EAAS,CACZG,EAAS,CAAE,MAAO,CAAA,EAAI,UAAW,GAAO,MAAO,KAAM,EACrD,MACF,CACA,IAAIG,EAAY,GAChB,OAAAH,EAAUI,IAAU,CAAE,GAAGA,EAAM,UAAW,GAAM,MAAO,IAAA,EAAO,GACxD,SAAY,CAChB,GAAI,CACF,MAAMC,EAAW,MAAM,MAAMR,CAAO,EACpC,GAAI,CAACQ,EAAS,GAAI,MAAM,IAAI,MAAM,iBAAiBA,EAAS,MAAM,IAAIA,EAAS,UAAU,EAAE,EAC3F,MAAMC,EAAS,MAAMD,EAAS,YAAA,EACxBE,EAAe,IAAI,aAEnBC,GADc,MAAMD,EAAa,gBAAgBD,CAAM,GACjC,eAAe,CAAC,EACtCG,EAAO,KAAK,IAAI,EAAG,KAAK,MAAMD,EAAQ,OAASV,CAAO,CAAC,EACvDY,EAAkB,CAAA,EACxB,QAASC,EAAI,EAAGA,EAAIb,EAASa,GAAK,EAAG,CACnC,IAAIC,EAAM,EACV,MAAMC,EAAQF,EAAIF,EACZK,EAAM,KAAK,IAAIN,EAAQ,OAAQK,EAAQJ,CAAI,EACjD,QAASM,EAAIF,EAAOE,EAAID,EAAKC,GAAK,EAChCH,EAAM,KAAK,IAAIA,EAAK,KAAK,IAAIJ,EAAQO,CAAC,GAAK,CAAC,CAAC,EAE/CL,EAAM,KAAKE,CAAG,CAChB,CACA,MAAML,EAAa,MAAA,EACdJ,GACHH,EAAS,CAAE,MAAAU,EAAO,UAAW,GAAO,MAAO,KAAM,CAErD,OAASM,EAAO,CACTb,GACHH,EAAS,CACP,MAAO,CAAA,EACP,UAAW,GACX,MAAOgB,aAAiB,MAAQA,EAAM,QAAU,wBAAA,CACjD,CAEL,CACF,GAAA,EAEO,IAAM,CACXb,EAAY,EACd,CACF,EAAG,CAACL,EAASD,CAAO,CAAC,EAEdE,CACT"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../src/waveform/useAudioPeaks.ts","../../src/internal/fft.ts","../../src/waveform/analyzeAudioFile.ts","../../src/waveform/useAudioFileAnalysis.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\nexport type UseAudioPeaksState = {\n peaks: number[];\n isLoading: boolean;\n error: string | null;\n};\n\nexport function useAudioPeaks(fileUrl: string | null | undefined, buckets = 64): UseAudioPeaksState {\n const [state, setState] = useState<UseAudioPeaksState>({\n peaks: [],\n isLoading: false,\n error: null,\n });\n\n useEffect(() => {\n if (!fileUrl) {\n setState({ peaks: [], isLoading: false, error: null });\n return;\n }\n let cancelled = false;\n setState((prev) => ({ ...prev, isLoading: true, error: null }));\n void (async () => {\n try {\n const response = await fetch(fileUrl);\n if (!response.ok) throw new Error(`Fetch failed: ${response.status} ${response.statusText}`);\n const buffer = await response.arrayBuffer();\n const audioContext = new AudioContext();\n const audioBuffer = await audioContext.decodeAudioData(buffer);\n const channel = audioBuffer.getChannelData(0);\n const step = Math.max(1, Math.floor(channel.length / buckets));\n const peaks: number[] = [];\n for (let i = 0; i < buckets; i += 1) {\n let max = 0;\n const start = i * step;\n const end = Math.min(channel.length, start + step);\n for (let j = start; j < end; j += 1) {\n max = Math.max(max, Math.abs(channel[j] ?? 0));\n }\n peaks.push(max);\n }\n await audioContext.close();\n if (!cancelled) {\n setState({ peaks, isLoading: false, error: null });\n }\n } catch (error) {\n if (!cancelled) {\n setState({\n peaks: [],\n isLoading: false,\n error: error instanceof Error ? error.message : \"Failed to decode peaks\",\n });\n }\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, [buckets, fileUrl]);\n\n return state;\n}\n","/** In-place radix-2 Cooley–Tukey FFT; `length` must be a power of 2 and >= 2. */\nexport function fftInPlace(re: Float64Array, im: Float64Array): void {\n const n = re.length;\n if (n !== im.length || n < 2 || (n & (n - 1)) !== 0) {\n throw new Error(\"fftInPlace: length must be equal powers of 2 >= 2\");\n }\n\n let j = 0;\n for (let i = 0; i < n - 1; i += 1) {\n if (i < j) {\n const tr = re[i]!;\n const ti = im[i]!;\n re[i] = re[j]!;\n im[i] = im[j]!;\n re[j] = tr;\n im[j] = ti;\n }\n let k = n >> 1;\n while (k <= j) {\n j -= k;\n k >>= 1;\n }\n j += k;\n }\n\n for (let len = 2; len <= n; len <<= 1) {\n const ang = (-2 * Math.PI) / len;\n const wlenR = Math.cos(ang);\n const wlenI = Math.sin(ang);\n for (let i = 0; i < n; i += len) {\n let wr = 1;\n let wi = 0;\n const half = len >> 1;\n for (let k = 0; k < half; k += 1) {\n const u = i + k;\n const v = u + half;\n const tr = wr * re[v]! - wi * im[v]!;\n const ti = wr * im[v]! + wi * re[v]!;\n re[v] = re[u]! - tr;\n im[v] = im[u]! - ti;\n re[u] = re[u]! + tr;\n im[u] = im[u]! + ti;\n const nwr = wr * wlenR - wi * wlenI;\n const nwi = wr * wlenI + wi * wlenR;\n wr = nwr;\n wi = nwi;\n }\n }\n }\n}\n\n/** Magnitude spectrum for real input: length `n` (power of 2). Returns `n/2` magnitudes for bins 0..n/2-1. */\nexport function realFftMagnitudes(samples: Float64Array): Float64Array {\n const n = samples.length;\n if (n < 2 || (n & (n - 1)) !== 0) {\n throw new Error(\"realFftMagnitudes: length must be a power of 2 >= 2\");\n }\n const re = new Float64Array(n);\n const im = new Float64Array(n);\n for (let i = 0; i < n; i += 1) re[i] = samples[i]!;\n fftInPlace(re, im);\n const out = new Float64Array(n >> 1);\n for (let k = 0; k < n >> 1; k += 1) {\n out[k] = Math.hypot(re[k]!, im[k]!);\n }\n return out;\n}\n\nexport function hanningWindow(length: number): Float64Array {\n const w = new Float64Array(length);\n if (length === 1) {\n w[0] = 1;\n return w;\n }\n const denom = length - 1;\n for (let i = 0; i < length; i += 1) {\n w[i] = 0.5 * (1 - Math.cos((2 * Math.PI * i) / denom));\n }\n return w;\n}\n\nexport function clampFftSize(n: number): number {\n const p = 2 ** Math.round(Math.log2(n));\n return Math.min(8192, Math.max(32, p));\n}\n","import { clampFftSize, hanningWindow, realFftMagnitudes } from \"../internal/fft\";\n\nexport type AnalyzeAudioFileOptions = {\n /** Number of time rows in the amplitude grid (and spectrogram if enabled). Default 128. */\n timeSlices?: number;\n /** Sub-buckets per time slice for the amplitude grid. Default 8. */\n samplesPerSlice?: number;\n /** When true, include `spectrogram` using windowed FFT per time slice. Default false. */\n spectrogram?: boolean;\n /** FFT length for spectrogram (power of 2). Default 1024. */\n fftSize?: number;\n /** Number of frequency bins to keep per row (first bins; capped by fftSize/2). Default 256. */\n frequencyBins?: number;\n /** Channel index, or `\"mix\"` for equal mix of all channels. Default 0. */\n channel?: number | \"mix\";\n};\n\nexport type AudioFileAnalysis = {\n duration: number;\n sampleRate: number;\n /** Peak amplitudes in [0, 1]: `timeSlices` rows × `samplesPerSlice` columns. */\n amplitudeGrid: number[][];\n /** Optional magnitude spectrogram rows, each length `frequencyBins`, normalized to [0, 1] globally. */\n spectrogram?: number[][];\n};\n\nfunction mixChannels(buffer: AudioBuffer): Float32Array {\n const { numberOfChannels, length } = buffer;\n if (numberOfChannels === 1) {\n return buffer.getChannelData(0);\n }\n const out = new Float32Array(length);\n const scale = 1 / numberOfChannels;\n for (let c = 0; c < numberOfChannels; c += 1) {\n const ch = buffer.getChannelData(c);\n for (let i = 0; i < length; i += 1) {\n out[i] += ch[i]! * scale;\n }\n }\n return out;\n}\n\nfunction getChannel(buffer: AudioBuffer, channel: number | \"mix\"): Float32Array {\n if (channel === \"mix\") return mixChannels(buffer);\n const idx = Math.max(0, Math.min(buffer.numberOfChannels - 1, channel));\n return buffer.getChannelData(idx);\n}\n\nfunction buildAmplitudeGrid(\n channel: Float32Array,\n timeSlices: number,\n samplesPerSlice: number,\n): number[][] {\n const grid: number[][] = [];\n const len = channel.length;\n if (len === 0) {\n for (let t = 0; t < timeSlices; t += 1) {\n grid.push(Array.from({ length: samplesPerSlice }, () => 0));\n }\n return grid;\n }\n\n const segmentLen = len / timeSlices;\n\n for (let t = 0; t < timeSlices; t += 1) {\n const row: number[] = [];\n const segStart = Math.floor(t * segmentLen);\n const segEnd = Math.floor((t + 1) * segmentLen);\n const segLen = Math.max(1, segEnd - segStart);\n const subLen = segLen / samplesPerSlice;\n\n for (let s = 0; s < samplesPerSlice; s += 1) {\n const a = Math.floor(segStart + s * subLen);\n const b = Math.min(segEnd, Math.floor(segStart + (s + 1) * subLen));\n let peak = 0;\n for (let i = a; i < b; i += 1) {\n peak = Math.max(peak, Math.abs(channel[i] ?? 0));\n }\n row.push(peak);\n }\n grid.push(row);\n }\n return grid;\n}\n\nfunction buildSpectrogram(\n channel: Float32Array,\n timeSlices: number,\n fftSize: number,\n frequencyBins: number,\n): { rows: number[][]; maxMag: number } {\n const rows: number[][] = [];\n let maxMag = 1e-12;\n const len = channel.length;\n const n = clampFftSize(fftSize);\n const half = n >> 1;\n const bins = Math.min(frequencyBins, half);\n const window = hanningWindow(n);\n\n if (len < n) {\n for (let t = 0; t < timeSlices; t += 1) {\n rows.push(Array.from({ length: bins }, () => 0));\n }\n return { rows, maxMag: 1 };\n }\n\n for (let t = 0; t < timeSlices; t += 1) {\n const start =\n timeSlices <= 1\n ? 0\n : Math.min(Math.floor((t * (len - n)) / (timeSlices - 1)), len - n);\n const frame = new Float64Array(n);\n for (let i = 0; i < n; i += 1) {\n frame[i] = (channel[start + i] ?? 0) * (window[i] ?? 0);\n }\n const mags = realFftMagnitudes(frame);\n const row: number[] = [];\n for (let k = 0; k < bins; k += 1) {\n const v = mags[k] ?? 0;\n row.push(v);\n maxMag = Math.max(maxMag, v);\n }\n rows.push(row);\n }\n\n return { rows, maxMag };\n}\n\n/**\n * Decodes an `AudioBuffer` into visualization-friendly grids (no network).\n */\nexport function analyzeAudioBuffer(buffer: AudioBuffer, options: AnalyzeAudioFileOptions = {}): AudioFileAnalysis {\n const timeSlices = Math.max(1, options.timeSlices ?? 128);\n const samplesPerSlice = Math.max(1, options.samplesPerSlice ?? 8);\n const wantSpec = Boolean(options.spectrogram);\n const fftSize = options.fftSize ?? 1024;\n const frequencyBins = Math.max(1, options.frequencyBins ?? 256);\n const channel = options.channel ?? 0;\n\n const data = getChannel(buffer, channel);\n const amplitudeGrid = buildAmplitudeGrid(data, timeSlices, samplesPerSlice);\n\n const result: AudioFileAnalysis = {\n duration: buffer.duration,\n sampleRate: buffer.sampleRate,\n amplitudeGrid,\n };\n\n if (wantSpec) {\n const { rows, maxMag } = buildSpectrogram(data, timeSlices, fftSize, frequencyBins);\n const norm = maxMag > 0 ? 1 / maxMag : 1;\n result.spectrogram = rows.map((row) => row.map((v) => v * norm));\n }\n\n return result;\n}\n\n/**\n * Fetches a URL, decodes audio to an `AudioBuffer`, runs {@link analyzeAudioBuffer}, then closes the temporary `AudioContext`.\n */\nexport async function analyzeAudioFile(\n fileUrl: string,\n options: AnalyzeAudioFileOptions = {},\n): Promise<AudioFileAnalysis> {\n const response = await fetch(fileUrl);\n if (!response.ok) {\n throw new Error(`Fetch failed: ${response.status} ${response.statusText}`);\n }\n const raw = await response.arrayBuffer();\n const Context = window.AudioContext ?? (window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n if (!Context) {\n throw new Error(\"Web Audio API is not available\");\n }\n const audioContext = new Context();\n try {\n const buffer = await audioContext.decodeAudioData(raw.slice(0));\n return analyzeAudioBuffer(buffer, options);\n } finally {\n await audioContext.close();\n }\n}\n","import { useEffect, useState } from \"react\";\nimport { analyzeAudioFile, type AnalyzeAudioFileOptions, type AudioFileAnalysis } from \"./analyzeAudioFile\";\n\nexport type UseAudioFileAnalysisState = {\n data: AudioFileAnalysis | null;\n isLoading: boolean;\n error: string | null;\n};\n\nexport function useAudioFileAnalysis(\n fileUrl: string | null | undefined,\n options: AnalyzeAudioFileOptions = {},\n): UseAudioFileAnalysisState {\n const [state, setState] = useState<UseAudioFileAnalysisState>({\n data: null,\n isLoading: false,\n error: null,\n });\n\n useEffect(() => {\n if (!fileUrl) {\n setState({ data: null, isLoading: false, error: null });\n return;\n }\n if (typeof window === \"undefined\") {\n setState({ data: null, isLoading: false, error: null });\n return;\n }\n\n let cancelled = false;\n setState((prev) => ({ ...prev, isLoading: true, error: null }));\n\n void (async () => {\n try {\n const data = await analyzeAudioFile(fileUrl, options);\n if (!cancelled) {\n setState({ data, isLoading: false, error: null });\n }\n } catch (error) {\n if (!cancelled) {\n setState({\n data: null,\n isLoading: false,\n error: error instanceof Error ? error.message : \"Failed to analyze audio file\",\n });\n }\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, [\n fileUrl,\n options.timeSlices,\n options.samplesPerSlice,\n options.spectrogram,\n options.fftSize,\n options.frequencyBins,\n options.channel,\n ]);\n\n return state;\n}\n"],"names":["useAudioPeaks","fileUrl","buckets","state","setState","useState","useEffect","cancelled","prev","response","buffer","audioContext","channel","step","peaks","i","max","start","end","j","error","fftInPlace","re","im","n","tr","ti","k","len","ang","wlenR","wlenI","wr","wi","half","u","v","nwr","nwi","realFftMagnitudes","samples","out","hanningWindow","length","w","denom","clampFftSize","p","mixChannels","numberOfChannels","scale","c","ch","getChannel","idx","buildAmplitudeGrid","timeSlices","samplesPerSlice","grid","t","segmentLen","row","segStart","segEnd","subLen","s","a","b","peak","buildSpectrogram","fftSize","frequencyBins","rows","maxMag","bins","window","frame","mags","analyzeAudioBuffer","options","wantSpec","data","amplitudeGrid","result","norm","analyzeAudioFile","raw","Context","useAudioFileAnalysis"],"mappings":"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"}
|
package/dist/waveform/index.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
export { useAudioPeaks } from './useAudioPeaks';
|
|
2
2
|
export type { UseAudioPeaksState } from './useAudioPeaks';
|
|
3
|
+
export { analyzeAudioBuffer, analyzeAudioFile } from './analyzeAudioFile';
|
|
4
|
+
export type { AnalyzeAudioFileOptions, AudioFileAnalysis } from './analyzeAudioFile';
|
|
5
|
+
export { useAudioFileAnalysis } from './useAudioFileAnalysis';
|
|
6
|
+
export type { UseAudioFileAnalysisState } from './useAudioFileAnalysis';
|
|
3
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/waveform/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/waveform/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,YAAY,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACrF,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC"}
|
package/dist/waveform/index.js
CHANGED
|
@@ -1,42 +1,226 @@
|
|
|
1
|
-
import { useState as
|
|
2
|
-
function
|
|
3
|
-
const [
|
|
1
|
+
import { useState as x, useEffect as y } from "react";
|
|
2
|
+
function D(e, t = 64) {
|
|
3
|
+
const [r, a] = x({
|
|
4
4
|
peaks: [],
|
|
5
5
|
isLoading: !1,
|
|
6
6
|
error: null
|
|
7
7
|
});
|
|
8
|
-
return
|
|
9
|
-
if (!
|
|
10
|
-
|
|
8
|
+
return y(() => {
|
|
9
|
+
if (!e) {
|
|
10
|
+
a({ peaks: [], isLoading: !1, error: null });
|
|
11
11
|
return;
|
|
12
12
|
}
|
|
13
|
-
let
|
|
14
|
-
return
|
|
13
|
+
let o = !1;
|
|
14
|
+
return a((n) => ({ ...n, isLoading: !0, error: null })), (async () => {
|
|
15
15
|
try {
|
|
16
|
-
const
|
|
17
|
-
if (!
|
|
18
|
-
const
|
|
19
|
-
for (let
|
|
16
|
+
const n = await fetch(e);
|
|
17
|
+
if (!n.ok) throw new Error(`Fetch failed: ${n.status} ${n.statusText}`);
|
|
18
|
+
const l = await n.arrayBuffer(), s = new AudioContext(), f = (await s.decodeAudioData(l)).getChannelData(0), w = Math.max(1, Math.floor(f.length / t)), u = [];
|
|
19
|
+
for (let h = 0; h < t; h += 1) {
|
|
20
20
|
let i = 0;
|
|
21
|
-
const d =
|
|
22
|
-
for (let
|
|
23
|
-
i = Math.max(i, Math.abs(
|
|
24
|
-
|
|
21
|
+
const d = h * w, m = Math.min(f.length, d + w);
|
|
22
|
+
for (let c = d; c < m; c += 1)
|
|
23
|
+
i = Math.max(i, Math.abs(f[c] ?? 0));
|
|
24
|
+
u.push(i);
|
|
25
25
|
}
|
|
26
|
-
await
|
|
27
|
-
} catch (
|
|
28
|
-
|
|
26
|
+
await s.close(), o || a({ peaks: u, isLoading: !1, error: null });
|
|
27
|
+
} catch (n) {
|
|
28
|
+
o || a({
|
|
29
29
|
peaks: [],
|
|
30
30
|
isLoading: !1,
|
|
31
|
-
error:
|
|
31
|
+
error: n instanceof Error ? n.message : "Failed to decode peaks"
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
34
|
})(), () => {
|
|
35
|
-
|
|
35
|
+
o = !0;
|
|
36
36
|
};
|
|
37
|
-
}, [
|
|
37
|
+
}, [t, e]), r;
|
|
38
|
+
}
|
|
39
|
+
function A(e, t) {
|
|
40
|
+
const r = e.length;
|
|
41
|
+
if (r !== t.length || r < 2 || r & r - 1)
|
|
42
|
+
throw new Error("fftInPlace: length must be equal powers of 2 >= 2");
|
|
43
|
+
let a = 0;
|
|
44
|
+
for (let o = 0; o < r - 1; o += 1) {
|
|
45
|
+
if (o < a) {
|
|
46
|
+
const l = e[o], s = t[o];
|
|
47
|
+
e[o] = e[a], t[o] = t[a], e[a] = l, t[a] = s;
|
|
48
|
+
}
|
|
49
|
+
let n = r >> 1;
|
|
50
|
+
for (; n <= a; )
|
|
51
|
+
a -= n, n >>= 1;
|
|
52
|
+
a += n;
|
|
53
|
+
}
|
|
54
|
+
for (let o = 2; o <= r; o <<= 1) {
|
|
55
|
+
const n = -2 * Math.PI / o, l = Math.cos(n), s = Math.sin(n);
|
|
56
|
+
for (let g = 0; g < r; g += o) {
|
|
57
|
+
let f = 1, w = 0;
|
|
58
|
+
const u = o >> 1;
|
|
59
|
+
for (let h = 0; h < u; h += 1) {
|
|
60
|
+
const i = g + h, d = i + u, m = f * e[d] - w * t[d], c = f * t[d] + w * e[d];
|
|
61
|
+
e[d] = e[i] - m, t[d] = t[i] - c, e[i] = e[i] + m, t[i] = t[i] + c;
|
|
62
|
+
const M = f * l - w * s, p = f * s + w * l;
|
|
63
|
+
f = M, w = p;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function F(e) {
|
|
69
|
+
const t = e.length;
|
|
70
|
+
if (t < 2 || t & t - 1)
|
|
71
|
+
throw new Error("realFftMagnitudes: length must be a power of 2 >= 2");
|
|
72
|
+
const r = new Float64Array(t), a = new Float64Array(t);
|
|
73
|
+
for (let n = 0; n < t; n += 1) r[n] = e[n];
|
|
74
|
+
A(r, a);
|
|
75
|
+
const o = new Float64Array(t >> 1);
|
|
76
|
+
for (let n = 0; n < t >> 1; n += 1)
|
|
77
|
+
o[n] = Math.hypot(r[n], a[n]);
|
|
78
|
+
return o;
|
|
79
|
+
}
|
|
80
|
+
function L(e) {
|
|
81
|
+
const t = new Float64Array(e);
|
|
82
|
+
if (e === 1)
|
|
83
|
+
return t[0] = 1, t;
|
|
84
|
+
const r = e - 1;
|
|
85
|
+
for (let a = 0; a < e; a += 1)
|
|
86
|
+
t[a] = 0.5 * (1 - Math.cos(2 * Math.PI * a / r));
|
|
87
|
+
return t;
|
|
88
|
+
}
|
|
89
|
+
function C(e) {
|
|
90
|
+
const t = 2 ** Math.round(Math.log2(e));
|
|
91
|
+
return Math.min(8192, Math.max(32, t));
|
|
92
|
+
}
|
|
93
|
+
function k(e) {
|
|
94
|
+
const { numberOfChannels: t, length: r } = e;
|
|
95
|
+
if (t === 1)
|
|
96
|
+
return e.getChannelData(0);
|
|
97
|
+
const a = new Float32Array(r), o = 1 / t;
|
|
98
|
+
for (let n = 0; n < t; n += 1) {
|
|
99
|
+
const l = e.getChannelData(n);
|
|
100
|
+
for (let s = 0; s < r; s += 1)
|
|
101
|
+
a[s] += l[s] * o;
|
|
102
|
+
}
|
|
103
|
+
return a;
|
|
104
|
+
}
|
|
105
|
+
function B(e, t) {
|
|
106
|
+
if (t === "mix") return k(e);
|
|
107
|
+
const r = Math.max(0, Math.min(e.numberOfChannels - 1, t));
|
|
108
|
+
return e.getChannelData(r);
|
|
109
|
+
}
|
|
110
|
+
function E(e, t, r) {
|
|
111
|
+
const a = [], o = e.length;
|
|
112
|
+
if (o === 0) {
|
|
113
|
+
for (let l = 0; l < t; l += 1)
|
|
114
|
+
a.push(Array.from({ length: r }, () => 0));
|
|
115
|
+
return a;
|
|
116
|
+
}
|
|
117
|
+
const n = o / t;
|
|
118
|
+
for (let l = 0; l < t; l += 1) {
|
|
119
|
+
const s = [], g = Math.floor(l * n), f = Math.floor((l + 1) * n), u = Math.max(1, f - g) / r;
|
|
120
|
+
for (let h = 0; h < r; h += 1) {
|
|
121
|
+
const i = Math.floor(g + h * u), d = Math.min(f, Math.floor(g + (h + 1) * u));
|
|
122
|
+
let m = 0;
|
|
123
|
+
for (let c = i; c < d; c += 1)
|
|
124
|
+
m = Math.max(m, Math.abs(e[c] ?? 0));
|
|
125
|
+
s.push(m);
|
|
126
|
+
}
|
|
127
|
+
a.push(s);
|
|
128
|
+
}
|
|
129
|
+
return a;
|
|
130
|
+
}
|
|
131
|
+
function S(e, t, r, a) {
|
|
132
|
+
const o = [];
|
|
133
|
+
let n = 1e-12;
|
|
134
|
+
const l = e.length, s = C(r), g = s >> 1, f = Math.min(a, g), w = L(s);
|
|
135
|
+
if (l < s) {
|
|
136
|
+
for (let u = 0; u < t; u += 1)
|
|
137
|
+
o.push(Array.from({ length: f }, () => 0));
|
|
138
|
+
return { rows: o, maxMag: 1 };
|
|
139
|
+
}
|
|
140
|
+
for (let u = 0; u < t; u += 1) {
|
|
141
|
+
const h = t <= 1 ? 0 : Math.min(Math.floor(u * (l - s) / (t - 1)), l - s), i = new Float64Array(s);
|
|
142
|
+
for (let c = 0; c < s; c += 1)
|
|
143
|
+
i[c] = (e[h + c] ?? 0) * (w[c] ?? 0);
|
|
144
|
+
const d = F(i), m = [];
|
|
145
|
+
for (let c = 0; c < f; c += 1) {
|
|
146
|
+
const M = d[c] ?? 0;
|
|
147
|
+
m.push(M), n = Math.max(n, M);
|
|
148
|
+
}
|
|
149
|
+
o.push(m);
|
|
150
|
+
}
|
|
151
|
+
return { rows: o, maxMag: n };
|
|
152
|
+
}
|
|
153
|
+
function b(e, t = {}) {
|
|
154
|
+
const r = Math.max(1, t.timeSlices ?? 128), a = Math.max(1, t.samplesPerSlice ?? 8), o = !!t.spectrogram, n = t.fftSize ?? 1024, l = Math.max(1, t.frequencyBins ?? 256), s = t.channel ?? 0, g = B(e, s), f = E(g, r, a), w = {
|
|
155
|
+
duration: e.duration,
|
|
156
|
+
sampleRate: e.sampleRate,
|
|
157
|
+
amplitudeGrid: f
|
|
158
|
+
};
|
|
159
|
+
if (o) {
|
|
160
|
+
const { rows: u, maxMag: h } = S(g, r, n, l), i = h > 0 ? 1 / h : 1;
|
|
161
|
+
w.spectrogram = u.map((d) => d.map((m) => m * i));
|
|
162
|
+
}
|
|
163
|
+
return w;
|
|
164
|
+
}
|
|
165
|
+
async function z(e, t = {}) {
|
|
166
|
+
const r = await fetch(e);
|
|
167
|
+
if (!r.ok)
|
|
168
|
+
throw new Error(`Fetch failed: ${r.status} ${r.statusText}`);
|
|
169
|
+
const a = await r.arrayBuffer(), o = window.AudioContext ?? window.webkitAudioContext;
|
|
170
|
+
if (!o)
|
|
171
|
+
throw new Error("Web Audio API is not available");
|
|
172
|
+
const n = new o();
|
|
173
|
+
try {
|
|
174
|
+
const l = await n.decodeAudioData(a.slice(0));
|
|
175
|
+
return b(l, t);
|
|
176
|
+
} finally {
|
|
177
|
+
await n.close();
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function I(e, t = {}) {
|
|
181
|
+
const [r, a] = x({
|
|
182
|
+
data: null,
|
|
183
|
+
isLoading: !1,
|
|
184
|
+
error: null
|
|
185
|
+
});
|
|
186
|
+
return y(() => {
|
|
187
|
+
if (!e) {
|
|
188
|
+
a({ data: null, isLoading: !1, error: null });
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
if (typeof window > "u") {
|
|
192
|
+
a({ data: null, isLoading: !1, error: null });
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
let o = !1;
|
|
196
|
+
return a((n) => ({ ...n, isLoading: !0, error: null })), (async () => {
|
|
197
|
+
try {
|
|
198
|
+
const n = await z(e, t);
|
|
199
|
+
o || a({ data: n, isLoading: !1, error: null });
|
|
200
|
+
} catch (n) {
|
|
201
|
+
o || a({
|
|
202
|
+
data: null,
|
|
203
|
+
isLoading: !1,
|
|
204
|
+
error: n instanceof Error ? n.message : "Failed to analyze audio file"
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
})(), () => {
|
|
208
|
+
o = !0;
|
|
209
|
+
};
|
|
210
|
+
}, [
|
|
211
|
+
e,
|
|
212
|
+
t.timeSlices,
|
|
213
|
+
t.samplesPerSlice,
|
|
214
|
+
t.spectrogram,
|
|
215
|
+
t.fftSize,
|
|
216
|
+
t.frequencyBins,
|
|
217
|
+
t.channel
|
|
218
|
+
]), r;
|
|
38
219
|
}
|
|
39
220
|
export {
|
|
40
|
-
|
|
221
|
+
b as analyzeAudioBuffer,
|
|
222
|
+
z as analyzeAudioFile,
|
|
223
|
+
I as useAudioFileAnalysis,
|
|
224
|
+
D as useAudioPeaks
|
|
41
225
|
};
|
|
42
226
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/waveform/useAudioPeaks.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\nexport type UseAudioPeaksState = {\n peaks: number[];\n isLoading: boolean;\n error: string | null;\n};\n\nexport function useAudioPeaks(fileUrl: string | null | undefined, buckets = 64): UseAudioPeaksState {\n const [state, setState] = useState<UseAudioPeaksState>({\n peaks: [],\n isLoading: false,\n error: null,\n });\n\n useEffect(() => {\n if (!fileUrl) {\n setState({ peaks: [], isLoading: false, error: null });\n return;\n }\n let cancelled = false;\n setState((prev) => ({ ...prev, isLoading: true, error: null }));\n void (async () => {\n try {\n const response = await fetch(fileUrl);\n if (!response.ok) throw new Error(`Fetch failed: ${response.status} ${response.statusText}`);\n const buffer = await response.arrayBuffer();\n const audioContext = new AudioContext();\n const audioBuffer = await audioContext.decodeAudioData(buffer);\n const channel = audioBuffer.getChannelData(0);\n const step = Math.max(1, Math.floor(channel.length / buckets));\n const peaks: number[] = [];\n for (let i = 0; i < buckets; i += 1) {\n let max = 0;\n const start = i * step;\n const end = Math.min(channel.length, start + step);\n for (let j = start; j < end; j += 1) {\n max = Math.max(max, Math.abs(channel[j] ?? 0));\n }\n peaks.push(max);\n }\n await audioContext.close();\n if (!cancelled) {\n setState({ peaks, isLoading: false, error: null });\n }\n } catch (error) {\n if (!cancelled) {\n setState({\n peaks: [],\n isLoading: false,\n error: error instanceof Error ? error.message : \"Failed to decode peaks\",\n });\n }\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, [buckets, fileUrl]);\n\n return state;\n}\n"],"names":["useAudioPeaks","fileUrl","buckets","state","setState","useState","useEffect","cancelled","prev","response","buffer","audioContext","channel","step","peaks","i","max","start","end","j","error"],"mappings":";AAQO,SAASA,EAAcC,GAAoCC,IAAU,IAAwB;AAClG,QAAM,CAACC,GAAOC,CAAQ,IAAIC,EAA6B;AAAA,IACrD,OAAO,CAAA;AAAA,IACP,WAAW;AAAA,IACX,OAAO;AAAA,EAAA,CACR;AAED,SAAAC,EAAU,MAAM;AACd,QAAI,CAACL,GAAS;AACZ,MAAAG,EAAS,EAAE,OAAO,CAAA,GAAI,WAAW,IAAO,OAAO,MAAM;AACrD;AAAA,IACF;AACA,QAAIG,IAAY;AAChB,WAAAH,EAAS,CAACI,OAAU,EAAE,GAAGA,GAAM,WAAW,IAAM,OAAO,KAAA,EAAO,IACxD,YAAY;AAChB,UAAI;AACF,cAAMC,IAAW,MAAM,MAAMR,CAAO;AACpC,YAAI,CAACQ,EAAS,GAAI,OAAM,IAAI,MAAM,iBAAiBA,EAAS,MAAM,IAAIA,EAAS,UAAU,EAAE;AAC3F,cAAMC,IAAS,MAAMD,EAAS,YAAA,GACxBE,IAAe,IAAI,aAAA,GAEnBC,KADc,MAAMD,EAAa,gBAAgBD,CAAM,GACjC,eAAe,CAAC,GACtCG,IAAO,KAAK,IAAI,GAAG,KAAK,MAAMD,EAAQ,SAASV,CAAO,CAAC,GACvDY,IAAkB,CAAA;AACxB,iBAASC,IAAI,GAAGA,IAAIb,GAASa,KAAK,GAAG;AACnC,cAAIC,IAAM;AACV,gBAAMC,IAAQF,IAAIF,GACZK,IAAM,KAAK,IAAIN,EAAQ,QAAQK,IAAQJ,CAAI;AACjD,mBAASM,IAAIF,GAAOE,IAAID,GAAKC,KAAK;AAChC,YAAAH,IAAM,KAAK,IAAIA,GAAK,KAAK,IAAIJ,EAAQO,CAAC,KAAK,CAAC,CAAC;AAE/C,UAAAL,EAAM,KAAKE,CAAG;AAAA,QAChB;AACA,cAAML,EAAa,MAAA,GACdJ,KACHH,EAAS,EAAE,OAAAU,GAAO,WAAW,IAAO,OAAO,MAAM;AAAA,MAErD,SAASM,GAAO;AACd,QAAKb,KACHH,EAAS;AAAA,UACP,OAAO,CAAA;AAAA,UACP,WAAW;AAAA,UACX,OAAOgB,aAAiB,QAAQA,EAAM,UAAU;AAAA,QAAA,CACjD;AAAA,MAEL;AAAA,IACF,GAAA,GAEO,MAAM;AACX,MAAAb,IAAY;AAAA,IACd;AAAA,EACF,GAAG,CAACL,GAASD,CAAO,CAAC,GAEdE;AACT;"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/waveform/useAudioPeaks.ts","../../src/internal/fft.ts","../../src/waveform/analyzeAudioFile.ts","../../src/waveform/useAudioFileAnalysis.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\nexport type UseAudioPeaksState = {\n peaks: number[];\n isLoading: boolean;\n error: string | null;\n};\n\nexport function useAudioPeaks(fileUrl: string | null | undefined, buckets = 64): UseAudioPeaksState {\n const [state, setState] = useState<UseAudioPeaksState>({\n peaks: [],\n isLoading: false,\n error: null,\n });\n\n useEffect(() => {\n if (!fileUrl) {\n setState({ peaks: [], isLoading: false, error: null });\n return;\n }\n let cancelled = false;\n setState((prev) => ({ ...prev, isLoading: true, error: null }));\n void (async () => {\n try {\n const response = await fetch(fileUrl);\n if (!response.ok) throw new Error(`Fetch failed: ${response.status} ${response.statusText}`);\n const buffer = await response.arrayBuffer();\n const audioContext = new AudioContext();\n const audioBuffer = await audioContext.decodeAudioData(buffer);\n const channel = audioBuffer.getChannelData(0);\n const step = Math.max(1, Math.floor(channel.length / buckets));\n const peaks: number[] = [];\n for (let i = 0; i < buckets; i += 1) {\n let max = 0;\n const start = i * step;\n const end = Math.min(channel.length, start + step);\n for (let j = start; j < end; j += 1) {\n max = Math.max(max, Math.abs(channel[j] ?? 0));\n }\n peaks.push(max);\n }\n await audioContext.close();\n if (!cancelled) {\n setState({ peaks, isLoading: false, error: null });\n }\n } catch (error) {\n if (!cancelled) {\n setState({\n peaks: [],\n isLoading: false,\n error: error instanceof Error ? error.message : \"Failed to decode peaks\",\n });\n }\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, [buckets, fileUrl]);\n\n return state;\n}\n","/** In-place radix-2 Cooley–Tukey FFT; `length` must be a power of 2 and >= 2. */\nexport function fftInPlace(re: Float64Array, im: Float64Array): void {\n const n = re.length;\n if (n !== im.length || n < 2 || (n & (n - 1)) !== 0) {\n throw new Error(\"fftInPlace: length must be equal powers of 2 >= 2\");\n }\n\n let j = 0;\n for (let i = 0; i < n - 1; i += 1) {\n if (i < j) {\n const tr = re[i]!;\n const ti = im[i]!;\n re[i] = re[j]!;\n im[i] = im[j]!;\n re[j] = tr;\n im[j] = ti;\n }\n let k = n >> 1;\n while (k <= j) {\n j -= k;\n k >>= 1;\n }\n j += k;\n }\n\n for (let len = 2; len <= n; len <<= 1) {\n const ang = (-2 * Math.PI) / len;\n const wlenR = Math.cos(ang);\n const wlenI = Math.sin(ang);\n for (let i = 0; i < n; i += len) {\n let wr = 1;\n let wi = 0;\n const half = len >> 1;\n for (let k = 0; k < half; k += 1) {\n const u = i + k;\n const v = u + half;\n const tr = wr * re[v]! - wi * im[v]!;\n const ti = wr * im[v]! + wi * re[v]!;\n re[v] = re[u]! - tr;\n im[v] = im[u]! - ti;\n re[u] = re[u]! + tr;\n im[u] = im[u]! + ti;\n const nwr = wr * wlenR - wi * wlenI;\n const nwi = wr * wlenI + wi * wlenR;\n wr = nwr;\n wi = nwi;\n }\n }\n }\n}\n\n/** Magnitude spectrum for real input: length `n` (power of 2). Returns `n/2` magnitudes for bins 0..n/2-1. */\nexport function realFftMagnitudes(samples: Float64Array): Float64Array {\n const n = samples.length;\n if (n < 2 || (n & (n - 1)) !== 0) {\n throw new Error(\"realFftMagnitudes: length must be a power of 2 >= 2\");\n }\n const re = new Float64Array(n);\n const im = new Float64Array(n);\n for (let i = 0; i < n; i += 1) re[i] = samples[i]!;\n fftInPlace(re, im);\n const out = new Float64Array(n >> 1);\n for (let k = 0; k < n >> 1; k += 1) {\n out[k] = Math.hypot(re[k]!, im[k]!);\n }\n return out;\n}\n\nexport function hanningWindow(length: number): Float64Array {\n const w = new Float64Array(length);\n if (length === 1) {\n w[0] = 1;\n return w;\n }\n const denom = length - 1;\n for (let i = 0; i < length; i += 1) {\n w[i] = 0.5 * (1 - Math.cos((2 * Math.PI * i) / denom));\n }\n return w;\n}\n\nexport function clampFftSize(n: number): number {\n const p = 2 ** Math.round(Math.log2(n));\n return Math.min(8192, Math.max(32, p));\n}\n","import { clampFftSize, hanningWindow, realFftMagnitudes } from \"../internal/fft\";\n\nexport type AnalyzeAudioFileOptions = {\n /** Number of time rows in the amplitude grid (and spectrogram if enabled). Default 128. */\n timeSlices?: number;\n /** Sub-buckets per time slice for the amplitude grid. Default 8. */\n samplesPerSlice?: number;\n /** When true, include `spectrogram` using windowed FFT per time slice. Default false. */\n spectrogram?: boolean;\n /** FFT length for spectrogram (power of 2). Default 1024. */\n fftSize?: number;\n /** Number of frequency bins to keep per row (first bins; capped by fftSize/2). Default 256. */\n frequencyBins?: number;\n /** Channel index, or `\"mix\"` for equal mix of all channels. Default 0. */\n channel?: number | \"mix\";\n};\n\nexport type AudioFileAnalysis = {\n duration: number;\n sampleRate: number;\n /** Peak amplitudes in [0, 1]: `timeSlices` rows × `samplesPerSlice` columns. */\n amplitudeGrid: number[][];\n /** Optional magnitude spectrogram rows, each length `frequencyBins`, normalized to [0, 1] globally. */\n spectrogram?: number[][];\n};\n\nfunction mixChannels(buffer: AudioBuffer): Float32Array {\n const { numberOfChannels, length } = buffer;\n if (numberOfChannels === 1) {\n return buffer.getChannelData(0);\n }\n const out = new Float32Array(length);\n const scale = 1 / numberOfChannels;\n for (let c = 0; c < numberOfChannels; c += 1) {\n const ch = buffer.getChannelData(c);\n for (let i = 0; i < length; i += 1) {\n out[i] += ch[i]! * scale;\n }\n }\n return out;\n}\n\nfunction getChannel(buffer: AudioBuffer, channel: number | \"mix\"): Float32Array {\n if (channel === \"mix\") return mixChannels(buffer);\n const idx = Math.max(0, Math.min(buffer.numberOfChannels - 1, channel));\n return buffer.getChannelData(idx);\n}\n\nfunction buildAmplitudeGrid(\n channel: Float32Array,\n timeSlices: number,\n samplesPerSlice: number,\n): number[][] {\n const grid: number[][] = [];\n const len = channel.length;\n if (len === 0) {\n for (let t = 0; t < timeSlices; t += 1) {\n grid.push(Array.from({ length: samplesPerSlice }, () => 0));\n }\n return grid;\n }\n\n const segmentLen = len / timeSlices;\n\n for (let t = 0; t < timeSlices; t += 1) {\n const row: number[] = [];\n const segStart = Math.floor(t * segmentLen);\n const segEnd = Math.floor((t + 1) * segmentLen);\n const segLen = Math.max(1, segEnd - segStart);\n const subLen = segLen / samplesPerSlice;\n\n for (let s = 0; s < samplesPerSlice; s += 1) {\n const a = Math.floor(segStart + s * subLen);\n const b = Math.min(segEnd, Math.floor(segStart + (s + 1) * subLen));\n let peak = 0;\n for (let i = a; i < b; i += 1) {\n peak = Math.max(peak, Math.abs(channel[i] ?? 0));\n }\n row.push(peak);\n }\n grid.push(row);\n }\n return grid;\n}\n\nfunction buildSpectrogram(\n channel: Float32Array,\n timeSlices: number,\n fftSize: number,\n frequencyBins: number,\n): { rows: number[][]; maxMag: number } {\n const rows: number[][] = [];\n let maxMag = 1e-12;\n const len = channel.length;\n const n = clampFftSize(fftSize);\n const half = n >> 1;\n const bins = Math.min(frequencyBins, half);\n const window = hanningWindow(n);\n\n if (len < n) {\n for (let t = 0; t < timeSlices; t += 1) {\n rows.push(Array.from({ length: bins }, () => 0));\n }\n return { rows, maxMag: 1 };\n }\n\n for (let t = 0; t < timeSlices; t += 1) {\n const start =\n timeSlices <= 1\n ? 0\n : Math.min(Math.floor((t * (len - n)) / (timeSlices - 1)), len - n);\n const frame = new Float64Array(n);\n for (let i = 0; i < n; i += 1) {\n frame[i] = (channel[start + i] ?? 0) * (window[i] ?? 0);\n }\n const mags = realFftMagnitudes(frame);\n const row: number[] = [];\n for (let k = 0; k < bins; k += 1) {\n const v = mags[k] ?? 0;\n row.push(v);\n maxMag = Math.max(maxMag, v);\n }\n rows.push(row);\n }\n\n return { rows, maxMag };\n}\n\n/**\n * Decodes an `AudioBuffer` into visualization-friendly grids (no network).\n */\nexport function analyzeAudioBuffer(buffer: AudioBuffer, options: AnalyzeAudioFileOptions = {}): AudioFileAnalysis {\n const timeSlices = Math.max(1, options.timeSlices ?? 128);\n const samplesPerSlice = Math.max(1, options.samplesPerSlice ?? 8);\n const wantSpec = Boolean(options.spectrogram);\n const fftSize = options.fftSize ?? 1024;\n const frequencyBins = Math.max(1, options.frequencyBins ?? 256);\n const channel = options.channel ?? 0;\n\n const data = getChannel(buffer, channel);\n const amplitudeGrid = buildAmplitudeGrid(data, timeSlices, samplesPerSlice);\n\n const result: AudioFileAnalysis = {\n duration: buffer.duration,\n sampleRate: buffer.sampleRate,\n amplitudeGrid,\n };\n\n if (wantSpec) {\n const { rows, maxMag } = buildSpectrogram(data, timeSlices, fftSize, frequencyBins);\n const norm = maxMag > 0 ? 1 / maxMag : 1;\n result.spectrogram = rows.map((row) => row.map((v) => v * norm));\n }\n\n return result;\n}\n\n/**\n * Fetches a URL, decodes audio to an `AudioBuffer`, runs {@link analyzeAudioBuffer}, then closes the temporary `AudioContext`.\n */\nexport async function analyzeAudioFile(\n fileUrl: string,\n options: AnalyzeAudioFileOptions = {},\n): Promise<AudioFileAnalysis> {\n const response = await fetch(fileUrl);\n if (!response.ok) {\n throw new Error(`Fetch failed: ${response.status} ${response.statusText}`);\n }\n const raw = await response.arrayBuffer();\n const Context = window.AudioContext ?? (window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n if (!Context) {\n throw new Error(\"Web Audio API is not available\");\n }\n const audioContext = new Context();\n try {\n const buffer = await audioContext.decodeAudioData(raw.slice(0));\n return analyzeAudioBuffer(buffer, options);\n } finally {\n await audioContext.close();\n }\n}\n","import { useEffect, useState } from \"react\";\nimport { analyzeAudioFile, type AnalyzeAudioFileOptions, type AudioFileAnalysis } from \"./analyzeAudioFile\";\n\nexport type UseAudioFileAnalysisState = {\n data: AudioFileAnalysis | null;\n isLoading: boolean;\n error: string | null;\n};\n\nexport function useAudioFileAnalysis(\n fileUrl: string | null | undefined,\n options: AnalyzeAudioFileOptions = {},\n): UseAudioFileAnalysisState {\n const [state, setState] = useState<UseAudioFileAnalysisState>({\n data: null,\n isLoading: false,\n error: null,\n });\n\n useEffect(() => {\n if (!fileUrl) {\n setState({ data: null, isLoading: false, error: null });\n return;\n }\n if (typeof window === \"undefined\") {\n setState({ data: null, isLoading: false, error: null });\n return;\n }\n\n let cancelled = false;\n setState((prev) => ({ ...prev, isLoading: true, error: null }));\n\n void (async () => {\n try {\n const data = await analyzeAudioFile(fileUrl, options);\n if (!cancelled) {\n setState({ data, isLoading: false, error: null });\n }\n } catch (error) {\n if (!cancelled) {\n setState({\n data: null,\n isLoading: false,\n error: error instanceof Error ? error.message : \"Failed to analyze audio file\",\n });\n }\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, [\n fileUrl,\n options.timeSlices,\n options.samplesPerSlice,\n options.spectrogram,\n options.fftSize,\n options.frequencyBins,\n options.channel,\n ]);\n\n return state;\n}\n"],"names":["useAudioPeaks","fileUrl","buckets","state","setState","useState","useEffect","cancelled","prev","response","buffer","audioContext","channel","step","peaks","i","max","start","end","j","error","fftInPlace","re","im","n","tr","ti","k","len","ang","wlenR","wlenI","wr","wi","half","u","v","nwr","nwi","realFftMagnitudes","samples","out","hanningWindow","length","w","denom","clampFftSize","p","mixChannels","numberOfChannels","scale","c","ch","getChannel","idx","buildAmplitudeGrid","timeSlices","samplesPerSlice","grid","t","segmentLen","row","segStart","segEnd","subLen","s","a","b","peak","buildSpectrogram","fftSize","frequencyBins","rows","maxMag","bins","window","frame","mags","analyzeAudioBuffer","options","wantSpec","data","amplitudeGrid","result","norm","analyzeAudioFile","raw","Context","useAudioFileAnalysis"],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AnalyzeAudioFileOptions, AudioFileAnalysis } from './analyzeAudioFile';
|
|
2
|
+
export type UseAudioFileAnalysisState = {
|
|
3
|
+
data: AudioFileAnalysis | null;
|
|
4
|
+
isLoading: boolean;
|
|
5
|
+
error: string | null;
|
|
6
|
+
};
|
|
7
|
+
export declare function useAudioFileAnalysis(fileUrl: string | null | undefined, options?: AnalyzeAudioFileOptions): UseAudioFileAnalysisState;
|
|
8
|
+
//# sourceMappingURL=useAudioFileAnalysis.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAudioFileAnalysis.d.ts","sourceRoot":"","sources":["../../src/waveform/useAudioFileAnalysis.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,KAAK,uBAAuB,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5G,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAAC;AAEF,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAClC,OAAO,GAAE,uBAA4B,GACpC,yBAAyB,CAmD3B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lucaismyname/ginger",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"description": "A headless React audio player",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -42,6 +42,8 @@
|
|
|
42
42
|
"scripts": {
|
|
43
43
|
"build": "vite build",
|
|
44
44
|
"test": "vitest run",
|
|
45
|
+
"test:watch": "vitest",
|
|
46
|
+
"test:coverage": "vitest run --coverage",
|
|
45
47
|
"prepublishOnly": "npm run build"
|
|
46
48
|
},
|
|
47
49
|
"peerDependencies": {
|
|
@@ -58,6 +60,7 @@
|
|
|
58
60
|
"@types/react": "^18.3.12",
|
|
59
61
|
"@types/react-dom": "^18.3.1",
|
|
60
62
|
"@vitejs/plugin-react": "^4.3.4",
|
|
63
|
+
"@vitest/coverage-v8": "^4.1.4",
|
|
61
64
|
"jsdom": "^29.0.2",
|
|
62
65
|
"react": "^18.3.1",
|
|
63
66
|
"react-dom": "^18.3.1",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GingerSplitContexts-4YZ-OJ9V.js","sources":["../src/context/GingerSplitContexts.tsx"],"sourcesContent":["import { createContext, useContext, useMemo, type Dispatch, type MutableRefObject } from \"react\";\nimport type {\n GingerAction,\n GingerInitPayload,\n GingerMediaSlice,\n GingerPlaybackSlice,\n GingerState,\n PlaylistMeta,\n RepeatMode,\n Track,\n} from \"../types\";\n\nexport type GingerPlaybackActions = {\n init: (payload: GingerInitPayload) => void;\n play: () => void;\n pause: () => void;\n togglePlayPause: () => void;\n next: () => void;\n prev: () => void;\n setRepeatMode: (mode: RepeatMode) => void;\n cycleRepeat: () => void;\n toggleShuffle: () => void;\n setQueue: (tracks: Track[], currentIndex?: number) => void;\n insertTrackAt: (track: Track, index?: number, autoPlay?: boolean) => void;\n removeTrackAt: (index: number) => void;\n moveTrack: (fromIndex: number, toIndex: number) => void;\n enqueueNext: (track: Track) => void;\n playTrackAt: (index: number) => void;\n selectTrackAt: (index: number) => void;\n setPlaylistMeta: (meta: PlaylistMeta | null) => void;\n dispatch: Dispatch<GingerAction>;\n};\n\nexport type GingerPlaybackContextValue = GingerPlaybackSlice & GingerPlaybackActions;\n\nexport type GingerMediaActions = {\n seek: (timeSeconds: number) => void;\n setVolume: (volume: number) => void;\n setMuted: (muted: boolean) => void;\n toggleMute: () => void;\n setPlaybackRate: (rate: number) => void;\n audioRef: MutableRefObject<HTMLAudioElement | null>;\n notifyEnded: () => void;\n dispatch: Dispatch<GingerAction>;\n};\n\nexport type GingerMediaContextValue = GingerMediaSlice & GingerMediaActions;\n\nconst GingerPlaybackContext = createContext<GingerPlaybackContextValue | null>(null);\nconst GingerMediaContext = createContext<GingerMediaContextValue | null>(null);\n\nexport function useGingerPlayback(): GingerPlaybackContextValue {\n const ctx = useContext(GingerPlaybackContext);\n if (!ctx) throw new Error(\"Ginger hooks must be used within <Ginger.Provider>\");\n return ctx;\n}\n\nexport function useGingerMedia(): GingerMediaContextValue {\n const ctx = useContext(GingerMediaContext);\n if (!ctx) throw new Error(\"Ginger hooks must be used within <Ginger.Provider>\");\n return ctx;\n}\n\n/** Full merged state; prefer over `useGingerContext().state` so updates follow playback vs media splits. */\nexport function useGingerState(): GingerState {\n const pb = useGingerPlayback();\n const md = useGingerMedia();\n return useMemo(() => gingerStateFromContextValues(pb, md), [pb, md]);\n}\n\n/** Merge playback + media slices (for selectors and `useGinger`). */\nexport function gingerStateFromContexts(\n playback: GingerPlaybackSlice,\n media: GingerMediaSlice,\n): GingerState {\n return { ...playback, ...media };\n}\n\n/** Merge full context values into `GingerState` (strips action fields). */\nexport function gingerStateFromContextValues(\n pb: GingerPlaybackContextValue,\n md: GingerMediaContextValue,\n): GingerState {\n const {\n init: _i,\n play: _p,\n pause: _pa,\n togglePlayPause: _t,\n next: _n,\n prev: _pr,\n setRepeatMode: _sr,\n cycleRepeat: _cr,\n toggleShuffle: _ts,\n setQueue: _sq,\n insertTrackAt: _ita,\n removeTrackAt: _rta,\n moveTrack: _mt,\n enqueueNext: _en,\n playTrackAt: _pta,\n selectTrackAt: _sta,\n setPlaylistMeta: _spm,\n dispatch: _d1,\n ...playbackRest\n } = pb;\n const {\n seek: _sk,\n setVolume: _sv,\n setMuted: _sm,\n toggleMute: _tm,\n setPlaybackRate: _spr,\n audioRef: _ar,\n notifyEnded: _ne,\n dispatch: _d2,\n ...mediaRest\n } = md;\n return { ...playbackRest, ...mediaRest };\n}\n\nexport { GingerPlaybackContext, GingerMediaContext };\n"],"names":["GingerPlaybackContext","createContext","GingerMediaContext","useGingerPlayback","ctx","useContext","useGingerMedia","useGingerState","pb","md","useMemo","gingerStateFromContextValues","gingerStateFromContexts","playback","media","_i","_p","_pa","_t","_n","_pr","_sr","_cr","_ts","_sq","_ita","_rta","_mt","_en","_pta","_sta","_spm","_d1","playbackRest","_sk","_sv","_sm","_tm","_spr","_ar","_ne","_d2","mediaRest"],"mappings":";AAgDA,MAAMA,IAAwBC,EAAiD,IAAI,GAC7EC,IAAqBD,EAA8C,IAAI;AAEtE,SAASE,IAAgD;AAC9D,QAAMC,IAAMC,EAAWL,CAAqB;AAC5C,MAAI,CAACI,EAAK,OAAM,IAAI,MAAM,oDAAoD;AAC9E,SAAOA;AACT;AAEO,SAASE,IAA0C;AACxD,QAAMF,IAAMC,EAAWH,CAAkB;AACzC,MAAI,CAACE,EAAK,OAAM,IAAI,MAAM,oDAAoD;AAC9E,SAAOA;AACT;AAGO,SAASG,IAA8B;AAC5C,QAAMC,IAAKL,EAAA,GACLM,IAAKH,EAAA;AACX,SAAOI,EAAQ,MAAMC,EAA6BH,GAAIC,CAAE,GAAG,CAACD,GAAIC,CAAE,CAAC;AACrE;AAGO,SAASG,EACdC,GACAC,GACa;AACb,SAAO,EAAE,GAAGD,GAAU,GAAGC,EAAA;AAC3B;AAGO,SAASH,EACdH,GACAC,GACa;AACb,QAAM;AAAA,IACJ,MAAMM;AAAA,IACN,MAAMC;AAAA,IACN,OAAOC;AAAA,IACP,iBAAiBC;AAAA,IACjB,MAAMC;AAAA,IACN,MAAMC;AAAA,IACN,eAAeC;AAAA,IACf,aAAaC;AAAA,IACb,eAAeC;AAAA,IACf,UAAUC;AAAA,IACV,eAAeC;AAAA,IACf,eAAeC;AAAA,IACf,WAAWC;AAAA,IACX,aAAaC;AAAA,IACb,aAAaC;AAAA,IACb,eAAeC;AAAA,IACf,iBAAiBC;AAAA,IACjB,UAAUC;AAAA,IACV,GAAGC;AAAA,EAAA,IACDzB,GACE;AAAA,IACJ,MAAM0B;AAAA,IACN,WAAWC;AAAA,IACX,UAAUC;AAAA,IACV,YAAYC;AAAA,IACZ,iBAAiBC;AAAA,IACjB,UAAUC;AAAA,IACV,aAAaC;AAAA,IACb,UAAUC;AAAA,IACV,GAAGC;AAAA,EAAA,IACDjC;AACJ,SAAO,EAAE,GAAGwB,GAAc,GAAGS,EAAA;AAC/B;"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
"use strict";const n=require("react"),r=n.createContext(null),s=n.createContext(null);function a(){const e=n.useContext(r);if(!e)throw new Error("Ginger hooks must be used within <Ginger.Provider>");return e}function o(){const e=n.useContext(s);if(!e)throw new Error("Ginger hooks must be used within <Ginger.Provider>");return e}function g(){const e=a(),t=o();return n.useMemo(()=>i(e,t),[e,t])}function _(e,t){return{...e,...t}}function i(e,t){const{init:l,play:d,pause:m,togglePlayPause:p,next:x,prev:k,setRepeatMode:G,cycleRepeat:y,toggleShuffle:C,setQueue:f,insertTrackAt:P,removeTrackAt:b,moveTrack:h,enqueueNext:M,playTrackAt:R,selectTrackAt:S,setPlaylistMeta:v,dispatch:w,...u}=e,{seek:T,setVolume:A,setMuted:F,toggleMute:q,setPlaybackRate:E,audioRef:V,notifyEnded:N,dispatch:Q,...c}=t;return{...u,...c}}exports.GingerMediaContext=s;exports.GingerPlaybackContext=r;exports.gingerStateFromContextValues=i;exports.gingerStateFromContexts=_;exports.useGingerMedia=o;exports.useGingerPlayback=a;exports.useGingerState=g;
|
|
2
|
-
//# sourceMappingURL=GingerSplitContexts-Bze1Bqe2.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GingerSplitContexts-Bze1Bqe2.cjs","sources":["../src/context/GingerSplitContexts.tsx"],"sourcesContent":["import { createContext, useContext, useMemo, type Dispatch, type MutableRefObject } from \"react\";\nimport type {\n GingerAction,\n GingerInitPayload,\n GingerMediaSlice,\n GingerPlaybackSlice,\n GingerState,\n PlaylistMeta,\n RepeatMode,\n Track,\n} from \"../types\";\n\nexport type GingerPlaybackActions = {\n init: (payload: GingerInitPayload) => void;\n play: () => void;\n pause: () => void;\n togglePlayPause: () => void;\n next: () => void;\n prev: () => void;\n setRepeatMode: (mode: RepeatMode) => void;\n cycleRepeat: () => void;\n toggleShuffle: () => void;\n setQueue: (tracks: Track[], currentIndex?: number) => void;\n insertTrackAt: (track: Track, index?: number, autoPlay?: boolean) => void;\n removeTrackAt: (index: number) => void;\n moveTrack: (fromIndex: number, toIndex: number) => void;\n enqueueNext: (track: Track) => void;\n playTrackAt: (index: number) => void;\n selectTrackAt: (index: number) => void;\n setPlaylistMeta: (meta: PlaylistMeta | null) => void;\n dispatch: Dispatch<GingerAction>;\n};\n\nexport type GingerPlaybackContextValue = GingerPlaybackSlice & GingerPlaybackActions;\n\nexport type GingerMediaActions = {\n seek: (timeSeconds: number) => void;\n setVolume: (volume: number) => void;\n setMuted: (muted: boolean) => void;\n toggleMute: () => void;\n setPlaybackRate: (rate: number) => void;\n audioRef: MutableRefObject<HTMLAudioElement | null>;\n notifyEnded: () => void;\n dispatch: Dispatch<GingerAction>;\n};\n\nexport type GingerMediaContextValue = GingerMediaSlice & GingerMediaActions;\n\nconst GingerPlaybackContext = createContext<GingerPlaybackContextValue | null>(null);\nconst GingerMediaContext = createContext<GingerMediaContextValue | null>(null);\n\nexport function useGingerPlayback(): GingerPlaybackContextValue {\n const ctx = useContext(GingerPlaybackContext);\n if (!ctx) throw new Error(\"Ginger hooks must be used within <Ginger.Provider>\");\n return ctx;\n}\n\nexport function useGingerMedia(): GingerMediaContextValue {\n const ctx = useContext(GingerMediaContext);\n if (!ctx) throw new Error(\"Ginger hooks must be used within <Ginger.Provider>\");\n return ctx;\n}\n\n/** Full merged state; prefer over `useGingerContext().state` so updates follow playback vs media splits. */\nexport function useGingerState(): GingerState {\n const pb = useGingerPlayback();\n const md = useGingerMedia();\n return useMemo(() => gingerStateFromContextValues(pb, md), [pb, md]);\n}\n\n/** Merge playback + media slices (for selectors and `useGinger`). */\nexport function gingerStateFromContexts(\n playback: GingerPlaybackSlice,\n media: GingerMediaSlice,\n): GingerState {\n return { ...playback, ...media };\n}\n\n/** Merge full context values into `GingerState` (strips action fields). */\nexport function gingerStateFromContextValues(\n pb: GingerPlaybackContextValue,\n md: GingerMediaContextValue,\n): GingerState {\n const {\n init: _i,\n play: _p,\n pause: _pa,\n togglePlayPause: _t,\n next: _n,\n prev: _pr,\n setRepeatMode: _sr,\n cycleRepeat: _cr,\n toggleShuffle: _ts,\n setQueue: _sq,\n insertTrackAt: _ita,\n removeTrackAt: _rta,\n moveTrack: _mt,\n enqueueNext: _en,\n playTrackAt: _pta,\n selectTrackAt: _sta,\n setPlaylistMeta: _spm,\n dispatch: _d1,\n ...playbackRest\n } = pb;\n const {\n seek: _sk,\n setVolume: _sv,\n setMuted: _sm,\n toggleMute: _tm,\n setPlaybackRate: _spr,\n audioRef: _ar,\n notifyEnded: _ne,\n dispatch: _d2,\n ...mediaRest\n } = md;\n return { ...playbackRest, ...mediaRest };\n}\n\nexport { GingerPlaybackContext, GingerMediaContext };\n"],"names":["GingerPlaybackContext","createContext","GingerMediaContext","useGingerPlayback","ctx","useContext","useGingerMedia","useGingerState","pb","md","useMemo","gingerStateFromContextValues","gingerStateFromContexts","playback","media","_i","_p","_pa","_t","_n","_pr","_sr","_cr","_ts","_sq","_ita","_rta","_mt","_en","_pta","_sta","_spm","_d1","playbackRest","_sk","_sv","_sm","_tm","_spr","_ar","_ne","_d2","mediaRest"],"mappings":"sCAgDMA,EAAwBC,EAAAA,cAAiD,IAAI,EAC7EC,EAAqBD,EAAAA,cAA8C,IAAI,EAEtE,SAASE,GAAgD,CAC9D,MAAMC,EAAMC,EAAAA,WAAWL,CAAqB,EAC5C,GAAI,CAACI,EAAK,MAAM,IAAI,MAAM,oDAAoD,EAC9E,OAAOA,CACT,CAEO,SAASE,GAA0C,CACxD,MAAMF,EAAMC,EAAAA,WAAWH,CAAkB,EACzC,GAAI,CAACE,EAAK,MAAM,IAAI,MAAM,oDAAoD,EAC9E,OAAOA,CACT,CAGO,SAASG,GAA8B,CAC5C,MAAMC,EAAKL,EAAA,EACLM,EAAKH,EAAA,EACX,OAAOI,EAAAA,QAAQ,IAAMC,EAA6BH,EAAIC,CAAE,EAAG,CAACD,EAAIC,CAAE,CAAC,CACrE,CAGO,SAASG,EACdC,EACAC,EACa,CACb,MAAO,CAAE,GAAGD,EAAU,GAAGC,CAAA,CAC3B,CAGO,SAASH,EACdH,EACAC,EACa,CACb,KAAM,CACJ,KAAMM,EACN,KAAMC,EACN,MAAOC,EACP,gBAAiBC,EACjB,KAAMC,EACN,KAAMC,EACN,cAAeC,EACf,YAAaC,EACb,cAAeC,EACf,SAAUC,EACV,cAAeC,EACf,cAAeC,EACf,UAAWC,EACX,YAAaC,EACb,YAAaC,EACb,cAAeC,EACf,gBAAiBC,EACjB,SAAUC,EACV,GAAGC,CAAA,EACDzB,EACE,CACJ,KAAM0B,EACN,UAAWC,EACX,SAAUC,EACV,WAAYC,EACZ,gBAAiBC,EACjB,SAAUC,EACV,YAAaC,EACb,SAAUC,EACV,GAAGC,CAAA,EACDjC,EACJ,MAAO,CAAE,GAAGwB,EAAc,GAAGS,CAAA,CAC/B"}
|
package/dist/ginger-DYoHDn8T.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
"use strict";const c=require("react/jsx-runtime"),d=require("react"),h=require("./GingerSplitContexts-Bze1Bqe2.cjs"),je=d.createContext(null);function Er(){const e=d.useContext(je);if(!e)throw new Error("Ginger components must be used within <Ginger.Provider>");return e}function Ce(e){const{buffered:r,duration:n}=e;return!(n>0)||r.length===0?0:Math.min(1,r.end(r.length-1)/n)}function Ir({className:e,style:r,preload:n="metadata",crossOrigin:t,respectReducedMotion:a=!1}){var M;const{audioRef:u,dispatch:o,state:i,notifyEnded:l}=Er(),p=((M=i.tracks[i.currentIndex])==null?void 0:M.fileUrl)??"",m=d.useRef({currentTime:-1,duration:-1,bufferedFraction:-1}),[b,T]=d.useState(!1);d.useEffect(()=>{if(!a||typeof window>"u")return;const g=window.matchMedia("(prefers-reduced-motion: reduce)"),y=()=>T(g.matches);return y(),g.addEventListener("change",y),()=>g.removeEventListener("change",y)},[a]);const E=(g,y=!1)=>{const R={currentTime:g.currentTime,duration:g.duration,bufferedFraction:Ce(g)},P=m.current,H=b?.5:.25,ke=Math.abs(R.currentTime-P.currentTime)>=H||Math.abs(R.duration-P.duration)>=.01||Math.abs(R.bufferedFraction-P.bufferedFraction)>=.01;!y&&!ke||(m.current=R,o({type:"MEDIA_TIME_UPDATE",payload:R}))};return d.useEffect(()=>{const g=u.current;g&&(g.volume=i.volume,g.muted=i.muted,g.playbackRate=i.playbackRate)},[u,i.volume,i.muted,i.playbackRate]),d.useEffect(()=>{const g=u.current;if(g){if(!p){g.removeAttribute("src"),m.current={currentTime:-1,duration:-1,bufferedFraction:-1};return}g.getAttribute("src")!==p&&(g.src=p,g.load(),m.current={currentTime:-1,duration:-1,bufferedFraction:-1})}},[u,i.currentIndex,i.tracks,p]),c.jsx("audio",{ref:u,className:e,style:r,preload:n,crossOrigin:t,controls:!1,playsInline:!0,onTimeUpdate:g=>{E(g.currentTarget)},onLoadedMetadata:g=>{const y=g.currentTarget;m.current={currentTime:-1,duration:-1,bufferedFraction:-1},o({type:"MEDIA_LOADED_METADATA",payload:{duration:y.duration,bufferedFraction:Ce(y)}})},onSeeking:g=>E(g.currentTarget,!0),onSeeked:g=>E(g.currentTarget,!0),onEnded:()=>l(),onPlay:()=>o({type:"MEDIA_PLAY"}),onPause:()=>o({type:"MEDIA_PAUSE"}),onWaiting:()=>o({type:"MEDIA_WAITING"}),onCanPlay:()=>o({type:"MEDIA_CANPLAY"}),onProgress:g=>E(g.currentTarget,!0),onVolumeChange:g=>{const y=g.currentTarget;o({type:"MEDIA_VOLUME_SYNC",payload:{volume:y.volume,muted:y.muted}})},onError:()=>{var P;const g=u.current,y=(P=g==null?void 0:g.error)==null?void 0:P.code;o({type:"MEDIA_ERROR",payload:{message:y===1?"MEDIA_ERR_ABORTED":y===2?"MEDIA_ERR_NETWORK":y===3?"MEDIA_ERR_DECODE":y===4?"MEDIA_ERR_SRC_NOT_SUPPORTED":"MEDIA_ERR_UNKNOWN"}})}})}function I(e,r){return r<=0?0:Math.max(0,Math.min(r-1,e))}function _e(e,r){if(e.length<=1)return[...e];const n=e[r];if(!n)return[...e];const t=e.filter((a,u)=>u!==r);for(let a=t.length-1;a>0;a--){const u=Math.floor(Math.random()*(a+1));[t[a],t[u]]=[t[u],t[a]]}return[n,...t]}function Y(e){return e?e.id!=null&&e.id!==""?`id:${e.id}`:`file:${e.fileUrl}`:""}function Pr(e,r){const n=Y(r);if(!n)return 0;const t=e.findIndex(a=>Y(a)===n);return t===-1?0:t}function Ne(e,r,n){const t=[...e],a=Math.max(0,Math.min(t.length,n??t.length));return t.splice(a,0,r),t}function Sr(e,r){if(r<0||r>=e.length)return[...e];const n=[...e];return n.splice(r,1),n}function Ar(e,r,n){if(r===n||r<0||r>=e.length||n<0||n>=e.length)return[...e];const t=[...e],[a]=t.splice(r,1);return a?(t.splice(n,0,a),t):[...e]}function Rr(e,r,n){return Ne(e,n,Math.max(0,Math.min(e.length,r+1)))}function Gr(e){const{tracks:r,currentIndex:n,repeatMode:t,playbackMode:a}=e,u=r.length;return u===0?{kind:"stop",nextIndex:0}:t==="one"?{kind:"replay_same"}:a==="single"?{kind:"stop",nextIndex:I(n,u)}:n<u-1?{kind:"advance",nextIndex:n+1}:t==="all"?{kind:"wrap",nextIndex:0}:{kind:"stop",nextIndex:I(n,u)}}function Cr(e){const{tracks:r,currentIndex:n,repeatMode:t,playbackMode:a}=e,u=r.length;return u===0?0:a==="single"?I(n,u):n<u-1?n+1:t==="all"?0:I(n,u)}function jr(e){const{tracks:r,currentIndex:n,repeatMode:t,playbackMode:a}=e,u=r.length;return u===0?0:a==="single"?I(n,u):n>0?n-1:t==="all"?u-1:0}function _r(e){return e==="off"?"all":e==="all"?"one":"off"}function Nr(e,r){return(e==null?void 0:e.artworkUrl)??r??void 0}function wr(e,r){return(e==null?void 0:e.album)??r??void 0}function C(e){return e.tracks[e.currentIndex]??null}function Ie(e){return e.errorMessage?"error":e.tracks.length===0?"idle":e.isBuffering?"loading":e.isPaused?Number.isFinite(e.duration)&&e.duration>0&&e.currentTime>=e.duration-.05?"ended":"paused":"playing"}function B(e){var t;const r=e.duration;if(Number.isFinite(r)&&r>0)return r;const n=(t=e.tracks[e.currentIndex])==null?void 0:t.durationSeconds;return typeof n=="number"&&Number.isFinite(n)&&n>0?n:0}function we(e){const n=B(e)-e.currentTime;return Number.isFinite(n)?Math.max(0,n):0}function Pe(e){const r=B(e);return r>0?Math.min(1,Math.max(0,e.currentTime/r)):0}function De(e){var n;const r=C(e);return Nr(r,(n=e.playlistMeta)==null?void 0:n.artworkUrl)}function Le(e){var n;const r=C(e);return wr(r,(n=e.playlistMeta)==null?void 0:n.subtitle)}function L(e,r){function n(t){const a=h.useGingerState(),o=(r(a)??"").trim(),{className:i,style:l,fallback:p,empty:m,children:b}=t;if(!o){const T=m??p??null;return T?c.jsx("span",{className:i,style:l,children:T}):null}return b?c.jsx("span",{className:i,style:l,children:b(o,a)}):c.jsx("span",{className:i,style:l,children:o})}return n.displayName=e,n}function F(e,r){return L(e,n=>r(C(n)))}const Dr=F("Ginger.Current.Title",e=>e==null?void 0:e.title),Lr=F("Ginger.Current.Artist",e=>e==null?void 0:e.artist),Fr=L("Ginger.Current.Album",e=>Le(e)),Ur=F("Ginger.Current.Description",e=>e==null?void 0:e.description),Vr=L("Ginger.Current.Copyright",e=>{var n;const r=C(e);return(r==null?void 0:r.copyright)??((n=e.playlistMeta)==null?void 0:n.copyright)}),Br=F("Ginger.Current.Genre",e=>e==null?void 0:e.genre),$r=F("Ginger.Current.Label",e=>e==null?void 0:e.label),Or=F("Ginger.Current.Isrc",e=>e==null?void 0:e.isrc),Yr=F("Ginger.Current.TrackNumber",e=>(e==null?void 0:e.trackNumber)!=null?String(e.trackNumber):void 0);function Fe({className:e,style:r,fallback:n,empty:t,children:a,format:u}){var p;const o=h.useGingerState(),i=(p=C(o))==null?void 0:p.year;if(typeof i!="number"||!Number.isFinite(i)){const m=t??n??null;return m?c.jsx("span",{className:e,style:r,children:m}):null}const l=u?u(i):String(i);return a?c.jsx("span",{className:e,style:r,children:a(l,o)}):c.jsx("span",{className:e,style:r,children:l})}Fe.displayName="Ginger.Current.Year";function Ue({className:e,style:r,fallback:n,empty:t,children:a,preserveWhitespace:u=!0}){var m;const o=h.useGingerState(),i=((m=C(o))==null?void 0:m.lyrics)??"",l=u?i.replace(/^\s+|\s+$/g,""):i.trim();if(!l){const b=t??n??null;return b?c.jsx("span",{className:e,style:r,children:b}):null}const p=u?{whiteSpace:"pre-wrap"}:void 0;return a?c.jsx("span",{className:e,style:{...p,...r},children:a(l,o)}):c.jsx("span",{className:e,style:{...p,...r},children:l})}Ue.displayName="Ginger.Current.Lyrics";function Ve({visible:e=!1,className:r,style:n,fallback:t,empty:a,children:u}){var l;const o=h.useGingerState();if(!e)return null;const i=((l=C(o))==null?void 0:l.fileUrl)??"";if(!i){const p=a??t??null;return p?c.jsx("span",{className:r,style:n,children:p}):null}return u?c.jsx("span",{className:r,style:n,children:u(i,o)}):c.jsx("span",{className:r,style:n,children:i})}Ve.displayName="Ginger.Current.FileUrl";function Be({className:e,style:r,fallback:n,empty:t,sizes:a,loading:u,onError:o,decoding:i,unstyled:l=!1,imgStyle:p}){const m=h.useGingerState(),b=C(m),T=De(m);if(!T){const M=t??n??null;return M?c.jsx("span",{className:e,style:r,children:M}):null}const E=[b==null?void 0:b.title,b==null?void 0:b.artist].filter(Boolean).join(" — ")||"Artwork";return c.jsx("div",{className:e,style:l?{...r}:{background:"var(--ginger-artwork-bg, transparent)",borderRadius:"var(--ginger-artwork-radius, 0)",overflow:"hidden",...r},children:c.jsx("img",{src:T,alt:E,sizes:a,loading:u,decoding:i,onError:o,style:{display:l?void 0:"block",width:l?void 0:"100%",height:l?void 0:"100%",objectFit:l?void 0:"cover",...p}})})}Be.displayName="Ginger.Current.Artwork";function $e({base:e=0,className:r,style:n,fallback:t,empty:a,children:u}){const o=h.useGingerState();if(o.tracks.length===0){const p=a??t??null;return p?c.jsx("span",{className:r,style:n,children:p}):null}const l=String(o.currentIndex+e);return u?c.jsx("span",{className:r,style:n,children:u(l,o)}):c.jsx("span",{className:r,style:n,children:l})}$e.displayName="Ginger.Current.QueueIndex";function Oe({className:e,style:r,fallback:n,empty:t,children:a}){const u=h.useGingerState(),o=String(u.tracks.length);if(u.tracks.length===0){const i=t??n??null;return i?c.jsx("span",{className:e,style:r,children:i}):null}return a?c.jsx("span",{className:e,style:r,children:a(o,u)}):c.jsx("span",{className:e,style:r,children:o})}Oe.displayName="Ginger.Current.QueueLength";function Ye({base:e=0,separator:r=" / ",className:n,style:t,fallback:a,empty:u,children:o}){const i=h.useGingerState(),l=i.tracks.length;if(l===0){const T=u??a??null;return T?c.jsx("span",{className:n,style:t,children:T}):null}const p=String(i.currentIndex+e),m=String(l),b=`${p}${r}${m}`;return o?c.jsx("span",{className:n,style:t,children:o({index:p,length:m,label:b},i)}):c.jsx("span",{className:n,style:t,children:b})}Ye.displayName="Ginger.Current.QueuePosition";function xe(e){if(!Number.isFinite(e)||e<0)return"0:00";const r=Math.floor(e%60);return`${Math.floor(e/60)}:${r.toString().padStart(2,"0")}`}function Se(e,r,n){const{className:t,style:a,fallback:u,empty:o,children:i,format:l=xe}=n;if(!(e>=0)||!Number.isFinite(e)){const m=o??u??null;return m?c.jsx("span",{className:t,style:a,children:m}):null}const p=l(e);return i?c.jsx("span",{className:t,style:a,children:i(p,r)}):c.jsx("span",{className:t,style:a,children:p})}function Qe(e){const r=h.useGingerState();return Se(r.currentTime,r,e)}Qe.displayName="Ginger.Current.Elapsed";function He(e){const r=h.useGingerState();return Se(B(r),r,e)}He.displayName="Ginger.Current.Duration";function Xe(e){const r=h.useGingerState();return Se(we(r),r,e)}Xe.displayName="Ginger.Current.Remaining";function Ke({className:e,style:r,fallback:n,empty:t,children:a}){const u=h.useGingerState(),o=B(u),i=Pe(u);if(!(o>0)){const l=t??n??null;return l?c.jsx("span",{className:e,style:r,children:l}):null}return a?c.jsx("span",{className:e,style:r,children:a({fraction:i,currentTime:u.currentTime,duration:o},u)}):c.jsx("span",{className:e,style:r,children:`${Math.round(i*100)}%`})}Ke.displayName="Ginger.Current.Progress";function qe({className:e,style:r,height:n=4,showBuffered:t=!1,unstyled:a=!1}){const u=h.useGingerState(),o=`${Math.round(Pe(u)*100)}%`,i=`${Math.round(Math.min(1,Math.max(0,u.bufferedFraction))*100)}%`;return c.jsxs("div",{className:e,style:a?{...r}:{width:"100%",height:n,background:"var(--ginger-muted-color, #e5e7eb)",borderRadius:999,overflow:"hidden",position:"relative",...r},"aria-hidden":!0,children:[t?c.jsx("div",{style:{position:a?void 0:"absolute",left:a?void 0:0,top:a?void 0:0,height:a?void 0:"100%",width:i,background:a?void 0:"var(--ginger-buffer-color, rgba(107, 114, 128, 0.35))"}}):null,c.jsx("div",{style:{position:a?void 0:"relative",width:o,height:a?void 0:"100%",background:a?void 0:"var(--ginger-primary-color, #111827)"}})]})}qe.displayName="Ginger.Current.TimeRail";function We({className:e,style:r,height:n=4,unstyled:t=!1}){const a=h.useGingerState(),u=`${Math.round(Math.min(1,Math.max(0,a.bufferedFraction))*100)}%`;return c.jsx("div",{className:e,style:t?{...r}:{width:"100%",height:n,background:"var(--ginger-muted-color, #e5e7eb)",borderRadius:999,overflow:"hidden",...r},"aria-hidden":!0,children:c.jsx("div",{style:{width:u,height:t?void 0:"100%",background:t?void 0:"var(--ginger-buffer-color, rgba(107, 114, 128, 0.35))"}})})}We.displayName="Ginger.Current.BufferRail";function ze({className:e,style:r,fallback:n,empty:t,children:a}){const u=h.useGingerState(),o=Ie(u);return a?c.jsx("span",{className:e,style:r,children:a(o,u)}):c.jsx("span",{className:e,style:r,children:o})}ze.displayName="Ginger.Current.PlaybackState";function Je({className:e,style:r,fallback:n,empty:t,live:a="polite",children:u}){const o=h.useGingerState(),i=o.errorMessage??"";if(!i){const l=t??n??null;return l?c.jsx("span",{className:e,style:r,children:l}):null}return u?c.jsx("span",{className:e,style:r,"aria-live":a,children:u(i,o)}):c.jsx("span",{className:e,style:r,"aria-live":a,children:i})}Je.displayName="Ginger.Current.ErrorMessage";const O={seek:"Seek",volume:"Volume",playbackSpeed:"Playback speed",nextTrack:"Next track",previousTrack:"Previous track",shuffle:"Shuffle",mute:"Mute",unmute:"Unmute",play:"Play",pause:"Pause",repeat:{off:"Repeat off",all:"Repeat all",one:"Repeat one"},playbackRateNormal:"1× normal",playbackRateTimes:e=>`${e}×`};function Qr(e){return e?{...O,...e,repeat:{...O.repeat,...e.repeat}}:O}const Ze=d.createContext(O);function Hr({locale:e,children:r}){const n=Qr(e);return c.jsx(Ze.Provider,{value:n,children:r})}function S(){return d.useContext(Ze)}function er(){const e=h.useGingerPlayback(),r=h.useGingerMedia(),n=S(),t=d.useMemo(()=>h.gingerStateFromContextValues(e,r),[e,r]),a=B(t),u=a>0?t.currentTime:0,o=Number.isFinite(u)?u:0,i=a>0?`${xe(o)} of ${xe(a)}`:xe(o),l=p=>{r.seek(Number(p.currentTarget.value))};return{state:t,value:o,min:0,max:a>0?a:1,step:"any",ariaValueText:i,ariaLabel:n.seek,onSeekInput:l,onSeekChange:l}}function rr(){const e=h.useGingerPlayback(),r=h.useGingerMedia(),n=S(),t=d.useMemo(()=>h.gingerStateFromContextValues(e,r),[e,r]),a=u=>{r.setVolume(Number(u.currentTarget.value))};return{state:t,value:t.volume,min:0,max:1,step:"any",ariaValueText:`${Math.round(t.volume*100)}%`,ariaLabel:n.volume,onVolumeInput:a,onVolumeChange:a}}function nr(e){const r=h.useGingerPlayback(),n=S(),t=(e==null?void 0:e.playAriaLabel)??n.play,a=(e==null?void 0:e.pauseAriaLabel)??n.pause;return{isPaused:r.isPaused,toggle:r.togglePlayPause,ariaLabel:r.isPaused?t:a}}function tr({playLabel:e="Play",pauseLabel:r="Pause",playAriaLabel:n,pauseAriaLabel:t,type:a="button",onClick:u,...o}){const i=S(),l=typeof e=="string"?e:i.play,p=typeof r=="string"?r:i.pause,m=nr({playAriaLabel:n??l,pauseAriaLabel:t??p});return c.jsx("button",{...o,type:a,"aria-label":m.ariaLabel,onClick:b=>{m.toggle(),u==null||u(b)},children:m.isPaused?e:r})}tr.displayName="Ginger.Control.PlayPause";function ar({type:e="button",onClick:r,...n}){const{repeatMode:t,cycleRepeat:a}=h.useGingerPlayback(),o=S().repeat[t];return c.jsx("button",{...n,type:e,"aria-label":o,onClick:i=>{a(),r==null||r(i)},children:o})}ar.displayName="Ginger.Control.Repeat";function ur({type:e="button",children:r="Next",onClick:n,...t}){const{next:a}=h.useGingerPlayback(),u=S();return c.jsx("button",{...t,type:e,"aria-label":u.nextTrack,onClick:o=>{a(),n==null||n(o)},children:r})}ur.displayName="Ginger.Control.Next";function ir({type:e="button",children:r="Previous",onClick:n,...t}){const{prev:a}=h.useGingerPlayback(),u=S();return c.jsx("button",{...t,type:e,"aria-label":u.previousTrack,onClick:o=>{a(),n==null||n(o)},children:r})}ir.displayName="Ginger.Control.Previous";function or({type:e="button",children:r="Shuffle",onClick:n,...t}){const{isShuffled:a,toggleShuffle:u}=h.useGingerPlayback(),o=S();return c.jsx("button",{...t,type:e,"aria-pressed":a,"aria-label":o.shuffle,onClick:i=>{u(),n==null||n(i)},children:r})}or.displayName="Ginger.Control.Shuffle";function sr({inputStyle:e,style:r,unstyled:n=!1,...t}){const a=er(),u=n?{...r,...e}:{width:"100%",...r,...e};return c.jsx("input",{...t,type:"range",min:a.min,max:a.max,step:a.step,value:a.value,"aria-label":a.ariaLabel,"aria-valuetext":a.ariaValueText,onInput:a.onSeekInput,onChange:a.onSeekChange,style:u})}sr.displayName="Ginger.Control.SeekBar";function lr({inputStyle:e,style:r,unstyled:n=!1,...t}){const a=rr(),u=n?{...r,...e}:{width:"100%",...r,...e};return c.jsx("input",{...t,type:"range",min:a.min,max:a.max,step:a.step,value:a.value,"aria-label":a.ariaLabel,"aria-valuetext":a.ariaValueText,onInput:a.onVolumeInput,onChange:a.onVolumeChange,style:u})}lr.displayName="Ginger.Control.Volume";function cr({muteLabel:e,unmuteLabel:r,type:n="button",onClick:t,...a}){const{muted:u,toggleMute:o}=h.useGingerMedia(),i=S(),l=e??i.mute,p=r??i.unmute;return c.jsx("button",{...a,type:n,"aria-pressed":u,"aria-label":u?i.unmute:i.mute,onClick:m=>{o(),t==null||t(m)},children:u?p:l})}cr.displayName="Ginger.Control.Mute";const Xr=[.5,.75,1,1.25,1.5,2];function dr({rates:e=Xr,style:r,...n}){const{playbackRate:t,setPlaybackRate:a}=h.useGingerMedia(),u=S(),o=d.useMemo(()=>Array.from(new Set([...e,t])).sort((i,l)=>i-l),[e,t]);return c.jsx("select",{...n,"aria-label":u.playbackSpeed,value:String(t),style:r,onChange:i=>a(Number(i.currentTarget.value)),children:o.map(i=>c.jsx("option",{value:String(i),children:i===1?u.playbackRateNormal:u.playbackRateTimes(i)},i))})}dr.displayName="Ginger.Control.PlaybackRate";const Ee=d.createContext(null);function Kr(){const e=d.useContext(Ee);if(!e)throw new Error("Ginger.Playlist.Track must be used inside <Ginger.Playlist>");return e}function fr({children:e,unstyled:r=!1,rowStyle:n,renderTrack:t,playOnSelect:a=!0,style:u,...o}){const{tracks:i,currentIndex:l,playTrackAt:p,selectTrackAt:m}=h.useGingerPlayback(),b=r?{...u}:{listStyle:"none",margin:0,padding:0,fontFamily:"var(--ginger-font-family, system-ui, sans-serif)",fontSize:"var(--ginger-font-size, 14px)",color:"var(--ginger-primary-color, #111827)",...u};return e!==void 0?c.jsx(Ee.Provider,{value:{playOnSelect:a},children:c.jsx("ul",{style:b,...o,children:e})}):c.jsx(Ee.Provider,{value:{playOnSelect:a},children:c.jsx("ul",{style:b,...o,children:i.map((E,M)=>{const g=M===l;return c.jsx("li",{children:c.jsx("button",{type:"button",onClick:()=>{a?p(M):m(M)},style:{width:r?void 0:"100%",textAlign:r?void 0:"left",border:r?void 0:"none",background:r?void 0:g?"var(--ginger-playlist-active-bg, rgba(17, 24, 39, 0.06))":"transparent",color:r?void 0:"inherit",font:r?void 0:"inherit",cursor:r?void 0:"pointer",padding:r?void 0:"var(--ginger-playlist-row-padding, 6px 8px)",...n},children:t?t(E,M,g):c.jsxs("span",{children:[E.title,E.artist?` — ${E.artist}`:""]})})},`${M}-${Y(E)}`)})})})}fr.displayName="Ginger.Playlist";function pr({index:e,unstyled:r=!1,className:n,style:t,children:a,liProps:u,onClick:o,...i}){const{playOnSelect:l}=Kr(),{tracks:p,currentIndex:m,playTrackAt:b,selectTrackAt:T}=h.useGingerPlayback(),E=e===m,M=p[e],g=M!=null?c.jsxs("span",{children:[M.title,M.artist?` — ${M.artist}`:""]}):null;return c.jsx("li",{...u,children:c.jsx("button",{type:"button","aria-current":E?"true":void 0,"data-ginger-active":E||void 0,className:n,style:{width:r?void 0:"100%",textAlign:r?void 0:"left",border:r?void 0:"none",background:r?void 0:E?"var(--ginger-playlist-active-bg, rgba(17, 24, 39, 0.06))":"transparent",color:r?void 0:"inherit",font:r?void 0:"inherit",cursor:r?void 0:"pointer",padding:r?void 0:"var(--ginger-playlist-row-padding, 6px 8px)",...t},...i,onClick:y=>{o==null||o(y),!y.defaultPrevented&&(l?b(e):T(e))},children:a??g})})}pr.displayName="Ginger.Playlist.Track";const qr=Object.assign(fr,{Track:pr}),Wr=L("Ginger.Queue.Title",e=>{var r;return(r=e.playlistMeta)==null?void 0:r.title}),zr=L("Ginger.Queue.Subtitle",e=>{var r;return(r=e.playlistMeta)==null?void 0:r.subtitle}),Jr=L("Ginger.Queue.Description",e=>{var r;return(r=e.playlistMeta)==null?void 0:r.description}),Zr=L("Ginger.Queue.Copyright",e=>{var r;return(r=e.playlistMeta)==null?void 0:r.copyright});function gr({className:e,style:r,fallback:n,empty:t,unstyled:a=!1,imgStyle:u}){var p,m;const o=h.useGingerState(),i=(p=o.playlistMeta)==null?void 0:p.artworkUrl;if(!i){const b=t??n??null;return b?c.jsx("span",{className:e,style:r,children:b}):null}const l=((m=o.playlistMeta)==null?void 0:m.title)??"Playlist artwork";return c.jsx("span",{className:e,style:a?{...r}:{display:"inline-block",background:"var(--ginger-artwork-bg, #f3f4f6)",borderRadius:"var(--ginger-artwork-radius, 6px)",overflow:"hidden",...r},children:c.jsx("img",{src:i,alt:l,style:{display:a?void 0:"block",width:a?void 0:"100%",height:a?void 0:"100%",objectFit:a?void 0:"cover",...u}})})}gr.displayName="Ginger.Queue.Artwork";function Q(e){return Number.isFinite(e)?Math.min(1,Math.max(0,e)):1}function he(e){return Number.isFinite(e)?Math.min(4,Math.max(.25,e)):1}const D={currentTime:0,duration:0,bufferedFraction:0,isBuffering:!1,errorMessage:null},en={...D,volume:1,muted:!1,playbackRate:1};function mr(e){const r=[...e.tracks];let n=I(e.currentIndex??0,r.length),t=null,a=r;return e.isShuffled&&r.length>1&&(t=[...r],a=_e(r,n),n=0),{tracks:a,currentIndex:n,playbackMode:e.playbackMode??"playlist",isPaused:e.isPaused??!0,isShuffled:!!(e.isShuffled&&a.length>1),repeatMode:e.repeatMode??"off",originalTracks:t,playlistMeta:e.playlistMeta??null,...en,volume:Q(e.volume??1),muted:e.muted??!1,playbackRate:he(e.playbackRate??1)}}function rn(e,r){switch(r.type){case"INIT":{const{tracks:n,currentIndex:t,playlistMeta:a,isPaused:u,isShuffled:o,repeatMode:i,playbackMode:l,volume:p,muted:m,playbackRate:b}=r.payload;return mr({tracks:n,currentIndex:t,playlistMeta:a??null,isPaused:u??!0,isShuffled:o??!1,repeatMode:i??"off",playbackMode:l??"playlist",volume:p,muted:m,playbackRate:b})}case"SET_QUEUE":{const{tracks:n,currentIndex:t}=r.payload,a=[...n],u=I(t??e.currentIndex,a.length);return{...e,tracks:a,currentIndex:u,isShuffled:!1,originalTracks:null,...D}}case"INSERT_TRACK":{const n=r.payload.index??e.tracks.length,t=Ne(e.tracks,r.payload.track,n);if(r.payload.autoPlay){const u=I(n,t.length);return{...e,tracks:t,currentIndex:u,isShuffled:!1,originalTracks:null,isPaused:!1,...D}}const a=n<=e.currentIndex?e.currentIndex+1:e.currentIndex;return{...e,tracks:t,isShuffled:!1,originalTracks:null,currentIndex:I(a,t.length)}}case"REMOVE_TRACK":{const n=r.payload.index,t=Sr(e.tracks,n),a=n<e.currentIndex?e.currentIndex-1:n===e.currentIndex?Math.min(e.currentIndex,Math.max(0,t.length-1)):e.currentIndex;return{...e,tracks:t,isShuffled:!1,originalTracks:null,currentIndex:I(a,t.length),...n===e.currentIndex?D:{}}}case"MOVE_TRACK":{const{fromIndex:n,toIndex:t}=r.payload,a=Ar(e.tracks,n,t);let u=e.currentIndex;return e.currentIndex===n?u=t:n<e.currentIndex&&t>=e.currentIndex?u-=1:n>e.currentIndex&&t<=e.currentIndex&&(u+=1),{...e,tracks:a,isShuffled:!1,originalTracks:null,currentIndex:I(u,a.length)}}case"ADD_NEXT":{const n=Rr(e.tracks,e.currentIndex,r.payload.track);return{...e,tracks:n,isShuffled:!1,originalTracks:null}}case"SET_INDEX":{const n=I(r.payload.index,e.tracks.length),t=r.payload.autoPlay,a=t===!0?!1:t===!1?!0:e.isPaused;return{...e,currentIndex:n,...D,isPaused:a}}case"PLAY":return{...e,isPaused:!1};case"PAUSE":return{...e,isPaused:!0};case"TOGGLE_PAUSE":return{...e,isPaused:!e.isPaused};case"SET_REPEAT":return{...e,repeatMode:r.payload};case"CYCLE_REPEAT":return{...e,repeatMode:_r(e.repeatMode)};case"TOGGLE_SHUFFLE":{if(e.tracks.length<=1)return{...e,isShuffled:!1,originalTracks:null};if(!e.isShuffled){const u=[...e.tracks],o=_e(u,e.currentIndex);return{...e,isShuffled:!0,originalTracks:u,tracks:o,currentIndex:0}}const n=e.originalTracks?[...e.originalTracks]:[...e.tracks],t=e.tracks[e.currentIndex],a=Pr(n,t);return{...e,isShuffled:!1,originalTracks:null,tracks:n,currentIndex:I(a,n.length)}}case"NEXT":{const n=Cr(e),t=n===e.currentIndex;return{...e,currentIndex:n,...t?{}:D,isPaused:t?e.isPaused:!1}}case"PREV":{const n=jr(e),t=n===e.currentIndex;return{...e,currentIndex:n,...t?{}:D,isPaused:t?e.isPaused:!1}}case"MEDIA_TIME_UPDATE":return{...e,currentTime:r.payload.currentTime,duration:Number.isFinite(r.payload.duration)?r.payload.duration:e.duration,bufferedFraction:r.payload.bufferedFraction,isBuffering:!1};case"MEDIA_LOADED_METADATA":return{...e,duration:Number.isFinite(r.payload.duration)?r.payload.duration:e.duration,bufferedFraction:r.payload.bufferedFraction,errorMessage:null};case"SET_PLAYLIST_META":return{...e,playlistMeta:r.payload};case"MEDIA_ERROR":return{...e,errorMessage:r.payload.message,isPaused:!0,isBuffering:!1};case"MEDIA_WAITING":return{...e,isBuffering:!0};case"MEDIA_CANPLAY":return{...e,isBuffering:!1,errorMessage:null};case"MEDIA_PLAY":return{...e,isPaused:!1,isBuffering:!1};case"MEDIA_PAUSE":return{...e,isPaused:!0};case"RESET_MEDIA_TIMES":return{...e,currentTime:0,duration:0,bufferedFraction:0};case"SET_VOLUME":return{...e,volume:Q(r.payload)};case"SET_MUTED":return{...e,muted:r.payload};case"TOGGLE_MUTE":return{...e,muted:!e.muted};case"SET_PLAYBACK_RATE":return{...e,playbackRate:he(r.payload)};case"MEDIA_VOLUME_SYNC":{const{volume:n,muted:t}=r.payload,a=Q(n);return a===e.volume&&t===e.muted?e:{...e,volume:a,muted:t}}default:return e}}function Te(){return typeof navigator>"u"||!("mediaSession"in navigator)?null:navigator.mediaSession}function nn(e,r,n){const t=r.tracks[r.currentIndex],a=t==null?void 0:t.title,u=t==null?void 0:t.artist,o=t==null?void 0:t.album,i=t==null?void 0:t.artworkUrl;d.useEffect(()=>{const l=Te();!e||!l||(l.metadata=new MediaMetadata({title:a??"Unknown track",artist:u,album:o,artwork:i?[{src:i}]:void 0}))},[e,a,u,o,i]),d.useEffect(()=>{const l=Te();!e||!l||(l.playbackState=r.isPaused?"paused":"playing")},[e,r.isPaused]),d.useEffect(()=>{const l=Te();if(!(!e||!l)){try{l.setActionHandler("play",n.play),l.setActionHandler("pause",n.pause),l.setActionHandler("nexttrack",n.next),l.setActionHandler("previoustrack",n.prev),l.setActionHandler("seekto",p=>{typeof p.seekTime=="number"&&Number.isFinite(p.seekTime)&&n.seek(p.seekTime)})}catch{}return()=>{try{l.setActionHandler("play",null),l.setActionHandler("pause",null),l.setActionHandler("nexttrack",null),l.setActionHandler("previoustrack",null),l.setActionHandler("seekto",null)}catch{}}}},[e,n])}const tn={"--ginger-primary-color":"#111827","--ginger-muted-color":"#6b7280","--ginger-font-size":"14px","--ginger-font-family":"system-ui, sans-serif","--ginger-playlist-row-padding":"6px 8px","--ginger-artwork-radius":"6px","--ginger-artwork-bg":"#f3f4f6","--ginger-playlist-active-bg":"rgba(17, 24, 39, 0.06)","--ginger-buffer-color":"rgba(107, 114, 128, 0.35)","--ginger-focus-ring":"0 0 0 2px rgba(59, 130, 246, 0.45)"};function an({children:e,initialTracks:r=[],initialIndex:n=0,initialPlaylistMeta:t=null,initialShuffle:a=!1,initialRepeatMode:u="off",initialPlaybackMode:o="playlist",initialPaused:i=!0,initialVolume:l=1,initialMuted:p=!1,initialPlaybackRate:m=1,initialStateKey:b,locale:T,mediaSession:E=!1,beforePlay:M,onPlayBlocked:g,persistence:y,hydrateOnMount:R=!1,resumeOnTrackChange:P=!1,unstyled:H=!1,className:ke,style:ve,onTrackChange:X,onPlay:K,onPause:q,onQueueEnd:W,onError:z}){var Ge;const w=d.useRef(null),[s,x]=d.useReducer(rn,void 0,()=>mr({tracks:r,currentIndex:n,playlistMeta:t,isPaused:i,isShuffled:a,repeatMode:u,playbackMode:o,volume:l,muted:p,playbackRate:m})),Ae=d.useRef(s),Me=d.useRef({tracks:r,currentIndex:n,playlistMeta:t,isPaused:i,isShuffled:a,repeatMode:u,playbackMode:o,volume:l,muted:p,playbackRate:m});Me.current={tracks:r,currentIndex:n,playlistMeta:t,isPaused:i,isShuffled:a,repeatMode:u,playbackMode:o,volume:l,muted:p,playbackRate:m};const $=d.useRef(void 0);d.useEffect(()=>{if(b===void 0){$.current=void 0;return}if($.current===void 0){$.current=b;return}if($.current===b)return;$.current=b;const f=Me.current;x({type:"INIT",payload:{tracks:f.tracks,currentIndex:f.currentIndex,playlistMeta:f.playlistMeta,isPaused:f.isPaused,isShuffled:f.isShuffled,repeatMode:f.repeatMode,playbackMode:f.playbackMode,volume:f.volume,muted:f.muted,playbackRate:f.playbackRate}})},[b,x]),d.useEffect(()=>{Ae.current=s},[s]);const Re=s.tracks[s.currentIndex]??null;d.useEffect(()=>{X==null||X(Re,s.currentIndex)},[Re,s.currentIndex,X]),d.useEffect(()=>{s.errorMessage&&(z==null||z(s.errorMessage))},[s.errorMessage,z]);const J=d.useRef(void 0);d.useEffect(()=>{if(J.current===void 0){J.current=s.isPaused;return}J.current!==s.isPaused&&(s.isPaused?q==null||q():K==null||K()),J.current=s.isPaused},[s.isPaused,q,K]);const j=d.useCallback(()=>{x({type:"PLAY"})},[]),_=d.useCallback(()=>{var f;x({type:"PAUSE"}),(f=w.current)==null||f.pause()},[]),Z=d.useCallback(()=>{s.isPaused?j():_()},[_,j,s.isPaused]),N=d.useCallback(f=>{const k=w.current;k&&Number.isFinite(f)&&(k.currentTime=Math.max(0,f))},[]),ee=d.useCallback(f=>{x({type:"SET_VOLUME",payload:Q(f)})},[]),re=d.useCallback(f=>{x({type:"SET_MUTED",payload:f})},[]),ne=d.useCallback(()=>{x({type:"TOGGLE_MUTE"})},[]),te=d.useCallback(f=>{x({type:"SET_PLAYBACK_RATE",payload:he(f)})},[]),U=d.useCallback(()=>{x({type:"NEXT"})},[]),V=d.useCallback(()=>{x({type:"PREV"})},[]),ae=d.useCallback(f=>{x({type:"SET_REPEAT",payload:f})},[]),ue=d.useCallback(()=>{x({type:"CYCLE_REPEAT"})},[]),ie=d.useCallback(()=>{x({type:"TOGGLE_SHUFFLE"})},[]),oe=d.useCallback((f,k)=>{x({type:"SET_QUEUE",payload:{tracks:f,currentIndex:k}})},[]),se=d.useCallback((f,k,v)=>{x({type:"INSERT_TRACK",payload:{track:f,index:k,autoPlay:v}})},[]),le=d.useCallback(f=>{x({type:"REMOVE_TRACK",payload:{index:f}})},[]),ce=d.useCallback((f,k)=>{x({type:"MOVE_TRACK",payload:{fromIndex:f,toIndex:k}})},[]),de=d.useCallback(f=>{x({type:"ADD_NEXT",payload:{track:f}})},[]),fe=d.useCallback(f=>{x({type:"SET_INDEX",payload:{index:f,autoPlay:!0}})},[]),pe=d.useCallback(f=>{x({type:"SET_INDEX",payload:{index:f,autoPlay:!1}})},[]),ge=d.useCallback(f=>{x({type:"SET_PLAYLIST_META",payload:f})},[]),me=d.useCallback(f=>{x({type:"INIT",payload:f})},[]);d.useEffect(()=>{if(!y||!R)return;const f=y.get("ginger:volume"),k=y.get("ginger:muted"),v=y.get("ginger:playbackRate"),G=y.get("ginger:repeatMode"),be=y.get("ginger:currentIndex"),A=Me.current;x({type:"INIT",payload:{tracks:A.tracks,playlistMeta:A.playlistMeta,isPaused:A.isPaused,isShuffled:A.isShuffled,playbackMode:A.playbackMode,currentIndex:typeof be=="number"?be:A.currentIndex,repeatMode:G==="off"||G==="all"||G==="one"?G:A.repeatMode,volume:typeof f=="number"?f:A.volume,muted:typeof k=="boolean"?k:A.muted,playbackRate:typeof v=="number"?v:A.playbackRate}})},[R,y]),d.useEffect(()=>{y&&(y.set("ginger:volume",s.volume),y.set("ginger:muted",s.muted),y.set("ginger:playbackRate",s.playbackRate),y.set("ginger:repeatMode",s.repeatMode),y.set("ginger:currentIndex",s.currentIndex))},[y,s.volume,s.muted,s.playbackRate,s.repeatMode,s.currentIndex]),d.useEffect(()=>{if(!y||!P)return;const f=s.tracks[s.currentIndex];if(!f)return;const k=`ginger:resume:${Y(f)}`,v=y.get(k);typeof v=="number"&&Number.isFinite(v)&&N(v)},[y,P,s.currentIndex,s.tracks,N]),d.useEffect(()=>{if(!y||!P)return;const f=s.tracks[s.currentIndex];if(!f||!(s.currentTime>=0))return;const k=`ginger:resume:${Y(f)}`,v=setTimeout(()=>y.set(k,s.currentTime),250);return()=>clearTimeout(v)},[y,P,s.currentIndex,s.tracks,s.currentTime]);const yr=(Ge=s.tracks[s.currentIndex])==null?void 0:Ge.fileUrl;d.useEffect(()=>{const f=w.current;if(!f)return;if(s.isPaused){f.pause();return}let k=!1;return(async()=>{if(M){let v=!1;try{v=await M()}catch(G){const be=G instanceof Error?G.message:"beforePlay rejected";x({type:"MEDIA_ERROR",payload:{message:be}});return}if(!v){k||(x({type:"PAUSE"}),g==null||g());return}}k||f.play().catch(v=>{const G=v instanceof Error?v.message:typeof v=="string"?v:"Playback failed (e.g. autoplay blocked or unavailable source)";x({type:"MEDIA_ERROR",payload:{message:G}})})})(),()=>{k=!0}},[M,yr,g,s.isPaused]);const ye=d.useCallback(()=>{const f=Gr(Ae.current);if(f.kind==="replay_same"){const v=w.current;v&&(v.currentTime=0),x({type:"PLAY"});return}if(f.kind==="stop"){x({type:"PAUSE"}),W==null||W();return}const k=f.nextIndex;x({type:"SET_INDEX",payload:{index:k,autoPlay:!0}})},[W]),br=d.useMemo(()=>({play:j,pause:_,next:U,prev:V,seek:N}),[j,_,U,V,N]);nn(!!E,s,br);const xr=T!=null&&T.seek&&/[\u0590-\u08FF]/.test(T.seek)?"rtl":"ltr",hr=d.useMemo(()=>({state:s,dispatch:x,audioRef:w,notifyEnded:ye,init:me,play:j,pause:_,togglePlayPause:Z,seek:N,setVolume:ee,setMuted:re,toggleMute:ne,setPlaybackRate:te,next:U,prev:V,setRepeatMode:ae,cycleRepeat:ue,toggleShuffle:ie,setQueue:oe,insertTrackAt:se,removeTrackAt:le,moveTrack:ce,enqueueNext:de,playTrackAt:fe,selectTrackAt:pe,setPlaylistMeta:ge}),[ue,x,me,U,ye,_,j,fe,se,le,ce,de,pe,V,N,re,te,oe,ae,ge,ee,s,ne,Z,ie]),kr=d.useMemo(()=>({tracks:s.tracks,currentIndex:s.currentIndex,isPaused:s.isPaused,isShuffled:s.isShuffled,repeatMode:s.repeatMode,originalTracks:s.originalTracks,playlistMeta:s.playlistMeta,init:me,play:j,pause:_,togglePlayPause:Z,next:U,prev:V,setRepeatMode:ae,cycleRepeat:ue,toggleShuffle:ie,playbackMode:s.playbackMode,setQueue:oe,insertTrackAt:se,removeTrackAt:le,moveTrack:ce,enqueueNext:de,playTrackAt:fe,selectTrackAt:pe,setPlaylistMeta:ge,dispatch:x}),[s.tracks,s.currentIndex,s.isPaused,s.isShuffled,s.repeatMode,s.playbackMode,s.originalTracks,s.playlistMeta,me,j,_,Z,U,V,ae,ue,ie,oe,se,le,ce,de,fe,pe,ge,x]),vr=d.useMemo(()=>({currentTime:s.currentTime,duration:s.duration,bufferedFraction:s.bufferedFraction,isBuffering:s.isBuffering,errorMessage:s.errorMessage,volume:s.volume,muted:s.muted,playbackRate:s.playbackRate,seek:N,setVolume:ee,setMuted:re,toggleMute:ne,setPlaybackRate:te,audioRef:w,notifyEnded:ye,dispatch:x}),[s.currentTime,s.duration,s.bufferedFraction,s.isBuffering,s.errorMessage,s.volume,s.muted,s.playbackRate,N,ee,re,ne,te,w,ye,x]),Mr=Ie(s),Tr=d.useMemo(()=>H?ve:{...tn,...ve},[ve,H]);return c.jsx(Hr,{locale:T,children:c.jsx(h.GingerPlaybackContext.Provider,{value:kr,children:c.jsx(h.GingerMediaContext.Provider,{value:vr,children:c.jsx(je.Provider,{value:hr,children:c.jsx("div",{className:ke,style:Tr,"data-ginger-playback":Mr,dir:xr,children:e})})})})})}const un={Provider:an,Player:Ir,Current:{Title:Dr,Artist:Lr,Album:Fr,Description:Ur,Copyright:Vr,Genre:Br,Label:$r,Isrc:Or,TrackNumber:Yr,Year:Fe,Lyrics:Ue,FileUrl:Ve,Artwork:Be,QueueIndex:$e,QueueLength:Oe,QueuePosition:Ye,Elapsed:Qe,Duration:He,Remaining:Xe,Progress:Ke,TimeRail:qe,BufferRail:We,PlaybackState:ze,ErrorMessage:Je},Queue:{Title:Wr,Subtitle:zr,Description:Jr,Copyright:Zr,Artwork:gr},Control:{PlayPause:tr,Repeat:ar,Next:ur,Previous:ir,Shuffle:or,SeekBar:sr,Volume:lr,Mute:cr,PlaybackRate:dr},Playlist:qr};exports.Ginger=un;exports.clampPlaybackRate=he;exports.clampVolume=Q;exports.defaultGingerLocale=O;exports.derivePlaybackUiState=Ie;exports.effectiveDuration=B;exports.effectiveRemaining=we;exports.getCurrentTrack=C;exports.progressFraction=Pe;exports.resolvedAlbumLine=Le;exports.resolvedArtwork=De;exports.useGingerLocale=S;exports.usePlayPauseBinding=nr;exports.useSeekBarBinding=er;exports.useVolumeSlider=rr;
|
|
2
|
-
//# sourceMappingURL=ginger-DYoHDn8T.cjs.map
|