mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-03-20 12:11:28 -07:00
Enhance AniList character dictionary sync and subtitle features (#15)
This commit is contained in:
@@ -4,6 +4,7 @@ import process from 'node:process';
|
||||
|
||||
import { createTokenizerDepsRuntime, tokenizeSubtitle } from '../src/core/services/tokenizer.js';
|
||||
import { createFrequencyDictionaryLookup } from '../src/core/services/frequency-dictionary.js';
|
||||
import { resolveYomitanExtensionPath as resolveBuiltYomitanExtensionPath } from '../src/core/services/yomitan-extension-paths.js';
|
||||
import { MecabTokenizer } from '../src/mecab-tokenizer.js';
|
||||
import type { MergedToken, FrequencyDictionaryLookup } from '../src/types.js';
|
||||
|
||||
@@ -14,7 +15,7 @@ interface CliOptions {
|
||||
emitDiagnostics: boolean;
|
||||
mecabCommand?: string;
|
||||
mecabDictionaryPath?: string;
|
||||
forceMecabOnly?: boolean;
|
||||
forceMecabOnly: boolean;
|
||||
yomitanExtensionPath?: string;
|
||||
yomitanUserDataPath?: string;
|
||||
emitColoredLine: boolean;
|
||||
@@ -48,7 +49,7 @@ function parseCliArgs(argv: string[]): CliOptions {
|
||||
let colorBand1 = '#ed8796';
|
||||
let colorBand2 = '#f5a97f';
|
||||
let colorBand3 = '#f9e2af';
|
||||
let colorBand4 = '#a6e3a1';
|
||||
let colorBand4 = '#8bd5ca';
|
||||
let colorBand5 = '#8aadf4';
|
||||
let colorKnown = '#a6da95';
|
||||
let colorNPlusOne = '#c6a0f6';
|
||||
@@ -94,7 +95,7 @@ function parseCliArgs(argv: string[]): CliOptions {
|
||||
if (!next) {
|
||||
throw new Error('Missing value for --yomitan-extension');
|
||||
}
|
||||
yomitanExtensionPath = path.resolve(next);
|
||||
yomitanExtensionPath = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -103,7 +104,7 @@ function parseCliArgs(argv: string[]): CliOptions {
|
||||
if (!next) {
|
||||
throw new Error('Missing value for --yomitan-user-data');
|
||||
}
|
||||
yomitanUserDataPath = path.resolve(next);
|
||||
yomitanUserDataPath = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -225,12 +226,12 @@ function parseCliArgs(argv: string[]): CliOptions {
|
||||
}
|
||||
|
||||
if (arg.startsWith('--yomitan-extension=')) {
|
||||
yomitanExtensionPath = path.resolve(arg.slice('--yomitan-extension='.length));
|
||||
yomitanExtensionPath = arg.slice('--yomitan-extension='.length);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg.startsWith('--yomitan-user-data=')) {
|
||||
yomitanUserDataPath = path.resolve(arg.slice('--yomitan-user-data='.length));
|
||||
yomitanUserDataPath = arg.slice('--yomitan-user-data='.length);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -524,7 +525,10 @@ function destroyUnknownParserWindow(window: unknown): void {
|
||||
}
|
||||
}
|
||||
|
||||
async function createYomitanRuntimeState(userDataPath: string): Promise<YomitanRuntimeState> {
|
||||
async function createYomitanRuntimeState(
|
||||
userDataPath: string,
|
||||
extensionPath?: string,
|
||||
): Promise<YomitanRuntimeState> {
|
||||
const state: YomitanRuntimeState = {
|
||||
yomitanExt: null,
|
||||
parserWindow: null,
|
||||
@@ -547,6 +551,7 @@ async function createYomitanRuntimeState(userDataPath: string): Promise<YomitanR
|
||||
const loadYomitanExtension = (await import('../src/core/services/yomitan-extension-loader.js'))
|
||||
.loadYomitanExtension as (options: {
|
||||
userDataPath: string;
|
||||
extensionPath?: string;
|
||||
getYomitanParserWindow: () => unknown;
|
||||
setYomitanParserWindow: (window: unknown) => void;
|
||||
setYomitanParserReadyPromise: (promise: Promise<void> | null) => void;
|
||||
@@ -556,6 +561,7 @@ async function createYomitanRuntimeState(userDataPath: string): Promise<YomitanR
|
||||
|
||||
const extension = await loadYomitanExtension({
|
||||
userDataPath,
|
||||
extensionPath,
|
||||
getYomitanParserWindow: () => state.parserWindow,
|
||||
setYomitanParserWindow: (window) => {
|
||||
state.parserWindow = window;
|
||||
@@ -589,17 +595,16 @@ async function createYomitanRuntimeStateWithSearch(
|
||||
userDataPath: string,
|
||||
extensionPath?: string,
|
||||
): Promise<YomitanRuntimeState> {
|
||||
const preferredPath = extensionPath ? path.resolve(extensionPath) : undefined;
|
||||
const defaultVendorPath = path.resolve(process.cwd(), 'vendor', 'yomitan');
|
||||
const candidates = [...(preferredPath ? [preferredPath] : []), defaultVendorPath];
|
||||
const resolvedExtensionPath = resolveBuiltYomitanExtensionPath({
|
||||
explicitPath: extensionPath,
|
||||
cwd: process.cwd(),
|
||||
});
|
||||
const candidates = resolvedExtensionPath ? [resolvedExtensionPath] : [];
|
||||
|
||||
for (const candidate of candidates) {
|
||||
if (!candidate) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
if (fs.existsSync(path.join(candidate, 'manifest.json'))) {
|
||||
const state = await createYomitanRuntimeState(userDataPath);
|
||||
const state = await createYomitanRuntimeState(userDataPath, candidate);
|
||||
if (state.available) {
|
||||
return state;
|
||||
}
|
||||
@@ -613,7 +618,7 @@ async function createYomitanRuntimeStateWithSearch(
|
||||
}
|
||||
}
|
||||
|
||||
return createYomitanRuntimeState(userDataPath);
|
||||
return createYomitanRuntimeState(userDataPath, resolvedExtensionPath ?? undefined);
|
||||
}
|
||||
|
||||
async function getFrequencyLookup(dictionaryPath: string): Promise<FrequencyDictionaryLookup> {
|
||||
@@ -678,7 +683,7 @@ function getBandColor(
|
||||
}
|
||||
const normalizedBand = Math.ceil((safeRank / topX) * bandedColors.length);
|
||||
const band = Math.min(bandedColors.length, Math.max(1, normalizedBand));
|
||||
return bandedColors[band - 1];
|
||||
return bandedColors[band - 1] ?? colorSingle;
|
||||
}
|
||||
|
||||
function getTokenColor(token: MergedToken, args: CliOptions): string {
|
||||
@@ -845,7 +850,26 @@ async function main(): Promise<void> {
|
||||
? simplifyTokenWithVerbose(token, getFrequencyRank)
|
||||
: simplifyToken(token),
|
||||
) ?? null;
|
||||
const diagnostics = {
|
||||
const diagnostics: {
|
||||
yomitan: {
|
||||
available: boolean;
|
||||
loaded: boolean;
|
||||
forceMecabOnly: boolean;
|
||||
note: string | null;
|
||||
};
|
||||
mecab: {
|
||||
command: string;
|
||||
dictionaryPath: string | null;
|
||||
available: boolean;
|
||||
status?: 'ok' | 'no-tokens';
|
||||
note?: string;
|
||||
};
|
||||
tokenizer: {
|
||||
sourceHint: 'none' | 'yomitan-merged' | 'mecab-merge';
|
||||
mergedTokenCount: number;
|
||||
totalTokenCount: number;
|
||||
};
|
||||
} = {
|
||||
yomitan: {
|
||||
available: Boolean(yomitanState?.available),
|
||||
loaded: useYomitan,
|
||||
@@ -864,11 +888,11 @@ async function main(): Promise<void> {
|
||||
},
|
||||
};
|
||||
if (tokens === null) {
|
||||
diagnostics.mecab['status'] = 'no-tokens';
|
||||
diagnostics.mecab['note'] =
|
||||
diagnostics.mecab.status = 'no-tokens';
|
||||
diagnostics.mecab.note =
|
||||
'MeCab returned no parseable tokens. This is often caused by a missing/invalid MeCab dictionary path.';
|
||||
} else {
|
||||
diagnostics.mecab['status'] = 'ok';
|
||||
diagnostics.mecab.status = 'ok';
|
||||
}
|
||||
|
||||
const output = {
|
||||
|
||||
Reference in New Issue
Block a user