@wavv/ui 2.4.15-alpha.2 → 2.4.15-alpha.3
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/build/components/Audio.js +49 -7
- package/package.json +1 -1
|
@@ -15,7 +15,12 @@ const Audio = ({ src, title, width, infoPosition, centerAlignContent, small, tin
|
|
|
15
15
|
const audioRef = useRef(null);
|
|
16
16
|
const isSeekingRef = useRef(false);
|
|
17
17
|
const seekedTimeoutRef = useRef(null);
|
|
18
|
+
const lastRequestedSeekSecondsRef = useRef(null);
|
|
19
|
+
const seekVerifyRetryCountRef = useRef(0);
|
|
20
|
+
const seekVerifyTimeoutRef = useRef(null);
|
|
18
21
|
const END_EPSILON_SECONDS = 0.75;
|
|
22
|
+
const SEEK_TOLERANCE_SECONDS = 0.5;
|
|
23
|
+
const MAX_SEEK_VERIFY_RETRIES = 3;
|
|
19
24
|
const { height = 30, showHoverTime = false, playedColor, unplayedColor } = 'object' == typeof waveform ? waveform : {};
|
|
20
25
|
const play = ()=>{
|
|
21
26
|
const { current: audio } = audioRef;
|
|
@@ -40,6 +45,7 @@ const Audio = ({ src, title, width, infoPosition, centerAlignContent, small, tin
|
|
|
40
45
|
if (isPlaying) pause();
|
|
41
46
|
else {
|
|
42
47
|
if (isNearEnd(progress)) {
|
|
48
|
+
lastRequestedSeekSecondsRef.current = null;
|
|
43
49
|
setProgress(0);
|
|
44
50
|
setDisplayCurrent('0:00');
|
|
45
51
|
const { current: audio } = audioRef;
|
|
@@ -68,6 +74,7 @@ const Audio = ({ src, title, width, infoPosition, centerAlignContent, small, tin
|
|
|
68
74
|
if (onPause) onPause(event);
|
|
69
75
|
};
|
|
70
76
|
const handleAudioStop = (event)=>{
|
|
77
|
+
lastRequestedSeekSecondsRef.current = null;
|
|
71
78
|
setIsPlaying(false);
|
|
72
79
|
setIsCleared(true);
|
|
73
80
|
setProgress(0);
|
|
@@ -114,6 +121,7 @@ const Audio = ({ src, title, width, infoPosition, centerAlignContent, small, tin
|
|
|
114
121
|
]);
|
|
115
122
|
useEffect(()=>()=>{
|
|
116
123
|
if (seekedTimeoutRef.current) clearTimeout(seekedTimeoutRef.current);
|
|
124
|
+
if (seekVerifyTimeoutRef.current) clearTimeout(seekVerifyTimeoutRef.current);
|
|
117
125
|
}, []);
|
|
118
126
|
const formatTime = (time)=>{
|
|
119
127
|
if (!Number.isFinite(time) || time < 0) return '0:00';
|
|
@@ -121,17 +129,41 @@ const Audio = ({ src, title, width, infoPosition, centerAlignContent, small, tin
|
|
|
121
129
|
const secs = Math.floor(time % 60);
|
|
122
130
|
return `${mins}:${secs.toString().padStart(2, '0')}`;
|
|
123
131
|
};
|
|
132
|
+
const performSeek = (targetSeconds)=>{
|
|
133
|
+
const { current: audio } = audioRef;
|
|
134
|
+
if (!audio || !Number.isFinite(targetSeconds)) return false;
|
|
135
|
+
try {
|
|
136
|
+
audio.currentTime = targetSeconds;
|
|
137
|
+
return true;
|
|
138
|
+
} catch (_e) {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
124
142
|
const updateProgress = ()=>{
|
|
125
143
|
if (isSeekingRef.current) return;
|
|
126
144
|
const { current: audio } = audioRef;
|
|
127
|
-
if (audio)
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
145
|
+
if (!audio) return;
|
|
146
|
+
const currentTime = audio.currentTime;
|
|
147
|
+
if (!Number.isFinite(currentTime) || currentTime < 0) return;
|
|
148
|
+
const requestedSeek = lastRequestedSeekSecondsRef.current;
|
|
149
|
+
if ('number' == typeof requestedSeek) {
|
|
150
|
+
const drift = Math.abs(currentTime - requestedSeek);
|
|
151
|
+
if (drift > SEEK_TOLERANCE_SECONDS) {
|
|
152
|
+
if (seekVerifyRetryCountRef.current < MAX_SEEK_VERIFY_RETRIES) {
|
|
153
|
+
seekVerifyRetryCountRef.current += 1;
|
|
154
|
+
performSeek(requestedSeek);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
lastRequestedSeekSecondsRef.current = null;
|
|
158
|
+
seekVerifyRetryCountRef.current = 0;
|
|
159
|
+
return;
|
|
133
160
|
}
|
|
161
|
+
lastRequestedSeekSecondsRef.current = null;
|
|
162
|
+
seekVerifyRetryCountRef.current = 0;
|
|
134
163
|
}
|
|
164
|
+
const current = formatTime(currentTime);
|
|
165
|
+
setProgress(currentTime);
|
|
166
|
+
setDisplayCurrent(current);
|
|
135
167
|
};
|
|
136
168
|
const handleLoad = ()=>{
|
|
137
169
|
const { current: audio } = audioRef;
|
|
@@ -169,6 +201,8 @@ const Audio = ({ src, title, width, infoPosition, centerAlignContent, small, tin
|
|
|
169
201
|
const maxSeekTarget = Math.max(0, totalDuration - END_EPSILON_SECONDS);
|
|
170
202
|
const clamped = Math.min(Math.max(sliderPosition, 0), maxSeekTarget);
|
|
171
203
|
isSeekingRef.current = true;
|
|
204
|
+
lastRequestedSeekSecondsRef.current = clamped;
|
|
205
|
+
seekVerifyRetryCountRef.current = 0;
|
|
172
206
|
if (seekedTimeoutRef.current) clearTimeout(seekedTimeoutRef.current);
|
|
173
207
|
seekedTimeoutRef.current = setTimeout(()=>{
|
|
174
208
|
isSeekingRef.current = false;
|
|
@@ -176,7 +210,15 @@ const Audio = ({ src, title, width, infoPosition, centerAlignContent, small, tin
|
|
|
176
210
|
}, 300);
|
|
177
211
|
setProgress(clamped);
|
|
178
212
|
setDisplayCurrent(formatTime(clamped));
|
|
179
|
-
|
|
213
|
+
performSeek(clamped);
|
|
214
|
+
if (seekVerifyTimeoutRef.current) clearTimeout(seekVerifyTimeoutRef.current);
|
|
215
|
+
seekVerifyTimeoutRef.current = window.setTimeout(()=>{
|
|
216
|
+
seekVerifyTimeoutRef.current = null;
|
|
217
|
+
const { current: audio } = audioRef;
|
|
218
|
+
if (!audio || null === lastRequestedSeekSecondsRef.current) return;
|
|
219
|
+
const ct = audio.currentTime ?? 0;
|
|
220
|
+
if (Math.abs(ct - clamped) > SEEK_TOLERANCE_SECONDS) performSeek(clamped);
|
|
221
|
+
}, 150);
|
|
180
222
|
};
|
|
181
223
|
const hideSlider = isCleared && hideSliderOnStop;
|
|
182
224
|
const hideTime = isCleared && hideTimeOnStop;
|