@djangocfg/ui-nextjs 2.1.82 → 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.
Files changed (33) hide show
  1. package/package.json +4 -4
  2. package/src/tools/AudioPlayer/@refactoring3/00-IMPLEMENTATION-ROADMAP.md +1146 -0
  3. package/src/tools/AudioPlayer/@refactoring3/01-WAVESURFER-STREAMING-ANALYSIS.md +611 -0
  4. package/src/tools/AudioPlayer/@refactoring3/02-MEDIA-VIEWER-ANALYSIS.md +560 -0
  5. package/src/tools/AudioPlayer/@refactoring3/03-HYBRID-ARCHITECTURE-PROPOSAL.md +769 -0
  6. package/src/tools/AudioPlayer/@refactoring3/04-CRACKLING-ISSUE-DIAGNOSIS.md +373 -0
  7. package/src/tools/AudioPlayer/README.md +177 -205
  8. package/src/tools/AudioPlayer/components/AudioPlayer.tsx +9 -4
  9. package/src/tools/AudioPlayer/components/HybridAudioPlayer.tsx +251 -0
  10. package/src/tools/AudioPlayer/components/HybridSimplePlayer.tsx +291 -0
  11. package/src/tools/AudioPlayer/components/HybridWaveform.tsx +279 -0
  12. package/src/tools/AudioPlayer/components/SimpleAudioPlayer.tsx +16 -26
  13. package/src/tools/AudioPlayer/components/index.ts +6 -1
  14. package/src/tools/AudioPlayer/context/AudioProvider.tsx +8 -3
  15. package/src/tools/AudioPlayer/context/HybridAudioProvider.tsx +121 -0
  16. package/src/tools/AudioPlayer/context/index.ts +14 -2
  17. package/src/tools/AudioPlayer/hooks/index.ts +11 -0
  18. package/src/tools/AudioPlayer/hooks/useHybridAudio.ts +387 -0
  19. package/src/tools/AudioPlayer/hooks/useHybridAudioAnalysis.ts +95 -0
  20. package/src/tools/AudioPlayer/hooks/useSharedWebAudio.ts +6 -3
  21. package/src/tools/AudioPlayer/index.ts +31 -0
  22. package/src/tools/AudioPlayer/progressive/ProgressiveAudioPlayer.tsx +8 -0
  23. package/src/tools/index.ts +22 -0
  24. package/src/tools/AudioPlayer/@refactoring/00-PLAN.md +0 -148
  25. package/src/tools/AudioPlayer/@refactoring/01-TYPES.md +0 -301
  26. package/src/tools/AudioPlayer/@refactoring/02-HOOKS.md +0 -281
  27. package/src/tools/AudioPlayer/@refactoring/03-CONTEXT.md +0 -328
  28. package/src/tools/AudioPlayer/@refactoring/04-COMPONENTS.md +0 -251
  29. package/src/tools/AudioPlayer/@refactoring/05-EFFECTS.md +0 -427
  30. package/src/tools/AudioPlayer/@refactoring/06-UTILS-AND-INDEX.md +0 -193
  31. package/src/tools/AudioPlayer/@refactoring/07-EXECUTION-CHECKLIST.md +0 -146
  32. package/src/tools/AudioPlayer/@refactoring2/ISSUE_ANALYSIS.md +0 -187
  33. package/src/tools/AudioPlayer/@refactoring2/PLAN.md +0 -372
