@djangocfg/ui-nextjs 2.1.81 → 2.1.83
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/package.json +4 -4
- package/src/tools/AudioPlayer/@refactoring3/00-IMPLEMENTATION-ROADMAP.md +1146 -0
- package/src/tools/AudioPlayer/@refactoring3/01-WAVESURFER-STREAMING-ANALYSIS.md +611 -0
- package/src/tools/AudioPlayer/@refactoring3/02-MEDIA-VIEWER-ANALYSIS.md +560 -0
- package/src/tools/AudioPlayer/@refactoring3/03-HYBRID-ARCHITECTURE-PROPOSAL.md +769 -0
- package/src/tools/AudioPlayer/@refactoring3/04-CRACKLING-ISSUE-DIAGNOSIS.md +373 -0
- package/src/tools/AudioPlayer/README.md +177 -205
- package/src/tools/AudioPlayer/components/AudioPlayer.tsx +9 -4
- package/src/tools/AudioPlayer/components/HybridAudioPlayer.tsx +251 -0
- package/src/tools/AudioPlayer/components/HybridSimplePlayer.tsx +291 -0
- package/src/tools/AudioPlayer/components/HybridWaveform.tsx +279 -0
- package/src/tools/AudioPlayer/components/SimpleAudioPlayer.tsx +16 -26
- package/src/tools/AudioPlayer/components/index.ts +6 -1
- package/src/tools/AudioPlayer/context/AudioProvider.tsx +16 -8
- package/src/tools/AudioPlayer/context/HybridAudioProvider.tsx +121 -0
- package/src/tools/AudioPlayer/context/index.ts +14 -2
- package/src/tools/AudioPlayer/hooks/index.ts +11 -0
- package/src/tools/AudioPlayer/hooks/useHybridAudio.ts +387 -0
- package/src/tools/AudioPlayer/hooks/useHybridAudioAnalysis.ts +95 -0
- package/src/tools/AudioPlayer/hooks/useSharedWebAudio.ts +6 -3
- package/src/tools/AudioPlayer/index.ts +31 -0
- package/src/tools/AudioPlayer/progressive/ProgressiveAudioPlayer.tsx +8 -0
- package/src/tools/ImageViewer/hooks/useImageLoading.ts +33 -9
- package/src/tools/VideoPlayer/hooks/useVideoPositionCache.ts +13 -6
- package/src/tools/VideoPlayer/providers/StreamProvider.tsx +38 -22
- package/src/tools/index.ts +22 -0
- package/src/tools/AudioPlayer/@refactoring/00-PLAN.md +0 -148
- package/src/tools/AudioPlayer/@refactoring/01-TYPES.md +0 -301
- package/src/tools/AudioPlayer/@refactoring/02-HOOKS.md +0 -281
- package/src/tools/AudioPlayer/@refactoring/03-CONTEXT.md +0 -328
- package/src/tools/AudioPlayer/@refactoring/04-COMPONENTS.md +0 -251
- package/src/tools/AudioPlayer/@refactoring/05-EFFECTS.md +0 -427
- package/src/tools/AudioPlayer/@refactoring/06-UTILS-AND-INDEX.md +0 -193
- package/src/tools/AudioPlayer/@refactoring/07-EXECUTION-CHECKLIST.md +0 -146
- package/src/tools/AudioPlayer/@refactoring2/ISSUE_ANALYSIS.md +0 -187
- package/src/tools/AudioPlayer/@refactoring2/PLAN.md +0 -372
|
@@ -1,264 +1,225 @@
|
|
|
1
1
|
# AudioPlayer
|
|
2
2
|
|
|
3
|
-
Audio player with
|
|
3
|
+
Audio player library with multiple player implementations for different use cases.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Player Comparison
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
| Feature | HybridSimplePlayer | SimpleAudioPlayer | ProgressiveAudioPlayer |
|
|
8
|
+
|---------|-------------------|-------------------|------------------------|
|
|
9
|
+
| **Recommended for** | Streaming, general use | Local files, full waveform | Large streaming files |
|
|
10
|
+
| **Audio Engine** | HTML5 `<audio>` | WaveSurfer.js | HTML5 `<audio>` |
|
|
11
|
+
| **Visualization** | Real-time frequency bars | Static waveform | Progressive waveform |
|
|
12
|
+
| **Reactive Effects** | ✅ Full support | ✅ Full support | ❌ No |
|
|
13
|
+
| **Streaming Support** | ✅ Native | ⚠️ Requires prefetch | ✅ Native |
|
|
14
|
+
| **Seek Any Position** | ✅ Yes | ⚠️ Limited by buffer | ✅ Yes |
|
|
15
|
+
| **No Crackling** | ✅ Guaranteed | ⚠️ Fixed in v2.1.82 | ✅ Yes |
|
|
16
|
+
| **Memory Usage** | Low | High (full file) | Low |
|
|
17
|
+
|
|
18
|
+
---
|
|
14
19
|
|
|
15
20
|
## Quick Start (Recommended)
|
|
16
21
|
|
|
22
|
+
### HybridSimplePlayer — Best for Most Cases
|
|
23
|
+
|
|
17
24
|
```tsx
|
|
18
|
-
import {
|
|
25
|
+
import { HybridSimplePlayer } from '@djangocfg/ui-nextjs';
|
|
19
26
|
|
|
20
27
|
// Minimal
|
|
21
|
-
<
|
|
28
|
+
<HybridSimplePlayer src="https://example.com/audio.mp3" />
|
|
22
29
|
|
|
23
|
-
// With metadata
|
|
24
|
-
<
|
|
30
|
+
// With metadata and reactive cover
|
|
31
|
+
<HybridSimplePlayer
|
|
25
32
|
src={audioUrl}
|
|
26
33
|
title="Track Title"
|
|
27
34
|
artist="Artist Name"
|
|
28
35
|
coverArt="/path/to/cover.jpg"
|
|
36
|
+
reactiveCover
|
|
37
|
+
variant="spotlight"
|
|
29
38
|
/>
|
|
30
39
|
|
|
31
40
|
// Full customization
|
|
32
|
-
<
|
|
41
|
+
<HybridSimplePlayer
|
|
33
42
|
src={audioUrl}
|
|
34
43
|
title="Track Title"
|
|
35
44
|
coverArt={coverUrl}
|
|
36
45
|
showWaveform
|
|
37
|
-
showEqualizer={false}
|
|
38
46
|
reactiveCover
|
|
39
47
|
variant="spotlight"
|
|
48
|
+
intensity="medium"
|
|
49
|
+
colorScheme="vibrant"
|
|
40
50
|
layout="horizontal"
|
|
41
51
|
/>
|
|
42
52
|
```
|
|
43
53
|
|
|
44
|
-
###
|
|
54
|
+
### HybridSimplePlayer Props
|
|
45
55
|
|
|
46
56
|
| Prop | Type | Default | Description |
|
|
47
57
|
|------|------|---------|-------------|
|
|
48
58
|
| `src` | `string` | required | Audio URL |
|
|
49
|
-
| `prefetch` | `boolean` | `true` | Pre-fetch audio as blob (required for streaming URLs to enable seek) |
|
|
50
59
|
| `title` | `string` | - | Track title |
|
|
51
60
|
| `artist` | `string` | - | Artist name |
|
|
52
61
|
| `coverArt` | `string \| ReactNode` | - | Cover image URL or custom element |
|
|
53
62
|
| `coverSize` | `'sm' \| 'md' \| 'lg'` | `'md'` | Cover art size |
|
|
54
|
-
| `showWaveform` | `boolean` | `true` | Show
|
|
55
|
-
| `
|
|
63
|
+
| `showWaveform` | `boolean` | `true` | Show frequency visualization |
|
|
64
|
+
| `waveformMode` | `'frequency' \| 'static'` | `'frequency'` | Visualization mode |
|
|
65
|
+
| `waveformHeight` | `number` | `64` | Waveform height in pixels |
|
|
56
66
|
| `showTimer` | `boolean` | `true` | Show time display |
|
|
57
67
|
| `showVolume` | `boolean` | `true` | Show volume control |
|
|
58
68
|
| `showLoop` | `boolean` | `true` | Show loop/repeat button |
|
|
59
69
|
| `reactiveCover` | `boolean` | `true` | Enable reactive effects |
|
|
60
|
-
| `variant` | `VisualizationVariant` |
|
|
61
|
-
| `intensity` | `EffectIntensity` |
|
|
62
|
-
| `colorScheme` | `EffectColorScheme` |
|
|
70
|
+
| `variant` | `VisualizationVariant` | `'spotlight'` | Effect variant |
|
|
71
|
+
| `intensity` | `EffectIntensity` | `'medium'` | Effect intensity |
|
|
72
|
+
| `colorScheme` | `EffectColorScheme` | `'primary'` | Effect colors |
|
|
63
73
|
| `autoPlay` | `boolean` | `false` | Auto-play on load |
|
|
74
|
+
| `loop` | `boolean` | `false` | Loop playback |
|
|
64
75
|
| `layout` | `'vertical' \| 'horizontal'` | `'vertical'` | Layout direction |
|
|
65
76
|
|
|
66
|
-
> **Note:** The `prefetch` option is enabled by default. This fetches the entire audio file as a blob before loading into WaveSurfer, which is required for seeking to work correctly with streaming URLs. For very large files (> 50MB), consider using `prefetch={false}` and the Progressive player mode instead.
|
|
67
|
-
|
|
68
77
|
---
|
|
69
78
|
|
|
70
79
|
## Advanced Usage
|
|
71
80
|
|
|
72
|
-
|
|
81
|
+
### Using HybridAudioProvider + HybridAudioPlayer
|
|
73
82
|
|
|
74
|
-
|
|
75
|
-
import { useRef } from 'react';
|
|
76
|
-
import { AudioProvider, AudioPlayer } from '@djangocfg/ui-nextjs';
|
|
83
|
+
For full control over the hybrid player:
|
|
77
84
|
|
|
78
|
-
|
|
79
|
-
|
|
85
|
+
```tsx
|
|
86
|
+
import { HybridAudioProvider, HybridAudioPlayer, useHybridAudioContext } from '@djangocfg/ui-nextjs';
|
|
80
87
|
|
|
88
|
+
function MyPlayer({ audioUrl }: { audioUrl: string }) {
|
|
81
89
|
return (
|
|
82
|
-
<
|
|
83
|
-
|
|
84
|
-
containerRef={containerRef}
|
|
85
|
-
>
|
|
86
|
-
<AudioPlayer
|
|
87
|
-
ref={containerRef}
|
|
90
|
+
<HybridAudioProvider src={audioUrl}>
|
|
91
|
+
<HybridAudioPlayer
|
|
88
92
|
showControls
|
|
89
93
|
showWaveform
|
|
90
94
|
showTimer
|
|
91
95
|
showVolume
|
|
92
96
|
/>
|
|
93
|
-
|
|
97
|
+
<CustomControls />
|
|
98
|
+
</HybridAudioProvider>
|
|
94
99
|
);
|
|
95
100
|
}
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
## Components
|
|
99
|
-
|
|
100
|
-
### AudioProvider
|
|
101
101
|
|
|
102
|
-
|
|
102
|
+
function CustomControls() {
|
|
103
|
+
const { state, controls, audioLevels } = useHybridAudioContext();
|
|
103
104
|
|
|
104
|
-
|
|
105
|
-
<
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
progressColor: 'hsl(217 91% 60%)',
|
|
115
|
-
height: 64,
|
|
116
|
-
barWidth: 3,
|
|
117
|
-
barRadius: 3,
|
|
118
|
-
barGap: 2,
|
|
119
|
-
}}
|
|
120
|
-
>
|
|
121
|
-
{children}
|
|
122
|
-
</AudioProvider>
|
|
105
|
+
return (
|
|
106
|
+
<div>
|
|
107
|
+
<p>Playing: {state.isPlaying ? 'Yes' : 'No'}</p>
|
|
108
|
+
<p>Bass level: {(audioLevels.bass * 100).toFixed(0)}%</p>
|
|
109
|
+
<button onClick={controls.togglePlay}>
|
|
110
|
+
{state.isPlaying ? 'Pause' : 'Play'}
|
|
111
|
+
</button>
|
|
112
|
+
</div>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
123
115
|
```
|
|
124
116
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
| Prop | Type | Default | Description |
|
|
128
|
-
|------|------|---------|-------------|
|
|
129
|
-
| `uri` | `string` | required | Audio URL |
|
|
130
|
-
| `prefetch` | `boolean` | `false` | Pre-fetch as blob (enables seek for streaming URLs) |
|
|
117
|
+
### Hybrid Hooks
|
|
131
118
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
Main player component with waveform and controls.
|
|
135
|
-
|
|
136
|
-
| Prop | Type | Default | Description |
|
|
137
|
-
|------|------|---------|-------------|
|
|
138
|
-
| `showControls` | `boolean` | `true` | Show playback controls |
|
|
139
|
-
| `showWaveform` | `boolean` | `true` | Show waveform visualization |
|
|
140
|
-
| `showEqualizer` | `boolean` | `false` | Show equalizer animation |
|
|
141
|
-
| `showTimer` | `boolean` | `true` | Show time display |
|
|
142
|
-
| `showVolume` | `boolean` | `true` | Show volume slider |
|
|
143
|
-
| `className` | `string` | - | Additional CSS class |
|
|
144
|
-
|
|
145
|
-
### AudioEqualizer
|
|
119
|
+
#### useHybridAudioContext
|
|
146
120
|
|
|
147
|
-
|
|
121
|
+
Full access to audio state, controls, and Web Audio API:
|
|
148
122
|
|
|
149
123
|
```tsx
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
/>
|
|
124
|
+
const {
|
|
125
|
+
state, // { isReady, isPlaying, currentTime, duration, volume, isMuted, isLooping, buffered }
|
|
126
|
+
controls, // { play, pause, togglePlay, seek, seekTo, skip, setVolume, toggleMute, toggleLoop, restart }
|
|
127
|
+
audioLevels, // { bass, mid, high, overall } - for reactive effects
|
|
128
|
+
webAudio, // { context, analyser, sourceNode } - for custom visualizations
|
|
129
|
+
audioRef, // React ref to HTMLAudioElement
|
|
130
|
+
} = useHybridAudioContext();
|
|
158
131
|
```
|
|
159
132
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
Album art wrapper with audio-reactive effects.
|
|
133
|
+
#### Specialized Hooks
|
|
163
134
|
|
|
164
135
|
```tsx
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
intensity="medium" // 'subtle' | 'medium' | 'strong'
|
|
168
|
-
colorScheme="primary" // 'primary' | 'vibrant' | 'cool' | 'warm'
|
|
169
|
-
onClick={() => nextVariant()}
|
|
170
|
-
>
|
|
171
|
-
<img src={coverArt} alt="Album cover" />
|
|
172
|
-
</AudioReactiveCover>
|
|
173
|
-
```
|
|
136
|
+
// State only (read-only)
|
|
137
|
+
const { isPlaying, currentTime, duration } = useHybridAudioState();
|
|
174
138
|
|
|
175
|
-
|
|
139
|
+
// Controls only (no re-render on time updates)
|
|
140
|
+
const { play, pause, togglePlay, seek } = useHybridAudioControls();
|
|
176
141
|
|
|
177
|
-
|
|
142
|
+
// Audio levels for reactive effects
|
|
143
|
+
const { bass, mid, high, overall } = useHybridAudioLevels();
|
|
178
144
|
|
|
179
|
-
|
|
180
|
-
|
|
145
|
+
// Web Audio API access
|
|
146
|
+
const { context, analyser, sourceNode } = useHybridWebAudio();
|
|
181
147
|
```
|
|
182
148
|
|
|
183
|
-
|
|
149
|
+
---
|
|
184
150
|
|
|
185
|
-
|
|
151
|
+
## WaveSurfer-based Player (Legacy)
|
|
186
152
|
|
|
187
|
-
|
|
153
|
+
For cases where you need the static waveform visualization:
|
|
188
154
|
|
|
189
155
|
```tsx
|
|
190
|
-
|
|
191
|
-
isReady,
|
|
192
|
-
isPlaying,
|
|
193
|
-
currentTime,
|
|
194
|
-
duration,
|
|
195
|
-
volume,
|
|
196
|
-
isMuted,
|
|
197
|
-
audioLevels, // { bass, mid, high, overall }
|
|
198
|
-
play,
|
|
199
|
-
pause,
|
|
200
|
-
togglePlay,
|
|
201
|
-
seek,
|
|
202
|
-
seekTo,
|
|
203
|
-
skip,
|
|
204
|
-
setVolume,
|
|
205
|
-
toggleMute,
|
|
206
|
-
restart,
|
|
207
|
-
} = useAudio();
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### useAudioControls
|
|
211
|
-
|
|
212
|
-
Controls only (no re-render on time updates).
|
|
156
|
+
import { SimpleAudioPlayer } from '@djangocfg/ui-nextjs';
|
|
213
157
|
|
|
214
|
-
|
|
215
|
-
|
|
158
|
+
<SimpleAudioPlayer
|
|
159
|
+
src={audioUrl}
|
|
160
|
+
prefetch={true} // Required for streaming URLs
|
|
161
|
+
title="Track Title"
|
|
162
|
+
showWaveform
|
|
163
|
+
reactiveCover
|
|
164
|
+
/>
|
|
216
165
|
```
|
|
217
166
|
|
|
218
|
-
|
|
167
|
+
> **Note:** `prefetch={true}` downloads the entire file before playing. For large files or streaming, use `HybridSimplePlayer` instead.
|
|
219
168
|
|
|
220
|
-
|
|
169
|
+
---
|
|
221
170
|
|
|
222
|
-
|
|
223
|
-
const { isPlaying, currentTime, duration, volume } = useAudioState();
|
|
224
|
-
```
|
|
171
|
+
## Components
|
|
225
172
|
|
|
226
|
-
###
|
|
173
|
+
### HybridWaveform
|
|
227
174
|
|
|
228
|
-
|
|
175
|
+
Real-time frequency visualization canvas:
|
|
229
176
|
|
|
230
177
|
```tsx
|
|
231
|
-
|
|
178
|
+
<HybridWaveform
|
|
179
|
+
mode="frequency" // 'frequency' | 'static'
|
|
180
|
+
height={64}
|
|
181
|
+
barWidth={3}
|
|
182
|
+
barGap={2}
|
|
183
|
+
barRadius={2}
|
|
184
|
+
progressColor="hsl(217 91% 60%)"
|
|
185
|
+
waveColor="hsl(217 91% 60% / 0.3)"
|
|
186
|
+
bufferedColor="hsl(217 91% 60% / 0.15)"
|
|
187
|
+
onSeek={(time) => console.log('Seeked to', time)}
|
|
188
|
+
/>
|
|
232
189
|
```
|
|
233
190
|
|
|
234
|
-
###
|
|
191
|
+
### AudioReactiveCover
|
|
235
192
|
|
|
236
|
-
|
|
193
|
+
Album art wrapper with audio-reactive effects:
|
|
237
194
|
|
|
238
195
|
```tsx
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
nextVariant
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
} = useAudioVisualization();
|
|
196
|
+
<AudioReactiveCover
|
|
197
|
+
variant="spotlight" // 'glow' | 'orbs' | 'spotlight' | 'mesh'
|
|
198
|
+
intensity="medium" // 'subtle' | 'medium' | 'strong'
|
|
199
|
+
colorScheme="primary" // 'primary' | 'vibrant' | 'cool' | 'warm'
|
|
200
|
+
onClick={() => nextVariant()}
|
|
201
|
+
>
|
|
202
|
+
<img src={coverArt} alt="Album cover" />
|
|
203
|
+
</AudioReactiveCover>
|
|
248
204
|
```
|
|
249
205
|
|
|
250
|
-
###
|
|
206
|
+
### AudioEqualizer
|
|
251
207
|
|
|
252
|
-
|
|
208
|
+
Real-time frequency visualizer with animated bars:
|
|
253
209
|
|
|
254
210
|
```tsx
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
211
|
+
<AudioEqualizer
|
|
212
|
+
barCount={24}
|
|
213
|
+
height={48}
|
|
214
|
+
gap={2}
|
|
215
|
+
showPeaks
|
|
216
|
+
barColor="hsl(217 91% 60%)"
|
|
217
|
+
peakColor="hsl(217 91% 70%)"
|
|
218
|
+
/>
|
|
260
219
|
```
|
|
261
220
|
|
|
221
|
+
---
|
|
222
|
+
|
|
262
223
|
## Keyboard Shortcuts
|
|
263
224
|
|
|
264
225
|
| Key | Action |
|
|
@@ -271,21 +232,14 @@ useAudioHotkeys({
|
|
|
271
232
|
| `M` | Mute/Unmute |
|
|
272
233
|
| `0-9` | Jump to 0-90% |
|
|
273
234
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
waveColor?: string; // Unplayed wave color
|
|
279
|
-
progressColor?: string; // Played wave color
|
|
280
|
-
cursorColor?: string; // Playhead cursor color
|
|
281
|
-
cursorWidth?: number; // Cursor width in px
|
|
282
|
-
height?: number; // Waveform height in px
|
|
283
|
-
barWidth?: number; // Bar width in px
|
|
284
|
-
barRadius?: number; // Bar corner radius
|
|
285
|
-
barGap?: number; // Gap between bars
|
|
286
|
-
}
|
|
235
|
+
Enable with:
|
|
236
|
+
|
|
237
|
+
```tsx
|
|
238
|
+
useAudioHotkeys({ enabled: true, skipDuration: 10, volumeStep: 0.1 });
|
|
287
239
|
```
|
|
288
240
|
|
|
241
|
+
---
|
|
242
|
+
|
|
289
243
|
## Effect Variants
|
|
290
244
|
|
|
291
245
|
| Variant | Description |
|
|
@@ -296,45 +250,63 @@ interface WaveformOptions {
|
|
|
296
250
|
| `mesh` | Large gradient blobs with movement |
|
|
297
251
|
| `none` | Effects disabled |
|
|
298
252
|
|
|
253
|
+
---
|
|
254
|
+
|
|
299
255
|
## Architecture
|
|
300
256
|
|
|
301
257
|
```
|
|
302
258
|
AudioPlayer/
|
|
303
259
|
├── index.ts # Public API exports
|
|
304
|
-
├── types/
|
|
305
|
-
│ ├── index.ts # Type re-exports
|
|
306
|
-
│ ├── audio.ts # Audio state & source types
|
|
307
|
-
│ ├── components.ts # Component prop types
|
|
308
|
-
│ └── effects.ts # Visualization effect types
|
|
260
|
+
├── types/ # TypeScript types
|
|
309
261
|
├── hooks/
|
|
310
|
-
│ ├──
|
|
311
|
-
│ ├──
|
|
312
|
-
│ ├──
|
|
313
|
-
│ ├── useVisualization.tsx # Visualization settings
|
|
262
|
+
│ ├── useHybridAudio.ts # 🆕 HTML5 audio + Web Audio hook
|
|
263
|
+
│ ├── useHybridAudioAnalysis.ts # 🆕 Frequency analysis for hybrid
|
|
264
|
+
│ ├── useSharedWebAudio.ts # Shared AudioContext (WaveSurfer)
|
|
314
265
|
│ ├── useAudioAnalysis.ts # Web Audio frequency analysis
|
|
315
|
-
│
|
|
316
|
-
|
|
317
|
-
│ ├── index.ts
|
|
318
|
-
│ └── formatTime.ts # Time formatting
|
|
266
|
+
│ ├── useAudioHotkeys.ts # Keyboard shortcuts
|
|
267
|
+
│ └── useVisualization.tsx # Visualization settings
|
|
319
268
|
├── context/
|
|
320
|
-
│ ├──
|
|
321
|
-
│ ├── AudioProvider.tsx #
|
|
322
|
-
│ └── selectors.ts #
|
|
269
|
+
│ ├── HybridAudioProvider.tsx # 🆕 Hybrid audio context
|
|
270
|
+
│ ├── AudioProvider.tsx # WaveSurfer context
|
|
271
|
+
│ └── selectors.ts # Hook selectors
|
|
323
272
|
├── components/
|
|
324
|
-
│ ├──
|
|
325
|
-
│ ├──
|
|
326
|
-
│ ├──
|
|
273
|
+
│ ├── HybridAudioPlayer.tsx # 🆕 Main hybrid player
|
|
274
|
+
│ ├── HybridSimplePlayer.tsx # 🆕 All-in-one hybrid wrapper
|
|
275
|
+
│ ├── HybridWaveform.tsx # 🆕 Frequency visualization
|
|
276
|
+
│ ├── AudioPlayer.tsx # WaveSurfer player
|
|
277
|
+
│ ├── SimpleAudioPlayer.tsx # WaveSurfer wrapper
|
|
327
278
|
│ ├── AudioEqualizer.tsx # Frequency bars
|
|
328
|
-
│
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
│ ├── index.ts
|
|
332
|
-
│ ├── AudioReactiveCover.tsx # Reactive album art
|
|
333
|
-
│ └── effects/ # Effect components
|
|
334
|
-
│ ├── GlowEffect.tsx
|
|
335
|
-
│ ├── OrbsEffect.tsx
|
|
336
|
-
│ ├── SpotlightEffect.tsx
|
|
337
|
-
│ └── MeshEffect.tsx
|
|
338
|
-
└── effects/
|
|
339
|
-
└── index.ts # Effect calculations
|
|
279
|
+
│ └── ReactiveCover/ # Reactive effects
|
|
280
|
+
├── progressive/ # Progressive/streaming player
|
|
281
|
+
└── effects/ # Effect calculations
|
|
340
282
|
```
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## Migration Guide
|
|
287
|
+
|
|
288
|
+
### From SimpleAudioPlayer to HybridSimplePlayer
|
|
289
|
+
|
|
290
|
+
```tsx
|
|
291
|
+
// Before
|
|
292
|
+
<SimpleAudioPlayer
|
|
293
|
+
src={url}
|
|
294
|
+
prefetch={true}
|
|
295
|
+
showWaveform
|
|
296
|
+
reactiveCover
|
|
297
|
+
variant="spotlight"
|
|
298
|
+
/>
|
|
299
|
+
|
|
300
|
+
// After
|
|
301
|
+
<HybridSimplePlayer
|
|
302
|
+
src={url}
|
|
303
|
+
showWaveform
|
|
304
|
+
reactiveCover
|
|
305
|
+
variant="spotlight"
|
|
306
|
+
/>
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Key differences:
|
|
310
|
+
- No `prefetch` prop needed — streaming works natively
|
|
311
|
+
- `waveformMode="frequency"` shows real-time bars instead of static waveform
|
|
312
|
+
- Same reactive effects support
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* AudioPlayer -
|
|
4
|
+
* AudioPlayer - WaveSurfer-based player component (Legacy)
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* @deprecated Consider using `HybridAudioPlayer` instead for better streaming
|
|
7
|
+
* support and guaranteed no audio crackling.
|
|
8
|
+
*
|
|
9
|
+
* Uses AudioContext for state management.
|
|
10
|
+
* Renders waveform (via container ref), controls, timer, and equalizer.
|
|
11
|
+
* Supports keyboard shortcuts for playback control.
|
|
12
|
+
*
|
|
13
|
+
* @see HybridAudioPlayer for the recommended alternative
|
|
9
14
|
*/
|
|
10
15
|
|
|
11
16
|
import { forwardRef } from 'react';
|