@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.
- 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 +8 -3
- 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/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,193 +0,0 @@
|
|
|
1
|
-
# Phase 7-8: Utils and Main Index
|
|
2
|
-
|
|
3
|
-
## `utils/formatTime.ts`
|
|
4
|
-
|
|
5
|
-
Extract from `AudioPlayer.tsx`.
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
/**
|
|
9
|
-
* Format seconds to mm:ss display format.
|
|
10
|
-
*/
|
|
11
|
-
export function formatTime(seconds: number): string {
|
|
12
|
-
if (!seconds || !isFinite(seconds) || seconds < 0) return '0:00';
|
|
13
|
-
const mins = Math.floor(seconds / 60);
|
|
14
|
-
const secs = Math.floor(seconds % 60);
|
|
15
|
-
return `${mins}:${secs.toString().padStart(2, '0')}`;
|
|
16
|
-
}
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## `utils/index.ts`
|
|
22
|
-
|
|
23
|
-
```typescript
|
|
24
|
-
export { formatTime } from './formatTime';
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## Main `index.ts` (Final Public API)
|
|
30
|
-
|
|
31
|
-
```typescript
|
|
32
|
-
/**
|
|
33
|
-
* AudioPlayer - Audio playback with waveform visualization
|
|
34
|
-
*
|
|
35
|
-
* Built on WaveSurfer.js with audio-reactive effects
|
|
36
|
-
*/
|
|
37
|
-
|
|
38
|
-
// =============================================================================
|
|
39
|
-
// COMPONENTS
|
|
40
|
-
// =============================================================================
|
|
41
|
-
|
|
42
|
-
// Simple wrapper (recommended)
|
|
43
|
-
export { SimpleAudioPlayer } from './components';
|
|
44
|
-
export type { SimpleAudioPlayerProps } from './components';
|
|
45
|
-
|
|
46
|
-
// Core components
|
|
47
|
-
export { AudioPlayer } from './components';
|
|
48
|
-
export { AudioEqualizer } from './components';
|
|
49
|
-
export { AudioReactiveCover } from './components';
|
|
50
|
-
export { AudioShortcutsPopover } from './components';
|
|
51
|
-
export { VisualizationToggle } from './components';
|
|
52
|
-
|
|
53
|
-
// =============================================================================
|
|
54
|
-
// CONTEXT & HOOKS
|
|
55
|
-
// =============================================================================
|
|
56
|
-
|
|
57
|
-
// Provider and hooks
|
|
58
|
-
export {
|
|
59
|
-
AudioProvider,
|
|
60
|
-
useAudio,
|
|
61
|
-
useAudioControls,
|
|
62
|
-
useAudioState,
|
|
63
|
-
useAudioElement,
|
|
64
|
-
} from './context';
|
|
65
|
-
|
|
66
|
-
// Hotkeys
|
|
67
|
-
export { useAudioHotkeys, AUDIO_SHORTCUTS } from './hooks';
|
|
68
|
-
|
|
69
|
-
// Visualization settings
|
|
70
|
-
export {
|
|
71
|
-
useAudioVisualization,
|
|
72
|
-
VisualizationProvider,
|
|
73
|
-
VARIANT_INFO,
|
|
74
|
-
INTENSITY_INFO,
|
|
75
|
-
COLOR_SCHEME_INFO,
|
|
76
|
-
} from './hooks';
|
|
77
|
-
|
|
78
|
-
// =============================================================================
|
|
79
|
-
// EFFECTS
|
|
80
|
-
// =============================================================================
|
|
81
|
-
|
|
82
|
-
export {
|
|
83
|
-
INTENSITY_CONFIG,
|
|
84
|
-
COLOR_SCHEMES,
|
|
85
|
-
getEffectConfig,
|
|
86
|
-
getColors,
|
|
87
|
-
prepareEffectColors,
|
|
88
|
-
calculateGlowLayers,
|
|
89
|
-
calculateOrbs,
|
|
90
|
-
calculateMeshGradients,
|
|
91
|
-
calculateSpotlight,
|
|
92
|
-
EFFECT_ANIMATIONS,
|
|
93
|
-
} from './effects';
|
|
94
|
-
|
|
95
|
-
// =============================================================================
|
|
96
|
-
// TYPES
|
|
97
|
-
// =============================================================================
|
|
98
|
-
|
|
99
|
-
export type {
|
|
100
|
-
// Audio types
|
|
101
|
-
AudioSource,
|
|
102
|
-
PlaybackStatus,
|
|
103
|
-
WaveformOptions,
|
|
104
|
-
EqualizerOptions,
|
|
105
|
-
SharedWebAudioContext,
|
|
106
|
-
AudioContextState,
|
|
107
|
-
// Component props
|
|
108
|
-
AudioPlayerProps,
|
|
109
|
-
AudioEqualizerProps,
|
|
110
|
-
AudioReactiveCoverProps,
|
|
111
|
-
AudioViewerProps,
|
|
112
|
-
// Effect types
|
|
113
|
-
EffectVariant,
|
|
114
|
-
EffectIntensity,
|
|
115
|
-
EffectColorScheme,
|
|
116
|
-
AudioLevels,
|
|
117
|
-
EffectConfig,
|
|
118
|
-
EffectColors,
|
|
119
|
-
EffectLayer,
|
|
120
|
-
} from './types';
|
|
121
|
-
|
|
122
|
-
// Visualization types
|
|
123
|
-
export type {
|
|
124
|
-
VisualizationSettings,
|
|
125
|
-
VisualizationVariant,
|
|
126
|
-
VisualizationIntensity,
|
|
127
|
-
VisualizationColorScheme,
|
|
128
|
-
UseAudioVisualizationReturn,
|
|
129
|
-
VisualizationProviderProps,
|
|
130
|
-
} from './hooks';
|
|
131
|
-
|
|
132
|
-
// Hotkey types
|
|
133
|
-
export type {
|
|
134
|
-
AudioHotkeyOptions,
|
|
135
|
-
ShortcutItem,
|
|
136
|
-
ShortcutGroup,
|
|
137
|
-
} from './hooks';
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
---
|
|
141
|
-
|
|
142
|
-
## Folder Structure Summary
|
|
143
|
-
|
|
144
|
-
After refactoring:
|
|
145
|
-
|
|
146
|
-
```
|
|
147
|
-
AudioPlayer/
|
|
148
|
-
├── index.ts # ~80 lines (exports only)
|
|
149
|
-
│
|
|
150
|
-
├── types/
|
|
151
|
-
│ ├── index.ts # ~30 lines
|
|
152
|
-
│ ├── audio.ts # ~80 lines
|
|
153
|
-
│ ├── components.ts # ~50 lines
|
|
154
|
-
│ └── effects.ts # ~60 lines
|
|
155
|
-
│
|
|
156
|
-
├── hooks/
|
|
157
|
-
│ ├── index.ts # ~30 lines
|
|
158
|
-
│ ├── useSharedWebAudio.ts # ~90 lines
|
|
159
|
-
│ ├── useAudioAnalysis.ts # ~100 lines
|
|
160
|
-
│ ├── useAudioHotkeys.ts # ~150 lines
|
|
161
|
-
│ └── useVisualization.tsx # ~200 lines
|
|
162
|
-
│
|
|
163
|
-
├── context/
|
|
164
|
-
│ ├── index.ts # ~5 lines
|
|
165
|
-
│ ├── AudioProvider.tsx # ~180 lines
|
|
166
|
-
│ └── selectors.ts # ~60 lines
|
|
167
|
-
│
|
|
168
|
-
├── components/
|
|
169
|
-
│ ├── index.ts # ~15 lines
|
|
170
|
-
│ ├── AudioPlayer.tsx # ~200 lines
|
|
171
|
-
│ ├── AudioEqualizer.tsx # ~200 lines
|
|
172
|
-
│ ├── SimpleAudioPlayer.tsx # ~280 lines
|
|
173
|
-
│ ├── ShortcutsPopover.tsx # ~95 lines
|
|
174
|
-
│ ├── VisualizationToggle.tsx # ~70 lines
|
|
175
|
-
│ └── ReactiveCover/
|
|
176
|
-
│ ├── index.tsx # ~100 lines
|
|
177
|
-
│ ├── GlowEffect.tsx # ~80 lines
|
|
178
|
-
│ ├── OrbsEffect.tsx # ~40 lines
|
|
179
|
-
│ ├── SpotlightEffect.tsx # ~60 lines
|
|
180
|
-
│ └── MeshEffect.tsx # ~50 lines
|
|
181
|
-
│
|
|
182
|
-
├── effects/
|
|
183
|
-
│ ├── index.ts # ~20 lines
|
|
184
|
-
│ ├── constants.ts # ~50 lines
|
|
185
|
-
│ ├── calculations.ts # ~250 lines
|
|
186
|
-
│ └── animations.ts # ~80 lines
|
|
187
|
-
│
|
|
188
|
-
└── utils/
|
|
189
|
-
├── index.ts # ~3 lines
|
|
190
|
-
└── formatTime.ts # ~10 lines
|
|
191
|
-
|
|
192
|
-
Total: ~23 files, avg ~85 lines per file (vs current 12 files, avg ~240 lines)
|
|
193
|
-
```
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
# Execution Checklist
|
|
2
|
-
|
|
3
|
-
## Pre-flight
|
|
4
|
-
|
|
5
|
-
- [ ] Run `pnpm check` - ensure current code compiles
|
|
6
|
-
- [ ] Commit current state as backup
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
## Phase 1: Create Folder Structure
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
cd src/tools/AudioPlayer
|
|
14
|
-
mkdir -p types hooks context components/ReactiveCover effects utils
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
- [ ] Create `types/` folder
|
|
18
|
-
- [ ] Create `hooks/` folder
|
|
19
|
-
- [ ] Create `context/` folder
|
|
20
|
-
- [ ] Create `components/` folder
|
|
21
|
-
- [ ] Create `components/ReactiveCover/` folder
|
|
22
|
-
- [ ] Create `effects/` subfolder (already exists, will add files)
|
|
23
|
-
- [ ] Create `utils/` folder
|
|
24
|
-
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
## Phase 2: Types Split
|
|
28
|
-
|
|
29
|
-
- [ ] Create `types/audio.ts`
|
|
30
|
-
- [ ] Create `types/components.ts`
|
|
31
|
-
- [ ] Create `types/effects.ts`
|
|
32
|
-
- [ ] Create `types/index.ts`
|
|
33
|
-
- [ ] Run `pnpm check`
|
|
34
|
-
|
|
35
|
-
---
|
|
36
|
-
|
|
37
|
-
## Phase 3: Hooks Extraction
|
|
38
|
-
|
|
39
|
-
- [ ] Create `hooks/useSharedWebAudio.ts` (extract from context.tsx)
|
|
40
|
-
- [ ] Create `hooks/useAudioAnalysis.ts` (extract from context.tsx)
|
|
41
|
-
- [ ] Move `useAudioHotkeys.ts` → `hooks/useAudioHotkeys.ts`
|
|
42
|
-
- [ ] Move `useAudioVisualization.tsx` → `hooks/useVisualization.tsx`
|
|
43
|
-
- [ ] Create `hooks/index.ts`
|
|
44
|
-
- [ ] Run `pnpm check`
|
|
45
|
-
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
## Phase 4: Context Refactoring
|
|
49
|
-
|
|
50
|
-
- [ ] Create `context/AudioProvider.tsx`
|
|
51
|
-
- [ ] Create `context/selectors.ts`
|
|
52
|
-
- [ ] Create `context/index.ts`
|
|
53
|
-
- [ ] Delete old `context.tsx`
|
|
54
|
-
- [ ] Run `pnpm check`
|
|
55
|
-
|
|
56
|
-
---
|
|
57
|
-
|
|
58
|
-
## Phase 5: Components Reorganization
|
|
59
|
-
|
|
60
|
-
- [ ] Move `AudioPlayer.tsx` → `components/AudioPlayer.tsx`
|
|
61
|
-
- [ ] Move `AudioEqualizer.tsx` → `components/AudioEqualizer.tsx`
|
|
62
|
-
- [ ] Move `SimpleAudioPlayer.tsx` → `components/SimpleAudioPlayer.tsx`
|
|
63
|
-
- [ ] Move `AudioShortcutsPopover.tsx` → `components/ShortcutsPopover.tsx`
|
|
64
|
-
- [ ] Move `VisualizationToggle.tsx` → `components/VisualizationToggle.tsx`
|
|
65
|
-
- [ ] Split `AudioReactiveCover.tsx` into `components/ReactiveCover/`
|
|
66
|
-
- [ ] Create `components/ReactiveCover/index.tsx`
|
|
67
|
-
- [ ] Create `components/ReactiveCover/GlowEffect.tsx`
|
|
68
|
-
- [ ] Create `components/ReactiveCover/OrbsEffect.tsx`
|
|
69
|
-
- [ ] Create `components/ReactiveCover/SpotlightEffect.tsx`
|
|
70
|
-
- [ ] Create `components/ReactiveCover/MeshEffect.tsx`
|
|
71
|
-
- [ ] Create `components/index.ts`
|
|
72
|
-
- [ ] Delete old component files from root
|
|
73
|
-
- [ ] Run `pnpm check`
|
|
74
|
-
|
|
75
|
-
---
|
|
76
|
-
|
|
77
|
-
## Phase 6: Effects Refactoring
|
|
78
|
-
|
|
79
|
-
- [ ] Create `effects/constants.ts`
|
|
80
|
-
- [ ] Create `effects/calculations.ts`
|
|
81
|
-
- [ ] Create `effects/animations.ts`
|
|
82
|
-
- [ ] Update `effects/index.ts`
|
|
83
|
-
- [ ] Run `pnpm check`
|
|
84
|
-
|
|
85
|
-
---
|
|
86
|
-
|
|
87
|
-
## Phase 7: Utils
|
|
88
|
-
|
|
89
|
-
- [ ] Create `utils/formatTime.ts`
|
|
90
|
-
- [ ] Create `utils/index.ts`
|
|
91
|
-
- [ ] Run `pnpm check`
|
|
92
|
-
|
|
93
|
-
---
|
|
94
|
-
|
|
95
|
-
## Phase 8: Update Main Index
|
|
96
|
-
|
|
97
|
-
- [ ] Rewrite `index.ts` with new import paths
|
|
98
|
-
- [ ] Run `pnpm check`
|
|
99
|
-
|
|
100
|
-
---
|
|
101
|
-
|
|
102
|
-
## Phase 9: Cleanup & Verification
|
|
103
|
-
|
|
104
|
-
- [ ] Delete old files:
|
|
105
|
-
- [ ] `context.tsx`
|
|
106
|
-
- [ ] `types.ts`
|
|
107
|
-
- [ ] `useAudioHotkeys.ts` (moved)
|
|
108
|
-
- [ ] `useAudioVisualization.tsx` (moved)
|
|
109
|
-
- [ ] `AudioPlayer.tsx` (moved)
|
|
110
|
-
- [ ] `AudioEqualizer.tsx` (moved)
|
|
111
|
-
- [ ] `SimpleAudioPlayer.tsx` (moved)
|
|
112
|
-
- [ ] `AudioShortcutsPopover.tsx` (moved)
|
|
113
|
-
- [ ] `VisualizationToggle.tsx` (moved)
|
|
114
|
-
- [ ] `AudioReactiveCover.tsx` (split)
|
|
115
|
-
|
|
116
|
-
- [ ] Run `pnpm check` - final verification
|
|
117
|
-
- [ ] Test in playground
|
|
118
|
-
- [ ] Commit refactoring
|
|
119
|
-
|
|
120
|
-
---
|
|
121
|
-
|
|
122
|
-
## Rollback Plan
|
|
123
|
-
|
|
124
|
-
If something goes wrong:
|
|
125
|
-
|
|
126
|
-
```bash
|
|
127
|
-
git checkout HEAD -- src/tools/AudioPlayer/
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
---
|
|
131
|
-
|
|
132
|
-
## Files to Delete (after successful migration)
|
|
133
|
-
|
|
134
|
-
```
|
|
135
|
-
src/tools/AudioPlayer/
|
|
136
|
-
├── context.tsx # → context/AudioProvider.tsx + context/selectors.ts
|
|
137
|
-
├── types.ts # → types/*.ts
|
|
138
|
-
├── useAudioHotkeys.ts # → hooks/useAudioHotkeys.ts
|
|
139
|
-
├── useAudioVisualization.tsx # → hooks/useVisualization.tsx
|
|
140
|
-
├── AudioPlayer.tsx # → components/AudioPlayer.tsx
|
|
141
|
-
├── AudioEqualizer.tsx # → components/AudioEqualizer.tsx
|
|
142
|
-
├── SimpleAudioPlayer.tsx # → components/SimpleAudioPlayer.tsx
|
|
143
|
-
├── AudioShortcutsPopover.tsx # → components/ShortcutsPopover.tsx
|
|
144
|
-
├── VisualizationToggle.tsx # → components/VisualizationToggle.tsx
|
|
145
|
-
└── AudioReactiveCover.tsx # → components/ReactiveCover/*.tsx
|
|
146
|
-
```
|
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
# Audio Player Seek Issue Analysis
|
|
2
|
-
|
|
3
|
-
**Date:** 2025-12-27
|
|
4
|
-
**Issue:** При seek на позицию > 2 минут аудио перестаёт воспроизводиться
|
|
5
|
-
|
|
6
|
-
## Симптомы
|
|
7
|
-
|
|
8
|
-
1. Трек начинает проигрываться нормально
|
|
9
|
-
2. Seek на позицию < 2 минут работает
|
|
10
|
-
3. Seek на позицию > 2 минут - воспроизведение останавливается
|
|
11
|
-
4. После seek > 2 минут, возврат на < 2 минут тоже не работает
|
|
12
|
-
|
|
13
|
-
## Корневая причина
|
|
14
|
-
|
|
15
|
-
### Проблема в архитектуре streaming + WaveSurfer
|
|
16
|
-
|
|
17
|
-
**WaveSurfer.js** по умолчанию загружает **весь аудиофайл** в память перед воспроизведением. Но в текущей реализации используется **HTTP Range streaming**, который возвращает данные **по частям**.
|
|
18
|
-
|
|
19
|
-
#### Ключевые константы (Django backend):
|
|
20
|
-
|
|
21
|
-
```python
|
|
22
|
-
# viewsets.py
|
|
23
|
-
DEFAULT_CHUNK_SIZE = 2 * 1024 * 1024 # 2 MB
|
|
24
|
-
MAX_CHUNK_SIZE = 10 * 1024 * 1024 # 10 MB
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
#### Что происходит:
|
|
28
|
-
|
|
29
|
-
1. **Загрузка аудио:**
|
|
30
|
-
- WaveSurfer запрашивает URL: `/api/terminal/media-stream/{session_id}/stream/?path=...`
|
|
31
|
-
- Backend возвращает **только первые 2 MB** (DEFAULT_CHUNK_SIZE)
|
|
32
|
-
- WaveSurfer декодирует эти 2 MB и считает файл "готовым"
|
|
33
|
-
|
|
34
|
-
2. **При seek на < 2 минут:**
|
|
35
|
-
- Данные уже в буфере (первые 2 MB)
|
|
36
|
-
- Seek работает
|
|
37
|
-
|
|
38
|
-
3. **При seek на > 2 минут:**
|
|
39
|
-
- Данные НЕ загружены (за пределами первых 2 MB)
|
|
40
|
-
- WaveSurfer пытается seek в "пустоту"
|
|
41
|
-
- HTML5 Audio element не может воспроизвести незагруженные данные
|
|
42
|
-
- Плеер "зависает"
|
|
43
|
-
|
|
44
|
-
4. **После неудачного seek:**
|
|
45
|
-
- Состояние плеера повреждено
|
|
46
|
-
- Даже возврат на загруженную часть не работает
|
|
47
|
-
|
|
48
|
-
### Почему именно 2 минуты?
|
|
49
|
-
|
|
50
|
-
MP3 128kbps ≈ 16 KB/сек
|
|
51
|
-
2 MB / 16 KB = **125 секунд ≈ 2 минуты**
|
|
52
|
-
|
|
53
|
-
Для других битрейтов:
|
|
54
|
-
- 192kbps: ~87 секунд
|
|
55
|
-
- 256kbps: ~65 секунд
|
|
56
|
-
- 320kbps: ~52 секунды
|
|
57
|
-
|
|
58
|
-
## Решения
|
|
59
|
-
|
|
60
|
-
### Вариант 1: Полная загрузка файла (Рекомендуется для небольших файлов)
|
|
61
|
-
|
|
62
|
-
**Изменить AudioViewer.tsx:**
|
|
63
|
-
|
|
64
|
-
```typescript
|
|
65
|
-
// Вместо streaming для аудио < 50MB, загружать полностью
|
|
66
|
-
const shouldFullLoad = file.size < 50 * 1024 * 1024 && isAudio;
|
|
67
|
-
|
|
68
|
-
if (shouldFullLoad) {
|
|
69
|
-
// Загрузить через RPC или fetch весь файл
|
|
70
|
-
const response = await fetch(streamUrl);
|
|
71
|
-
const blob = await response.blob();
|
|
72
|
-
const blobUrl = URL.createObjectURL(blob);
|
|
73
|
-
setSrc(blobUrl);
|
|
74
|
-
} else {
|
|
75
|
-
// Streaming для больших файлов
|
|
76
|
-
setSrc(streamUrl);
|
|
77
|
-
}
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
### Вариант 2: Использовать Media Source Extensions (MSE)
|
|
81
|
-
|
|
82
|
-
WaveSurfer поддерживает MSE для progressive loading:
|
|
83
|
-
|
|
84
|
-
```typescript
|
|
85
|
-
// AudioProvider.tsx
|
|
86
|
-
const options = useMemo(() => ({
|
|
87
|
-
container: containerRef,
|
|
88
|
-
url: source.uri,
|
|
89
|
-
// Включить backend режим для streaming
|
|
90
|
-
backend: 'MediaElement',
|
|
91
|
-
mediaControls: false,
|
|
92
|
-
// ...
|
|
93
|
-
}), [...]);
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
**Требует изменений в backend** для правильной обработки Range requests.
|
|
97
|
-
|
|
98
|
-
### Вариант 3: Исправить backend Range handling
|
|
99
|
-
|
|
100
|
-
**Django viewsets.py** - убрать ограничение chunk size для аудио:
|
|
101
|
-
|
|
102
|
-
```python
|
|
103
|
-
def stream(self, request, session_id: str):
|
|
104
|
-
# Для аудио - возвращать весь файл или больший chunk
|
|
105
|
-
if mime_type.startswith('audio/') and file_size < 100 * 1024 * 1024:
|
|
106
|
-
# Возвращать весь файл для аудио < 100MB
|
|
107
|
-
chunk_size = file_size
|
|
108
|
-
else:
|
|
109
|
-
chunk_size = min(requested_length or DEFAULT_CHUNK_SIZE, MAX_CHUNK_SIZE)
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### Вариант 4: Использовать HTML5 Audio напрямую (без WaveSurfer waveform)
|
|
113
|
-
|
|
114
|
-
Для streaming источников отключить waveform rendering:
|
|
115
|
-
|
|
116
|
-
```typescript
|
|
117
|
-
<SimpleAudioPlayer
|
|
118
|
-
src={streamUrl}
|
|
119
|
-
showWaveform={false} // Отключить waveform для streaming
|
|
120
|
-
// ...
|
|
121
|
-
/>
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
HTML5 `<audio>` элемент сам обрабатывает Range requests корректно.
|
|
125
|
-
|
|
126
|
-
## Быстрое временное решение
|
|
127
|
-
|
|
128
|
-
В `AudioViewer.tsx` изменить условие для использования blob вместо streaming для аудио:
|
|
129
|
-
|
|
130
|
-
```typescript
|
|
131
|
-
// Текущий код:
|
|
132
|
-
const shouldStream = (file.loadMethod === 'http_stream' || file.loadMethod === 'http_transcode')
|
|
133
|
-
&& !hasContent && sessionId;
|
|
134
|
-
|
|
135
|
-
// Изменить на:
|
|
136
|
-
const isAudio = file.mimeType?.startsWith('audio/');
|
|
137
|
-
const shouldStream = !isAudio && (file.loadMethod === 'http_stream' || file.loadMethod === 'http_transcode')
|
|
138
|
-
&& !hasContent && sessionId;
|
|
139
|
-
|
|
140
|
-
// Для аудио - загружать через fetch
|
|
141
|
-
if (isAudio && sessionId && !hasContent) {
|
|
142
|
-
const fetchAudio = async () => {
|
|
143
|
-
const url = getStreamUrlWithTranscode(sessionId, file.path, needsTranscode);
|
|
144
|
-
const response = await fetch(url);
|
|
145
|
-
const blob = await response.blob();
|
|
146
|
-
setSrc(URL.createObjectURL(blob));
|
|
147
|
-
};
|
|
148
|
-
fetchAudio();
|
|
149
|
-
}
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
## Дополнительные находки
|
|
153
|
-
|
|
154
|
-
### Баг в useAudioHotkeys.ts (исправлен)
|
|
155
|
-
|
|
156
|
-
В `/projects/solution/frontend/packages/ui-nextjs/src/tools/AudioPlayer/hooks/useAudioHotkeys.ts` был баг:
|
|
157
|
-
|
|
158
|
-
```typescript
|
|
159
|
-
// Было (НЕПРАВИЛЬНО):
|
|
160
|
-
skip(duration * percent - duration * (volume || 0));
|
|
161
|
-
|
|
162
|
-
// Стало (ПРАВИЛЬНО):
|
|
163
|
-
const targetTime = duration * percent;
|
|
164
|
-
skip(targetTime - currentTime);
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
Использовался `volume` (громкость) вместо `currentTime` для расчёта seek позиции.
|
|
168
|
-
|
|
169
|
-
## Файлы для изменения
|
|
170
|
-
|
|
171
|
-
1. **Frontend:**
|
|
172
|
-
- `cmdop/projects/solution/frontend/apps/web/app/_layouts/FileWorkspace/viewers/media/AudioViewer.tsx`
|
|
173
|
-
|
|
174
|
-
2. **Backend (опционально):**
|
|
175
|
-
- `cmdop/projects/solution/django/apps/terminal/views/api/media_stream/viewsets.py`
|
|
176
|
-
|
|
177
|
-
3. **UI Library (уже исправлено):**
|
|
178
|
-
- `djangocfg/projects/solution/frontend/packages/ui-nextjs/src/tools/AudioPlayer/hooks/useAudioHotkeys.ts`
|
|
179
|
-
|
|
180
|
-
## Архитектурная рекомендация
|
|
181
|
-
|
|
182
|
-
Для аудиофайлов рекомендуется:
|
|
183
|
-
- **< 50 MB**: Полная загрузка в blob (лучший UX, работает seek)
|
|
184
|
-
- **50-200 MB**: HTML5 Audio без waveform (streaming, но без визуализации)
|
|
185
|
-
- **> 200 MB**: Показать предупреждение, предложить скачать
|
|
186
|
-
|
|
187
|
-
WaveSurfer waveform visualization требует полной загрузки файла для корректной работы.
|