diff --git a/src/core/services/subtitle-processing-controller.test.ts b/src/core/services/subtitle-processing-controller.test.ts index f12afeb..94ca5c1 100644 --- a/src/core/services/subtitle-processing-controller.test.ts +++ b/src/core/services/subtitle-processing-controller.test.ts @@ -76,3 +76,26 @@ test('subtitle processing falls back to plain subtitle when tokenization returns assert.deepEqual(emitted, [{ text: 'fallback', tokens: null }]); }); + +test('subtitle processing can refresh current subtitle without text change', async () => { + const emitted: SubtitleData[] = []; + let tokenizeCalls = 0; + const controller = createSubtitleProcessingController({ + tokenizeSubtitle: async (text) => { + tokenizeCalls += 1; + return { text, tokens: [] }; + }, + emitSubtitle: (payload) => emitted.push(payload), + }); + + controller.onSubtitleChange('same'); + await flushMicrotasks(); + controller.refreshCurrentSubtitle(); + await flushMicrotasks(); + + assert.equal(tokenizeCalls, 2); + assert.deepEqual(emitted, [ + { text: 'same', tokens: [] }, + { text: 'same', tokens: [] }, + ]); +}); diff --git a/src/core/services/subtitle-processing-controller.ts b/src/core/services/subtitle-processing-controller.ts index 5d74e0a..a88f2cd 100644 --- a/src/core/services/subtitle-processing-controller.ts +++ b/src/core/services/subtitle-processing-controller.ts @@ -9,6 +9,7 @@ export interface SubtitleProcessingControllerDeps { export interface SubtitleProcessingController { onSubtitleChange: (text: string) => void; + refreshCurrentSubtitle: () => void; } export function createSubtitleProcessingController( @@ -18,6 +19,7 @@ export function createSubtitleProcessingController( let lastEmittedText = ''; let processing = false; let staleDropCount = 0; + let refreshRequested = false; const now = deps.now ?? (() => Date.now()); const processLatest = (): void => { @@ -30,6 +32,8 @@ export function createSubtitleProcessingController( void (async () => { while (true) { const text = latestText; + const forceRefresh = refreshRequested; + refreshRequested = false; const startedAtMs = now(); if (!text.trim()) { @@ -69,7 +73,7 @@ export function createSubtitleProcessingController( }) .finally(() => { processing = false; - if (latestText !== lastEmittedText) { + if (refreshRequested || latestText !== lastEmittedText) { processLatest(); } }); @@ -83,5 +87,12 @@ export function createSubtitleProcessingController( latestText = text; processLatest(); }, + refreshCurrentSubtitle: () => { + if (!latestText.trim()) { + return; + } + refreshRequested = true; + processLatest(); + }, }; } diff --git a/src/main.ts b/src/main.ts index 140bc07..4335e96 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2972,6 +2972,9 @@ function setVisibleOverlayVisible(visible: boolean): void { function setInvisibleOverlayVisible(visible: boolean): void { setInvisibleOverlayVisibleHandler(visible); + if (visible) { + subtitleProcessingController.refreshCurrentSubtitle(); + } } function toggleVisibleOverlay(): void {