@lucaismyname/ginger 0.0.29 → 0.0.31

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 (67) hide show
  1. package/README.md +140 -8
  2. package/dist/analyzer/liveAudioGraph.d.ts +14 -1
  3. package/dist/analyzer/liveAudioGraph.d.ts.map +1 -1
  4. package/dist/analyzer/useGingerLiveAnalyzer.d.ts +6 -0
  5. package/dist/analyzer/useGingerLiveAnalyzer.d.ts.map +1 -1
  6. package/dist/client.cjs +1 -1
  7. package/dist/client.js +36 -29
  8. package/dist/client.js.map +1 -1
  9. package/dist/components/playlist/GingerPlaylist.d.ts.map +1 -1
  10. package/dist/context/GingerProvider.d.ts +1 -1
  11. package/dist/context/GingerProvider.d.ts.map +1 -1
  12. package/dist/core/playbackReducer.d.ts.map +1 -1
  13. package/dist/equalizer/index.cjs +2 -0
  14. package/dist/equalizer/index.cjs.map +1 -0
  15. package/dist/equalizer/index.d.ts +3 -0
  16. package/dist/equalizer/index.d.ts.map +1 -0
  17. package/dist/equalizer/index.js +51 -0
  18. package/dist/equalizer/index.js.map +1 -0
  19. package/dist/equalizer/useGingerEqualizer.d.ts +41 -0
  20. package/dist/equalizer/useGingerEqualizer.d.ts.map +1 -0
  21. package/dist/ginger-L2ZFgzH4.js +2223 -0
  22. package/dist/ginger-L2ZFgzH4.js.map +1 -0
  23. package/dist/ginger-NEcOSSJD.cjs +2 -0
  24. package/dist/ginger-NEcOSSJD.cjs.map +1 -0
  25. package/dist/hooks/useGingerChapterProgress.d.ts +14 -0
  26. package/dist/hooks/useGingerChapterProgress.d.ts.map +1 -0
  27. package/dist/hooks/useGingerKeyboardShortcuts.d.ts +6 -0
  28. package/dist/hooks/useGingerKeyboardShortcuts.d.ts.map +1 -1
  29. package/dist/hooks/useGingerPlaybackHistory.d.ts +26 -0
  30. package/dist/hooks/useGingerPlaybackHistory.d.ts.map +1 -0
  31. package/dist/hooks/useGingerSleepTimer.d.ts.map +1 -1
  32. package/dist/hooks/useGingerVolumeFade.d.ts +22 -0
  33. package/dist/hooks/useGingerVolumeFade.d.ts.map +1 -0
  34. package/dist/index.cjs +1 -1
  35. package/dist/index.d.ts +18 -2
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +36 -29
  38. package/dist/index.js.map +1 -1
  39. package/dist/liveAudioGraph-CmEsdLgZ.js +150 -0
  40. package/dist/liveAudioGraph-CmEsdLgZ.js.map +1 -0
  41. package/dist/liveAudioGraph-D1BXMv_u.cjs +2 -0
  42. package/dist/liveAudioGraph-D1BXMv_u.cjs.map +1 -0
  43. package/dist/selectors-BalBCc7X.js +127 -0
  44. package/dist/selectors-BalBCc7X.js.map +1 -0
  45. package/dist/selectors-YXnP8Y8g.cjs +2 -0
  46. package/dist/selectors-YXnP8Y8g.cjs.map +1 -0
  47. package/dist/store.d.ts +46 -0
  48. package/dist/store.d.ts.map +1 -0
  49. package/dist/testing/index.cjs +1 -1
  50. package/dist/testing/index.js +1 -1
  51. package/dist/testing/mockWebAudio.d.ts +15 -1
  52. package/dist/testing/mockWebAudio.d.ts.map +1 -1
  53. package/dist/types.d.ts +30 -8
  54. package/dist/types.d.ts.map +1 -1
  55. package/dist/useGingerChapterProgress-BOqUimE7.cjs +2 -0
  56. package/dist/useGingerChapterProgress-BOqUimE7.cjs.map +1 -0
  57. package/dist/useGingerChapterProgress-DLYdGytK.js +321 -0
  58. package/dist/useGingerChapterProgress-DLYdGytK.js.map +1 -0
  59. package/package.json +7 -2
  60. package/dist/ginger-B26HM2Ja.cjs +0 -2
  61. package/dist/ginger-B26HM2Ja.cjs.map +0 -1
  62. package/dist/ginger-DlNYfHbV.js +0 -2278
  63. package/dist/ginger-DlNYfHbV.js.map +0 -1
  64. package/dist/useNextTrackPrefetch-Y_fs2JEx.js +0 -265
  65. package/dist/useNextTrackPrefetch-Y_fs2JEx.js.map +0 -1
  66. package/dist/useNextTrackPrefetch-wSILz6TL.cjs +0 -2
  67. package/dist/useNextTrackPrefetch-wSILz6TL.cjs.map +0 -1
package/dist/types.d.ts CHANGED
@@ -21,6 +21,16 @@ export type GingerLocaleMessages = {
21
21
  playbackRateNormal: string;
22
22
  playbackRateTimes: (rate: number) => string;
23
23
  };
