fix(overlay): refresh current subtitle when enabling invisible layer

This commit is contained in:
2026-02-21 21:28:04 -08:00
parent 8b8a99dc79
commit 430c4e7120
3 changed files with 38 additions and 1 deletions

View File

@@ -76,3 +76,26 @@ test('subtitle processing falls back to plain subtitle when tokenization returns
assert.deepEqual(emitted, [{ text: 'fallback', tokens: null }]); 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: [] },
]);
});

View File

@@ -9,6 +9,7 @@ export interface SubtitleProcessingControllerDeps {
export interface SubtitleProcessingController { export interface SubtitleProcessingController {
onSubtitleChange: (text: string) => void; onSubtitleChange: (text: string) => void;
refreshCurrentSubtitle: () => void;
} }
export function createSubtitleProcessingController( export function createSubtitleProcessingController(
@@ -18,6 +19,7 @@ export function createSubtitleProcessingController(
let lastEmittedText = ''; let lastEmittedText = '';
let processing = false; let processing = false;
let staleDropCount = 0; let staleDropCount = 0;
let refreshRequested = false;
const now = deps.now ?? (() => Date.now()); const now = deps.now ?? (() => Date.now());
const processLatest = (): void => { const processLatest = (): void => {
@@ -30,6 +32,8 @@ export function createSubtitleProcessingController(
void (async () => { void (async () => {
while (true) { while (true) {
const text = latestText; const text = latestText;
const forceRefresh = refreshRequested;
refreshRequested = false;
const startedAtMs = now(); const startedAtMs = now();
if (!text.trim()) { if (!text.trim()) {
@@ -69,7 +73,7 @@ export function createSubtitleProcessingController(
}) })
.finally(() => { .finally(() => {
processing = false; processing = false;
if (latestText !== lastEmittedText) { if (refreshRequested || latestText !== lastEmittedText) {
processLatest(); processLatest();
} }
}); });
@@ -83,5 +87,12 @@ export function createSubtitleProcessingController(
latestText = text; latestText = text;
processLatest(); processLatest();
}, },
refreshCurrentSubtitle: () => {
if (!latestText.trim()) {
return;
}
refreshRequested = true;
processLatest();
},
}; };
} }

View File

@@ -2972,6 +2972,9 @@ function setVisibleOverlayVisible(visible: boolean): void {
function setInvisibleOverlayVisible(visible: boolean): void { function setInvisibleOverlayVisible(visible: boolean): void {
setInvisibleOverlayVisibleHandler(visible); setInvisibleOverlayVisibleHandler(visible);
if (visible) {
subtitleProcessingController.refreshCurrentSubtitle();
}
} }
function toggleVisibleOverlay(): void { function toggleVisibleOverlay(): void {