commit 5be052b18632699f6292d2af434d481691ed6198 truex <truex@equwal.com> 2026-09-26 20:09:35 -0700 Remove four functions that the app no longer uses waitUntil and seekArgument were ports from SubRead Overlay and the KOReader plugin; OverlayClock polls and rounds the seek itself. lastCueAt replaced cueIndexAt. The SubRead language check in book-subtitles.ts replaced whisperCode, and it also knows jpn+eng. Their tests go with them.
src/book-text.ts | 5 ----- src/play-clock.ts | 11 ----------- src/player-state.ts | 5 ----- src/subtitles.ts | 7 ------- test/book-text.test.ts | 11 +---------- test/play-clock.test.ts | 34 +--------------------------------- test/player-state.test.ts | 11 +---------- test/subtitles.test.ts | 34 +--------------------------------- 8 files changed, 4 insertions(+), 114 deletions(-)
diff --git a/src/book-text.ts b/src/book-text.ts index efc050a..d447771 100644 --- a/src/book-text.ts +++ b/src/book-text.ts @@ -84,8 +84,3 @@ export function bookText(tokens: readonly OcrToken[]): string { endPage(); return pages.map((p) => p.join('\n')).join('\n\n') + (pages.length > 0 ? '\n' : ''); } - -/** The Whisper language code for a tesseract language ("jpn", "jpn_vert", "jpn+eng", "eng"). */ -export function whisperCode(ocrLang: string): 'ja' | 'en' { - return ocrLang.startsWith('jpn') ? 'ja' : 'en'; -} diff --git a/src/play-clock.ts b/src/play-clock.ts index eb6cc8f..c6cb7ed 100644 --- a/src/play-clock.ts +++ b/src/play-clock.ts @@ -17,14 +17,3 @@ export function positionAt(clock: PlayClock, nowMs: number): number { if (!clock.playing) return clock.positionMs; return clock.positionMs + (nowMs - clock.reportedAtMs) * clock.speed; } - -/** - * How long to wait, on the clock of the device, until the media is at - * `targetMs`. Null when the media does not move forward, or is already there. - */ -export function waitUntil(clock: PlayClock, targetMs: number, nowMs: number): number | null { - if (!clock.playing || clock.speed <= 0) return null; - const left = targetMs - positionAt(clock, nowMs); - if (left <= 0) return null; - return Math.ceil(left / clock.speed); -} diff --git a/src/player-state.ts b/src/player-state.ts index e497c5c..1512a5c 100644 --- a/src/player-state.ts +++ b/src/player-state.ts @@ -51,8 +51,3 @@ export function parseState(line: string | null | undefined): PlayerState | Playe package: fields.get('package') ?? '', }; } - -/** The argument of a seek call: the position in milliseconds, as a whole number. */ -export function seekArgument(ms: number): string { - return String(Math.max(0, Math.round(ms))); -} diff --git a/src/subtitles.ts b/src/subtitles.ts index 4af23d2..1f6540a 100644 --- a/src/subtitles.ts +++ b/src/subtitles.ts @@ -89,10 +89,3 @@ export function lastCueAt(cues: readonly Pick<Cue, 'start'>[], t: number): numbe } return found; } - -/** Index of the cue active at time t, or -1. Cues must be sorted by start. */ -export function cueIndexAt(cues: readonly Cue[], t: number): number { - const found = lastCueAt(cues, t); - if (found >= 0 && t < cues[found]!.end) return found; - return -1; -} diff --git a/test/book-text.test.ts b/test/book-text.test.ts index 3c8bec5..e9fc27c 100644 --- a/test/book-text.test.ts +++ b/test/book-text.test.ts @@ -1,7 +1,7 @@ import fc from 'fast-check'; import { describe, expect, it } from 'vitest'; import type { OcrToken } from '../src/align'; -import { bookText, joinWords, whisperCode } from '../src/book-text'; +import { bookText, joinWords } from '../src/book-text'; const box = { x0: 0, y0: 0, x1: 1, y1: 1 }; @@ -109,12 +109,3 @@ describe('bookText', () => { ); }); }); - -describe('whisperCode', () => { - it('maps tesseract languages to Whisper codes', () => { - expect(whisperCode('jpn')).toBe('ja'); - expect(whisperCode('jpn_vert')).toBe('ja'); - expect(whisperCode('jpn+eng')).toBe('ja'); - expect(whisperCode('eng')).toBe('en'); - }); -}); diff --git a/test/play-clock.test.ts b/test/play-clock.test.ts index cbfb9be..bc04ebe 100644 --- a/test/play-clock.test.ts +++ b/test/play-clock.test.ts @@ -1,6 +1,6 @@ import fc from 'fast-check'; import { describe, expect, it } from 'vitest'; -import { positionAt, waitUntil, type PlayClock } from '../src/play-clock'; +import { positionAt, type PlayClock } from '../src/play-clock'; const ms = fc.nat({ max: 10 ** 8 }); const speed = fc.double({ min: 0.25, max: 4, noNaN: true, noDefaultInfinity: true }); @@ -45,35 +45,3 @@ describe('positionAt', () => { ); }); }); - -describe('waitUntil', () => { - it('gives the real time until the target', () => { - const c: PlayClock = { positionMs: 1000, reportedAtMs: 0, speed: 2, playing: true }; - expect(waitUntil(c, 3000, 0)).toBe(1000); - expect(waitUntil(c, 3000, 500)).toBe(500); - }); - - it('gives null when paused or already past the target', () => { - const paused: PlayClock = { positionMs: 0, reportedAtMs: 0, speed: 1, playing: false }; - expect(waitUntil(paused, 100, 0)).toBeNull(); - const playing = { ...paused, playing: true }; - expect(waitUntil(playing, 0, 0)).toBeNull(); - expect(waitUntil(playing, -5, 0)).toBeNull(); - }); - - it('lands on the target after the wait', () => { - fc.assert( - fc.property(clock, ms, ms, (c, now, target) => { - const playing = { ...c, playing: true }; - const wait = waitUntil(playing, target, now); - if (wait === null) { - expect(positionAt(playing, now)).toBeGreaterThanOrEqual(target); - } else { - expect(wait).toBeGreaterThan(0); - // The wait is whole milliseconds; the float product can fall a hair short. - expect(positionAt(playing, now + wait)).toBeGreaterThanOrEqual(target - 1e-6); - } - }), - ); - }); -}); diff --git a/test/player-state.test.ts b/test/player-state.test.ts index 666cc26..6221538 100644 --- a/test/player-state.test.ts +++ b/test/player-state.test.ts @@ -1,6 +1,6 @@ import fc from 'fast-check'; import { describe, expect, it } from 'vitest'; -import { isPlayerError, parseState, seekArgument, type PlayerState } from '../src/player-state'; +import { isPlayerError, parseState, type PlayerState } from '../src/player-state'; function state(line: string): PlayerState { const parsed = parseState(line); @@ -54,15 +54,6 @@ describe('parseState', () => { expect(state('playing=1;position=5').package).toBe(''); }); - it('round trips a position through the seek argument', () => { - for (const ms of [0, 1, 1000, 96153, 3600500, 12345678.9]) { - const argument = seekArgument(ms); - expect(argument).toMatch(/^\d+$/); - expect(state(`playing=0;position=${argument}`).positionMs).toBeCloseTo(ms, -1); - } - expect(seekArgument(-3)).toBe('0'); - }); - it('round trips any state line', () => { const pkg = fc.stringMatching(/^[a-z][a-z0-9_.]{0,30}$/); const speed = fc.double({ min: 0.25, max: 4, noNaN: true, noDefaultInfinity: true }); diff --git a/test/subtitles.test.ts b/test/subtitles.test.ts index 31d7259..355cf76 100644 --- a/test/subtitles.test.ts +++ b/test/subtitles.test.ts @@ -1,6 +1,6 @@ import fc from 'fast-check'; import { describe, expect, it } from 'vitest'; -import { cueIndexAt, decodeSubtitles, lastCueAt, parseSubtitles } from '../src/subtitles'; +import { decodeSubtitles, lastCueAt, parseSubtitles } from '../src/subtitles'; const SRT = `1 00:00:01,000 --> 00:00:03,500 @@ -109,38 +109,6 @@ describe('decodeSubtitles', () => { }); }); -describe('cueIndexAt', () => { - const cues = parseSubtitles(SRT); - - it('finds the active cue and returns -1 in gaps', () => { - expect(cueIndexAt(cues, 0.5)).toBe(-1); - expect(cueIndexAt(cues, 1)).toBe(0); - expect(cueIndexAt(cues, 3.49)).toBe(0); - expect(cueIndexAt(cues, 3.5)).toBe(1); - expect(cueIndexAt(cues, 6)).toBe(-1); - }); - - it('agrees with a linear scan over non-overlapping cues', () => { - // Each item is (gap before the cue, cue length). - const gapsAndLengths = fc.array(fc.tuple(fc.nat({ max: 20 }), fc.nat({ max: 20 })), { - maxLength: 30, - }); - fc.assert( - fc.property(gapsAndLengths, fc.nat({ max: 1300 }), (items, t) => { - let clock = 0; - const sorted = items.map(([gap, len]) => { - const start = clock + gap; - clock = start + len; - return { start, end: clock, text: 'x' }; - }); - const got = cueIndexAt(sorted, t); - const linear = sorted.findIndex((c) => c.start <= t && t < c.end); - expect(got).toBe(linear); - }), - ); - }); -}); - describe('lastCueAt', () => { const cues = [ { start: 1, end: 2 },