import React from "react" import classnames from "classnames" import { motion, AnimatePresence } from "motion/react" import { usePlayerStateContext } from "@contexts/WithPlayerContext" // eslint-disable-next-line const LyricsText = React.forwardRef((props, textRef) => { const [playerState] = usePlayerStateContext() const { lyrics } = props const [syncInterval, setSyncInterval] = React.useState(null) const [currentLineIndex, setCurrentLineIndex] = React.useState(0) const [visible, setVisible] = React.useState(false) function syncPlayback() { const currentTrackTime = app.cores.player.controls.seek() * 1000 const lineIndex = lyrics.synced_lyrics.findIndex((line) => { return ( currentTrackTime >= line.startTimeMs && currentTrackTime <= line.endTimeMs ) }) if (lineIndex === -1) { if (!visible) { setVisible(false) } return false } const line = lyrics.synced_lyrics[lineIndex] setCurrentLineIndex(lineIndex) if (line.break) { return setVisible(false) } if (line.text) { return setVisible(true) } } function startSyncInterval() { if (!lyrics || !lyrics.synced_lyrics) { stopSyncInterval() return false } if (playerState.playback_status !== "playing") { stopSyncInterval() return false } if (syncInterval) { stopSyncInterval() } setSyncInterval(setInterval(syncPlayback, 100)) } function stopSyncInterval() { clearInterval(syncInterval) setSyncInterval(null) } //* Handle when current line index change React.useEffect(() => { if (currentLineIndex === 0) { setVisible(false) } else { setVisible(true) if (textRef.current) { // find line element by id const lineElement = textRef.current.querySelector( `#lyrics-line-${currentLineIndex}`, ) // center scroll to current line if (lineElement) { lineElement.scrollIntoView({ behavior: "smooth", block: "center", }) } else { // scroll to top textRef.current.scrollTop = 0 } } } }, [currentLineIndex]) //* Handle when playback status change React.useEffect(() => { startSyncInterval() }, [playerState.playback_status]) //* Handle when manifest object change, reset... React.useEffect(() => { setVisible(false) setCurrentLineIndex(0) }, [playerState.track_manifest]) React.useEffect(() => { startSyncInterval() }, [lyrics]) React.useEffect(() => { return () => { clearInterval(syncInterval) } }, []) if (!lyrics?.synced_lyrics) { return null } return (
{visible && ( {lyrics.synced_lyrics.map((line, index) => { return (

{line.text}

) })}
)}
) }) export default LyricsText