From 6c502749501524acfaa307be17adf521dc3f52c8 Mon Sep 17 00:00:00 2001 From: Brent Vollebregt Date: Mon, 22 Jan 2024 17:06:40 +1300 Subject: [PATCH] Use smoothing delay to calculate lyric position rather than API requests --- client/src/components/Player.tsx | 2 +- client/src/hooks/useSmoothProgress.ts | 4 +-- client/src/pages/LyricsView/LyricsDisplay.tsx | 28 +++++++++++-------- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/client/src/components/Player.tsx b/client/src/components/Player.tsx index ac60772..27f2570 100644 --- a/client/src/components/Player.tsx +++ b/client/src/components/Player.tsx @@ -118,7 +118,7 @@ const Player: React.FC = ({ currentlyPlayingSong, token }) => { - {formatMilliseconds(progressMs)} + {formatMilliseconds(smoothedProgressMs)} { const [progress, setProgress] = useState(0); const [userSlidingProgress, setUserSlidingProgress] = useState(false); @@ -26,7 +27,6 @@ const useSmoothProgress = ( clearTimeout(smoothProgressTimer); } - const smoothingDelay = 500; setSmoothProgressTimer( setInterval(() => { if (!userSlidingProgress && isPlaying) { diff --git a/client/src/pages/LyricsView/LyricsDisplay.tsx b/client/src/pages/LyricsView/LyricsDisplay.tsx index 82dc3dc..71308eb 100644 --- a/client/src/pages/LyricsView/LyricsDisplay.tsx +++ b/client/src/pages/LyricsView/LyricsDisplay.tsx @@ -13,13 +13,11 @@ import SearchIcon from "@material-ui/icons/Search"; import SyncEnabledIcon from "@material-ui/icons/Sync"; import SyncDisabledIcon from "@material-ui/icons/SyncDisabled"; import MarkJS from "mark.js"; -import React, { useEffect, useRef, useState } from "react"; +import React, { useEffect, useMemo, useRef, useState } from "react"; import { IFoundLyrics } from "../../../../src/dto"; +import useSmoothProgress from "../../hooks/useSmoothProgress"; import "./LyricsDisplay.css"; -// adjusting for latency to highlight lyrics due to the time it takes to render the components on screen -const LATENCY_ADJUSTMENT_MAGIC_VALUE_MS = 0.135; - interface IProps { lyricsDetails: IFoundLyrics; progressMs: number; @@ -35,6 +33,14 @@ const LyricsDisplay: React.FunctionComponent = ({ lyricsDetails, progres const [searchShown, setSearchShown] = useState(false); const [syncEnabled, setSyncEnabled] = useState(true); + const { progress: smoothedProgressMs } = useSmoothProgress( + progressMs, + Infinity, + !paused, + null, + 250 + ); + const isSyncingPossible = lyricsDetails.syncedLyrics !== null; // Highlight text when the search is changed @@ -61,9 +67,12 @@ const LyricsDisplay: React.FunctionComponent = ({ lyricsDetails, progres if (syncEnabled && element !== null) { element.scrollIntoView({ behavior: "smooth", block: "center", inline: "nearest" }); } - }, [syncEnabled, progressMs]); + }, [syncEnabled, smoothedProgressMs]); - const lyricsState = calculateLyricsState(lyricsDetails, progressMs, syncEnabled, paused); + const lyricsState = useMemo( + () => calculateLyricsState(lyricsDetails, smoothedProgressMs, syncEnabled, paused), + [lyricsDetails, smoothedProgressMs, syncEnabled, paused] + ); const onUserSearch = (event: React.ChangeEvent) => setSearch(event.currentTarget.value ?? ""); @@ -135,7 +144,6 @@ const calculateLyricsState = ( paused: boolean ) => { const progressSeconds = progressMs / 1000; - const artificialProgressSeconds = progressSeconds + LATENCY_ADJUSTMENT_MAGIC_VALUE_MS / 1000; // If there is no syncedLyricsArray or sync is disabled or the song is paused, return the plain lyrics if (lyricsDetails.syncedLyrics === null || !syncEnabled || paused) { @@ -148,15 +156,13 @@ const calculateLyricsState = ( // Calculate the current lyric state based on progress const passedLyricsAndCurrent = - lyricsDetails.syncedLyrics.filter(x => x.timestamp <= artificialProgressSeconds) ?? []; + lyricsDetails.syncedLyrics.filter(x => x.timestamp <= progressSeconds) ?? []; const passedLyrics = passedLyricsAndCurrent.slice(0, -1); const currentLyrics = passedLyricsAndCurrent.length > 0 ? passedLyricsAndCurrent[passedLyricsAndCurrent.length - 1] : null; - const upcomingLyrics = lyricsDetails.syncedLyrics.filter( - x => x.timestamp > artificialProgressSeconds - ); + const upcomingLyrics = lyricsDetails.syncedLyrics.filter(x => x.timestamp > progressSeconds); return { before: passedLyrics.map(x => x.content).join(" \n "),