mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-08-05 07:21:34 -07:00
fix(character-dictionary): drop single-letter mob name disambiguators
- AniList mob names like 女子A/"Joshi A" romanize their trailing disambiguator letter into a single kana term (A → ア) that collides with common interjections (あ〜); filter these out unless kanji - bump CHARACTER_DICTIONARY_FORMAT_VERSION to 20 to invalidate cached dictionaries built with the old term set - add tests covering the dropped disambiguator and a kept single-kanji name part
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
export const ANILIST_GRAPHQL_URL = 'https://graphql.anilist.co';
|
export const ANILIST_GRAPHQL_URL = 'https://graphql.anilist.co';
|
||||||
export const ANILIST_REQUEST_DELAY_MS = 2000;
|
export const ANILIST_REQUEST_DELAY_MS = 2000;
|
||||||
export const CHARACTER_IMAGE_DOWNLOAD_DELAY_MS = 250;
|
export const CHARACTER_IMAGE_DOWNLOAD_DELAY_MS = 250;
|
||||||
export const CHARACTER_DICTIONARY_FORMAT_VERSION = 19;
|
export const CHARACTER_DICTIONARY_FORMAT_VERSION = 20;
|
||||||
export const CHARACTER_DICTIONARY_MERGED_TITLE = 'SubMiner Character Dictionary';
|
export const CHARACTER_DICTIONARY_MERGED_TITLE = 'SubMiner Character Dictionary';
|
||||||
|
|
||||||
export const HONORIFIC_SUFFIXES = [
|
export const HONORIFIC_SUFFIXES = [
|
||||||
|
|||||||
@@ -36,3 +36,35 @@ test('buildNameTerms adds surname honorifics from Japanese localized aliases', (
|
|||||||
assert.ok(terms.includes('馬渕さん'));
|
assert.ok(terms.includes('馬渕さん'));
|
||||||
assert.ok(!terms.includes('송치'));
|
assert.ok(!terms.includes('송치'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('buildNameTerms drops the disambiguator letter of a mob character name', () => {
|
||||||
|
const terms = buildNameTerms(
|
||||||
|
characterRecord({
|
||||||
|
firstNameHint: '',
|
||||||
|
lastNameHint: '',
|
||||||
|
fullName: 'Joshi A',
|
||||||
|
nativeName: '女子A',
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
// ア would match every あ〜 in the subtitles; the letter is a disambiguator
|
||||||
|
// (Girl A / Girl B), not a name.
|
||||||
|
assert.ok(!terms.includes('ア'));
|
||||||
|
assert.ok(!terms.includes('アさん'));
|
||||||
|
assert.ok(terms.includes('女子A'));
|
||||||
|
assert.ok(terms.includes('ジョシア'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('buildNameTerms keeps a single-kanji name part', () => {
|
||||||
|
const terms = buildNameTerms(
|
||||||
|
characterRecord({
|
||||||
|
firstNameHint: 'Sora',
|
||||||
|
lastNameHint: 'Yamada',
|
||||||
|
fullName: 'Sora Yamada',
|
||||||
|
nativeName: '山田 空',
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.ok(terms.includes('山田'));
|
||||||
|
assert.ok(terms.includes('空'));
|
||||||
|
});
|
||||||
|
|||||||
@@ -42,6 +42,15 @@ export function expandRawNameVariants(rawName: string): string[] {
|
|||||||
return [...variants];
|
return [...variants];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AniList disambiguates unnamed mob characters with a trailing letter (女子A /
|
||||||
|
// "Joshi A"), and a single letter romanizes into a single-kana alias (A → ア)
|
||||||
|
// that collides with interjections (あ〜 matching ア). A one-character form is
|
||||||
|
// only a real lookup target when it is kanji, so every other single-character
|
||||||
|
// form is dropped before it can become a term.
|
||||||
|
function isUsableNameTerm(name: string): boolean {
|
||||||
|
return [...name].length > 1 || containsKanji(name);
|
||||||
|
}
|
||||||
|
|
||||||
export function isJapaneseNameSplitCandidate(name: string): boolean {
|
export function isJapaneseNameSplitCandidate(name: string): boolean {
|
||||||
const compact = name.replace(/[\s\u3000・・·•]/g, '');
|
const compact = name.replace(/[\s\u3000・・·•]/g, '');
|
||||||
return (
|
return (
|
||||||
@@ -97,8 +106,11 @@ export function buildNameTerms(
|
|||||||
|
|
||||||
const split = name.split(/[\s\u3000]+/).filter((part) => part.trim().length > 0);
|
const split = name.split(/[\s\u3000]+/).filter((part) => part.trim().length > 0);
|
||||||
if (split.length === 2) {
|
if (split.length === 2) {
|
||||||
target.add(split[0]!);
|
for (const part of split) {
|
||||||
target.add(split[1]!);
|
if (isUsableNameTerm(part)) {
|
||||||
|
target.add(part);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const splitByMiddleDot = name
|
const splitByMiddleDot = name
|
||||||
@@ -107,7 +119,9 @@ export function buildNameTerms(
|
|||||||
.filter((part) => part.length > 0);
|
.filter((part) => part.length > 0);
|
||||||
if (splitByMiddleDot.length >= 2) {
|
if (splitByMiddleDot.length >= 2) {
|
||||||
for (const part of splitByMiddleDot) {
|
for (const part of splitByMiddleDot) {
|
||||||
target.add(part);
|
if (isUsableNameTerm(part)) {
|
||||||
|
target.add(part);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,6 +150,7 @@ export function buildNameTerms(
|
|||||||
|
|
||||||
const withHonorifics = new Set<string>();
|
const withHonorifics = new Set<string>();
|
||||||
for (const entry of base) {
|
for (const entry of base) {
|
||||||
|
if (!isUsableNameTerm(entry)) continue;
|
||||||
withHonorifics.add(entry);
|
withHonorifics.add(entry);
|
||||||
for (const suffix of HONORIFIC_SUFFIXES) {
|
for (const suffix of HONORIFIC_SUFFIXES) {
|
||||||
withHonorifics.add(`${entry}${suffix.term}`);
|
withHonorifics.add(`${entry}${suffix.term}`);
|
||||||
|
|||||||
Reference in New Issue
Block a user