feat(dictionary): add Hachidori backend support

- Add backend selection, setup gating, Anki integration, and external host support
- Add launcher flags, documentation, packaging, and focused tests
- Open on-demand overlay modals on the first attempt
This commit is contained in:
2026-09-22 00:21:19 -07:00
parent 1508863dbb
commit d9fdc7ef6d
446 changed files with 109060 additions and 244 deletions
+19
View File
@@ -8,6 +8,7 @@ import {
isStandaloneTexthookerCommand,
parseArgs,
shouldRunYomitanOnlyStartup,
shouldRunDictionarySettingsOnlyStartup,
shouldStartApp,
} from './args';
@@ -475,3 +476,21 @@ test('hasExplicitCommand and shouldStartApp preserve command intent', () => {
assert.equal(hasExplicitCommand(setup), true);
assert.equal(shouldStartApp(setup), true);
});
test('Hachidori settings starts the app without overlay or mpv prerequisites', () => {
const args = parseArgs(['--hachidori']);
assert.equal(args.hachidori, true);
assert.equal(args.yomitan, false);
assert.equal(hasExplicitCommand(args), true);
assert.equal(shouldStartApp(args), true);
assert.equal(shouldRunDictionarySettingsOnlyStartup(args), true);
assert.equal(shouldRunYomitanOnlyStartup(args), false);
assert.equal(commandNeedsOverlayRuntime(args), false);
assert.equal(commandNeedsOverlayStartupPrereqs(args), false);
assert.equal(isStandaloneTexthookerCommand(parseArgs(['--texthooker', '--hachidori'])), false);
assert.equal(
shouldRunDictionarySettingsOnlyStartup(parseArgs(['--hachidori', '--start'])),
false,
);
assert.equal(shouldRunDictionarySettingsOnlyStartup(parseArgs(['--yomitan'])), true);
});
+11 -1
View File
@@ -13,6 +13,7 @@ export interface CliArgs {
toggleVisibleOverlay: boolean;
togglePrimarySubtitleBar: boolean;
yomitan: boolean;
hachidori: boolean;
settings: boolean;
syncWindow: boolean;
setup: boolean;
@@ -134,6 +135,7 @@ export function parseArgs(argv: string[]): CliArgs {
toggleVisibleOverlay: false,
togglePrimarySubtitleBar: false,
yomitan: false,
hachidori: false,
settings: false,
syncWindow: false,
setup: false,
@@ -285,6 +287,7 @@ export function parseArgs(argv: string[]): CliArgs {
else if (arg === '--toggle-visible-overlay') args.toggleVisibleOverlay = true;
else if (arg === '--toggle-primary-subtitle-bar') args.togglePrimarySubtitleBar = true;
else if (arg === '--yomitan') args.yomitan = true;
else if (arg === '--hachidori') args.hachidori = true;
else if (arg === '--settings') args.settings = true;
else if (arg === '--sync-window') args.syncWindow = true;
else if (arg === '--setup') args.setup = true;
@@ -568,6 +571,7 @@ export function hasExplicitCommand(args: CliArgs): boolean {
args.toggleVisibleOverlay ||
args.togglePrimarySubtitleBar ||
args.yomitan ||
args.hachidori ||
args.settings ||
args.syncWindow ||
args.setup ||
@@ -647,6 +651,7 @@ export function isStandaloneTexthookerCommand(args: CliArgs): boolean {
!args.toggleVisibleOverlay &&
!args.togglePrimarySubtitleBar &&
!args.yomitan &&
!args.hachidori &&
!args.settings &&
!args.syncWindow &&
!args.setup &&
@@ -719,6 +724,7 @@ export function shouldStartApp(args: CliArgs): boolean {
args.toggleVisibleOverlay ||
args.togglePrimarySubtitleBar ||
args.yomitan ||
args.hachidori ||
args.settings ||
args.syncWindow ||
args.setup ||
@@ -769,8 +775,12 @@ export function shouldStartApp(args: CliArgs): boolean {
}
export function shouldRunYomitanOnlyStartup(args: CliArgs): boolean {
return args.yomitan && !args.hachidori && shouldRunDictionarySettingsOnlyStartup(args);
}
export function shouldRunDictionarySettingsOnlyStartup(args: CliArgs): boolean {
return (
args.yomitan &&
(args.yomitan || args.hachidori) &&
!args.background &&
!args.start &&
!args.stop &&
+1
View File
@@ -24,6 +24,7 @@ test('printHelp includes configured texthooker port', () => {
assert.match(output, /--setup\s+Open first-run setup window/);
assert.match(output, /--settings\s+Open SubMiner settings window/);
assert.match(output, /--yomitan\s+Open Yomitan settings window/);
assert.match(output, /--hachidori\s+Open Hachidori settings window/);
assert.match(output, /--mark-watched\s+Mark current video watched and advance playlist/);
assert.match(output, /--anilist-status/);
assert.match(output, /--anilist-retry-queue/);
+1
View File
@@ -25,6 +25,7 @@ ${B}Overlay${R}
--show-visible-overlay Show subtitle overlay
--hide-visible-overlay Hide subtitle overlay
--yomitan Open Yomitan settings window
--hachidori Open Hachidori settings window
--settings Open SubMiner settings window
--setup Open first-run setup window
--auto-start-overlay Auto-hide mpv subs, show overlay on connect