Skip to content

Commit

Permalink
Use smoothing delay to calculate lyric position rather than API requests
Browse files Browse the repository at this point in the history
  • Loading branch information
brentvollebregt committed Jan 22, 2024
1 parent 5bb5122 commit 6c50274
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 14 deletions.
2 changes: 1 addition & 1 deletion client/src/components/Player.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ const Player: React.FC<PlayerProps> = ({ currentlyPlayingSong, token }) => {
</div>

<Box display="inline-flex" alignItems="center" className={classes.sliderWrapper}>
<span className={classes.timeControl}>{formatMilliseconds(progressMs)}</span>
<span className={classes.timeControl}>{formatMilliseconds(smoothedProgressMs)}</span>

<Slider
valueLabelDisplay="off"
Expand Down
4 changes: 2 additions & 2 deletions client/src/hooks/useSmoothProgress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ const useSmoothProgress = (
progressMs: number,
duration: number,
isPlaying: boolean,
token: IToken | null
token: IToken | null,
smoothingDelay: number = 500
) => {
const [progress, setProgress] = useState(0);
const [userSlidingProgress, setUserSlidingProgress] = useState(false);
Expand All @@ -26,7 +27,6 @@ const useSmoothProgress = (
clearTimeout(smoothProgressTimer);
}

const smoothingDelay = 500;
setSmoothProgressTimer(
setInterval(() => {
if (!userSlidingProgress && isPlaying) {
Expand Down
28 changes: 17 additions & 11 deletions client/src/pages/LyricsView/LyricsDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -35,6 +33,14 @@ const LyricsDisplay: React.FunctionComponent<IProps> = ({ 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
Expand All @@ -61,9 +67,12 @@ const LyricsDisplay: React.FunctionComponent<IProps> = ({ 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<HTMLTextAreaElement | HTMLInputElement>) =>
setSearch(event.currentTarget.value ?? "");
Expand Down Expand Up @@ -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) {
Expand All @@ -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 "),
Expand Down

0 comments on commit 6c50274

Please sign in to comment.