first commit
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
# `useAudioFingerprint` — React hook for the fingerprint pipeline
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`useAudioFingerprint(source, options?)` drives a `FingerprintBackend` off a
|
||||
React-managed `AudioDocument` and returns the live state, the resulting
|
||||
fingerprint when done, a `0..1` progress fraction, and any error encountered.
|
||||
The hook centralises the abort-on-unmount and progress wiring so component
|
||||
authors do not have to repeat that work across uploaders, visualisers, and
|
||||
match displays.
|
||||
|
||||
## Features
|
||||
|
||||
- `source` can be `undefined`/`null` to mean "do nothing" — useful while
|
||||
waiting for an upload to decode.
|
||||
- `state` cycles through `'idle'` → `'fingerprinting'` → `'done'` (or
|
||||
`'error'`); a fresh source resets the cycle.
|
||||
- Abort-on-unmount and abort-on-source-change via internal `AbortController`.
|
||||
- Backend swap via `options.backend`; defaults to `LocalBackend`.
|
||||
- Wraps non-`ReactAudioFingerprintError` rejections in `FINGERPRINT_FAILED`.
|
||||
- Suppresses `ABORTED` errors — they settle back to `'idle'`.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```tsx
|
||||
import { useAudioFingerprint } from "@suaveplan/react-audio-fingerprint/hooks/use-audio-fingerprint";
|
||||
|
||||
function FingerprintPreview({ doc }: { doc: AudioDocument }) {
|
||||
const { state, fingerprint, progress } = useAudioFingerprint(doc);
|
||||
if (state === "fingerprinting") return <progress value={progress} />;
|
||||
if (state === "done") return <span>{fingerprint?.length} pairs</span>;
|
||||
return null;
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
Inject a custom backend (e.g. the optional Python backend) and surface errors:
|
||||
|
||||
```tsx
|
||||
import { useAudioFingerprint } from "@suaveplan/react-audio-fingerprint/hooks/use-audio-fingerprint";
|
||||
|
||||
function Surface({ doc, backend }: { doc: AudioDocument; backend: FingerprintBackend }) {
|
||||
const { state, error, fingerprint } = useAudioFingerprint(doc, { backend });
|
||||
if (state === "error") return <Banner code={error?.code}>{error?.message}</Banner>;
|
||||
if (state === "done") return <Result fp={fingerprint!} />;
|
||||
return <Spinner />;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `useAudioFingerprint(source, options?): UseAudioFingerprintResult`.
|
||||
- `source: AudioDocument | undefined | null`.
|
||||
- `options?: { backend?: FingerprintBackend }`.
|
||||
- `UseAudioFingerprintResult = { state, fingerprint, progress, error }`.
|
||||
- `state: 'idle' | 'fingerprinting' | 'done' | 'error'`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The hook uses `useMemo` to stabilise the default `LocalBackend` so changing
|
||||
unrelated props does not retrigger the effect. The `alive` flag guarding all
|
||||
post-await `setState` calls is the canonical React pattern for protecting
|
||||
against the lifecycle race between an async fetch completing and a fast
|
||||
unmount. Aborts settle to `'idle'` (not `'error'`) so user-driven cancels do
|
||||
not produce a banner. Non-Suaveplan errors get wrapped so consumers can always
|
||||
discriminate via `error.code` without an `instanceof` chain.
|
||||
Reference in New Issue
Block a user