All files / src/hooks useActiveCue.ts

100% Statements 16/16
100% Branches 4/4
100% Functions 6/6
100% Lines 12/12

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42                                3x             286x   286x 30x     286x 157x 157x 35x 21x 21x   35x     286x    
// SPDX-License-Identifier: GPL-3.0-only
// Copyright (C) 2026 Max Boksem. See NOTICE for additional terms under GPLv3 section 7.
 
import { useEffect, useState } from "react";
import { clockAt, followReading, isNewReading, nextTick, startClock } from "@/lib/subtitle-clock";
import { cueAt } from "@/lib/subtitle-timing";
import type { SubtitleCue } from "@/lib/types";
 
/**
 * The cue to show for the video's position. The player only reads mpv's
 * position once a second, so this runs a clock from the last `position`,
 * which was read at `positionAt` in `performance.now()` milliseconds, and
 * renders again as a cue starts or ends. `moving` is whether the picture
 * moves on, so the clock stops while the video is paused or waits for the
 * stream. A positive `delay` shows each cue later, as mpv's `sub-delay` does.
 */
export const useActiveCue = (
	cues: SubtitleCue[],
	position: number,
	positionAt: number,
	delay: number,
	moving: boolean
): SubtitleCue | undefined => {
	const [clock, setClock] = useState(() => startClock({ position, at: positionAt, moving }));
	// A new reading moves the clock before this render shows anything.
	if (isNewReading(clock, position, positionAt)) {
		setClock(followReading(clock, { position, at: positionAt, moving }));
	}
 
	useEffect(() => {
		const wait = nextTick(clock, cues, delay, moving, performance.now());
		if (wait === null) return;
		const timer = setTimeout(() => {
			const now = performance.now();
			setClock((c) => ({ ...clockAt(c, now), moving }));
		}, wait);
		return () => clearTimeout(timer);
	}, [clock, cues, delay, moving]);
 
	return cueAt(cues, clock.position - delay);
};