@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.
Files changed (82) hide show
  1. package/README.md +80 -2
  2. package/dist/{GingerSplitContexts-4YZ-OJ9V.js → GingerSplitContexts-BzBExb95.js} +22 -21
  3. package/dist/GingerSplitContexts-BzBExb95.js.map +1 -0
  4. package/dist/GingerSplitContexts-C7puo0M7.cjs +2 -0
  5. package/dist/GingerSplitContexts-C7puo0M7.cjs.map +1 -0
  6. package/dist/analyzer/liveAudioGraph.d.ts +14 -0
  7. package/dist/analyzer/liveAudioGraph.d.ts.map +1 -0
  8. package/dist/analyzer/useGingerLiveAnalyzer.d.ts +21 -0
  9. package/dist/analyzer/useGingerLiveAnalyzer.d.ts.map +1 -0
  10. package/dist/audio/GingerPlayer.d.ts.map +1 -1
  11. package/dist/audio/GingerPlayer.test.d.ts +2 -0
  12. package/dist/audio/GingerPlayer.test.d.ts.map +1 -0
  13. package/dist/client.cjs +1 -1
  14. package/dist/client.js +21 -18
  15. package/dist/context/GingerContext.d.ts +2 -1
  16. package/dist/context/GingerContext.d.ts.map +1 -1
  17. package/dist/context/GingerProvider.d.ts.map +1 -1
  18. package/dist/context/GingerSplitContexts.d.ts +2 -1
  19. package/dist/context/GingerSplitContexts.d.ts.map +1 -1
  20. package/dist/core/playbackReducer.d.ts.map +1 -1
  21. package/dist/core/queue.d.ts.map +1 -1
  22. package/dist/experimental-gapless/index.cjs +1 -1
  23. package/dist/experimental-gapless/index.js +1 -1
  24. package/dist/ginger-BTPRqWHs.js +1621 -0
  25. package/dist/ginger-BTPRqWHs.js.map +1 -0
  26. package/dist/ginger-BiI69vrn.cjs +2 -0
  27. package/dist/ginger-BiI69vrn.cjs.map +1 -0
  28. package/dist/hooks/hooks.test.d.ts +2 -0
  29. package/dist/hooks/hooks.test.d.ts.map +1 -0
  30. package/dist/hooks/useGinger.d.ts +1 -0
  31. package/dist/hooks/useGinger.d.ts.map +1 -1
  32. package/dist/index.cjs +1 -1
  33. package/dist/index.d.ts +4 -0
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +21 -18
  36. package/dist/internal/fft.d.ts +7 -0
  37. package/dist/internal/fft.d.ts.map +1 -0
  38. package/dist/internal/fft.test.d.ts +2 -0
  39. package/dist/internal/fft.test.d.ts.map +1 -0
  40. package/dist/media/useMediaSession.d.ts.map +1 -1
  41. package/dist/media/useMediaSession.test.d.ts +2 -0
  42. package/dist/media/useMediaSession.test.d.ts.map +1 -0
  43. package/dist/testing/helpers.d.ts +21 -0
  44. package/dist/testing/helpers.d.ts.map +1 -0
  45. package/dist/testing/index.cjs +19 -19
  46. package/dist/testing/index.cjs.map +1 -1
  47. package/dist/testing/index.d.ts +2 -7
  48. package/dist/testing/index.d.ts.map +1 -1
  49. package/dist/testing/index.js +33 -4
  50. package/dist/testing/index.js.map +1 -1
  51. package/dist/testing/renderGinger.d.ts +8 -0
  52. package/dist/testing/renderGinger.d.ts.map +1 -0
  53. package/dist/types.d.ts +5 -0
  54. package/dist/types.d.ts.map +1 -1
  55. package/dist/useSeekDrag-Br1V0Vao.js +290 -0
  56. package/dist/useSeekDrag-Br1V0Vao.js.map +1 -0
  57. package/dist/useSeekDrag-aS7uk26h.cjs +2 -0
  58. package/dist/useSeekDrag-aS7uk26h.cjs.map +1 -0
  59. package/dist/waveform/analyzeAudioFile.d.ts +31 -0
  60. package/dist/waveform/analyzeAudioFile.d.ts.map +1 -0
  61. package/dist/waveform/analyzeAudioFile.test.d.ts +2 -0
  62. package/dist/waveform/analyzeAudioFile.test.d.ts.map +1 -0
  63. package/dist/waveform/index.cjs +1 -1
  64. package/dist/waveform/index.cjs.map +1 -1
  65. package/dist/waveform/index.d.ts +4 -0
  66. package/dist/waveform/index.d.ts.map +1 -1
  67. package/dist/waveform/index.js +207 -23
  68. package/dist/waveform/index.js.map +1 -1
  69. package/dist/waveform/useAudioFileAnalysis.d.ts +8 -0
  70. package/dist/waveform/useAudioFileAnalysis.d.ts.map +1 -0
  71. package/package.json +4 -1
  72. package/dist/GingerSplitContexts-4YZ-OJ9V.js.map +0 -1
  73. package/dist/GingerSplitContexts-Bze1Bqe2.cjs +0 -2
  74. package/dist/GingerSplitContexts-Bze1Bqe2.cjs.map +0 -1
  75. package/dist/ginger-DYoHDn8T.cjs +0 -2
  76. package/dist/ginger-DYoHDn8T.cjs.map +0 -1
  77. package/dist/ginger-Dntdd6zH.js +0 -1599
  78. package/dist/ginger-Dntdd6zH.js.map +0 -1
  79. package/dist/useSeekDrag-DBzoym0-.cjs +0 -2
  80. package/dist/useSeekDrag-DBzoym0-.cjs.map +0 -1
  81. package/dist/useSeekDrag-jLsYA-uG.js +0 -174
  82. 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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"}
@@ -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"}
@@ -1,42 +1,226 @@
1
- import { useState as m, useEffect as w } from "react";
2
- function L(a, o = 64) {
3
- const [h, t] = m({
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 w(() => {
9
- if (!a) {
10
- t({ peaks: [], isLoading: !1, error: null });
8
+ return y(() => {
9
+ if (!e) {
10
+ a({ peaks: [], isLoading: !1, error: null });
11
11
  return;
12
12
  }
13
- let r = !1;
14
- return t((e) => ({ ...e, isLoading: !0, error: null })), (async () => {
13
+ let o = !1;
14
+ return a((n) => ({ ...n, isLoading: !0, error: null })), (async () => {
15
15
  try {
16
- const e = await fetch(a);
17
- if (!e.ok) throw new Error(`Fetch failed: ${e.status} ${e.statusText}`);
18
- const p = await e.arrayBuffer(), u = new AudioContext(), s = (await u.decodeAudioData(p)).getChannelData(0), l = Math.max(1, Math.floor(s.length / o)), c = [];
19
- for (let n = 0; n < o; n += 1) {
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 = n * l, g = Math.min(s.length, d + l);
22
- for (let f = d; f < g; f += 1)
23
- i = Math.max(i, Math.abs(s[f] ?? 0));
24
- c.push(i);
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 u.close(), r || t({ peaks: c, isLoading: !1, error: null });
27
- } catch (e) {
28
- r || t({
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: e instanceof Error ? e.message : "Failed to decode peaks"
31
+ error: n instanceof Error ? n.message : "Failed to decode peaks"
32
32
  });
33
33
  }
34
34
  })(), () => {
35
- r = !0;
35
+ o = !0;
36
36
  };
37
- }, [o, a]), h;
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
- L as useAudioPeaks
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.13",
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"}
@@ -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