Add vendor dict fallback logic

This commit is contained in:
2026-02-15 22:45:03 -08:00
parent dae1f817e0
commit 01a48f4714
21 changed files with 1194 additions and 19 deletions

View File

@@ -0,0 +1,80 @@
import * as path from "path";
import type { FrequencyDictionaryLookup } from "../types";
import { createFrequencyDictionaryLookupService } from "../core/services";
export interface FrequencyDictionarySearchPathDeps {
getDictionaryRoots: () => string[];
getSourcePath?: () => string | undefined;
}
export interface FrequencyDictionaryRuntimeDeps {
isFrequencyDictionaryEnabled: () => boolean;
getSearchPaths: () => string[];
setFrequencyRankLookup: (lookup: FrequencyDictionaryLookup) => void;
log: (message: string) => void;
}
let frequencyDictionaryLookupInitialized = false;
let frequencyDictionaryLookupInitialization: Promise<void> | null = null;
export function getFrequencyDictionarySearchPaths(
deps: FrequencyDictionarySearchPathDeps,
): string[] {
const dictionaryRoots = deps.getDictionaryRoots();
const sourcePath = deps.getSourcePath?.();
const rawSearchPaths: string[] = [];
if (sourcePath && sourcePath.trim()) {
rawSearchPaths.push(sourcePath.trim());
rawSearchPaths.push(path.join(sourcePath.trim(), "frequency-dictionary"));
rawSearchPaths.push(path.join(sourcePath.trim(), "vendor", "frequency-dictionary"));
}
for (const dictionaryRoot of dictionaryRoots) {
rawSearchPaths.push(dictionaryRoot);
rawSearchPaths.push(path.join(dictionaryRoot, "frequency-dictionary"));
rawSearchPaths.push(path.join(dictionaryRoot, "vendor", "frequency-dictionary"));
}
return [...new Set(rawSearchPaths)];
}
export async function initializeFrequencyDictionaryLookup(
deps: FrequencyDictionaryRuntimeDeps,
): Promise<void> {
const lookup = await createFrequencyDictionaryLookupService({
searchPaths: deps.getSearchPaths(),
log: deps.log,
});
deps.setFrequencyRankLookup(lookup);
}
export async function ensureFrequencyDictionaryLookup(
deps: FrequencyDictionaryRuntimeDeps,
): Promise<void> {
if (!deps.isFrequencyDictionaryEnabled()) {
return;
}
if (frequencyDictionaryLookupInitialized) {
return;
}
if (!frequencyDictionaryLookupInitialization) {
frequencyDictionaryLookupInitialization = initializeFrequencyDictionaryLookup(deps)
.then(() => {
frequencyDictionaryLookupInitialized = true;
})
.catch((error) => {
frequencyDictionaryLookupInitialization = null;
throw error;
});
}
await frequencyDictionaryLookupInitialization;
}
export function createFrequencyDictionaryRuntimeService(
deps: FrequencyDictionaryRuntimeDeps,
): { ensureFrequencyDictionaryLookup: () => Promise<void> } {
return {
ensureFrequencyDictionaryLookup: () => ensureFrequencyDictionaryLookup(deps),
};
}

View File

@@ -7,6 +7,7 @@ import type {
SubtitlePosition,
KikuFieldGroupingChoice,
JlptLevel,
FrequencyDictionaryLookup,
} from "../types";
import type { CliArgs } from "../cli/args";
import type { SubtitleTimingTracker } from "../subtitle-timing-tracker";
@@ -55,6 +56,7 @@ export interface AppState {
autoStartOverlay: boolean;
texthookerOnlyMode: boolean;
jlptLevelLookup: (term: string) => JlptLevel | null;
frequencyRankLookup: FrequencyDictionaryLookup;
}
export interface AppStateInitialValues {
@@ -115,6 +117,7 @@ export function createAppState(values: AppStateInitialValues): AppState {
autoStartOverlay: values.autoStartOverlay ?? false,
texthookerOnlyMode: values.texthookerOnlyMode ?? false,
jlptLevelLookup: () => null,
frequencyRankLookup: () => null,
};
}