All files / src/lib skip.ts

100% Statements 9/9
100% Branches 13/13
100% Functions 1/1
100% Lines 9/9

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 43 44 45 46        2x                                             2x             20x 20x 20x 20x 20x       20x 20x    
// SPDX-License-Identifier: GPL-3.0-only
// Copyright (C) 2026 Max Boksem. See NOTICE for additional terms under GPLv3 section 7.
 
/** A skip this soon after the last one in the same direction adds to it. */
export const SKIP_RUN_MS = 1500;
 
/** Skips in a row in one direction, which add up. */
export interface SkipRun {
	/** 1 for forward, -1 for back. */
	direction: number;
	/** The position the first skip of the run started from, in seconds. */
	origin: number;
	/** Where the latest skip is headed, in seconds. */
	target: number;
	/** When the latest skip happened, in milliseconds. */
	at: number;
	/** How far the run has moved, in whole seconds. */
	total: number;
}
 
/**
 * Works out where a skip lands. The position is only polled once a second and
 * lags behind a seek, so a skip soon after another one in the same direction
 * starts from where that one was going. A skip stops at the start, or a second
 * before the end when the duration is known, and the run's total counts only
 * the distance it really moved.
 */
export const nextSkip = (
	last: SkipRun | null,
	position: number,
	duration: number,
	seconds: number,
	now: number
): SkipRun => {
	const direction = Math.sign(seconds);
	const run = last && now - last.at < SKIP_RUN_MS && last.direction === direction ? last : null;
	const origin = run ? run.origin : position;
	const from = run ? run.target : position;
	const end = duration > 0 ? duration - 1 : Infinity;
	// Clamping only ever shortens a skip. It never turns a forward skip from
	// past the end into a step back.
	const target =
		seconds < 0 ? Math.max(0, from + seconds) : Math.max(from, Math.min(from + seconds, end));
	return { direction, origin, target, at: now, total: Math.round(target - origin) };
};