fix(youtube): keep auto captions on screen for their full span

YouTube's sentence-level ASR emits long caption rows with a placeholder
d="3000", while the caption actually displays until the next window
event. Trusting `d` made long lines vanish mid-speech and leave a blank
gap until the next cue.

Rolling auto-caption documents (rows with a="1") now end each cue at the
next event timestamp instead of t + d, matching YouTube's own display
timing. Manual and non-rolling TimedText keep duration-based timing so
real silence gaps are preserved.
This commit is contained in:
2026-08-26 00:07:42 -07:00
parent c2c25c0da6
commit f8ca8681dc
3 changed files with 78 additions and 7 deletions
@@ -39,6 +39,36 @@ test('convertYoutubeTimedTextToVtt does not swallow text after zero-length overl
);
});
test('convertYoutubeTimedTextToVtt extends rolling captions to the next window event', () => {
// Real-world shape of YouTube's sentence-level auto captions: window-append
// filler rows (a="1", sometimes without d) mark the display timeline, while
// long text rows carry a placeholder d="3000" far shorter than the speech.
const result = convertYoutubeTimedTextToVtt(
[
'<timedtext><body>',
'<p t="98550" d="3010" w="1" a="1">\n</p>',
'<p t="98560" d="3000" w="1"><s ac="0">ありがとうって言えないよね。こんなんじゃ。</s></p>',
'<p t="106950" w="1" a="1">\n</p>',
'<p t="106960" d="3799" w="1"><s ac="0">私だったら無理だよ。</s></p>',
'</body></timedtext>',
].join('\n'),
);
assert.equal(
result,
[
'WEBVTT',
'',
'00:01:38.560 --> 00:01:46.950',
'ありがとうって言えないよね。こんなんじゃ。',
'',
'00:01:46.960 --> 00:01:50.759',
'私だったら無理だよ。',
'',
].join('\n'),
);
});
test('normalizeYoutubeAutoVtt strips cumulative rolling-caption prefixes', () => {
const result = normalizeYoutubeAutoVtt(
[