fix(startup): async dictionary loading and unblock first tokenization

- move JLPT/frequency dictionary init off sync fs APIs and add cooperative yielding during entry processing

- decouple first tokenization from full warmup by gating only on Yomitan readiness while MeCab/dictionary warmups continue in parallel

- update mpv pause-until-ready OSD copy to tokenization-focused wording and refresh gate regression assertions
This commit is contained in:
2026-03-02 01:48:17 -08:00
parent 737101fe9e
commit aff4e91bbb
8 changed files with 357 additions and 38 deletions

View File

@@ -142,21 +142,40 @@ export function composeMpvRuntimeHandlers<
return nPlusOneEnabled || jlptEnabled || frequencyEnabled;
};
let tokenizationWarmupInFlight: Promise<void> | null = null;
let tokenizationPrerequisiteWarmupInFlight: Promise<void> | null = null;
let tokenizationPrerequisiteWarmupCompleted = false;
let tokenizationWarmupCompleted = false;
const ensureTokenizationPrerequisites = (): Promise<void> => {
if (tokenizationPrerequisiteWarmupCompleted) {
return Promise.resolve();
}
if (!tokenizationPrerequisiteWarmupInFlight) {
tokenizationPrerequisiteWarmupInFlight = options.warmups.startBackgroundWarmupsMainDeps
.ensureYomitanExtensionLoaded()
.then(() => {
tokenizationPrerequisiteWarmupCompleted = true;
})
.finally(() => {
tokenizationPrerequisiteWarmupInFlight = null;
});
}
return tokenizationPrerequisiteWarmupInFlight;
};
const startTokenizationWarmups = (): Promise<void> => {
if (tokenizationWarmupCompleted) {
return Promise.resolve();
}
if (!tokenizationWarmupInFlight) {
tokenizationWarmupInFlight = (async () => {
await options.warmups.startBackgroundWarmupsMainDeps.ensureYomitanExtensionLoaded();
const warmupTasks: Promise<unknown>[] = [ensureTokenizationPrerequisites()];
if (
shouldInitializeMecabForAnnotations() &&
!options.tokenizer.createMecabTokenizerAndCheckMainDeps.getMecabTokenizer()
) {
await createMecabTokenizerAndCheck().catch(() => {});
warmupTasks.push(createMecabTokenizerAndCheck().catch(() => {}));
}
await prewarmSubtitleDictionaries({ showLoadingOsd: true });
warmupTasks.push(prewarmSubtitleDictionaries({ showLoadingOsd: true }).catch(() => {}));
await Promise.all(warmupTasks);
tokenizationWarmupCompleted = true;
})().finally(() => {
tokenizationWarmupInFlight = null;
@@ -165,9 +184,8 @@ export function composeMpvRuntimeHandlers<
return tokenizationWarmupInFlight;
};
const tokenizeSubtitle = async (text: string): Promise<TTokenizedSubtitle> => {
if (!tokenizationWarmupCompleted) {
await startTokenizationWarmups();
}
if (!tokenizationWarmupCompleted) void startTokenizationWarmups();
await ensureTokenizationPrerequisites();
return options.tokenizer.tokenizeSubtitle(
text,
options.tokenizer.createTokenizerRuntimeDeps(buildTokenizerDepsHandler()),