24
+ /** A single chapter marker within a track. */
25
+ export type TrackChapter = {
26
+ title: string;
27
+ startSeconds: number;
28
+ };
29
+ /** A single time-stamped lyric line; used for `lyricsTimed` and LRC parsing output. */
30
+ export type TrackLyricLine = {
31
+ time: number;
32
+ text: string;
33
+ };
24
34
  export type Track = {
25
35
  /** Optional stable identity for duplicate URLs / queue mutations */
26
36
  id?: string;
@@ -37,14 +47,8 @@ export type Track = {
37
47
  isrc?: string;
38
48
  trackNumber?: number;
39
49
  lyrics?: string;
40
- lyricsTimed?: Array<{
41
- time: number;
42
- text: string;
43
- }>;
44
- chapters?: Array<{
45
- title: string;
46
- startSeconds: number;
47
- }>;
50
+ lyricsTimed?: TrackLyricLine[];
51
+ chapters?: TrackChapter[];
48
52
  /** Hint before metadata loads; never overrides finite media duration */
49
53
  durationSeconds?: number;
50
54
  /** App-specific data for custom UI; not read by Ginger core */
@@ -252,6 +256,24 @@ export type GingerProviderProps = {
252
256
  onPause?: () => void;
253
257
  onQueueEnd?: () => void;
254
258
  onError?: (message: string) => void;
259
+ onVolumeChange?: (volume: number, muted: boolean) => void;
260
+ onPlaybackRateChange?: (rate: number) => void;
261
+ /**
262
+ * Called whenever `seek()` is invoked (i.e. a programmatic or user-initiated scrub).
263
+ * Fires with the requested time in seconds.
264
+ */
265
+ onSeek?: (timeSeconds: number) => void;
266
+ /**
267
+ * Explicit layout direction for the provider root. When set, this takes priority over the
268
+ * automatic RTL heuristic derived from locale strings.
269
+ */
270
+ dir?: "ltr" | "rtl" | "auto";
271
+ /**
272
+ * Seconds threshold for "restart current track" on previous action.
273
+ * When `currentTime > prevRestartThresholdSeconds`, pressing previous restarts the track
274
+ * instead of skipping to the prior one. Set to `0` to disable. Default: `3`.
275
+ */
276
+ prevRestartThresholdSeconds?: number;
255
277
  };
256
278
  export type GingerPersistenceAdapter = {
257
279
  get: (key: string) => unknown;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";const t=require("react"),D=require("./liveAudioGraph-D1BXMv_u.cjs"),w=require("./GingerSplitContexts-C7puo0M7.cjs"),U=require("./selectors-YXnP8Y8g.cjs"),C=require("./ginger-NEcOSSJD.cjs"),F=new Uint8Array(0),q=new Uint8Array(0);function z(s={}){const{enabled:e=!0,fftSize:r=2048,smoothingTimeConstant:n=.8,minDecibels:u=-100,maxDecibels:c=-30}=s,{audioRef:a,state:o}=D.useGinger(),d=t.useMemo(()=>({fftSize:r,smoothingTimeConstant:n,minDecibels:u,maxDecibels:c}),[r,n,u,c]),[l,m]=t.useState(0),[f,i]=t.useState(null),[h,R]=t.useState(!1),[S,p]=t.useState({frequencyBinCount:0,sampleRate:0}),g=t.useRef(F),v=t.useRef(q),G=t.useCallback(async()=>{const x=y.current;x&&x.state==="suspended"&&await x.resume()},[]),y=t.useRef(null),I=t.useRef(null);return t.useLayoutEffect(()=>{if(!e||typeof window>"u")return;let x=!1,E=null,A=null,T=0;const N=()=>{const k=y.current;k&&R(k.state==="suspended")},V=()=>{if(x)return;const k=I.current,P=g.current,M=v.current;k&&P.length>0&&M.length>0&&(k.getByteFrequencyData(P),k.getByteTimeDomainData(M),m(L=>L+1)),T=requestAnimationFrame(V)},B=()=>{const k=a.current;if(!k||x)return"no-element";try{const{id:P,context:M,analyser:L}=D.attachLiveAnalyser(k,d);E=P,A=k,y.current=M,I.current=L,R(M.state==="suspended"),i(null),M.addEventListener("statechange",N);const b=L.frequencyBinCount,H=L.fftSize;return g.current=new Uint8Array(b),v.current=new Uint8Array(H),p({frequencyBinCount:b,sampleRate:M.sampleRate}),T=requestAnimationFrame(V),"ok"}catch(P){const M=P instanceof Error?P.message:"Failed to attach live analyser";return i(M),y.current=null,I.current=null,g.current=F,v.current=q,p({frequencyBinCount:0,sampleRate:0}),"error"}},K=B();if(K!=="ok"){let k=0;const P=120;let M=0;const L=()=>{if(x)return;const b=B();b==="ok"||b==="error"||(M+=1,!(M>=P)&&(k=requestAnimationFrame(L)))};return K==="no-element"&&(k=requestAnimationFrame(L)),()=>{var b;x=!0,cancelAnimationFrame(k),cancelAnimationFrame(T),E!=null&&A&&D.detachLiveAnalyser(A,E),(b=y.current)==null||b.removeEventListener("statechange",N),y.current=null,I.current=null,g.current=F,v.current=q}}return()=>{var k;x=!0,cancelAnimationFrame(T),E!=null&&A&&D.detachLiveAnalyser(A,E),(k=y.current)==null||k.removeEventListener("statechange",N),y.current=null,I.current=null,g.current=F,v.current=q,p({frequencyBinCount:0,sampleRate:0})}},[e,a,d,o.currentIndex]),{frequencyData:g.current,timeDomainData:v.current,frequencyBinCount:S.frequencyBinCount,sampleRate:S.sampleRate,isSuspended:h,error:f,resume:G,frame:l}}function X(s=!0,e={}){const{togglePlayPause:r,next:n,prev:u}=w.useGingerPlayback(),{toggleMute:c,seek:a,currentTime:o,duration:d}=w.useGingerMedia(),{mute:l,seekForward:m,seekBackward:f}=e;t.useEffect(()=>{if(!s||typeof window>"u")return;const i=(e.playPause??" ").toLowerCase(),h=(e.next??"ArrowRight").toLowerCase(),R=(e.previous??"ArrowLeft").toLowerCase(),S=l==null?void 0:l.toLowerCase(),p=m==null?void 0:m.toLowerCase(),g=f==null?void 0:f.toLowerCase(),v=e.seekSeconds??5,G=y=>{const I=y.target;if(I&&(["INPUT","TEXTAREA","SELECT"].includes(I.tagName)||I.isContentEditable))return;const x=y.key.toLowerCase();if(x===i)y.preventDefault(),r();else if(x===h)y.preventDefault(),n();else if(x===R)y.preventDefault(),u();else if(S&&x===S)y.preventDefault(),c();else if(p&&x===p){y.preventDefault();const E=d>0?d:Number.POSITIVE_INFINITY;a(Math.min(E,o+v))}else g&&x===g&&(y.preventDefault(),a(Math.max(0,o-v)))};return window.addEventListener("keydown",G),()=>window.removeEventListener("keydown",G)},[e.next,e.playPause,e.previous,e.seekSeconds,o,d,s,l,n,u,a,f,m,c,r])}function O(s){const{durationMs:e,stopAfterTracks:r,respectPause:n=!0,enabled:u=!0,onFire:c}=s,{currentIndex:a,pause:o,isPaused:d}=w.useGingerPlayback(),l=t.useRef(r??0),m=t.useRef(a),f=t.useRef(e??0),i=t.useRef(null);t.useEffect(()=>{l.current=r??0},[r]);const h=t.useRef(e);t.useEffect(()=>{h.current!==e&&(f.current=e??0,h.current=e)},[e]),t.useEffect(()=>{if(!u||!e||e<=0){f.current=e??0,i.current=null;return}if(n&&d){if(i.current!==null){const S=Date.now()-i.current;f.current=Math.max(0,f.current-S),i.current=null}return}i.current=Date.now();const R=setTimeout(()=>{f.current=0,i.current=null,o(),c==null||c()},f.current);return()=>{if(clearTimeout(R),i.current!==null){const S=Date.now()-i.current;f.current=Math.max(0,f.current-S),i.current=null}}},[e,u,d,c,o,n]),t.useEffect(()=>{if(!u||!r||r<=0)return;const R=m.current;m.current=a,a!==R&&(l.current-=1,l.current<=0&&(o(),c==null||c()))},[a,u,c,o,r])}function Y(s=!1){const e=w.useGingerState(),r=t.useRef(e);t.useEffect(()=>{if(!s||typeof console>"u")return;const n=r.current;n!==e&&console.debug("[ginger]",{from:{currentIndex:n.currentIndex,isPaused:n.isPaused,currentTime:n.currentTime,repeatMode:n.repeatMode},to:{currentIndex:e.currentIndex,isPaused:e.isPaused,currentTime:e.currentTime,repeatMode:e.repeatMode}}),r.current=e},[s,e])}function _(s){return Math.max(0,Math.min(1,s))}function j(s){const e=w.useGingerMedia(),r=w.useGingerPlayback(),{seek:n}=e,[u,c]=t.useState(0),[a,o]=t.useState(!1),d=U.progressFraction(w.gingerStateFromContextValues(r,e)),l=a?u:d,m=t.useCallback(f=>{if(!(s>0))return;const i=f.currentTarget,h=i.getBoundingClientRect(),R=g=>{const v=_((g-h.left)/h.width);c(v),n(v*s)};o(!0),i.setPointerCapture(f.pointerId),R(f.clientX);const S=g=>R(g.clientX),p=g=>{R(g.clientX),o(!1),i.releasePointerCapture(f.pointerId),i.removeEventListener("pointermove",S),i.removeEventListener("pointerup",p),i.removeEventListener("pointercancel",p)};i.addEventListener("pointermove",S),i.addEventListener("pointerup",p),i.addEventListener("pointercancel",p)},[s,n]);return{fraction:u,displayFraction:l,isDragging:a,onPointerDown:m}}function J(s={}){const{enabled:e=!0,crossOrigin:r}=s,{tracks:n,currentIndex:u,repeatMode:c,playbackMode:a}=w.useGingerPlayback();t.useEffect(()=>{var m;if(!e||typeof document>"u")return;const o=U.computeNextIndex({tracks:n,currentIndex:u,repeatMode:c,playbackMode:a});if(o===u)return;const d=((m=n[o])==null?void 0:m.fileUrl)??"";if(!d)return;const l=document.createElement("audio");return l.preload="auto",r&&(l.crossOrigin=r),l.src=d,l.load(),()=>{l.removeAttribute("src"),l.load()}},[e,r,n,u,c,a])}function Q(s={}){let e=C.createInitialState({tracks:s.tracks??[],currentIndex:s.currentIndex,playlistMeta:s.playlistMeta,isPaused:s.isPaused,isShuffled:s.isShuffled,repeatMode:s.repeatMode,playbackMode:s.playbackMode,volume:s.volume,muted:s.muted,playbackRate:s.playbackRate});const r=new Set,n=a=>{const o=C.gingerReducer(e,a);if(o!==e){e=o;for(const d of r)d(e)}};return{getState:()=>e,dispatch:n,subscribe:a=>(r.add(a),()=>r.delete(a)),init:a=>{n({type:"INIT",payload:a})},clampVolume:C.clampVolume,clampPlaybackRate:C.clampPlaybackRate}}function W(s={}){const{maxLength:e=50}=s,{tracks:r,currentIndex:n}=w.useGingerPlayback(),[u,c]=t.useState([]),a=t.useRef(null),o=t.useRef(r);o.current=r,t.useEffect(()=>{const l=r[n];if(!l||a.current===n)return;a.current=n;const m={track:l,index:n,playedAt:Date.now()};c(f=>{const i=[...f,m];return i.length>e?i.slice(i.length-e):i})},[n,r,e]);const d=t.useCallback(()=>c([]),[]);return{history:u,clearHistory:d}}function Z(){const{setVolume:s,volume:e}=w.useGingerMedia(),[r,n]=t.useState(!1),u=t.useRef(0),c=t.useRef(!1),a=t.useCallback(()=>{cancelAnimationFrame(u.current),c.current=!0,n(!1)},[]);return{fadeVolumeTo:t.useCallback(({targetVolume:d,durationMs:l,onComplete:m})=>{cancelAnimationFrame(u.current),c.current=!1;const f=p=>Math.min(1,Math.max(0,p)),i=f(d),h=performance.now();let R=e;n(!0);const S=p=>{if(c.current)return;const g=p-h,v=Math.min(1,g/Math.max(1,l)),G=R+(i-R)*v;s(f(G)),v<1?u.current=requestAnimationFrame(S):(n(!1),m==null||m())};u.current=requestAnimationFrame(p=>{R=e,S(p)})},[s,e]),cancelFade:a,isFading:r}}function $(){const{tracks:s,currentIndex:e}=w.useGingerPlayback(),{currentTime:r,duration:n}=w.useGingerMedia(),u=t.useMemo(()=>{var a;return[...((a=s[e])==null?void 0:a.chapters)??[]].filter(o=>o&&Number.isFinite(o.startSeconds)&&o.startSeconds>=0).sort((o,d)=>o.startSeconds-d.startSeconds)},[s,e]);return t.useMemo(()=>{if(u.length===0)return{progress:0,elapsed:0,remaining:0};let c=-1;for(let h=u.length-1;h>=0;h--)if(r>=u[h].startSeconds){c=h;break}if(c===-1)return{progress:0,elapsed:0,remaining:0};const a=u[c],o=u[c+1],d=(o==null?void 0:o.startSeconds)??(n>0?n:r),l=Math.max(0,d-a.startSeconds),m=Math.max(0,r-a.startSeconds),f=Math.max(0,d-r);return{progress:l>0?Math.min(1,m/l):0,elapsed:m,remaining:f}},[u,r,n])}exports.createGingerStore=Q;exports.useGingerChapterProgress=$;exports.useGingerDebugLog=Y;exports.useGingerKeyboardShortcuts=X;exports.useGingerLiveAnalyzer=z;exports.useGingerPlaybackHistory=W;exports.useGingerSleepTimer=O;exports.useGingerVolumeFade=Z;exports.useNextTrackPrefetch=J;exports.useSeekDrag=j;
2
+ //# sourceMappingURL=useGingerChapterProgress-BOqUimE7.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGingerChapterProgress-BOqUimE7.cjs","sources":["../src/analyzer/useGingerLiveAnalyzer.ts","../src/hooks/useGingerKeyboardShortcuts.ts","../src/hooks/useGingerSleepTimer.ts","../src/hooks/useGingerDebugLog.ts","../src/hooks/useSeekDrag.ts","../src/hooks/useNextTrackPrefetch.ts","../src/store.ts","../src/hooks/useGingerPlaybackHistory.ts","../src/hooks/useGingerVolumeFade.ts","../src/hooks/useGingerChapterProgress.ts"],"sourcesContent":["import { useCallback, useLayoutEffect, useMemo, useRef, useState } from \"react\";\nimport { useGinger } from \"../hooks/useGinger\";\nimport { type LiveAnalyserOptions, attachLiveAnalyser, detachLiveAnalyser } from \"./liveAudioGraph\";\n\nexport type UseGingerLiveAnalyzerOptions = {\n /** When false, the analyser is detached and no frames are read. Default true. */\n enabled?: boolean;\n fftSize?: number;\n smoothingTimeConstant?: number;\n minDecibels?: number;\n maxDecibels?: number;\n};\n\nexport type UseGingerLiveAnalyzerResult = {\n /** Byte frequency data (0–255); length equals `frequencyBinCount`. Updated each animation frame while enabled. */\n frequencyData: Uint8Array;\n /** Byte time-domain data (0–255); length equals `fftSize`. */\n timeDomainData: Uint8Array;\n frequencyBinCount: number;\n sampleRate: number;\n isSuspended: boolean;\n error: string | null;\n resume: () => Promise<void>;\n /**\n * Monotonically increasing counter incremented each animation frame.\n * Use as a `useMemo` / `useEffect` dependency to respond to new audio data, since\n * `frequencyData` and `timeDomainData` are mutated in-place (their reference never changes).\n */\n frame: number;\n};\n\nconst emptyFreq = new Uint8Array(0);\nconst emptyTime = new Uint8Array(0);\n\nexport function useGingerLiveAnalyzer(\n options: UseGingerLiveAnalyzerOptions = {},\n): UseGingerLiveAnalyzerResult {\n const {\n enabled = true,\n fftSize = 2048,\n smoothingTimeConstant = 0.8,\n minDecibels = -100,\n maxDecibels = -30,\n } = options;\n\n const { audioRef, state } = useGinger();\n const opts = useMemo<LiveAnalyserOptions>(\n () => ({\n fftSize,\n smoothingTimeConstant,\n minDecibels,\n maxDecibels,\n }),\n [fftSize, smoothingTimeConstant, minDecibels, maxDecibels],\n );\n\n const [frame, setFrame] = useState(0);\n const [error, setError] = useState<string | null>(null);\n const [isSuspended, setIsSuspended] = useState(false);\n const [meta, setMeta] = useState({ frequencyBinCount: 0, sampleRate: 0 });\n\n const freqRef = useRef<Uint8Array>(emptyFreq);\n const timeRef = useRef<Uint8Array>(emptyTime);\n\n const resume = useCallback(async () => {\n const ctx = contextHolderRef.current;\n if (ctx && ctx.state === \"suspended\") {\n await ctx.resume();\n }\n }, []);\n\n const contextHolderRef = useRef<AudioContext | null>(null);\n const analyserHolderRef = useRef<AnalyserNode | null>(null);\n\n useLayoutEffect(() => {\n if (!enabled || typeof window === \"undefined\") {\n return;\n }\n\n let cancelled = false;\n let consumerId: number | null = null;\n let element: HTMLAudioElement | null = null;\n let rafId = 0;\n\n const onStateChange = () => {\n const ctx = contextHolderRef.current;\n if (ctx) setIsSuspended(ctx.state === \"suspended\");\n };\n\n const runLoop = () => {\n if (cancelled) return;\n const a = analyserHolderRef.current;\n const fq = freqRef.current;\n const td = timeRef.current;\n if (a && fq.length > 0 && td.length > 0) {\n a.getByteFrequencyData(fq as Uint8Array<ArrayBuffer>);\n a.getByteTimeDomainData(td as Uint8Array<ArrayBuffer>);\n setFrame((n) => n + 1);\n }\n rafId = requestAnimationFrame(runLoop);\n };\n\n type AttachOutcome = \"ok\" | \"no-element\" | \"error\";\n\n const attach = (): AttachOutcome => {\n const el = audioRef.current;\n if (!el || cancelled) return \"no-element\";\n try {\n const { id, context, analyser } = attachLiveAnalyser(el, opts);\n consumerId = id;\n element = el;\n contextHolderRef.current = context;\n analyserHolderRef.current = analyser;\n setIsSuspended(context.state === \"suspended\");\n setError(null);\n\n context.addEventListener(\"statechange\", onStateChange);\n\n const n = analyser.frequencyBinCount;\n const fft = analyser.fftSize;\n freqRef.current = new Uint8Array(n);\n timeRef.current = new Uint8Array(fft);\n setMeta({ frequencyBinCount: n, sampleRate: context.sampleRate });\n\n rafId = requestAnimationFrame(runLoop);\n return \"ok\";\n } catch (e) {\n const msg = e instanceof Error ? e.message : \"Failed to attach live analyser\";\n setError(msg);\n contextHolderRef.current = null;\n analyserHolderRef.current = null;\n freqRef.current = emptyFreq;\n timeRef.current = emptyTime;\n setMeta({ frequencyBinCount: 0, sampleRate: 0 });\n return \"error\";\n }\n };\n\n const first = attach();\n if (first !== \"ok\") {\n let retryRaf = 0;\n const maxAttempts = 120;\n let attempts = 0;\n\n const retryLoop = () => {\n if (cancelled) return;\n const out = attach();\n if (out === \"ok\" || out === \"error\") return;\n attempts += 1;\n if (attempts >= maxAttempts) return;\n retryRaf = requestAnimationFrame(retryLoop);\n };\n\n if (first === \"no-element\") {\n retryRaf = requestAnimationFrame(retryLoop);\n }\n\n return () => {\n cancelled = true;\n cancelAnimationFrame(retryRaf);\n cancelAnimationFrame(rafId);\n if (consumerId != null && element) {\n detachLiveAnalyser(element, consumerId);\n }\n contextHolderRef.current?.removeEventListener(\"statechange\", onStateChange);\n contextHolderRef.current = null;\n analyserHolderRef.current = null;\n freqRef.current = emptyFreq;\n timeRef.current = emptyTime;\n };\n }\n\n return () => {\n cancelled = true;\n cancelAnimationFrame(rafId);\n if (consumerId != null && element) {\n detachLiveAnalyser(element, consumerId);\n }\n contextHolderRef.current?.removeEventListener(\"statechange\", onStateChange);\n contextHolderRef.current = null;\n analyserHolderRef.current = null;\n freqRef.current = emptyFreq;\n timeRef.current = emptyTime;\n setMeta({ frequencyBinCount: 0, sampleRate: 0 });\n };\n }, [enabled, audioRef, opts, state.currentIndex]);\n\n return {\n frequencyData: freqRef.current,\n timeDomainData: timeRef.current,\n frequencyBinCount: meta.frequencyBinCount,\n sampleRate: meta.sampleRate,\n isSuspended,\n error,\n resume,\n frame,\n };\n}\n","import { useEffect } from \"react\";\nimport { useGingerMedia, useGingerPlayback } from \"../context/GingerSplitContexts\";\n\nexport type GingerKeyboardShortcutBindings = {\n playPause?: string;\n next?: string;\n previous?: string;\n mute?: string;\n /** Key to seek forward by `seekSeconds`. Default: undefined (disabled). */\n seekForward?: string;\n /** Key to seek backward by `seekSeconds`. Default: undefined (disabled). */\n seekBackward?: string;\n /** Seconds to seek per `seekForward` / `seekBackward` keypress. Default: 5. */\n seekSeconds?: number;\n};\n\nexport function useGingerKeyboardShortcuts(\n enabled = true,\n bindings: GingerKeyboardShortcutBindings = {},\n): void {\n const { togglePlayPause, next, prev } = useGingerPlayback();\n const { toggleMute, seek, currentTime, duration } = useGingerMedia();\n\n const {\n mute: muteBinding,\n seekForward: seekForwardBinding,\n seekBackward: seekBackwardBinding,\n } = bindings;\n\n useEffect(() => {\n if (!enabled || typeof window === \"undefined\") return;\n const playPause = (bindings.playPause ?? \" \").toLowerCase();\n const nextKey = (bindings.next ?? \"ArrowRight\").toLowerCase();\n const prevKey = (bindings.previous ?? \"ArrowLeft\").toLowerCase();\n const muteKey = muteBinding?.toLowerCase();\n const seekFwdKey = seekForwardBinding?.toLowerCase();\n const seekBwdKey = seekBackwardBinding?.toLowerCase();\n const seekSecs = bindings.seekSeconds ?? 5;\n\n const onKeyDown = (event: KeyboardEvent) => {\n const target = event.target as HTMLElement | null;\n if (\n target &&\n ([\"INPUT\", \"TEXTAREA\", \"SELECT\"].includes(target.tagName) || target.isContentEditable)\n )\n return;\n const key = event.key.toLowerCase();\n if (key === playPause) {\n event.preventDefault();\n togglePlayPause();\n } else if (key === nextKey) {\n event.preventDefault();\n next();\n } else if (key === prevKey) {\n event.preventDefault();\n prev();\n } else if (muteKey && key === muteKey) {\n event.preventDefault();\n toggleMute();\n } else if (seekFwdKey && key === seekFwdKey) {\n event.preventDefault();\n const dur = duration > 0 ? duration : Number.POSITIVE_INFINITY;\n seek(Math.min(dur, currentTime + seekSecs));\n } else if (seekBwdKey && key === seekBwdKey) {\n event.preventDefault();\n seek(Math.max(0, currentTime - seekSecs));\n }\n };\n window.addEventListener(\"keydown\", onKeyDown);\n return () => window.removeEventListener(\"keydown\", onKeyDown);\n }, [\n bindings.next,\n bindings.playPause,\n bindings.previous,\n bindings.seekSeconds,\n currentTime,\n duration,\n enabled,\n muteBinding,\n next,\n prev,\n seek,\n seekBackwardBinding,\n seekForwardBinding,\n toggleMute,\n togglePlayPause,\n ]);\n}\n","import { useEffect, useRef } from \"react\";\nimport { useGingerPlayback } from \"../context/GingerSplitContexts\";\n\nexport type GingerSleepTimerOptions = {\n durationMs?: number;\n stopAfterTracks?: number;\n respectPause?: boolean;\n enabled?: boolean;\n onFire?: () => void;\n};\n\nexport function useGingerSleepTimer(options: GingerSleepTimerOptions): void {\n const { durationMs, stopAfterTracks, respectPause = true, enabled = true, onFire } = options;\n const { currentIndex, pause, isPaused } = useGingerPlayback();\n const remainingTracksRef = useRef(stopAfterTracks ?? 0);\n const prevIndexRef = useRef(currentIndex);\n\n // Remaining milliseconds for the duration-based timer; carried across pause/resume cycles.\n const remainingMsRef = useRef(durationMs ?? 0);\n // Timestamp when the current timer segment started (set when playback resumes).\n const segmentStartRef = useRef<number | null>(null);\n\n useEffect(() => {\n remainingTracksRef.current = stopAfterTracks ?? 0;\n }, [stopAfterTracks]);\n\n // Keep remainingMsRef in sync when durationMs changes while the timer is inactive.\n const prevDurationMsRef = useRef(durationMs);\n useEffect(() => {\n if (prevDurationMsRef.current !== durationMs) {\n remainingMsRef.current = durationMs ?? 0;\n prevDurationMsRef.current = durationMs;\n }\n }, [durationMs]);\n\n useEffect(() => {\n if (!enabled || !durationMs || durationMs <= 0) {\n // Reset remaining when disabled or no duration\n remainingMsRef.current = durationMs ?? 0;\n segmentStartRef.current = null;\n return;\n }\n\n if (respectPause && isPaused) {\n // Snapshot how much time is left before pausing\n if (segmentStartRef.current !== null) {\n const elapsed = Date.now() - segmentStartRef.current;\n remainingMsRef.current = Math.max(0, remainingMsRef.current - elapsed);\n segmentStartRef.current = null;\n }\n return;\n }\n\n // Playing: start (or continue) the countdown from remainingMsRef\n segmentStartRef.current = Date.now();\n const id = setTimeout(() => {\n remainingMsRef.current = 0;\n segmentStartRef.current = null;\n pause();\n onFire?.();\n }, remainingMsRef.current);\n\n return () => {\n clearTimeout(id);\n // Snapshot remaining when effect cleans up (e.g. isPaused or deps changed)\n if (segmentStartRef.current !== null) {\n const elapsed = Date.now() - segmentStartRef.current;\n remainingMsRef.current = Math.max(0, remainingMsRef.current - elapsed);\n segmentStartRef.current = null;\n }\n };\n }, [durationMs, enabled, isPaused, onFire, pause, respectPause]);\n\n useEffect(() => {\n if (!enabled || !stopAfterTracks || stopAfterTracks <= 0) return;\n const prev = prevIndexRef.current;\n prevIndexRef.current = currentIndex;\n if (currentIndex === prev) return;\n remainingTracksRef.current -= 1;\n if (remainingTracksRef.current <= 0) {\n pause();\n onFire?.();\n }\n }, [currentIndex, enabled, onFire, pause, stopAfterTracks]);\n}\n","import { useEffect, useRef } from \"react\";\nimport { useGingerState } from \"../context/GingerSplitContexts\";\n\nexport function useGingerDebugLog(enabled = false): void {\n const state = useGingerState();\n const prevRef = useRef(state);\n\n useEffect(() => {\n if (!enabled || typeof console === \"undefined\") return;\n const prev = prevRef.current;\n if (prev !== state) {\n console.debug(\"[ginger]\", {\n from: {\n currentIndex: prev.currentIndex,\n isPaused: prev.isPaused,\n currentTime: prev.currentTime,\n repeatMode: prev.repeatMode,\n },\n to: {\n currentIndex: state.currentIndex,\n isPaused: state.isPaused,\n currentTime: state.currentTime,\n repeatMode: state.repeatMode,\n },\n });\n }\n prevRef.current = state;\n }, [enabled, state]);\n}\n","import { useCallback, useState } from \"react\";\nimport type { PointerEvent as ReactPointerEvent } from \"react\";\nimport {\n gingerStateFromContextValues,\n useGingerMedia,\n useGingerPlayback,\n} from \"../context/GingerSplitContexts\";\nimport { progressFraction } from \"../internal/selectors\";\n\nexport type SeekDragState = {\n /** Raw drag fraction — only updated during an active drag gesture. */\n fraction: number;\n /** Blended fraction: follows live playback when idle, drag position when dragging. */\n displayFraction: number;\n isDragging: boolean;\n onPointerDown: (event: ReactPointerEvent<HTMLElement>) => void;\n};\n\nfunction clamp01(value: number): number {\n return Math.max(0, Math.min(1, value));\n}\n\nexport function useSeekDrag(duration: number): SeekDragState {\n const media = useGingerMedia();\n const playback = useGingerPlayback();\n const { seek } = media;\n const [fraction, setFraction] = useState(0);\n const [isDragging, setIsDragging] = useState(false);\n\n const liveFraction = progressFraction(gingerStateFromContextValues(playback, media));\n const displayFraction = isDragging ? fraction : liveFraction;\n\n const onPointerDown = useCallback(\n (event: ReactPointerEvent<HTMLElement>) => {\n if (!(duration > 0)) return;\n const target = event.currentTarget;\n const rect = target.getBoundingClientRect();\n const update = (clientX: number) => {\n const ratio = clamp01((clientX - rect.left) / rect.width);\n setFraction(ratio);\n seek(ratio * duration);\n };\n setIsDragging(true);\n target.setPointerCapture(event.pointerId);\n update(event.clientX);\n const onMove = (moveEvent: PointerEvent) => update(moveEvent.clientX);\n const onUp = (upEvent: PointerEvent) => {\n update(upEvent.clientX);\n setIsDragging(false);\n target.releasePointerCapture(event.pointerId);\n target.removeEventListener(\"pointermove\", onMove);\n target.removeEventListener(\"pointerup\", onUp);\n target.removeEventListener(\"pointercancel\", onUp);\n };\n target.addEventListener(\"pointermove\", onMove);\n target.addEventListener(\"pointerup\", onUp);\n target.addEventListener(\"pointercancel\", onUp);\n },\n [duration, seek],\n );\n\n return { fraction, displayFraction, isDragging, onPointerDown };\n}\n","import { useEffect } from \"react\";\nimport { useGingerPlayback } from \"../context/GingerSplitContexts\";\nimport { computeNextIndex } from \"../core/transitions\";\n\nexport type UseNextTrackPrefetchOptions = {\n /** When false, no prefetch runs. Default true. */\n enabled?: boolean;\n /**\n * Match `crossOrigin` on `Ginger.Player` when `fileUrl` is cross-origin so the browser\n * can reuse cached media consistently.\n */\n crossOrigin?: \"\" | \"anonymous\" | \"use-credentials\" | undefined;\n};\n\n/**\n * Warms the browser cache for the **logical** next track (same rules as the Next control:\n * `computeNextIndex` from queue, repeat, and playback mode) using a detached `HTMLAudioElement`\n * with `preload=\"auto\"`. Safe to call alongside `Ginger.Player`; it does not replace main playback.\n */\nexport function useNextTrackPrefetch(options: UseNextTrackPrefetchOptions = {}): void {\n const { enabled = true, crossOrigin } = options;\n const { tracks, currentIndex, repeatMode, playbackMode } = useGingerPlayback();\n\n useEffect(() => {\n if (!enabled || typeof document === \"undefined\") return;\n const nextIndex = computeNextIndex({ tracks, currentIndex, repeatMode, playbackMode });\n if (nextIndex === currentIndex) return;\n const nextUrl = tracks[nextIndex]?.fileUrl ?? \"\";\n if (!nextUrl) return;\n\n const audio = document.createElement(\"audio\");\n audio.preload = \"auto\";\n if (crossOrigin) audio.crossOrigin = crossOrigin;\n audio.src = nextUrl;\n audio.load();\n\n return () => {\n audio.removeAttribute(\"src\");\n audio.load();\n };\n }, [enabled, crossOrigin, tracks, currentIndex, repeatMode, playbackMode]);\n}\n","import { clampPlaybackRate, clampVolume, createInitialState, gingerReducer } from \"./core/playbackReducer\";\nimport type { GingerAction, GingerInitPayload, GingerState, PlaylistMeta, RepeatMode, Track } from \"./types\";\n\nexport type GingerStoreOptions = {\n tracks?: Track[];\n currentIndex?: number;\n playlistMeta?: PlaylistMeta | null;\n isPaused?: boolean;\n isShuffled?: boolean;\n repeatMode?: RepeatMode;\n playbackMode?: GingerState[\"playbackMode\"];\n volume?: number;\n muted?: boolean;\n playbackRate?: number;\n};\n\nexport type GingerStore = {\n /** Returns the current state snapshot. */\n getState: () => GingerState;\n /** Dispatch an action to update state. Synchronously updates state and notifies listeners. */\n dispatch: (action: GingerAction) => void;\n /**\n * Subscribe to state changes. The listener is called after every `dispatch` that produces\n * a new state object. Returns an unsubscribe function.\n */\n subscribe: (listener: (state: GingerState) => void) => () => void;\n /** Convenience: re-initialise with a new set of init options (equivalent to `dispatch({ type: \"INIT\", ... })`). */\n init: (payload: GingerInitPayload) => void;\n /** Clamp helpers re-exported for convenience. */\n clampVolume: typeof clampVolume;\n clampPlaybackRate: typeof clampPlaybackRate;\n};\n\n/**\n * Framework-agnostic store wrapping `gingerReducer`.\n * Usable outside React — e.g. in Svelte, Vue, Node.js testing, or server-side rendering contexts.\n *\n * @example\n * ```ts\n * import { createGingerStore } from \"@lucaismyname/ginger\";\n *\n * const store = createGingerStore({ tracks: myTracks });\n * const unsub = store.subscribe((state) => console.log(state.currentIndex));\n * store.dispatch({ type: \"NEXT\" });\n * unsub();\n * ```\n */\nexport function createGingerStore(options: GingerStoreOptions = {}): GingerStore {\n let state = createInitialState({\n tracks: options.tracks ?? [],\n currentIndex: options.currentIndex,\n playlistMeta: options.playlistMeta,\n isPaused: options.isPaused,\n isShuffled: options.isShuffled,\n repeatMode: options.repeatMode,\n playbackMode: options.playbackMode,\n volume: options.volume,\n muted: options.muted,\n playbackRate: options.playbackRate,\n });\n\n const listeners = new Set<(state: GingerState) => void>();\n\n const dispatch = (action: GingerAction): void => {\n const next = gingerReducer(state, action);\n if (next !== state) {\n state = next;\n for (const listener of listeners) {\n listener(state);\n }\n }\n };\n\n const subscribe = (listener: (state: GingerState) => void): (() => void) => {\n listeners.add(listener);\n return () => listeners.delete(listener);\n };\n\n const init = (payload: GingerInitPayload): void => {\n dispatch({ type: \"INIT\", payload });\n };\n\n return {\n getState: () => state,\n dispatch,\n subscribe,\n init,\n clampVolume,\n clampPlaybackRate,\n };\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useGingerPlayback } from \"../context/GingerSplitContexts\";\nimport type { Track } from \"../types\";\n\nexport type GingerPlaybackHistoryEntry = {\n track: Track;\n /** The track's index in the queue at the time it was played. */\n index: number;\n /** Unix timestamp (ms) when the track started playing. */\n playedAt: number;\n};\n\nexport type UseGingerPlaybackHistoryOptions = {\n /** Maximum number of entries to keep. Oldest entries are dropped first. Default: 50. */\n maxLength?: number;\n};\n\nexport type UseGingerPlaybackHistoryResult = {\n /** Chronological list of played tracks; most recent entry is last. */\n history: GingerPlaybackHistoryEntry[];\n clearHistory: () => void;\n};\n\n/**\n * Records a history of played tracks in chronological order.\n * Useful for \"what was playing before\" in shuffle mode or for analytics.\n *\n * The history is stored in component state and does not survive remounts.\n * In shuffle mode, `index` reflects the position in the current shuffled queue.\n */\nexport function useGingerPlaybackHistory(\n options: UseGingerPlaybackHistoryOptions = {},\n): UseGingerPlaybackHistoryResult {\n const { maxLength = 50 } = options;\n const { tracks, currentIndex } = useGingerPlayback();\n\n const [history, setHistory] = useState<GingerPlaybackHistoryEntry[]>([]);\n const prevIndexRef = useRef<number | null>(null);\n const prevTracksRef = useRef(tracks);\n prevTracksRef.current = tracks;\n\n useEffect(() => {\n const track = tracks[currentIndex];\n if (!track) return;\n\n if (prevIndexRef.current === currentIndex) return;\n prevIndexRef.current = currentIndex;\n\n const entry: GingerPlaybackHistoryEntry = {\n track,\n index: currentIndex,\n playedAt: Date.now(),\n };\n\n setHistory((prev) => {\n const next = [...prev, entry];\n return next.length > maxLength ? next.slice(next.length - maxLength) : next;\n });\n }, [currentIndex, tracks, maxLength]);\n\n const clearHistory = useCallback(() => setHistory([]), []);\n\n return { history, clearHistory };\n}\n","import { useCallback, useRef, useState } from \"react\";\nimport { useGingerMedia } from \"../context/GingerSplitContexts\";\n\nexport type UseGingerVolumeFadeOptions = {\n /** Target volume to fade to (0–1). */\n targetVolume: number;\n /** Duration of the fade in milliseconds. */\n durationMs: number;\n /** Called when the fade completes normally (not when cancelled). */\n onComplete?: () => void;\n};\n\nexport type UseGingerVolumeFadeResult = {\n /** Start a volume fade. Cancels any in-progress fade. */\n fadeVolumeTo: (options: UseGingerVolumeFadeOptions) => void;\n /** Cancel the current fade and hold at the current volume. */\n cancelFade: () => void;\n /** True while a fade is in progress. */\n isFading: boolean;\n};\n\n/**\n * Smoothly interpolates volume over a given duration using `requestAnimationFrame`.\n * Useful for fade-in on track start, fade-out before sleep timer fires, or crossfade prep.\n */\nexport function useGingerVolumeFade(): UseGingerVolumeFadeResult {\n const { setVolume, volume } = useGingerMedia();\n const [isFading, setIsFading] = useState(false);\n\n const rafRef = useRef<number>(0);\n const cancelledRef = useRef(false);\n\n const cancelFade = useCallback(() => {\n cancelAnimationFrame(rafRef.current);\n cancelledRef.current = true;\n setIsFading(false);\n }, []);\n\n const fadeVolumeTo = useCallback(\n ({ targetVolume, durationMs, onComplete }: UseGingerVolumeFadeOptions) => {\n cancelAnimationFrame(rafRef.current);\n cancelledRef.current = false;\n\n const clamp = (v: number) => Math.min(1, Math.max(0, v));\n const target = clamp(targetVolume);\n const startTime = performance.now();\n\n // Capture start volume at the moment the fade begins\n let startVolume = volume;\n\n setIsFading(true);\n\n const tick = (now: number) => {\n if (cancelledRef.current) return;\n const elapsed = now - startTime;\n const progress = Math.min(1, elapsed / Math.max(1, durationMs));\n const current = startVolume + (target - startVolume) * progress;\n setVolume(clamp(current));\n\n if (progress < 1) {\n rafRef.current = requestAnimationFrame(tick);\n } else {\n setIsFading(false);\n onComplete?.();\n }\n };\n\n // Use a small delay so `volume` from closure is the current value\n rafRef.current = requestAnimationFrame((now) => {\n startVolume = volume;\n tick(now);\n });\n },\n [setVolume, volume],\n );\n\n return { fadeVolumeTo, cancelFade, isFading };\n}\n","import { useMemo } from \"react\";\nimport { useGingerMedia, useGingerPlayback } from \"../context/GingerSplitContexts\";\n\nexport type GingerChapterProgress = {\n /** Fraction (0–1) of the way through the active chapter. 0 when no chapter is active. */\n progress: number;\n /** Seconds elapsed since the start of the active chapter. */\n elapsed: number;\n /** Seconds remaining until the end of the active chapter (or until end of track if last chapter). */\n remaining: number;\n};\n\n/**\n * Returns detailed progress information for the currently active chapter.\n * Complements `useGingerChapters` with per-chapter playback fractions.\n */\nexport function useGingerChapterProgress(): GingerChapterProgress {\n const { tracks, currentIndex } = useGingerPlayback();\n const { currentTime, duration } = useGingerMedia();\n\n const chapters = useMemo(() => {\n const raw = tracks[currentIndex]?.chapters ?? [];\n return [...raw]\n .filter((c) => c && Number.isFinite(c.startSeconds) && c.startSeconds >= 0)\n .sort((a, b) => a.startSeconds - b.startSeconds);\n }, [tracks, currentIndex]);\n\n return useMemo<GingerChapterProgress>(() => {\n if (chapters.length === 0) return { progress: 0, elapsed: 0, remaining: 0 };\n\n // Find active chapter (last one whose start is <= currentTime)\n let activeIdx = -1;\n for (let i = chapters.length - 1; i >= 0; i--) {\n if (currentTime >= chapters[i]!.startSeconds) {\n activeIdx = i;\n break;\n }\n }\n\n if (activeIdx === -1) return { progress: 0, elapsed: 0, remaining: 0 };\n\n const chapter = chapters[activeIdx]!;\n const nextChapter = chapters[activeIdx + 1];\n const chapterEnd = nextChapter?.startSeconds ?? (duration > 0 ? duration : currentTime);\n const chapterDuration = Math.max(0, chapterEnd - chapter.startSeconds);\n const elapsed = Math.max(0, currentTime - chapter.startSeconds);\n const remaining = Math.max(0, chapterEnd - currentTime);\n const progress = chapterDuration > 0 ? Math.min(1, elapsed / chapterDuration) : 0;\n\n return { progress, elapsed, remaining };\n }, [chapters, currentTime, duration]);\n}\n"],"names":["emptyFreq","emptyTime","useGingerLiveAnalyzer","options","enabled","fftSize","smoothingTimeConstant","minDecibels","maxDecibels","audioRef","state","useGinger","opts","useMemo","frame","setFrame","useState","error","setError","isSuspended","setIsSuspended","meta","setMeta","freqRef","useRef","timeRef","resume","useCallback","ctx","contextHolderRef","analyserHolderRef","useLayoutEffect","cancelled","consumerId","element","rafId","onStateChange","runLoop","a","fq","td","n","attach","el","id","context","analyser","attachLiveAnalyser","fft","e","msg","first","retryRaf","maxAttempts","attempts","retryLoop","out","detachLiveAnalyser","_a","useGingerKeyboardShortcuts","bindings","togglePlayPause","next","prev","useGingerPlayback","toggleMute","seek","currentTime","duration","useGingerMedia","muteBinding","seekForwardBinding","seekBackwardBinding","useEffect","playPause","nextKey","prevKey","muteKey","seekFwdKey","seekBwdKey","seekSecs","onKeyDown","event","target","key","dur","useGingerSleepTimer","durationMs","stopAfterTracks","respectPause","onFire","currentIndex","pause","isPaused","remainingTracksRef","prevIndexRef","remainingMsRef","segmentStartRef","prevDurationMsRef","elapsed","useGingerDebugLog","useGingerState","prevRef","clamp01","value","useSeekDrag","media","playback","fraction","setFraction","isDragging","setIsDragging","liveFraction","progressFraction","gingerStateFromContextValues","displayFraction","onPointerDown","rect","update","clientX","ratio","onMove","moveEvent","onUp","upEvent","useNextTrackPrefetch","crossOrigin","tracks","repeatMode","playbackMode","nextIndex","computeNextIndex","nextUrl","audio","createGingerStore","createInitialState","listeners","dispatch","action","gingerReducer","listener","payload","clampVolume","clampPlaybackRate","useGingerPlaybackHistory","maxLength","history","setHistory","prevTracksRef","track","entry","clearHistory","useGingerVolumeFade","setVolume","volume","isFading","setIsFading","rafRef","cancelledRef","cancelFade","targetVolume","onComplete","clamp","v","startTime","startVolume","tick","now","progress","current","useGingerChapterProgress","chapters","c","b","activeIdx","i","chapter","nextChapter","chapterEnd","chapterDuration","remaining"],"mappings":"0MA+BMA,EAAY,IAAI,WAAW,CAAC,EAC5BC,EAAY,IAAI,WAAW,CAAC,EAE3B,SAASC,EACdC,EAAwC,GACX,CAC7B,KAAM,CACJ,QAAAC,EAAU,GACV,QAAAC,EAAU,KACV,sBAAAC,EAAwB,GACxB,YAAAC,EAAc,KACd,YAAAC,EAAc,GAAA,EACZL,EAEE,CAAE,SAAAM,EAAU,MAAAC,CAAA,EAAUC,YAAA,EACtBC,EAAOC,EAAAA,QACX,KAAO,CACL,QAAAR,EACA,sBAAAC,EACA,YAAAC,EACA,YAAAC,CAAA,GAEF,CAACH,EAASC,EAAuBC,EAAaC,CAAW,CAAA,EAGrD,CAACM,EAAOC,CAAQ,EAAIC,EAAAA,SAAS,CAAC,EAC9B,CAACC,EAAOC,CAAQ,EAAIF,EAAAA,SAAwB,IAAI,EAChD,CAACG,EAAaC,CAAc,EAAIJ,EAAAA,SAAS,EAAK,EAC9C,CAACK,EAAMC,CAAO,EAAIN,EAAAA,SAAS,CAAE,kBAAmB,EAAG,WAAY,EAAG,EAElEO,EAAUC,EAAAA,OAAmBxB,CAAS,EACtCyB,EAAUD,EAAAA,OAAmBvB,CAAS,EAEtCyB,EAASC,EAAAA,YAAY,SAAY,CACrC,MAAMC,EAAMC,EAAiB,QACzBD,GAAOA,EAAI,QAAU,aACvB,MAAMA,EAAI,OAAA,CAEd,EAAG,CAAA,CAAE,EAECC,EAAmBL,EAAAA,OAA4B,IAAI,EACnDM,EAAoBN,EAAAA,OAA4B,IAAI,EAE1DO,OAAAA,EAAAA,gBAAgB,IAAM,CACpB,GAAI,CAAC3B,GAAW,OAAO,OAAW,IAChC,OAGF,IAAI4B,EAAY,GACZC,EAA4B,KAC5BC,EAAmC,KACnCC,EAAQ,EAEZ,MAAMC,EAAgB,IAAM,CAC1B,MAAMR,EAAMC,EAAiB,QACzBD,GAAKR,EAAeQ,EAAI,QAAU,WAAW,CACnD,EAEMS,EAAU,IAAM,CACpB,GAAIL,EAAW,OACf,MAAMM,EAAIR,EAAkB,QACtBS,EAAKhB,EAAQ,QACbiB,EAAKf,EAAQ,QACfa,GAAKC,EAAG,OAAS,GAAKC,EAAG,OAAS,IACpCF,EAAE,qBAAqBC,CAA6B,EACpDD,EAAE,sBAAsBE,CAA6B,EACrDzB,EAAU0B,GAAMA,EAAI,CAAC,GAEvBN,EAAQ,sBAAsBE,CAAO,CACvC,EAIMK,EAAS,IAAqB,CAClC,MAAMC,EAAKlC,EAAS,QACpB,GAAI,CAACkC,GAAMX,EAAW,MAAO,aAC7B,GAAI,CACF,KAAM,CAAE,GAAAY,EAAI,QAAAC,EAAS,SAAAC,GAAaC,EAAAA,mBAAmBJ,EAAI/B,CAAI,EAC7DqB,EAAaW,EACbV,EAAUS,EACVd,EAAiB,QAAUgB,EAC3Bf,EAAkB,QAAUgB,EAC5B1B,EAAeyB,EAAQ,QAAU,WAAW,EAC5C3B,EAAS,IAAI,EAEb2B,EAAQ,iBAAiB,cAAeT,CAAa,EAErD,MAAMK,EAAIK,EAAS,kBACbE,EAAMF,EAAS,QACrB,OAAAvB,EAAQ,QAAU,IAAI,WAAWkB,CAAC,EAClChB,EAAQ,QAAU,IAAI,WAAWuB,CAAG,EACpC1B,EAAQ,CAAE,kBAAmBmB,EAAG,WAAYI,EAAQ,WAAY,EAEhEV,EAAQ,sBAAsBE,CAAO,EAC9B,IACT,OAASY,EAAG,CACV,MAAMC,EAAMD,aAAa,MAAQA,EAAE,QAAU,iCAC7C,OAAA/B,EAASgC,CAAG,EACZrB,EAAiB,QAAU,KAC3BC,EAAkB,QAAU,KAC5BP,EAAQ,QAAUvB,EAClByB,EAAQ,QAAUxB,EAClBqB,EAAQ,CAAE,kBAAmB,EAAG,WAAY,EAAG,EACxC,OACT,CACF,EAEM6B,EAAQT,EAAA,EACd,GAAIS,IAAU,KAAM,CAClB,IAAIC,EAAW,EACf,MAAMC,EAAc,IACpB,IAAIC,EAAW,EAEf,MAAMC,EAAY,IAAM,CACtB,GAAIvB,EAAW,OACf,MAAMwB,EAAMd,EAAA,EACRc,IAAQ,MAAQA,IAAQ,UAC5BF,GAAY,EACR,EAAAA,GAAYD,KAChBD,EAAW,sBAAsBG,CAAS,GAC5C,EAEA,OAAIJ,IAAU,eACZC,EAAW,sBAAsBG,CAAS,GAGrC,IAAM,OACXvB,EAAY,GACZ,qBAAqBoB,CAAQ,EAC7B,qBAAqBjB,CAAK,EACtBF,GAAc,MAAQC,GACxBuB,EAAAA,mBAAmBvB,EAASD,CAAU,GAExCyB,EAAA7B,EAAiB,UAAjB,MAAA6B,EAA0B,oBAAoB,cAAetB,GAC7DP,EAAiB,QAAU,KAC3BC,EAAkB,QAAU,KAC5BP,EAAQ,QAAUvB,EAClByB,EAAQ,QAAUxB,CACpB,CACF,CAEA,MAAO,IAAM,OACX+B,EAAY,GACZ,qBAAqBG,CAAK,EACtBF,GAAc,MAAQC,GACxBuB,EAAAA,mBAAmBvB,EAASD,CAAU,GAExCyB,EAAA7B,EAAiB,UAAjB,MAAA6B,EAA0B,oBAAoB,cAAetB,GAC7DP,EAAiB,QAAU,KAC3BC,EAAkB,QAAU,KAC5BP,EAAQ,QAAUvB,EAClByB,EAAQ,QAAUxB,EAClBqB,EAAQ,CAAE,kBAAmB,EAAG,WAAY,EAAG,CACjD,CACF,EAAG,CAAClB,EAASK,EAAUG,EAAMF,EAAM,YAAY,CAAC,EAEzC,CACL,cAAea,EAAQ,QACvB,eAAgBE,EAAQ,QACxB,kBAAmBJ,EAAK,kBACxB,WAAYA,EAAK,WACjB,YAAAF,EACA,MAAAF,EACA,OAAAS,EACA,MAAAZ,CAAA,CAEJ,CCrLO,SAAS6C,EACdvD,EAAU,GACVwD,EAA2C,CAAA,EACrC,CACN,KAAM,CAAE,gBAAAC,EAAiB,KAAAC,EAAM,KAAAC,CAAA,EAASC,EAAAA,kBAAA,EAClC,CAAE,WAAAC,EAAY,KAAAC,EAAM,YAAAC,EAAa,SAAAC,CAAA,EAAaC,EAAAA,eAAA,EAE9C,CACJ,KAAMC,EACN,YAAaC,EACb,aAAcC,CAAA,EACZZ,EAEJa,EAAAA,UAAU,IAAM,CACd,GAAI,CAACrE,GAAW,OAAO,OAAW,IAAa,OAC/C,MAAMsE,GAAad,EAAS,WAAa,KAAK,YAAA,EACxCe,GAAWf,EAAS,MAAQ,cAAc,YAAA,EAC1CgB,GAAWhB,EAAS,UAAY,aAAa,YAAA,EAC7CiB,EAAUP,GAAA,YAAAA,EAAa,cACvBQ,EAAaP,GAAA,YAAAA,EAAoB,cACjCQ,EAAaP,GAAA,YAAAA,EAAqB,cAClCQ,EAAWpB,EAAS,aAAe,EAEnCqB,EAAaC,GAAyB,CAC1C,MAAMC,EAASD,EAAM,OACrB,GACEC,IACC,CAAC,QAAS,WAAY,QAAQ,EAAE,SAASA,EAAO,OAAO,GAAKA,EAAO,mBAEpE,OACF,MAAMC,EAAMF,EAAM,IAAI,YAAA,EACtB,GAAIE,IAAQV,EACVQ,EAAM,eAAA,EACNrB,EAAA,UACSuB,IAAQT,EACjBO,EAAM,eAAA,EACNpB,EAAA,UACSsB,IAAQR,EACjBM,EAAM,eAAA,EACNnB,EAAA,UACSc,GAAWO,IAAQP,EAC5BK,EAAM,eAAA,EACNjB,EAAA,UACSa,GAAcM,IAAQN,EAAY,CAC3CI,EAAM,eAAA,EACN,MAAMG,EAAMjB,EAAW,EAAIA,EAAW,OAAO,kBAC7CF,EAAK,KAAK,IAAImB,EAAKlB,EAAca,CAAQ,CAAC,CAC5C,MAAWD,GAAcK,IAAQL,IAC/BG,EAAM,eAAA,EACNhB,EAAK,KAAK,IAAI,EAAGC,EAAca,CAAQ,CAAC,EAE5C,EACA,cAAO,iBAAiB,UAAWC,CAAS,EACrC,IAAM,OAAO,oBAAoB,UAAWA,CAAS,CAC9D,EAAG,CACDrB,EAAS,KACTA,EAAS,UACTA,EAAS,SACTA,EAAS,YACTO,EACAC,EACAhE,EACAkE,EACAR,EACAC,EACAG,EACAM,EACAD,EACAN,EACAJ,CAAA,CACD,CACH,CC5EO,SAASyB,EAAoBnF,EAAwC,CAC1E,KAAM,CAAE,WAAAoF,EAAY,gBAAAC,EAAiB,aAAAC,EAAe,GAAM,QAAArF,EAAU,GAAM,OAAAsF,GAAWvF,EAC/E,CAAE,aAAAwF,EAAc,MAAAC,EAAO,SAAAC,CAAA,EAAa7B,EAAAA,kBAAA,EACpC8B,EAAqBtE,EAAAA,OAAOgE,GAAmB,CAAC,EAChDO,EAAevE,EAAAA,OAAOmE,CAAY,EAGlCK,EAAiBxE,EAAAA,OAAO+D,GAAc,CAAC,EAEvCU,EAAkBzE,EAAAA,OAAsB,IAAI,EAElDiD,EAAAA,UAAU,IAAM,CACdqB,EAAmB,QAAUN,GAAmB,CAClD,EAAG,CAACA,CAAe,CAAC,EAGpB,MAAMU,EAAoB1E,EAAAA,OAAO+D,CAAU,EAC3Cd,EAAAA,UAAU,IAAM,CACVyB,EAAkB,UAAYX,IAChCS,EAAe,QAAUT,GAAc,EACvCW,EAAkB,QAAUX,EAEhC,EAAG,CAACA,CAAU,CAAC,EAEfd,EAAAA,UAAU,IAAM,CACd,GAAI,CAACrE,GAAW,CAACmF,GAAcA,GAAc,EAAG,CAE9CS,EAAe,QAAUT,GAAc,EACvCU,EAAgB,QAAU,KAC1B,MACF,CAEA,GAAIR,GAAgBI,EAAU,CAE5B,GAAII,EAAgB,UAAY,KAAM,CACpC,MAAME,EAAU,KAAK,IAAA,EAAQF,EAAgB,QAC7CD,EAAe,QAAU,KAAK,IAAI,EAAGA,EAAe,QAAUG,CAAO,EACrEF,EAAgB,QAAU,IAC5B,CACA,MACF,CAGAA,EAAgB,QAAU,KAAK,IAAA,EAC/B,MAAMrD,EAAK,WAAW,IAAM,CAC1BoD,EAAe,QAAU,EACzBC,EAAgB,QAAU,KAC1BL,EAAA,EACAF,GAAA,MAAAA,GACF,EAAGM,EAAe,OAAO,EAEzB,MAAO,IAAM,CAGX,GAFA,aAAapD,CAAE,EAEXqD,EAAgB,UAAY,KAAM,CACpC,MAAME,EAAU,KAAK,IAAA,EAAQF,EAAgB,QAC7CD,EAAe,QAAU,KAAK,IAAI,EAAGA,EAAe,QAAUG,CAAO,EACrEF,EAAgB,QAAU,IAC5B,CACF,CACF,EAAG,CAACV,EAAYnF,EAASyF,EAAUH,EAAQE,EAAOH,CAAY,CAAC,EAE/DhB,EAAAA,UAAU,IAAM,CACd,GAAI,CAACrE,GAAW,CAACoF,GAAmBA,GAAmB,EAAG,OAC1D,MAAMzB,EAAOgC,EAAa,QAC1BA,EAAa,QAAUJ,EACnBA,IAAiB5B,IACrB+B,EAAmB,SAAW,EAC1BA,EAAmB,SAAW,IAChCF,EAAA,EACAF,GAAA,MAAAA,KAEJ,EAAG,CAACC,EAAcvF,EAASsF,EAAQE,EAAOJ,CAAe,CAAC,CAC5D,CCjFO,SAASY,EAAkBhG,EAAU,GAAa,CACvD,MAAMM,EAAQ2F,EAAAA,eAAA,EACRC,EAAU9E,EAAAA,OAAOd,CAAK,EAE5B+D,EAAAA,UAAU,IAAM,CACd,GAAI,CAACrE,GAAW,OAAO,QAAY,IAAa,OAChD,MAAM2D,EAAOuC,EAAQ,QACjBvC,IAASrD,GACX,QAAQ,MAAM,WAAY,CACxB,KAAM,CACJ,aAAcqD,EAAK,aACnB,SAAUA,EAAK,SACf,YAAaA,EAAK,YAClB,WAAYA,EAAK,UAAA,EAEnB,GAAI,CACF,aAAcrD,EAAM,aACpB,SAAUA,EAAM,SAChB,YAAaA,EAAM,YACnB,WAAYA,EAAM,UAAA,CACpB,CACD,EAEH4F,EAAQ,QAAU5F,CACpB,EAAG,CAACN,EAASM,CAAK,CAAC,CACrB,CCVA,SAAS6F,EAAQC,EAAuB,CACtC,OAAO,KAAK,IAAI,EAAG,KAAK,IAAI,EAAGA,CAAK,CAAC,CACvC,CAEO,SAASC,EAAYrC,EAAiC,CAC3D,MAAMsC,EAAQrC,EAAAA,eAAA,EACRsC,EAAW3C,EAAAA,kBAAA,EACX,CAAE,KAAAE,GAASwC,EACX,CAACE,EAAUC,CAAW,EAAI7F,EAAAA,SAAS,CAAC,EACpC,CAAC8F,EAAYC,CAAa,EAAI/F,EAAAA,SAAS,EAAK,EAE5CgG,EAAeC,EAAAA,iBAAiBC,EAAAA,6BAA6BP,EAAUD,CAAK,CAAC,EAC7ES,EAAkBL,EAAaF,EAAWI,EAE1CI,EAAgBzF,EAAAA,YACnBuD,GAA0C,CACzC,GAAI,EAAEd,EAAW,GAAI,OACrB,MAAMe,EAASD,EAAM,cACfmC,EAAOlC,EAAO,sBAAA,EACdmC,EAAUC,GAAoB,CAClC,MAAMC,EAAQjB,GAASgB,EAAUF,EAAK,MAAQA,EAAK,KAAK,EACxDR,EAAYW,CAAK,EACjBtD,EAAKsD,EAAQpD,CAAQ,CACvB,EACA2C,EAAc,EAAI,EAClB5B,EAAO,kBAAkBD,EAAM,SAAS,EACxCoC,EAAOpC,EAAM,OAAO,EACpB,MAAMuC,EAAUC,GAA4BJ,EAAOI,EAAU,OAAO,EAC9DC,EAAQC,GAA0B,CACtCN,EAAOM,EAAQ,OAAO,EACtBb,EAAc,EAAK,EACnB5B,EAAO,sBAAsBD,EAAM,SAAS,EAC5CC,EAAO,oBAAoB,cAAesC,CAAM,EAChDtC,EAAO,oBAAoB,YAAawC,CAAI,EAC5CxC,EAAO,oBAAoB,gBAAiBwC,CAAI,CAClD,EACAxC,EAAO,iBAAiB,cAAesC,CAAM,EAC7CtC,EAAO,iBAAiB,YAAawC,CAAI,EACzCxC,EAAO,iBAAiB,gBAAiBwC,CAAI,CAC/C,EACA,CAACvD,EAAUF,CAAI,CAAA,EAGjB,MAAO,CAAE,SAAA0C,EAAU,gBAAAO,EAAiB,WAAAL,EAAY,cAAAM,CAAA,CAClD,CC3CO,SAASS,EAAqB1H,EAAuC,GAAU,CACpF,KAAM,CAAE,QAAAC,EAAU,GAAM,YAAA0H,CAAA,EAAgB3H,EAClC,CAAE,OAAA4H,EAAQ,aAAApC,EAAc,WAAAqC,EAAY,aAAAC,CAAA,EAAiBjE,EAAAA,kBAAA,EAE3DS,EAAAA,UAAU,IAAM,OACd,GAAI,CAACrE,GAAW,OAAO,SAAa,IAAa,OACjD,MAAM8H,EAAYC,EAAAA,iBAAiB,CAAE,OAAAJ,EAAQ,aAAApC,EAAc,WAAAqC,EAAY,aAAAC,EAAc,EACrF,GAAIC,IAAcvC,EAAc,OAChC,MAAMyC,IAAU1E,EAAAqE,EAAOG,CAAS,IAAhB,YAAAxE,EAAmB,UAAW,GAC9C,GAAI,CAAC0E,EAAS,OAEd,MAAMC,EAAQ,SAAS,cAAc,OAAO,EAC5C,OAAAA,EAAM,QAAU,OACZP,MAAmB,YAAcA,GACrCO,EAAM,IAAMD,EACZC,EAAM,KAAA,EAEC,IAAM,CACXA,EAAM,gBAAgB,KAAK,EAC3BA,EAAM,KAAA,CACR,CACF,EAAG,CAACjI,EAAS0H,EAAaC,EAAQpC,EAAcqC,EAAYC,CAAY,CAAC,CAC3E,CCMO,SAASK,EAAkBnI,EAA8B,GAAiB,CAC/E,IAAIO,EAAQ6H,EAAAA,mBAAmB,CAC7B,OAAQpI,EAAQ,QAAU,CAAA,EAC1B,aAAcA,EAAQ,aACtB,aAAcA,EAAQ,aACtB,SAAUA,EAAQ,SAClB,WAAYA,EAAQ,WACpB,WAAYA,EAAQ,WACpB,aAAcA,EAAQ,aACtB,OAAQA,EAAQ,OAChB,MAAOA,EAAQ,MACf,aAAcA,EAAQ,YAAA,CACvB,EAED,MAAMqI,MAAgB,IAEhBC,EAAYC,GAA+B,CAC/C,MAAM5E,EAAO6E,EAAAA,cAAcjI,EAAOgI,CAAM,EACxC,GAAI5E,IAASpD,EAAO,CAClBA,EAAQoD,EACR,UAAW8E,KAAYJ,EACrBI,EAASlI,CAAK,CAElB,CACF,EAWA,MAAO,CACL,SAAU,IAAMA,EAChB,SAAA+H,EACA,UAZiBG,IACjBJ,EAAU,IAAII,CAAQ,EACf,IAAMJ,EAAU,OAAOI,CAAQ,GAWtC,KARYC,GAAqC,CACjDJ,EAAS,CAAE,KAAM,OAAQ,QAAAI,CAAA,CAAS,CACpC,EAME,YACAC,EAAAA,YAAA,kBACAC,EAAAA,iBAAA,CAEJ,CC5DO,SAASC,EACd7I,EAA2C,GACX,CAChC,KAAM,CAAE,UAAA8I,EAAY,EAAA,EAAO9I,EACrB,CAAE,OAAA4H,EAAQ,aAAApC,CAAA,EAAiB3B,oBAAA,EAE3B,CAACkF,EAASC,CAAU,EAAInI,EAAAA,SAAuC,CAAA,CAAE,EACjE+E,EAAevE,EAAAA,OAAsB,IAAI,EACzC4H,EAAgB5H,EAAAA,OAAOuG,CAAM,EACnCqB,EAAc,QAAUrB,EAExBtD,EAAAA,UAAU,IAAM,CACd,MAAM4E,EAAQtB,EAAOpC,CAAY,EAGjC,GAFI,CAAC0D,GAEDtD,EAAa,UAAYJ,EAAc,OAC3CI,EAAa,QAAUJ,EAEvB,MAAM2D,EAAoC,CACxC,MAAAD,EACA,MAAO1D,EACP,SAAU,KAAK,IAAA,CAAI,EAGrBwD,EAAYpF,GAAS,CACnB,MAAMD,EAAO,CAAC,GAAGC,EAAMuF,CAAK,EAC5B,OAAOxF,EAAK,OAASmF,EAAYnF,EAAK,MAAMA,EAAK,OAASmF,CAAS,EAAInF,CACzE,CAAC,CACH,EAAG,CAAC6B,EAAcoC,EAAQkB,CAAS,CAAC,EAEpC,MAAMM,EAAe5H,EAAAA,YAAY,IAAMwH,EAAW,CAAA,CAAE,EAAG,CAAA,CAAE,EAEzD,MAAO,CAAE,QAAAD,EAAS,aAAAK,CAAA,CACpB,CCtCO,SAASC,GAAiD,CAC/D,KAAM,CAAE,UAAAC,EAAW,OAAAC,CAAA,EAAWrF,iBAAA,EACxB,CAACsF,EAAUC,CAAW,EAAI5I,EAAAA,SAAS,EAAK,EAExC6I,EAASrI,EAAAA,OAAe,CAAC,EACzBsI,EAAetI,EAAAA,OAAO,EAAK,EAE3BuI,EAAapI,EAAAA,YAAY,IAAM,CACnC,qBAAqBkI,EAAO,OAAO,EACnCC,EAAa,QAAU,GACvBF,EAAY,EAAK,CACnB,EAAG,CAAA,CAAE,EAwCL,MAAO,CAAE,aAtCYjI,EAAAA,YACnB,CAAC,CAAE,aAAAqI,EAAc,WAAAzE,EAAY,WAAA0E,KAA6C,CACxE,qBAAqBJ,EAAO,OAAO,EACnCC,EAAa,QAAU,GAEvB,MAAMI,EAASC,GAAc,KAAK,IAAI,EAAG,KAAK,IAAI,EAAGA,CAAC,CAAC,EACjDhF,EAAS+E,EAAMF,CAAY,EAC3BI,EAAY,YAAY,IAAA,EAG9B,IAAIC,EAAcX,EAElBE,EAAY,EAAI,EAEhB,MAAMU,EAAQC,GAAgB,CAC5B,GAAIT,EAAa,QAAS,OAC1B,MAAM3D,EAAUoE,EAAMH,EAChBI,EAAW,KAAK,IAAI,EAAGrE,EAAU,KAAK,IAAI,EAAGZ,CAAU,CAAC,EACxDkF,EAAUJ,GAAelF,EAASkF,GAAeG,EACvDf,EAAUS,EAAMO,CAAO,CAAC,EAEpBD,EAAW,EACbX,EAAO,QAAU,sBAAsBS,CAAI,GAE3CV,EAAY,EAAK,EACjBK,GAAA,MAAAA,IAEJ,EAGAJ,EAAO,QAAU,sBAAuBU,GAAQ,CAC9CF,EAAcX,EACdY,EAAKC,CAAG,CACV,CAAC,CACH,EACA,CAACd,EAAWC,CAAM,CAAA,EAGG,WAAAK,EAAY,SAAAJ,CAAA,CACrC,CC7DO,SAASe,GAAkD,CAChE,KAAM,CAAE,OAAA3C,EAAQ,aAAApC,CAAA,EAAiB3B,oBAAA,EAC3B,CAAE,YAAAG,EAAa,SAAAC,CAAA,EAAaC,iBAAA,EAE5BsG,EAAW9J,EAAAA,QAAQ,IAAM,OAE7B,MAAO,CAAC,KADI6C,EAAAqE,EAAOpC,CAAY,IAAnB,YAAAjC,EAAsB,WAAY,CAAA,CAChC,EACX,OAAQkH,GAAMA,GAAK,OAAO,SAASA,EAAE,YAAY,GAAKA,EAAE,cAAgB,CAAC,EACzE,KAAK,CAACtI,EAAGuI,IAAMvI,EAAE,aAAeuI,EAAE,YAAY,CACnD,EAAG,CAAC9C,EAAQpC,CAAY,CAAC,EAEzB,OAAO9E,EAAAA,QAA+B,IAAM,CAC1C,GAAI8J,EAAS,SAAW,EAAG,MAAO,CAAE,SAAU,EAAG,QAAS,EAAG,UAAW,CAAA,EAGxE,IAAIG,EAAY,GAChB,QAASC,EAAIJ,EAAS,OAAS,EAAGI,GAAK,EAAGA,IACxC,GAAI5G,GAAewG,EAASI,CAAC,EAAG,aAAc,CAC5CD,EAAYC,EACZ,KACF,CAGF,GAAID,IAAc,GAAI,MAAO,CAAE,SAAU,EAAG,QAAS,EAAG,UAAW,CAAA,EAEnE,MAAME,EAAUL,EAASG,CAAS,EAC5BG,EAAcN,EAASG,EAAY,CAAC,EACpCI,GAAaD,GAAA,YAAAA,EAAa,gBAAiB7G,EAAW,EAAIA,EAAWD,GACrEgH,EAAkB,KAAK,IAAI,EAAGD,EAAaF,EAAQ,YAAY,EAC/D7E,EAAU,KAAK,IAAI,EAAGhC,EAAc6G,EAAQ,YAAY,EACxDI,EAAY,KAAK,IAAI,EAAGF,EAAa/G,CAAW,EAGtD,MAAO,CAAE,SAFQgH,EAAkB,EAAI,KAAK,IAAI,EAAGhF,EAAUgF,CAAe,EAAI,EAE7D,QAAAhF,EAAS,UAAAiF,CAAA,CAC9B,EAAG,CAACT,EAAUxG,EAAaC,CAAQ,CAAC,CACtC"}
@@ -0,0 +1,321 @@
1
+ import { useMemo as V, useState as A, useRef as M, useCallback as C, useLayoutEffect as Y, useEffect as D } from "react";
2
+ import { u as _, a as j, d as z } from "./liveAudioGraph-CmEsdLgZ.js";
3
+ import { b as P, u as B, c as J, g as Q } from "./GingerSplitContexts-BzBExb95.js";
4
+ import { p as W, c as Z } from "./selectors-BalBCc7X.js";
5
+ import { m as $, e as ee, f as te, n as re } from "./ginger-L2ZFgzH4.js";
6
+ const G = new Uint8Array(0), N = new Uint8Array(0);
7
+ function ie(n = {}) {
8
+ const {
9
+ enabled: e = !0,
10
+ fftSize: t = 2048,
11
+ smoothingTimeConstant: r = 0.8,
12
+ minDecibels: c = -100,
13
+ maxDecibels: a = -30
14
+ } = n, { audioRef: s, state: o } = _(), f = V(
15
+ () => ({
16
+ fftSize: t,
17
+ smoothingTimeConstant: r,
18
+ minDecibels: c,
19
+ maxDecibels: a
20
+ }),
21
+ [t, r, c, a]
22
+ ), [i, m] = A(0), [l, u] = A(null), [h, x] = A(!1), [v, d] = A({ frequencyBinCount: 0, sampleRate: 0 }), p = M(G), w = M(N), E = C(async () => {
23
+ const k = g.current;
24
+ k && k.state === "suspended" && await k.resume();
25
+ }, []), g = M(null), R = M(null);
26
+ return Y(() => {
27
+ if (!e || typeof window > "u")
28
+ return;
29
+ let k = !1, F = null, b = null, q = 0;
30
+ const U = () => {
31
+ const y = g.current;
32
+ y && x(y.state === "suspended");
33
+ }, K = () => {
34
+ if (k) return;
35
+ const y = R.current, S = p.current, I = w.current;
36
+ y && S.length > 0 && I.length > 0 && (y.getByteFrequencyData(S), y.getByteTimeDomainData(I), m((L) => L + 1)), q = requestAnimationFrame(K);
37
+ }, H = () => {
38
+ const y = s.current;
39
+ if (!y || k) return "no-element";
40
+ try {
41
+ const { id: S, context: I, analyser: L } = j(y, f);
42
+ F = S, b = y, g.current = I, R.current = L, x(I.state === "suspended"), u(null), I.addEventListener("statechange", U);
43
+ const T = L.frequencyBinCount, O = L.fftSize;
44
+ return p.current = new Uint8Array(T), w.current = new Uint8Array(O), d({ frequencyBinCount: T, sampleRate: I.sampleRate }), q = requestAnimationFrame(K), "ok";
45
+ } catch (S) {
46
+ const I = S instanceof Error ? S.message : "Failed to attach live analyser";
47
+ return u(I), g.current = null, R.current = null, p.current = G, w.current = N, d({ frequencyBinCount: 0, sampleRate: 0 }), "error";
48
+ }
49
+ }, X = H();
50
+ if (X !== "ok") {
51
+ let y = 0;
52
+ const S = 120;
53
+ let I = 0;
54
+ const L = () => {
55
+ if (k) return;
56
+ const T = H();
57
+ T === "ok" || T === "error" || (I += 1, !(I >= S) && (y = requestAnimationFrame(L)));
58
+ };
59
+ return X === "no-element" && (y = requestAnimationFrame(L)), () => {
60
+ var T;
61
+ k = !0, cancelAnimationFrame(y), cancelAnimationFrame(q), F != null && b && z(b, F), (T = g.current) == null || T.removeEventListener("statechange", U), g.current = null, R.current = null, p.current = G, w.current = N;
62
+ };
63
+ }
64
+ return () => {
65
+ var y;
66
+ k = !0, cancelAnimationFrame(q), F != null && b && z(b, F), (y = g.current) == null || y.removeEventListener("statechange", U), g.current = null, R.current = null, p.current = G, w.current = N, d({ frequencyBinCount: 0, sampleRate: 0 });
67
+ };
68
+ }, [e, s, f, o.currentIndex]), {
69
+ frequencyData: p.current,
70
+ timeDomainData: w.current,
71
+ frequencyBinCount: v.frequencyBinCount,
72
+ sampleRate: v.sampleRate,
73
+ isSuspended: h,
74
+ error: l,
75
+ resume: E,
76
+ frame: i
77
+ };
78
+ }
79
+ function le(n = !0, e = {}) {
80
+ const { togglePlayPause: t, next: r, prev: c } = P(), { toggleMute: a, seek: s, currentTime: o, duration: f } = B(), {
81
+ mute: i,
82
+ seekForward: m,
83
+ seekBackward: l
84
+ } = e;
85
+ D(() => {
86
+ if (!n || typeof window > "u") return;
87
+ const u = (e.playPause ?? " ").toLowerCase(), h = (e.next ?? "ArrowRight").toLowerCase(), x = (e.previous ?? "ArrowLeft").toLowerCase(), v = i == null ? void 0 : i.toLowerCase(), d = m == null ? void 0 : m.toLowerCase(), p = l == null ? void 0 : l.toLowerCase(), w = e.seekSeconds ?? 5, E = (g) => {
88
+ const R = g.target;
89
+ if (R && (["INPUT", "TEXTAREA", "SELECT"].includes(R.tagName) || R.isContentEditable))
90
+ return;
91
+ const k = g.key.toLowerCase();
92
+ if (k === u)
93
+ g.preventDefault(), t();
94
+ else if (k === h)
95
+ g.preventDefault(), r();
96
+ else if (k === x)
97
+ g.preventDefault(), c();
98
+ else if (v && k === v)
99
+ g.preventDefault(), a();
100
+ else if (d && k === d) {
101
+ g.preventDefault();
102
+ const F = f > 0 ? f : Number.POSITIVE_INFINITY;
103
+ s(Math.min(F, o + w));
104
+ } else p && k === p && (g.preventDefault(), s(Math.max(0, o - w)));
105
+ };
106
+ return window.addEventListener("keydown", E), () => window.removeEventListener("keydown", E);
107
+ }, [
108
+ e.next,
109
+ e.playPause,
110
+ e.previous,
111
+ e.seekSeconds,
112
+ o,
113
+ f,
114
+ n,
115
+ i,
116
+ r,
117
+ c,
118
+ s,
119
+ l,
120
+ m,
121
+ a,
122
+ t
123
+ ]);
124
+ }
125
+ function fe(n) {
126
+ const { durationMs: e, stopAfterTracks: t, respectPause: r = !0, enabled: c = !0, onFire: a } = n, { currentIndex: s, pause: o, isPaused: f } = P(), i = M(t ?? 0), m = M(s), l = M(e ?? 0), u = M(null);
127
+ D(() => {
128
+ i.current = t ?? 0;
129
+ }, [t]);
130
+ const h = M(e);
131
+ D(() => {
132
+ h.current !== e && (l.current = e ?? 0, h.current = e);
133
+ }, [e]), D(() => {
134
+ if (!c || !e || e <= 0) {
135
+ l.current = e ?? 0, u.current = null;
136
+ return;
137
+ }
138
+ if (r && f) {
139
+ if (u.current !== null) {
140
+ const v = Date.now() - u.current;
141
+ l.current = Math.max(0, l.current - v), u.current = null;
142
+ }
143
+ return;
144
+ }
145
+ u.current = Date.now();
146
+ const x = setTimeout(() => {
147
+ l.current = 0, u.current = null, o(), a == null || a();
148
+ }, l.current);
149
+ return () => {
150
+ if (clearTimeout(x), u.current !== null) {
151
+ const v = Date.now() - u.current;
152
+ l.current = Math.max(0, l.current - v), u.current = null;
153
+ }
154
+ };
155
+ }, [e, c, f, a, o, r]), D(() => {
156
+ if (!c || !t || t <= 0) return;
157
+ const x = m.current;
158
+ m.current = s, s !== x && (i.current -= 1, i.current <= 0 && (o(), a == null || a()));
159
+ }, [s, c, a, o, t]);
160
+ }
161
+ function me(n = !1) {
162
+ const e = J(), t = M(e);
163
+ D(() => {
164
+ if (!n || typeof console > "u") return;
165
+ const r = t.current;
166
+ r !== e && console.debug("[ginger]", {
167
+ from: {
168
+ currentIndex: r.currentIndex,
169
+ isPaused: r.isPaused,
170
+ currentTime: r.currentTime,
171
+ repeatMode: r.repeatMode
172
+ },
173
+ to: {
174
+ currentIndex: e.currentIndex,
175
+ isPaused: e.isPaused,
176
+ currentTime: e.currentTime,
177
+ repeatMode: e.repeatMode
178
+ }
179
+ }), t.current = e;
180
+ }, [n, e]);
181
+ }
182
+ function ne(n) {
183
+ return Math.max(0, Math.min(1, n));
184
+ }
185
+ function de(n) {
186
+ const e = B(), t = P(), { seek: r } = e, [c, a] = A(0), [s, o] = A(!1), f = W(Q(t, e)), i = s ? c : f, m = C(
187
+ (l) => {
188
+ if (!(n > 0)) return;
189
+ const u = l.currentTarget, h = u.getBoundingClientRect(), x = (p) => {
190
+ const w = ne((p - h.left) / h.width);
191
+ a(w), r(w * n);
192
+ };
193
+ o(!0), u.setPointerCapture(l.pointerId), x(l.clientX);
194
+ const v = (p) => x(p.clientX), d = (p) => {
195
+ x(p.clientX), o(!1), u.releasePointerCapture(l.pointerId), u.removeEventListener("pointermove", v), u.removeEventListener("pointerup", d), u.removeEventListener("pointercancel", d);
196
+ };
197
+ u.addEventListener("pointermove", v), u.addEventListener("pointerup", d), u.addEventListener("pointercancel", d);
198
+ },
199
+ [n, r]
200
+ );
201
+ return { fraction: c, displayFraction: i, isDragging: s, onPointerDown: m };
202
+ }
203
+ function pe(n = {}) {
204
+ const { enabled: e = !0, crossOrigin: t } = n, { tracks: r, currentIndex: c, repeatMode: a, playbackMode: s } = P();
205
+ D(() => {
206
+ var m;
207
+ if (!e || typeof document > "u") return;
208
+ const o = Z({ tracks: r, currentIndex: c, repeatMode: a, playbackMode: s });
209
+ if (o === c) return;
210
+ const f = ((m = r[o]) == null ? void 0 : m.fileUrl) ?? "";
211
+ if (!f) return;
212
+ const i = document.createElement("audio");
213
+ return i.preload = "auto", t && (i.crossOrigin = t), i.src = f, i.load(), () => {
214
+ i.removeAttribute("src"), i.load();
215
+ };
216
+ }, [e, t, r, c, a, s]);
217
+ }
218
+ function ge(n = {}) {
219
+ let e = $({
220
+ tracks: n.tracks ?? [],
221
+ currentIndex: n.currentIndex,
222
+ playlistMeta: n.playlistMeta,
223
+ isPaused: n.isPaused,
224
+ isShuffled: n.isShuffled,
225
+ repeatMode: n.repeatMode,
226
+ playbackMode: n.playbackMode,
227
+ volume: n.volume,
228
+ muted: n.muted,
229
+ playbackRate: n.playbackRate
230
+ });
231
+ const t = /* @__PURE__ */ new Set(), r = (s) => {
232
+ const o = re(e, s);
233
+ if (o !== e) {
234
+ e = o;
235
+ for (const f of t)
236
+ f(e);
237
+ }
238
+ };
239
+ return {
240
+ getState: () => e,
241
+ dispatch: r,
242
+ subscribe: (s) => (t.add(s), () => t.delete(s)),
243
+ init: (s) => {
244
+ r({ type: "INIT", payload: s });
245
+ },
246
+ clampVolume: te,
247
+ clampPlaybackRate: ee
248
+ };
249
+ }
250
+ function ye(n = {}) {
251
+ const { maxLength: e = 50 } = n, { tracks: t, currentIndex: r } = P(), [c, a] = A([]), s = M(null), o = M(t);
252
+ o.current = t, D(() => {
253
+ const i = t[r];
254
+ if (!i || s.current === r) return;
255
+ s.current = r;
256
+ const m = {
257
+ track: i,
258
+ index: r,
259
+ playedAt: Date.now()
260
+ };
261
+ a((l) => {
262
+ const u = [...l, m];
263
+ return u.length > e ? u.slice(u.length - e) : u;
264
+ });
265
+ }, [r, t, e]);
266
+ const f = C(() => a([]), []);
267
+ return { history: c, clearHistory: f };
268
+ }
269
+ function he() {
270
+ const { setVolume: n, volume: e } = B(), [t, r] = A(!1), c = M(0), a = M(!1), s = C(() => {
271
+ cancelAnimationFrame(c.current), a.current = !0, r(!1);
272
+ }, []);
273
+ return { fadeVolumeTo: C(
274
+ ({ targetVolume: f, durationMs: i, onComplete: m }) => {
275
+ cancelAnimationFrame(c.current), a.current = !1;
276
+ const l = (d) => Math.min(1, Math.max(0, d)), u = l(f), h = performance.now();
277
+ let x = e;
278
+ r(!0);
279
+ const v = (d) => {
280
+ if (a.current) return;
281
+ const p = d - h, w = Math.min(1, p / Math.max(1, i)), E = x + (u - x) * w;
282
+ n(l(E)), w < 1 ? c.current = requestAnimationFrame(v) : (r(!1), m == null || m());
283
+ };
284
+ c.current = requestAnimationFrame((d) => {
285
+ x = e, v(d);
286
+ });
287
+ },
288
+ [n, e]
289
+ ), cancelFade: s, isFading: t };
290
+ }
291
+ function xe() {
292
+ const { tracks: n, currentIndex: e } = P(), { currentTime: t, duration: r } = B(), c = V(() => {
293
+ var s;
294
+ return [...((s = n[e]) == null ? void 0 : s.chapters) ?? []].filter((o) => o && Number.isFinite(o.startSeconds) && o.startSeconds >= 0).sort((o, f) => o.startSeconds - f.startSeconds);
295
+ }, [n, e]);
296
+ return V(() => {
297
+ if (c.length === 0) return { progress: 0, elapsed: 0, remaining: 0 };
298
+ let a = -1;
299
+ for (let h = c.length - 1; h >= 0; h--)
300
+ if (t >= c[h].startSeconds) {
301
+ a = h;
302
+ break;
303
+ }
304
+ if (a === -1) return { progress: 0, elapsed: 0, remaining: 0 };
305
+ const s = c[a], o = c[a + 1], f = (o == null ? void 0 : o.startSeconds) ?? (r > 0 ? r : t), i = Math.max(0, f - s.startSeconds), m = Math.max(0, t - s.startSeconds), l = Math.max(0, f - t);
306
+ return { progress: i > 0 ? Math.min(1, m / i) : 0, elapsed: m, remaining: l };
307
+ }, [c, t, r]);
308
+ }
309
+ export {
310
+ me as a,
311
+ le as b,
312
+ ge as c,
313
+ ie as d,
314
+ ye as e,
315
+ fe as f,
316
+ he as g,
317
+ pe as h,
318
+ de as i,
319
+ xe as u
320
+ };
321
+ //# sourceMappingURL=useGingerChapterProgress-DLYdGytK.js.map