@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.
- package/README.md +140 -8
- package/dist/analyzer/liveAudioGraph.d.ts +14 -1
- package/dist/analyzer/liveAudioGraph.d.ts.map +1 -1
- package/dist/analyzer/useGingerLiveAnalyzer.d.ts +6 -0
- package/dist/analyzer/useGingerLiveAnalyzer.d.ts.map +1 -1
- package/dist/client.cjs +1 -1
- package/dist/client.js +36 -29
- package/dist/client.js.map +1 -1
- package/dist/components/playlist/GingerPlaylist.d.ts.map +1 -1
- package/dist/context/GingerProvider.d.ts +1 -1
- package/dist/context/GingerProvider.d.ts.map +1 -1
- package/dist/core/playbackReducer.d.ts.map +1 -1
- package/dist/equalizer/index.cjs +2 -0
- package/dist/equalizer/index.cjs.map +1 -0
- package/dist/equalizer/index.d.ts +3 -0
- package/dist/equalizer/index.d.ts.map +1 -0
- package/dist/equalizer/index.js +51 -0
- package/dist/equalizer/index.js.map +1 -0
- package/dist/equalizer/useGingerEqualizer.d.ts +41 -0
- package/dist/equalizer/useGingerEqualizer.d.ts.map +1 -0
- package/dist/ginger-L2ZFgzH4.js +2223 -0
- package/dist/ginger-L2ZFgzH4.js.map +1 -0
- package/dist/ginger-NEcOSSJD.cjs +2 -0
- package/dist/ginger-NEcOSSJD.cjs.map +1 -0
- package/dist/hooks/useGingerChapterProgress.d.ts +14 -0
- package/dist/hooks/useGingerChapterProgress.d.ts.map +1 -0
- package/dist/hooks/useGingerKeyboardShortcuts.d.ts +6 -0
- package/dist/hooks/useGingerKeyboardShortcuts.d.ts.map +1 -1
- package/dist/hooks/useGingerPlaybackHistory.d.ts +26 -0
- package/dist/hooks/useGingerPlaybackHistory.d.ts.map +1 -0
- package/dist/hooks/useGingerSleepTimer.d.ts.map +1 -1
- package/dist/hooks/useGingerVolumeFade.d.ts +22 -0
- package/dist/hooks/useGingerVolumeFade.d.ts.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +18 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +36 -29
- package/dist/index.js.map +1 -1
- package/dist/liveAudioGraph-CmEsdLgZ.js +150 -0
- package/dist/liveAudioGraph-CmEsdLgZ.js.map +1 -0
- package/dist/liveAudioGraph-D1BXMv_u.cjs +2 -0
- package/dist/liveAudioGraph-D1BXMv_u.cjs.map +1 -0
- package/dist/selectors-BalBCc7X.js +127 -0
- package/dist/selectors-BalBCc7X.js.map +1 -0
- package/dist/selectors-YXnP8Y8g.cjs +2 -0
- package/dist/selectors-YXnP8Y8g.cjs.map +1 -0
- package/dist/store.d.ts +46 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/testing/index.cjs +1 -1
- package/dist/testing/index.js +1 -1
- package/dist/testing/mockWebAudio.d.ts +15 -1
- package/dist/testing/mockWebAudio.d.ts.map +1 -1
- package/dist/types.d.ts +30 -8
- package/dist/types.d.ts.map +1 -1
- package/dist/useGingerChapterProgress-BOqUimE7.cjs +2 -0
- package/dist/useGingerChapterProgress-BOqUimE7.cjs.map +1 -0
- package/dist/useGingerChapterProgress-DLYdGytK.js +321 -0
- package/dist/useGingerChapterProgress-DLYdGytK.js.map +1 -0
- package/package.json +7 -2
- package/dist/ginger-B26HM2Ja.cjs +0 -2
- package/dist/ginger-B26HM2Ja.cjs.map +0 -1
- package/dist/ginger-DlNYfHbV.js +0 -2278
- package/dist/ginger-DlNYfHbV.js.map +0 -1
- package/dist/useNextTrackPrefetch-Y_fs2JEx.js +0 -265
- package/dist/useNextTrackPrefetch-Y_fs2JEx.js.map +0 -1
- package/dist/useNextTrackPrefetch-wSILz6TL.cjs +0 -2
- package/dist/useNextTrackPrefetch-wSILz6TL.cjs.map +0 -1
|
@@ -1,265 +0,0 @@
|
|
|
1
|
-
import { useMemo as V, useState as R, useRef as M, useCallback as H, useLayoutEffect as J, useEffect as b } from "react";
|
|
2
|
-
import { b as S, u as z, g as O, c as Y } from "./GingerSplitContexts-BzBExb95.js";
|
|
3
|
-
import { r as Z, n as _, o as Q, q as $, s as ee, h as te, t as ne, v as re } from "./ginger-DlNYfHbV.js";
|
|
4
|
-
function se() {
|
|
5
|
-
const t = S(), e = z();
|
|
6
|
-
return V(() => {
|
|
7
|
-
const n = O(t, e);
|
|
8
|
-
return {
|
|
9
|
-
state: n,
|
|
10
|
-
currentTrack: ne(n),
|
|
11
|
-
playbackUi: te(n),
|
|
12
|
-
duration: ee(n),
|
|
13
|
-
remaining: $(n),
|
|
14
|
-
progress: Q(n),
|
|
15
|
-
artworkUrl: _(n),
|
|
16
|
-
albumLine: Z(n),
|
|
17
|
-
play: t.play,
|
|
18
|
-
pause: t.pause,
|
|
19
|
-
togglePlayPause: t.togglePlayPause,
|
|
20
|
-
seek: e.seek,
|
|
21
|
-
setVolume: e.setVolume,
|
|
22
|
-
setMuted: e.setMuted,
|
|
23
|
-
toggleMute: e.toggleMute,
|
|
24
|
-
setPlaybackRate: e.setPlaybackRate,
|
|
25
|
-
next: t.next,
|
|
26
|
-
prev: t.prev,
|
|
27
|
-
setRepeatMode: t.setRepeatMode,
|
|
28
|
-
cycleRepeat: t.cycleRepeat,
|
|
29
|
-
toggleShuffle: t.toggleShuffle,
|
|
30
|
-
setQueue: t.setQueue,
|
|
31
|
-
insertTrackAt: t.insertTrackAt,
|
|
32
|
-
removeTrackAt: t.removeTrackAt,
|
|
33
|
-
moveTrack: t.moveTrack,
|
|
34
|
-
enqueueNext: t.enqueueNext,
|
|
35
|
-
playTrackAt: t.playTrackAt,
|
|
36
|
-
selectTrackAt: t.selectTrackAt,
|
|
37
|
-
setPlaylistMeta: t.setPlaylistMeta,
|
|
38
|
-
setPlaybackMode: t.setPlaybackMode,
|
|
39
|
-
init: t.init,
|
|
40
|
-
audioRef: e.audioRef,
|
|
41
|
-
dispatch: t.dispatch
|
|
42
|
-
};
|
|
43
|
-
}, [t, e]);
|
|
44
|
-
}
|
|
45
|
-
const U = /* @__PURE__ */ new WeakMap();
|
|
46
|
-
function ae(t) {
|
|
47
|
-
const e = 2 ** Math.round(Math.log2(t));
|
|
48
|
-
return Math.min(32768, Math.max(32, e));
|
|
49
|
-
}
|
|
50
|
-
function oe(t, e) {
|
|
51
|
-
let n = U.get(t);
|
|
52
|
-
if (!n) {
|
|
53
|
-
const f = window.AudioContext ?? window.webkitAudioContext;
|
|
54
|
-
if (!f)
|
|
55
|
-
throw new Error("Web Audio API is not available");
|
|
56
|
-
const u = new f(), d = u.createMediaElementSource(t);
|
|
57
|
-
n = { context: u, source: d, consumers: /* @__PURE__ */ new Map(), nextId: 0 }, U.set(t, n);
|
|
58
|
-
}
|
|
59
|
-
const { context: s, source: o } = n, r = s.createAnalyser();
|
|
60
|
-
r.fftSize = ae(e.fftSize), r.smoothingTimeConstant = e.smoothingTimeConstant, r.minDecibels = e.minDecibels, r.maxDecibels = e.maxDecibels, o.connect(r);
|
|
61
|
-
const a = n.consumers.size === 0;
|
|
62
|
-
a && r.connect(s.destination);
|
|
63
|
-
const i = n.nextId;
|
|
64
|
-
return n.nextId += 1, n.consumers.set(i, { analyser: r, isPlaybackSink: a }), { id: i, context: s, analyser: r };
|
|
65
|
-
}
|
|
66
|
-
function X(t, e) {
|
|
67
|
-
const n = U.get(t);
|
|
68
|
-
if (!n) return;
|
|
69
|
-
const s = n.consumers.get(e);
|
|
70
|
-
if (!s) return;
|
|
71
|
-
const { analyser: o, isPlaybackSink: r } = s;
|
|
72
|
-
if (o.disconnect(), n.consumers.delete(e), n.consumers.size === 0) {
|
|
73
|
-
try {
|
|
74
|
-
n.source.disconnect();
|
|
75
|
-
} catch {
|
|
76
|
-
}
|
|
77
|
-
n.context.close(), U.delete(t);
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
if (r) {
|
|
81
|
-
const a = n.consumers.values().next().value;
|
|
82
|
-
a && (a.analyser.connect(n.context.destination), a.isPlaybackSink = !0);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
const q = new Uint8Array(0), F = new Uint8Array(0);
|
|
86
|
-
function fe(t = {}) {
|
|
87
|
-
const {
|
|
88
|
-
enabled: e = !0,
|
|
89
|
-
fftSize: n = 2048,
|
|
90
|
-
smoothingTimeConstant: s = 0.8,
|
|
91
|
-
minDecibels: o = -100,
|
|
92
|
-
maxDecibels: r = -30
|
|
93
|
-
} = t, { audioRef: a, state: i } = se(), f = V(
|
|
94
|
-
() => ({
|
|
95
|
-
fftSize: n,
|
|
96
|
-
smoothingTimeConstant: s,
|
|
97
|
-
minDecibels: o,
|
|
98
|
-
maxDecibels: r
|
|
99
|
-
}),
|
|
100
|
-
[n, s, o, r]
|
|
101
|
-
), [u, d] = R(0), [m, c] = R(null), [w, g] = R(!1), [C, A] = R({ frequencyBinCount: 0, sampleRate: 0 }), p = M(q), k = M(F), W = H(async () => {
|
|
102
|
-
const v = h.current;
|
|
103
|
-
v && v.state === "suspended" && await v.resume();
|
|
104
|
-
}, []), h = M(null), L = M(null);
|
|
105
|
-
return J(() => {
|
|
106
|
-
if (!e || typeof window > "u")
|
|
107
|
-
return;
|
|
108
|
-
let v = !1, D = null, E = null, I = 0;
|
|
109
|
-
const B = () => {
|
|
110
|
-
const l = h.current;
|
|
111
|
-
l && g(l.state === "suspended");
|
|
112
|
-
}, G = () => {
|
|
113
|
-
if (v) return;
|
|
114
|
-
const l = L.current, x = p.current, y = k.current;
|
|
115
|
-
l && x.length > 0 && y.length > 0 && (l.getByteFrequencyData(x), l.getByteTimeDomainData(y), d((P) => P + 1)), I = requestAnimationFrame(G);
|
|
116
|
-
}, N = () => {
|
|
117
|
-
const l = a.current;
|
|
118
|
-
if (!l || v) return "no-element";
|
|
119
|
-
try {
|
|
120
|
-
const { id: x, context: y, analyser: P } = oe(l, f);
|
|
121
|
-
D = x, E = l, h.current = y, L.current = P, g(y.state === "suspended"), c(null), y.addEventListener("statechange", B);
|
|
122
|
-
const T = P.frequencyBinCount, j = P.fftSize;
|
|
123
|
-
return p.current = new Uint8Array(T), k.current = new Uint8Array(j), A({ frequencyBinCount: T, sampleRate: y.sampleRate }), I = requestAnimationFrame(G), "ok";
|
|
124
|
-
} catch (x) {
|
|
125
|
-
const y = x instanceof Error ? x.message : "Failed to attach live analyser";
|
|
126
|
-
return c(y), h.current = null, L.current = null, p.current = q, k.current = F, A({ frequencyBinCount: 0, sampleRate: 0 }), "error";
|
|
127
|
-
}
|
|
128
|
-
}, K = N();
|
|
129
|
-
if (K !== "ok") {
|
|
130
|
-
let l = 0;
|
|
131
|
-
const x = 120;
|
|
132
|
-
let y = 0;
|
|
133
|
-
const P = () => {
|
|
134
|
-
if (v) return;
|
|
135
|
-
const T = N();
|
|
136
|
-
T === "ok" || T === "error" || (y += 1, !(y >= x) && (l = requestAnimationFrame(P)));
|
|
137
|
-
};
|
|
138
|
-
return K === "no-element" && (l = requestAnimationFrame(P)), () => {
|
|
139
|
-
var T;
|
|
140
|
-
v = !0, cancelAnimationFrame(l), cancelAnimationFrame(I), D != null && E && X(E, D), (T = h.current) == null || T.removeEventListener("statechange", B), h.current = null, L.current = null, p.current = q, k.current = F;
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
return () => {
|
|
144
|
-
var l;
|
|
145
|
-
v = !0, cancelAnimationFrame(I), D != null && E && X(E, D), (l = h.current) == null || l.removeEventListener("statechange", B), h.current = null, L.current = null, p.current = q, k.current = F, A({ frequencyBinCount: 0, sampleRate: 0 });
|
|
146
|
-
};
|
|
147
|
-
}, [e, a, f, i.currentIndex]), {
|
|
148
|
-
frequencyData: p.current,
|
|
149
|
-
timeDomainData: k.current,
|
|
150
|
-
frequencyBinCount: C.frequencyBinCount,
|
|
151
|
-
sampleRate: C.sampleRate,
|
|
152
|
-
isSuspended: w,
|
|
153
|
-
error: m,
|
|
154
|
-
resume: W
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
function de(t = !0, e = {}) {
|
|
158
|
-
const { togglePlayPause: n, next: s, prev: o } = S(), { toggleMute: r } = z(), a = e.mute;
|
|
159
|
-
b(() => {
|
|
160
|
-
if (!t || typeof window > "u") return;
|
|
161
|
-
const i = (e.playPause ?? " ").toLowerCase(), f = (e.next ?? "ArrowRight").toLowerCase(), u = (e.previous ?? "ArrowLeft").toLowerCase(), d = a == null ? void 0 : a.toLowerCase(), m = (c) => {
|
|
162
|
-
const w = c.target;
|
|
163
|
-
if (w && (["INPUT", "TEXTAREA", "SELECT"].includes(w.tagName) || w.isContentEditable))
|
|
164
|
-
return;
|
|
165
|
-
const g = c.key.toLowerCase();
|
|
166
|
-
g === i ? (c.preventDefault(), n()) : g === f ? (c.preventDefault(), s()) : g === u ? (c.preventDefault(), o()) : d && g === d && (c.preventDefault(), r());
|
|
167
|
-
};
|
|
168
|
-
return window.addEventListener("keydown", m), () => window.removeEventListener("keydown", m);
|
|
169
|
-
}, [
|
|
170
|
-
e.next,
|
|
171
|
-
e.playPause,
|
|
172
|
-
e.previous,
|
|
173
|
-
t,
|
|
174
|
-
a,
|
|
175
|
-
s,
|
|
176
|
-
o,
|
|
177
|
-
r,
|
|
178
|
-
n
|
|
179
|
-
]);
|
|
180
|
-
}
|
|
181
|
-
function me(t) {
|
|
182
|
-
const { durationMs: e, stopAfterTracks: n, respectPause: s = !0, enabled: o = !0, onFire: r } = t, { currentIndex: a, pause: i, isPaused: f } = S(), u = M(n ?? 0), d = M(a);
|
|
183
|
-
b(() => {
|
|
184
|
-
u.current = n ?? 0;
|
|
185
|
-
}, [n]), b(() => {
|
|
186
|
-
if (!o || !e || e <= 0 || s && f) return;
|
|
187
|
-
const m = setTimeout(() => {
|
|
188
|
-
i(), r == null || r();
|
|
189
|
-
}, e);
|
|
190
|
-
return () => clearTimeout(m);
|
|
191
|
-
}, [e, o, f, r, i, s]), b(() => {
|
|
192
|
-
if (!o || !n || n <= 0) return;
|
|
193
|
-
const m = d.current;
|
|
194
|
-
d.current = a, a !== m && (u.current -= 1, u.current <= 0 && (i(), r == null || r()));
|
|
195
|
-
}, [a, o, r, i, n]);
|
|
196
|
-
}
|
|
197
|
-
function pe(t = !1) {
|
|
198
|
-
const e = Y(), n = M(e);
|
|
199
|
-
b(() => {
|
|
200
|
-
if (!t || typeof console > "u") return;
|
|
201
|
-
const s = n.current;
|
|
202
|
-
s !== e && console.debug("[ginger]", {
|
|
203
|
-
from: {
|
|
204
|
-
currentIndex: s.currentIndex,
|
|
205
|
-
isPaused: s.isPaused,
|
|
206
|
-
currentTime: s.currentTime,
|
|
207
|
-
repeatMode: s.repeatMode
|
|
208
|
-
},
|
|
209
|
-
to: {
|
|
210
|
-
currentIndex: e.currentIndex,
|
|
211
|
-
isPaused: e.isPaused,
|
|
212
|
-
currentTime: e.currentTime,
|
|
213
|
-
repeatMode: e.repeatMode
|
|
214
|
-
}
|
|
215
|
-
}), n.current = e;
|
|
216
|
-
}, [t, e]);
|
|
217
|
-
}
|
|
218
|
-
function ce(t) {
|
|
219
|
-
return Math.max(0, Math.min(1, t));
|
|
220
|
-
}
|
|
221
|
-
function ye(t) {
|
|
222
|
-
const e = z(), n = S(), { seek: s } = e, [o, r] = R(0), [a, i] = R(!1), f = Q(O(n, e)), u = a ? o : f, d = H(
|
|
223
|
-
(m) => {
|
|
224
|
-
if (!(t > 0)) return;
|
|
225
|
-
const c = m.currentTarget, w = c.getBoundingClientRect(), g = (p) => {
|
|
226
|
-
const k = ce((p - w.left) / w.width);
|
|
227
|
-
r(k), s(k * t);
|
|
228
|
-
};
|
|
229
|
-
i(!0), c.setPointerCapture(m.pointerId), g(m.clientX);
|
|
230
|
-
const C = (p) => g(p.clientX), A = (p) => {
|
|
231
|
-
g(p.clientX), i(!1), c.releasePointerCapture(m.pointerId), c.removeEventListener("pointermove", C), c.removeEventListener("pointerup", A), c.removeEventListener("pointercancel", A);
|
|
232
|
-
};
|
|
233
|
-
c.addEventListener("pointermove", C), c.addEventListener("pointerup", A), c.addEventListener("pointercancel", A);
|
|
234
|
-
},
|
|
235
|
-
[t, s]
|
|
236
|
-
);
|
|
237
|
-
return { fraction: o, displayFraction: u, isDragging: a, onPointerDown: d };
|
|
238
|
-
}
|
|
239
|
-
function ge(t = {}) {
|
|
240
|
-
const { enabled: e = !0, crossOrigin: n } = t, { tracks: s, currentIndex: o, repeatMode: r, playbackMode: a } = S();
|
|
241
|
-
b(() => {
|
|
242
|
-
var d;
|
|
243
|
-
if (!e || typeof document > "u") return;
|
|
244
|
-
const i = re({ tracks: s, currentIndex: o, repeatMode: r, playbackMode: a });
|
|
245
|
-
if (i === o) return;
|
|
246
|
-
const f = ((d = s[i]) == null ? void 0 : d.fileUrl) ?? "";
|
|
247
|
-
if (!f) return;
|
|
248
|
-
const u = document.createElement("audio");
|
|
249
|
-
return u.preload = "auto", n && (u.crossOrigin = n), u.src = f, u.load(), () => {
|
|
250
|
-
u.removeAttribute("src"), u.load();
|
|
251
|
-
};
|
|
252
|
-
}, [e, n, s, o, r, a]);
|
|
253
|
-
}
|
|
254
|
-
export {
|
|
255
|
-
oe as a,
|
|
256
|
-
pe as b,
|
|
257
|
-
de as c,
|
|
258
|
-
X as d,
|
|
259
|
-
fe as e,
|
|
260
|
-
me as f,
|
|
261
|
-
ge as g,
|
|
262
|
-
ye as h,
|
|
263
|
-
se as u
|
|
264
|
-
};
|
|
265
|
-
//# sourceMappingURL=useNextTrackPrefetch-Y_fs2JEx.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useNextTrackPrefetch-Y_fs2JEx.js","sources":["../src/hooks/useGinger.ts","../src/analyzer/liveAudioGraph.ts","../src/analyzer/useGingerLiveAnalyzer.ts","../src/hooks/useGingerKeyboardShortcuts.ts","../src/hooks/useGingerSleepTimer.ts","../src/hooks/useGingerDebugLog.ts","../src/hooks/useSeekDrag.ts","../src/hooks/useNextTrackPrefetch.ts"],"sourcesContent":["import { useMemo } from \"react\";\nimport {\n gingerStateFromContextValues,\n useGingerMedia,\n useGingerPlayback,\n} from \"../context/GingerSplitContexts\";\nimport {\n derivePlaybackUiState,\n effectiveDuration,\n effectiveRemaining,\n getCurrentTrack,\n progressFraction,\n resolvedAlbumLine,\n resolvedArtwork,\n} from \"../internal/selectors\";\n\nexport function useGinger() {\n const pb = useGingerPlayback();\n const md = useGingerMedia();\n\n return useMemo(() => {\n const state = gingerStateFromContextValues(pb, md);\n return {\n state,\n currentTrack: getCurrentTrack(state),\n playbackUi: derivePlaybackUiState(state),\n duration: effectiveDuration(state),\n remaining: effectiveRemaining(state),\n progress: progressFraction(state),\n artworkUrl: resolvedArtwork(state),\n albumLine: resolvedAlbumLine(state),\n play: pb.play,\n pause: pb.pause,\n togglePlayPause: pb.togglePlayPause,\n seek: md.seek,\n setVolume: md.setVolume,\n setMuted: md.setMuted,\n toggleMute: md.toggleMute,\n setPlaybackRate: md.setPlaybackRate,\n next: pb.next,\n prev: pb.prev,\n setRepeatMode: pb.setRepeatMode,\n cycleRepeat: pb.cycleRepeat,\n toggleShuffle: pb.toggleShuffle,\n setQueue: pb.setQueue,\n insertTrackAt: pb.insertTrackAt,\n removeTrackAt: pb.removeTrackAt,\n moveTrack: pb.moveTrack,\n enqueueNext: pb.enqueueNext,\n playTrackAt: pb.playTrackAt,\n selectTrackAt: pb.selectTrackAt,\n setPlaylistMeta: pb.setPlaylistMeta,\n setPlaybackMode: pb.setPlaybackMode,\n init: pb.init,\n audioRef: md.audioRef,\n dispatch: pb.dispatch,\n };\n }, [pb, md]);\n}\n","/** One MediaElementAudioSourceNode per HTMLAudioElement; multiple AnalyserNodes may tap the source. */\n\nexport type LiveAnalyserOptions = {\n fftSize: number;\n smoothingTimeConstant: number;\n minDecibels: number;\n maxDecibels: number;\n};\n\ntype Consumer = {\n analyser: AnalyserNode;\n /** This analyser is wired to `audioContext.destination` so the graph is audible. */\n isPlaybackSink: boolean;\n};\n\ntype ElementEntry = {\n context: AudioContext;\n source: MediaElementAudioSourceNode;\n consumers: Map<number, Consumer>;\n nextId: number;\n};\n\nconst entries = new WeakMap<HTMLAudioElement, ElementEntry>();\n\nfunction clampFftSize(n: number): number {\n const p = 2 ** Math.round(Math.log2(n));\n return Math.min(32768, Math.max(32, p));\n}\n\nexport function attachLiveAnalyser(\n element: HTMLAudioElement,\n options: LiveAnalyserOptions,\n): { id: number; context: AudioContext; analyser: AnalyserNode } {\n let entry = entries.get(element);\n if (!entry) {\n const Context =\n window.AudioContext ??\n (window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n if (!Context) {\n throw new Error(\"Web Audio API is not available\");\n }\n const context = new Context();\n const source = context.createMediaElementSource(element);\n entry = { context, source, consumers: new Map(), nextId: 0 };\n entries.set(element, entry);\n }\n\n const { context, source } = entry;\n const analyser = context.createAnalyser();\n analyser.fftSize = clampFftSize(options.fftSize);\n analyser.smoothingTimeConstant = options.smoothingTimeConstant;\n analyser.minDecibels = options.minDecibels;\n analyser.maxDecibels = options.maxDecibels;\n\n source.connect(analyser);\n\n const isFirst = entry.consumers.size === 0;\n if (isFirst) {\n analyser.connect(context.destination);\n }\n\n const id = entry.nextId;\n entry.nextId += 1;\n entry.consumers.set(id, { analyser, isPlaybackSink: isFirst });\n\n return { id, context, analyser };\n}\n\nexport function detachLiveAnalyser(element: HTMLAudioElement, id: number): void {\n const entry = entries.get(element);\n if (!entry) return;\n\n const consumer = entry.consumers.get(id);\n if (!consumer) return;\n\n const { analyser, isPlaybackSink } = consumer;\n analyser.disconnect();\n entry.consumers.delete(id);\n\n if (entry.consumers.size === 0) {\n try {\n entry.source.disconnect();\n } catch {\n // ignore\n }\n void entry.context.close();\n entries.delete(element);\n return;\n }\n\n if (isPlaybackSink) {\n const first = entry.consumers.values().next().value as Consumer | undefined;\n if (first) {\n first.analyser.connect(entry.context.destination);\n first.isPlaybackSink = true;\n }\n }\n}\n","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\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 void frame;\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 };\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};\n\nexport function useGingerKeyboardShortcuts(\n enabled = true,\n bindings: GingerKeyboardShortcutBindings = {},\n): void {\n const { togglePlayPause, next, prev } = useGingerPlayback();\n const { toggleMute } = useGingerMedia();\n\n const muteBinding = bindings.mute;\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\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 }\n };\n window.addEventListener(\"keydown\", onKeyDown);\n return () => window.removeEventListener(\"keydown\", onKeyDown);\n }, [\n bindings.next,\n bindings.playPause,\n bindings.previous,\n enabled,\n muteBinding,\n next,\n prev,\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 useEffect(() => {\n remainingTracksRef.current = stopAfterTracks ?? 0;\n }, [stopAfterTracks]);\n\n useEffect(() => {\n if (!enabled || !durationMs || durationMs <= 0) return;\n if (respectPause && isPaused) return;\n const id = setTimeout(() => {\n pause();\n onFire?.();\n }, durationMs);\n return () => clearTimeout(id);\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"],"names":["useGinger","pb","useGingerPlayback","md","useGingerMedia","useMemo","state","gingerStateFromContextValues","getCurrentTrack","derivePlaybackUiState","effectiveDuration","effectiveRemaining","progressFraction","resolvedArtwork","resolvedAlbumLine","entries","clampFftSize","n","p","attachLiveAnalyser","element","options","entry","Context","context","source","analyser","isFirst","id","detachLiveAnalyser","consumer","isPlaybackSink","first","emptyFreq","emptyTime","useGingerLiveAnalyzer","enabled","fftSize","smoothingTimeConstant","minDecibels","maxDecibels","audioRef","opts","frame","setFrame","useState","error","setError","isSuspended","setIsSuspended","meta","setMeta","freqRef","useRef","timeRef","resume","useCallback","ctx","contextHolderRef","analyserHolderRef","useLayoutEffect","cancelled","consumerId","rafId","onStateChange","runLoop","a","fq","td","attach","el","fft","e","msg","retryRaf","maxAttempts","attempts","retryLoop","out","_a","useGingerKeyboardShortcuts","bindings","togglePlayPause","next","prev","toggleMute","muteBinding","useEffect","playPause","nextKey","prevKey","muteKey","onKeyDown","event","target","key","useGingerSleepTimer","durationMs","stopAfterTracks","respectPause","onFire","currentIndex","pause","isPaused","remainingTracksRef","prevIndexRef","useGingerDebugLog","useGingerState","prevRef","clamp01","value","useSeekDrag","duration","media","playback","seek","fraction","setFraction","isDragging","setIsDragging","liveFraction","displayFraction","onPointerDown","rect","update","clientX","ratio","onMove","moveEvent","onUp","upEvent","useNextTrackPrefetch","crossOrigin","tracks","repeatMode","playbackMode","nextIndex","computeNextIndex","nextUrl","audio"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
"use strict";const o=require("react"),v=require("./GingerSplitContexts-C7puo0M7.cjs"),P=require("./ginger-B26HM2Ja.cjs");function K(){const t=v.useGingerPlayback(),e=v.useGingerMedia();return o.useMemo(()=>{const n=v.gingerStateFromContextValues(t,e);return{state:n,currentTrack:P.getCurrentTrack(n),playbackUi:P.derivePlaybackUiState(n),duration:P.effectiveDuration(n),remaining:P.effectiveRemaining(n),progress:P.progressFraction(n),artworkUrl:P.resolvedArtwork(n),albumLine:P.resolvedAlbumLine(n),play:t.play,pause:t.pause,togglePlayPause:t.togglePlayPause,seek:e.seek,setVolume:e.setVolume,setMuted:e.setMuted,toggleMute:e.toggleMute,setPlaybackRate:e.setPlaybackRate,next:t.next,prev:t.prev,setRepeatMode:t.setRepeatMode,cycleRepeat:t.cycleRepeat,toggleShuffle:t.toggleShuffle,setQueue:t.setQueue,insertTrackAt:t.insertTrackAt,removeTrackAt:t.removeTrackAt,moveTrack:t.moveTrack,enqueueNext:t.enqueueNext,playTrackAt:t.playTrackAt,selectTrackAt:t.selectTrackAt,setPlaylistMeta:t.setPlaylistMeta,setPlaybackMode:t.setPlaybackMode,init:t.init,audioRef:e.audioRef,dispatch:t.dispatch}},[t,e])}const G=new WeakMap;function O(t){const e=2**Math.round(Math.log2(t));return Math.min(32768,Math.max(32,e))}function V(t,e){let n=G.get(t);if(!n){const d=window.AudioContext??window.webkitAudioContext;if(!d)throw new Error("Web Audio API is not available");const i=new d,m=i.createMediaElementSource(t);n={context:i,source:m,consumers:new Map,nextId:0},G.set(t,n)}const{context:s,source:c}=n,r=s.createAnalyser();r.fftSize=O(e.fftSize),r.smoothingTimeConstant=e.smoothingTimeConstant,r.minDecibels=e.minDecibels,r.maxDecibels=e.maxDecibels,c.connect(r);const a=n.consumers.size===0;a&&r.connect(s.destination);const l=n.nextId;return n.nextId+=1,n.consumers.set(l,{analyser:r,isPlaybackSink:a}),{id:l,context:s,analyser:r}}function U(t,e){const n=G.get(t);if(!n)return;const s=n.consumers.get(e);if(!s)return;const{analyser:c,isPlaybackSink:r}=s;if(c.disconnect(),n.consumers.delete(e),n.consumers.size===0){try{n.source.disconnect()}catch{}n.context.close(),G.delete(t);return}if(r){const a=n.consumers.values().next().value;a&&(a.analyser.connect(n.context.destination),a.isPlaybackSink=!0)}}const q=new Uint8Array(0),I=new Uint8Array(0);function Q(t={}){const{enabled:e=!0,fftSize:n=2048,smoothingTimeConstant:s=.8,minDecibels:c=-100,maxDecibels:r=-30}=t,{audioRef:a,state:l}=K(),d=o.useMemo(()=>({fftSize:n,smoothingTimeConstant:s,minDecibels:c,maxDecibels:r}),[n,s,c,r]),[i,m]=o.useState(0),[p,u]=o.useState(null),[R,k]=o.useState(!1),[S,h]=o.useState({frequencyBinCount:0,sampleRate:0}),g=o.useRef(q),x=o.useRef(I),X=o.useCallback(async()=>{const A=M.current;A&&A.state==="suspended"&&await A.resume()},[]),M=o.useRef(null),L=o.useRef(null);return o.useLayoutEffect(()=>{if(!e||typeof window>"u")return;let A=!1,C=null,E=null,D=0;const F=()=>{const f=M.current;f&&k(f.state==="suspended")},z=()=>{if(A)return;const f=L.current,w=g.current,y=x.current;f&&w.length>0&&y.length>0&&(f.getByteFrequencyData(w),f.getByteTimeDomainData(y),m(T=>T+1)),D=requestAnimationFrame(z)},B=()=>{const f=a.current;if(!f||A)return"no-element";try{const{id:w,context:y,analyser:T}=V(f,d);C=w,E=f,M.current=y,L.current=T,k(y.state==="suspended"),u(null),y.addEventListener("statechange",F);const b=T.frequencyBinCount,H=T.fftSize;return g.current=new Uint8Array(b),x.current=new Uint8Array(H),h({frequencyBinCount:b,sampleRate:y.sampleRate}),D=requestAnimationFrame(z),"ok"}catch(w){const y=w instanceof Error?w.message:"Failed to attach live analyser";return u(y),M.current=null,L.current=null,g.current=q,x.current=I,h({frequencyBinCount:0,sampleRate:0}),"error"}},N=B();if(N!=="ok"){let f=0;const w=120;let y=0;const T=()=>{if(A)return;const b=B();b==="ok"||b==="error"||(y+=1,!(y>=w)&&(f=requestAnimationFrame(T)))};return N==="no-element"&&(f=requestAnimationFrame(T)),()=>{var b;A=!0,cancelAnimationFrame(f),cancelAnimationFrame(D),C!=null&&E&&U(E,C),(b=M.current)==null||b.removeEventListener("statechange",F),M.current=null,L.current=null,g.current=q,x.current=I}}return()=>{var f;A=!0,cancelAnimationFrame(D),C!=null&&E&&U(E,C),(f=M.current)==null||f.removeEventListener("statechange",F),M.current=null,L.current=null,g.current=q,x.current=I,h({frequencyBinCount:0,sampleRate:0})}},[e,a,d,l.currentIndex]),{frequencyData:g.current,timeDomainData:x.current,frequencyBinCount:S.frequencyBinCount,sampleRate:S.sampleRate,isSuspended:R,error:p,resume:X}}function W(t=!0,e={}){const{togglePlayPause:n,next:s,prev:c}=v.useGingerPlayback(),{toggleMute:r}=v.useGingerMedia(),a=e.mute;o.useEffect(()=>{if(!t||typeof window>"u")return;const l=(e.playPause??" ").toLowerCase(),d=(e.next??"ArrowRight").toLowerCase(),i=(e.previous??"ArrowLeft").toLowerCase(),m=a==null?void 0:a.toLowerCase(),p=u=>{const R=u.target;if(R&&(["INPUT","TEXTAREA","SELECT"].includes(R.tagName)||R.isContentEditable))return;const k=u.key.toLowerCase();k===l?(u.preventDefault(),n()):k===d?(u.preventDefault(),s()):k===i?(u.preventDefault(),c()):m&&k===m&&(u.preventDefault(),r())};return window.addEventListener("keydown",p),()=>window.removeEventListener("keydown",p)},[e.next,e.playPause,e.previous,t,a,s,c,r,n])}function j(t){const{durationMs:e,stopAfterTracks:n,respectPause:s=!0,enabled:c=!0,onFire:r}=t,{currentIndex:a,pause:l,isPaused:d}=v.useGingerPlayback(),i=o.useRef(n??0),m=o.useRef(a);o.useEffect(()=>{i.current=n??0},[n]),o.useEffect(()=>{if(!c||!e||e<=0||s&&d)return;const p=setTimeout(()=>{l(),r==null||r()},e);return()=>clearTimeout(p)},[e,c,d,r,l,s]),o.useEffect(()=>{if(!c||!n||n<=0)return;const p=m.current;m.current=a,a!==p&&(i.current-=1,i.current<=0&&(l(),r==null||r()))},[a,c,r,l,n])}function J(t=!1){const e=v.useGingerState(),n=o.useRef(e);o.useEffect(()=>{if(!t||typeof console>"u")return;const s=n.current;s!==e&&console.debug("[ginger]",{from:{currentIndex:s.currentIndex,isPaused:s.isPaused,currentTime:s.currentTime,repeatMode:s.repeatMode},to:{currentIndex:e.currentIndex,isPaused:e.isPaused,currentTime:e.currentTime,repeatMode:e.repeatMode}}),n.current=e},[t,e])}function Y(t){return Math.max(0,Math.min(1,t))}function Z(t){const e=v.useGingerMedia(),n=v.useGingerPlayback(),{seek:s}=e,[c,r]=o.useState(0),[a,l]=o.useState(!1),d=P.progressFraction(v.gingerStateFromContextValues(n,e)),i=a?c:d,m=o.useCallback(p=>{if(!(t>0))return;const u=p.currentTarget,R=u.getBoundingClientRect(),k=g=>{const x=Y((g-R.left)/R.width);r(x),s(x*t)};l(!0),u.setPointerCapture(p.pointerId),k(p.clientX);const S=g=>k(g.clientX),h=g=>{k(g.clientX),l(!1),u.releasePointerCapture(p.pointerId),u.removeEventListener("pointermove",S),u.removeEventListener("pointerup",h),u.removeEventListener("pointercancel",h)};u.addEventListener("pointermove",S),u.addEventListener("pointerup",h),u.addEventListener("pointercancel",h)},[t,s]);return{fraction:c,displayFraction:i,isDragging:a,onPointerDown:m}}function _(t={}){const{enabled:e=!0,crossOrigin:n}=t,{tracks:s,currentIndex:c,repeatMode:r,playbackMode:a}=v.useGingerPlayback();o.useEffect(()=>{var m;if(!e||typeof document>"u")return;const l=P.computeNextIndex({tracks:s,currentIndex:c,repeatMode:r,playbackMode:a});if(l===c)return;const d=((m=s[l])==null?void 0:m.fileUrl)??"";if(!d)return;const i=document.createElement("audio");return i.preload="auto",n&&(i.crossOrigin=n),i.src=d,i.load(),()=>{i.removeAttribute("src"),i.load()}},[e,n,s,c,r,a])}exports.attachLiveAnalyser=V;exports.detachLiveAnalyser=U;exports.useGinger=K;exports.useGingerDebugLog=J;exports.useGingerKeyboardShortcuts=W;exports.useGingerLiveAnalyzer=Q;exports.useGingerSleepTimer=j;exports.useNextTrackPrefetch=_;exports.useSeekDrag=Z;
|
|
2
|
-
//# sourceMappingURL=useNextTrackPrefetch-wSILz6TL.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useNextTrackPrefetch-wSILz6TL.cjs","sources":["../src/hooks/useGinger.ts","../src/analyzer/liveAudioGraph.ts","../src/analyzer/useGingerLiveAnalyzer.ts","../src/hooks/useGingerKeyboardShortcuts.ts","../src/hooks/useGingerSleepTimer.ts","../src/hooks/useGingerDebugLog.ts","../src/hooks/useSeekDrag.ts","../src/hooks/useNextTrackPrefetch.ts"],"sourcesContent":["import { useMemo } from \"react\";\nimport {\n gingerStateFromContextValues,\n useGingerMedia,\n useGingerPlayback,\n} from \"../context/GingerSplitContexts\";\nimport {\n derivePlaybackUiState,\n effectiveDuration,\n effectiveRemaining,\n getCurrentTrack,\n progressFraction,\n resolvedAlbumLine,\n resolvedArtwork,\n} from \"../internal/selectors\";\n\nexport function useGinger() {\n const pb = useGingerPlayback();\n const md = useGingerMedia();\n\n return useMemo(() => {\n const state = gingerStateFromContextValues(pb, md);\n return {\n state,\n currentTrack: getCurrentTrack(state),\n playbackUi: derivePlaybackUiState(state),\n duration: effectiveDuration(state),\n remaining: effectiveRemaining(state),\n progress: progressFraction(state),\n artworkUrl: resolvedArtwork(state),\n albumLine: resolvedAlbumLine(state),\n play: pb.play,\n pause: pb.pause,\n togglePlayPause: pb.togglePlayPause,\n seek: md.seek,\n setVolume: md.setVolume,\n setMuted: md.setMuted,\n toggleMute: md.toggleMute,\n setPlaybackRate: md.setPlaybackRate,\n next: pb.next,\n prev: pb.prev,\n setRepeatMode: pb.setRepeatMode,\n cycleRepeat: pb.cycleRepeat,\n toggleShuffle: pb.toggleShuffle,\n setQueue: pb.setQueue,\n insertTrackAt: pb.insertTrackAt,\n removeTrackAt: pb.removeTrackAt,\n moveTrack: pb.moveTrack,\n enqueueNext: pb.enqueueNext,\n playTrackAt: pb.playTrackAt,\n selectTrackAt: pb.selectTrackAt,\n setPlaylistMeta: pb.setPlaylistMeta,\n setPlaybackMode: pb.setPlaybackMode,\n init: pb.init,\n audioRef: md.audioRef,\n dispatch: pb.dispatch,\n };\n }, [pb, md]);\n}\n","/** One MediaElementAudioSourceNode per HTMLAudioElement; multiple AnalyserNodes may tap the source. */\n\nexport type LiveAnalyserOptions = {\n fftSize: number;\n smoothingTimeConstant: number;\n minDecibels: number;\n maxDecibels: number;\n};\n\ntype Consumer = {\n analyser: AnalyserNode;\n /** This analyser is wired to `audioContext.destination` so the graph is audible. */\n isPlaybackSink: boolean;\n};\n\ntype ElementEntry = {\n context: AudioContext;\n source: MediaElementAudioSourceNode;\n consumers: Map<number, Consumer>;\n nextId: number;\n};\n\nconst entries = new WeakMap<HTMLAudioElement, ElementEntry>();\n\nfunction clampFftSize(n: number): number {\n const p = 2 ** Math.round(Math.log2(n));\n return Math.min(32768, Math.max(32, p));\n}\n\nexport function attachLiveAnalyser(\n element: HTMLAudioElement,\n options: LiveAnalyserOptions,\n): { id: number; context: AudioContext; analyser: AnalyserNode } {\n let entry = entries.get(element);\n if (!entry) {\n const Context =\n window.AudioContext ??\n (window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n if (!Context) {\n throw new Error(\"Web Audio API is not available\");\n }\n const context = new Context();\n const source = context.createMediaElementSource(element);\n entry = { context, source, consumers: new Map(), nextId: 0 };\n entries.set(element, entry);\n }\n\n const { context, source } = entry;\n const analyser = context.createAnalyser();\n analyser.fftSize = clampFftSize(options.fftSize);\n analyser.smoothingTimeConstant = options.smoothingTimeConstant;\n analyser.minDecibels = options.minDecibels;\n analyser.maxDecibels = options.maxDecibels;\n\n source.connect(analyser);\n\n const isFirst = entry.consumers.size === 0;\n if (isFirst) {\n analyser.connect(context.destination);\n }\n\n const id = entry.nextId;\n entry.nextId += 1;\n entry.consumers.set(id, { analyser, isPlaybackSink: isFirst });\n\n return { id, context, analyser };\n}\n\nexport function detachLiveAnalyser(element: HTMLAudioElement, id: number): void {\n const entry = entries.get(element);\n if (!entry) return;\n\n const consumer = entry.consumers.get(id);\n if (!consumer) return;\n\n const { analyser, isPlaybackSink } = consumer;\n analyser.disconnect();\n entry.consumers.delete(id);\n\n if (entry.consumers.size === 0) {\n try {\n entry.source.disconnect();\n } catch {\n // ignore\n }\n void entry.context.close();\n entries.delete(element);\n return;\n }\n\n if (isPlaybackSink) {\n const first = entry.consumers.values().next().value as Consumer | undefined;\n if (first) {\n first.analyser.connect(entry.context.destination);\n first.isPlaybackSink = true;\n }\n }\n}\n","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\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 void frame;\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 };\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};\n\nexport function useGingerKeyboardShortcuts(\n enabled = true,\n bindings: GingerKeyboardShortcutBindings = {},\n): void {\n const { togglePlayPause, next, prev } = useGingerPlayback();\n const { toggleMute } = useGingerMedia();\n\n const muteBinding = bindings.mute;\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\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 }\n };\n window.addEventListener(\"keydown\", onKeyDown);\n return () => window.removeEventListener(\"keydown\", onKeyDown);\n }, [\n bindings.next,\n bindings.playPause,\n bindings.previous,\n enabled,\n muteBinding,\n next,\n prev,\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 useEffect(() => {\n remainingTracksRef.current = stopAfterTracks ?? 0;\n }, [stopAfterTracks]);\n\n useEffect(() => {\n if (!enabled || !durationMs || durationMs <= 0) return;\n if (respectPause && isPaused) return;\n const id = setTimeout(() => {\n pause();\n onFire?.();\n }, durationMs);\n return () => clearTimeout(id);\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"],"names":["useGinger","pb","useGingerPlayback","md","useGingerMedia","useMemo","state","gingerStateFromContextValues","getCurrentTrack","derivePlaybackUiState","effectiveDuration","effectiveRemaining","progressFraction","resolvedArtwork","resolvedAlbumLine","entries","clampFftSize","n","p","attachLiveAnalyser","element","options","entry","Context","context","source","analyser","isFirst","id","detachLiveAnalyser","consumer","isPlaybackSink","first","emptyFreq","emptyTime","useGingerLiveAnalyzer","enabled","fftSize","smoothingTimeConstant","minDecibels","maxDecibels","audioRef","opts","frame","setFrame","useState","error","setError","isSuspended","setIsSuspended","meta","setMeta","freqRef","useRef","timeRef","resume","useCallback","ctx","contextHolderRef","analyserHolderRef","useLayoutEffect","cancelled","consumerId","rafId","onStateChange","runLoop","a","fq","td","attach","el","fft","e","msg","retryRaf","maxAttempts","attempts","retryLoop","out","_a","useGingerKeyboardShortcuts","bindings","togglePlayPause","next","prev","toggleMute","muteBinding","useEffect","playPause","nextKey","prevKey","muteKey","onKeyDown","event","target","key","useGingerSleepTimer","durationMs","stopAfterTracks","respectPause","onFire","currentIndex","pause","isPaused","remainingTracksRef","prevIndexRef","useGingerDebugLog","useGingerState","prevRef","clamp01","value","useSeekDrag","duration","media","playback","seek","fraction","setFraction","isDragging","setIsDragging","liveFraction","displayFraction","onPointerDown","rect","update","clientX","ratio","onMove","moveEvent","onUp","upEvent","useNextTrackPrefetch","crossOrigin","tracks","repeatMode","playbackMode","nextIndex","computeNextIndex","nextUrl","audio"],"mappings":"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"}
|