mirror of
https://github.com/navidrome/navidrome.git
synced 2026-06-19 07:37:15 +00:00
fix(ui): report playback when restarting current track via prev
The navidrome-music-player library rewinds the current track by directly mutating audio.currentTime when the Previous button is pressed with restartCurrentOnPrev (and other programmatic seek paths like singleLoop reset and mediaSession seek). It does not invoke its onAudioSeeked callback for these, so the play tracker never learned about the new position until the next ~30s heartbeat. Replace the React onAudioSeeked prop with a native HTML5 'seeked' event listener on the audio element, which fires for every seek (programmatic or via slider release). The handler is debounced by 250ms so the burst of seeks emitted while dragging the progress bar coalesces into a single reportPlayback call at the final position.
This commit is contained in:
@@ -272,18 +272,6 @@ const Player = () => {
|
||||
}
|
||||
}, [])
|
||||
|
||||
const onAudioSeeked = useCallback(
|
||||
(info) => {
|
||||
if (!info.isRadio && currentTrackId) {
|
||||
const posMs = Math.floor(info.currentTime * 1000)
|
||||
lastPositionMsRef.current = posMs
|
||||
const state = audioInstance?.paused ? 'paused' : 'playing'
|
||||
subsonic.reportPlayback(currentTrackId, posMs, state)
|
||||
}
|
||||
},
|
||||
[currentTrackId, audioInstance],
|
||||
)
|
||||
|
||||
const onAudioVolumeChange = useCallback(
|
||||
// sqrt to compensate for the logarithmic volume
|
||||
(volume) => dispatch(setVolume(Math.sqrt(volume))),
|
||||
@@ -436,6 +424,35 @@ const Player = () => {
|
||||
}
|
||||
}, [isMobilePlayer, audioInstance])
|
||||
|
||||
// Report every seek (including programmatic ones the library does not surface
|
||||
// via onAudioSeeked, e.g. restartCurrentOnPrev). Debounce coalesces drag
|
||||
// bursts into one report at the final position.
|
||||
useEffect(() => {
|
||||
if (!audioInstance) return
|
||||
let timer = null
|
||||
const flush = () => {
|
||||
timer = null
|
||||
if (
|
||||
!currentTrackIdRef.current ||
|
||||
playerStateRef.current?.current?.isRadio
|
||||
) {
|
||||
return
|
||||
}
|
||||
const posMs = Math.floor((audioInstance.currentTime || 0) * 1000)
|
||||
const state = audioInstance.paused ? 'paused' : 'playing'
|
||||
subsonic.reportPlayback(currentTrackIdRef.current, posMs, state)
|
||||
}
|
||||
const handleSeeked = () => {
|
||||
if (timer) clearTimeout(timer)
|
||||
timer = setTimeout(flush, 250)
|
||||
}
|
||||
audioInstance.addEventListener('seeked', handleSeeked)
|
||||
return () => {
|
||||
if (timer) clearTimeout(timer)
|
||||
audioInstance.removeEventListener('seeked', handleSeeked)
|
||||
}
|
||||
}, [audioInstance])
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={createMuiTheme(theme)}>
|
||||
<ReactJkMusicPlayer
|
||||
@@ -444,7 +461,6 @@ const Player = () => {
|
||||
onAudioListsChange={onAudioListsChange}
|
||||
onAudioVolumeChange={onAudioVolumeChange}
|
||||
onAudioProgress={onAudioProgress}
|
||||
onAudioSeeked={onAudioSeeked}
|
||||
onAudioPlay={onAudioPlay}
|
||||
onAudioPlayTrackChange={onAudioPlayTrackChange}
|
||||
onAudioPause={onAudioPause}
|
||||
|
||||
Reference in New Issue
Block a user