@@ -1,372 +0,0 @@
1
- # Progressive Audio Player - План рефакторинга
2
-
3
- ## Проблема
4
-
5
- WaveSurfer.js требует полной загрузки аудиофайла для рендеринга waveform. При HTTP Range streaming backend возвращает только 2MB chunks, что приводит к:
6
- - Seek на позицию > 2 минут не работает
7
- - После неудачного seek плеер "зависает"
8
-
9
- ## Решение
10
-
11
- Создать собственный `ProgressiveAudioPlayer` который:
12
- 1. Использует HTML5 `<audio>` для воспроизведения (нативные Range requests)
13
- 2. Рисует waveform прогрессивно по мере загрузки
14
- 3. Визуально показывает загруженную/незагруженную область
15
- 4. Полный контроль над seek поведением
16
-
17
- ---
18
-
19
- ## Архитектура
20
-
21
- ```
22
- ┌──────────────────────────────────────────────────────────────┐
23
- │ ProgressiveAudioPlayer │
24
- ├──────────────────────────────────────────────────────────────┤
25
- │ │
26
- │ ┌────────────────────────────────────────────────────────┐ │
27
- │ │ WaveformCanvas │ │
28
- │ │ ┌──────────────────┬─────────────────────────────────┐│ │
29
- │ │ │ ████████████████ │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ││ │
30
- │ │ │ (загружено) │ (placeholder/loading) ││ │
31
- │ │ └──────────────────┴─────────────────────────────────┘│ │
32
- │ │ ▲ cursor │ │
33
- │ └────────────────────────────────────────────────────────┘ │
34
- │ │
35
- │ ┌────────────────────────────────────────────────────────┐ │
36
- │ │ <audio> (hidden) - нативный HTML5 player │ │
37
- │ │ - src={streamingUrl} │ │
38
- │ │ - браузер сам делает Range requests │ │
39
- │ └────────────────────────────────────────────────────────┘ │
40
- │ │
41
- │ ┌────────────────────────────────────────────────────────┐ │
42
- │ │ Controls │ │
43
- │ │ [⏮] [▶/⏸] [⏭] [🔊━━━━] [🔁] 00:00 / 03:45 │ │
44
- │ └────────────────────────────────────────────────────────┘ │
45
- │ │
46
- └──────────────────────────────────────────────────────────────┘
47
- ```
48
-
49
- ---
50
-
51
- ## Компоненты
52
-
53
- ### 1. `useProgressiveWaveform` - хук для загрузки и декодирования
54
-
55
- ```typescript
56
- interface UseProgressiveWaveformOptions {
57
- url: string;
58
- chunkSize?: number; // размер chunk для загрузки (default: 512KB)
59
- samplesPerChunk?: number; // сколько peaks на chunk (default: 100)
60
- }
61
-
62
- interface UseProgressiveWaveformReturn {
63
- peaks: number[]; // массив peaks [0-1]
64
- loadedPercent: number; // сколько загружено (0-100)
65
- isLoading: boolean;
66
- error: Error | null;
67
- loadedRanges: [number, number][]; // загруженные диапазоны
68
- }
69
- ```
70
-
71
- **Алгоритм:**
72
- 1. Получить Content-Length через HEAD запрос
73
- 2. Разбить на chunks
74
- 3. Загружать chunks последовательно или параллельно
75
- 4. Декодировать через AudioContext.decodeAudioData()
76
- 5. Извлечь peaks из decoded buffer
77
- 6. Обновлять состояние по мере загрузки
78
-
79
- ### 2. `WaveformCanvas` - canvas компонент
80
-
81
- ```typescript
82
- interface WaveformCanvasProps {
83
- peaks: number[];
84
- loadedPercent: number;
85
- currentTime: number;
86
- duration: number;
87
- buffered: TimeRanges; // из audio.buffered
88
- onSeek: (time: number) => void;
89
-
90
- // Стилизация
91
- waveColor?: string;
92
- progressColor?: string;
93
- loadingColor?: string; // цвет незагруженной области
94
- cursorColor?: string;
95
- barWidth?: number;
96
- barGap?: number;
97
- height?: number;
98
- }
99
- ```
100
-
101
- **Отрисовка:**
102
- 1. Фон - незагруженная область (полупрозрачная или placeholder pattern)
103
- 2. Загруженные peaks - основной цвет
104
- 3. Проигранная часть - progressColor
105
- 4. Курсор текущей позиции
106
- 5. Buffered ranges индикатор (тонкая полоса снизу)
107
-
108
- ### 3. `useAudioElement` - хук для управления audio
109
-
110
- ```typescript
111
- interface UseAudioElementOptions {
112
- src: string;
113
- autoPlay?: boolean;
114
- onTimeUpdate?: (time: number) => void;
115
- onDurationChange?: (duration: number) => void;
116
- onBufferUpdate?: (buffered: TimeRanges) => void;
117
- onEnded?: () => void;
118
- onError?: (error: Error) => void;
119
- }
120
-
121
- interface UseAudioElementReturn {
122
- audioRef: RefObject<HTMLAudioElement>;
123
- isPlaying: boolean;
124
- currentTime: number;
125
- duration: number;
126
- volume: number;
127
- isMuted: boolean;
128
- buffered: TimeRanges;
129
-
130
- // Actions
131
- play: () => Promise<void>;
132
- pause: () => void;
133
- seek: (time: number) => void;
134
- setVolume: (vol: number) => void;
135
- toggleMute: () => void;
136
- }
137
- ```
138
-
139
- ### 4. `ProgressiveAudioPlayer` - главный компонент
140
-
141
- ```typescript
142
- interface ProgressiveAudioPlayerProps {
143
- src: string;
144
- title?: string;
145
- artist?: string;
146
- coverArt?: string;
147
-
148
- // Features
149
- showWaveform?: boolean;
150
- showControls?: boolean;
151
- showTimer?: boolean;
152
- showVolume?: boolean;
153
- showLoop?: boolean;
154
-
155
- // Callbacks
156
- onPlay?: () => void;
157
- onPause?: () => void;
158
- onEnded?: () => void;
159
- onError?: (error: Error) => void;
160
-
161
- // Styling
162
- className?: string;
163
- waveformOptions?: WaveformOptions;
164
- }
165
- ```
166
-
167
- ### 5. `ProgressiveAudioContext` - контекст (опционально)
168
-
169
- Для совместимости с существующими хуками:
170
- - `useAudioControls()`
171
- - `useAudioState()`
172
- - `useAudioElement()`
173
-
174
- ---
175
-
176
- ## Файловая структура
177
-
178
- ```
179
- AudioPlayer/
180
- ├── @refactoring2/
181
- │ └── PLAN.md (этот файл)
182
-
183
- ├── components/
184
- │ ├── ProgressiveAudioPlayer.tsx # NEW - главный компонент
185
- │ ├── WaveformCanvas.tsx # NEW - canvas waveform
186
- │ ├── AudioPlayer.tsx # существующий (WaveSurfer)
187
- │ └── SimpleAudioPlayer.tsx # существующий
188
-
189
- ├── hooks/
190
- │ ├── useProgressiveWaveform.ts # NEW - загрузка + декодирование
191
- │ ├── useAudioElement.ts # NEW - управление audio
192
- │ ├── useWaveformRenderer.ts # NEW - рендеринг на canvas
193
- │ └── useAudioHotkeys.ts # существующий (переиспользуем)
194
-
195
- ├── context/
196
- │ ├── ProgressiveAudioProvider.tsx # NEW - контекст
197
- │ └── AudioProvider.tsx # существующий (WaveSurfer)
198
-
199
- ├── utils/
200
- │ ├── peaks.ts # NEW - извлечение peaks
201
- │ ├── audioDecoder.ts # NEW - декодирование chunks
202
- │ └── formatTime.ts # существующий
203
-
204
- └── types/
205
- └── progressive.ts # NEW - типы
206
- ```
207
-
208
- ---
209
-
210
- ## Этапы реализации
211
-
212
- ### Этап 1: Базовые хуки (core) ✅ DONE
213
-
214
- **Файлы:**
215
- - `progressive/useAudioElement.ts` ✅
216
- - `progressive/peaks.ts` ✅
217
- - `progressive/types.ts` ✅
218
-
219
- **Задачи:**
220
- 1. [x] Создать `useAudioElement` - обёртка над HTMLAudioElement
221
- 2. [x] Создать `extractPeaks(audioBuffer)` - извлечение peaks из AudioBuffer
222
- 3. [x] Создать утилиты для peaks (merge, resample, smooth)
223
- 4. [x] Типы для всех новых компонентов
224
-
225
- ### Этап 2: Progressive загрузка ✅ DONE
226
-
227
- **Файлы:**
228
- - `progressive/useProgressiveWaveform.ts` ✅
229
-
230
- **Задачи:**
231
- 1. [x] HEAD запрос для Content-Length
232
- 2. [x] Chunked fetch с Range headers
233
- 3. [x] Декодирование каждого chunk
234
- 4. [x] Накопление peaks в состоянии
235
- 5. [x] Обработка ошибок и retry
236
-
237
- ### Этап 3: Canvas рендеринг ✅ DONE
238
-
239
- **Файлы:**
240
- - `progressive/WaveformCanvas.tsx` ✅
241
-
242
- **Задачи:**
243
- 1. [x] Canvas setup с правильным DPI
244
- 2. [x] Рендеринг peaks (bars)
245
- 3. [x] Progress overlay (проигранная часть)
246
- 4. [x] Loading indicator для незагруженной части
247
- 5. [x] Cursor (текущая позиция)
248
- 6. [x] Buffered ranges indicator
249
- 7. [x] Click/drag для seek
250
- 8. [x] Hover preview
251
-
252
- ### Этап 4: Главный компонент ✅ DONE
253
-
254
- **Файлы:**
255
- - `progressive/ProgressiveAudioPlayer.tsx` ✅
256
- - `progressive/index.ts` ✅
257
-
258
- **Задачи:**
259
- 1. [x] Собрать всё вместе
260
- 2. [x] Controls UI (play/pause, volume, etc.)
261
- 3. [x] Timer display
262
- 4. [x] Export из index.ts
263
- 5. [ ] Keyboard shortcuts (переиспользовать useAudioHotkeys) - TODO
264
-
265
- ### Этап 5: Интеграция и тесты 🔄 IN PROGRESS
266
-
267
- **Задачи:**
268
- 1. [x] Export из AudioPlayer/index.ts
269
- 2. [ ] Обновить AudioViewer в cmdop - использовать ProgressiveAudioPlayer
270
- 3. [ ] Playground example
271
- 4. [ ] Тестирование с разными форматами/размерами
272
- 5. [ ] Добавить Context для совместимости с существующими хуками
273
-
274
- ---
275
-
276
- ## Технические детали
277
-
278
- ### Декодирование chunks
279
-
280
- ```typescript
281
- async function decodeChunk(
282
- chunk: ArrayBuffer,
283
- audioContext: AudioContext
284
- ): Promise<Float32Array> {
285
- // Для MP3/AAC нужен полный frame
286
- // Возможно потребуется накопление данных
287
- const audioBuffer = await audioContext.decodeAudioData(chunk);
288
- return audioBuffer.getChannelData(0); // mono
289
- }
290
- ```
291
-
292
- **Проблема:** `decodeAudioData` требует валидный аудио-контейнер. Для streaming нужно:
293
- - Либо накапливать достаточно данных для декодирования
294
- - Либо использовать Web Codecs API (AudioDecoder)
295
- - Либо генерировать peaks на backend
296
-
297
- ### Альтернатива: Backend peaks
298
-
299
- Если декодирование на frontend сложное, можно:
300
- 1. Go генерирует peaks через FFmpeg при первом запросе
301
- 2. Кэширует в файл рядом с аудио
302
- 3. Frontend загружает peaks JSON отдельно
303
-
304
- ```bash
305
- # FFmpeg генерация peaks
306
- ffmpeg -i audio.mp3 -af "asetnsamples=n=1024,astats=metadata=1:reset=1" -f null - 2>&1 | grep lavfi.astats
307
- ```
308
-
309
- Или использовать `audiowaveform`:
310
- ```bash
311
- audiowaveform -i audio.mp3 -o peaks.json --pixels-per-second 10
312
- ```
313
-
314
- ---
315
-
316
- ## Миграция
317
-
318
- ### Для cmdop AudioViewer
319
-
320
- ```typescript
321
- // Было:
322
- <SimpleAudioPlayer src={streamUrl} showWaveform />
323
-
324
- // Стало:
325
- <ProgressiveAudioPlayer src={streamUrl} showWaveform />
326
- ```
327
-
328
- ### Backwards compatibility
329
-
330
- - Существующие компоненты остаются для blob/local файлов
331
- - `ProgressiveAudioPlayer` для streaming URLs
332
- - `SimpleAudioPlayer` получает prop `progressive?: boolean`
333
-
334
- ---
335
-
336
- ## Оценка сложности
337
-
338
- | Компонент | Сложность | Строки кода |
339
- |-----------|-----------|-------------|
340
- | useAudioElement | Низкая | ~80 |
341
- | peaks utils | Низкая | ~50 |
342
- | useProgressiveWaveform | Высокая | ~150 |
343
- | WaveformCanvas | Средняя | ~200 |
344
- | ProgressiveAudioPlayer | Средняя | ~150 |
345
- | Context | Низкая | ~100 |
346
- | **Итого** | | **~730** |
347
-
348
- **Сравнение:** WaveSurfer.js = ~15,000 строк
349
-
350
- ---
351
-
352
- ## Риски и альтернативы
353
-
354
- ### Риск 1: decodeAudioData требует полный файл
355
-
356
- **Решение:** Использовать Web Codecs API или генерировать peaks на backend
357
-
358
- ### Риск 2: Производительность canvas на длинных треках
359
-
360
- **Решение:** Виртуализация - рендерить только видимую область
361
-
362
- ### Риск 3: Совместимость браузеров
363
-
364
- **Решение:** AudioContext поддерживается везде, Web Codecs - fallback на backend peaks
365
-
366
- ---
367
-
368
- ## Следующий шаг
369
-
370
- Начать с **Этапа 1** - базовые хуки и утилиты.
371
-
372
- Или сначала проверить **backend peaks** подход - если Go может генерировать peaks, это упростит frontend.