From 35946624c29f4c96daaf6e316834bc93f03052c9 Mon Sep 17 00:00:00 2001 From: sudacode Date: Sun, 15 Mar 2026 12:46:43 -0700 Subject: [PATCH] feat: add preCacheTokenization and isCacheFull to SubtitleProcessingController --- .../subtitle-processing-controller.test.ts | 42 +++++++++++++++++++ .../subtitle-processing-controller.ts | 8 ++++ 2 files changed, 50 insertions(+) diff --git a/src/core/services/subtitle-processing-controller.test.ts b/src/core/services/subtitle-processing-controller.test.ts index 860eb5e..cc6095b 100644 --- a/src/core/services/subtitle-processing-controller.test.ts +++ b/src/core/services/subtitle-processing-controller.test.ts @@ -170,3 +170,45 @@ test('subtitle processing cache invalidation only affects future subtitle events assert.equal(callsByText.get('same'), 2); }); + +test('preCacheTokenization stores entry that is returned on next subtitle 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.preCacheTokenization('予め', { text: '予め', tokens: [] }); + controller.onSubtitleChange('予め'); + await flushMicrotasks(); + + assert.equal(tokenizeCalls, 0, 'should not call tokenize when pre-cached'); + assert.deepEqual(emitted, [{ text: '予め', tokens: [] }]); +}); + +test('isCacheFull returns false when cache is below limit', () => { + const controller = createSubtitleProcessingController({ + tokenizeSubtitle: async (text) => ({ text, tokens: null }), + emitSubtitle: () => {}, + }); + + assert.equal(controller.isCacheFull(), false); +}); + +test('isCacheFull returns true when cache reaches limit', async () => { + const controller = createSubtitleProcessingController({ + tokenizeSubtitle: async (text) => ({ text, tokens: [] }), + emitSubtitle: () => {}, + }); + + // Fill cache to the 256 limit + for (let i = 0; i < 256; i += 1) { + controller.preCacheTokenization(`line-${i}`, { text: `line-${i}`, tokens: [] }); + } + + assert.equal(controller.isCacheFull(), true); +}); diff --git a/src/core/services/subtitle-processing-controller.ts b/src/core/services/subtitle-processing-controller.ts index 20ea805..aebe820 100644 --- a/src/core/services/subtitle-processing-controller.ts +++ b/src/core/services/subtitle-processing-controller.ts @@ -11,6 +11,8 @@ export interface SubtitleProcessingController { onSubtitleChange: (text: string) => void; refreshCurrentSubtitle: (textOverride?: string) => void; invalidateTokenizationCache: () => void; + preCacheTokenization: (text: string, data: SubtitleData) => void; + isCacheFull: () => boolean; } export function createSubtitleProcessingController( @@ -130,5 +132,11 @@ export function createSubtitleProcessingController( invalidateTokenizationCache: () => { tokenizationCache.clear(); }, + preCacheTokenization: (text: string, data: SubtitleData) => { + setCachedTokenization(text, data); + }, + isCacheFull: () => { + return tokenizationCache.size >= SUBTITLE_TOKENIZATION_CACHE_LIMIT; + }, }; }