fix(dictionary): complete Hachidori imports and mining integration

This commit is contained in:
2026-09-22 15:01:23 -07:00
parent 15c74ef502
commit ab5e50adac
44 changed files with 756 additions and 40 deletions
+2
View File
@@ -23,6 +23,7 @@ export type {
const {
dictionaryBackend,
hachidori,
subtitlePosition,
keybindings,
websocket,
@@ -59,6 +60,7 @@ const { stats } = STATS_DEFAULT_CONFIG;
export const DEFAULT_CONFIG: ResolvedConfig = {
subtitleGeneration: { ...DEFAULT_SUBTITLE_GENERATION_CONFIG },
dictionaryBackend,
hachidori,
subtitlePosition,
keybindings,
websocket,
+2
View File
@@ -3,6 +3,7 @@ import { ResolvedConfig } from '../../types/config';
export const CORE_DEFAULT_CONFIG: Pick<
ResolvedConfig,
| 'dictionaryBackend'
| 'hachidori'
| 'subtitlePosition'
| 'keybindings'
| 'websocket'
@@ -20,6 +21,7 @@ export const CORE_DEFAULT_CONFIG: Pick<
| 'auto_start_overlay'
> = {
dictionaryBackend: 'yomitan',
hachidori: { externalHostManagementUrl: '' },
subtitlePosition: { yPercent: 10 },
keybindings: [],
websocket: {
+7
View File
@@ -81,6 +81,13 @@ export function buildCoreConfigOptionRegistry(
] as const;
return [
{
path: 'hachidori.externalHostManagementUrl',
kind: 'string',
defaultValue: defaultConfig.hachidori.externalHostManagementUrl,
description:
'Docker host management URL for automatic character dictionary uploads and replacement. Empty disables external uploads.',
},
{
path: 'dictionaryBackend',
kind: 'enum',
@@ -9,6 +9,14 @@ const CORE_TEMPLATE_SECTIONS: ConfigTemplateSection[] = [
],
key: 'dictionaryBackend',
},
{
title: 'Hachidori External Dictionary Imports',
description: [
'Configure the linked Docker host management URL, for example http://127.0.0.1:8780.',
],
notes: ['Used only while Hachidori is linked to an external host.'],
key: 'hachidori',
},
{
title: 'Japanese Subtitle Generation',
description: [
+16
View File
@@ -2,10 +2,26 @@ import { ResolveContext } from './context';
import { applyControllerConfig } from './controller';
import { isNotificationType, isOverlayNotificationPosition } from '../../types/notification';
import { asBoolean, asNumber, asString, isObject } from './shared';
import { parseHachidoriManagementUrl } from '../../shared/hachidori-sharing';
export function applyCoreDomainConfig(context: ResolveContext): void {
const { src, resolved, warn } = context;
if (isObject(src.hachidori) && src.hachidori.externalHostManagementUrl !== undefined) {
try {
resolved.hachidori.externalHostManagementUrl = parseHachidoriManagementUrl(
src.hachidori.externalHostManagementUrl,
);
} catch {
warn(
'hachidori.externalHostManagementUrl',
src.hachidori.externalHostManagementUrl,
resolved.hachidori.externalHostManagementUrl,
'Expected an HTTP(S) origin or an empty string.',
);
}
}
if (src.dictionaryBackend === 'yomitan' || src.dictionaryBackend === 'hachidori') {
resolved.dictionaryBackend = src.dictionaryBackend;
} else if (src.dictionaryBackend !== undefined) {
@@ -28,3 +28,24 @@ test('unknown dictionary backend values warn and preserve the default', () => {
assert.equal(warnings[0]?.path, 'dictionaryBackend');
}
});
test('Hachidori external import URL accepts HTTP origins and rejects invalid targets', () => {
assert.equal(resolveConfig({}).resolved.hachidori.externalHostManagementUrl, '');
const result = resolveConfig({
hachidori: { externalHostManagementUrl: 'http://127.0.0.1:8780/' },
});
assert.equal(result.resolved.hachidori.externalHostManagementUrl, 'http://127.0.0.1:8780');
assert.deepEqual(result.warnings, []);
for (const value of [
'file:///tmp/dict',
'http://host/import',
'http://user:password@host',
true,
]) {
const { context, warnings } = createResolveContext({});
context.src.hachidori = { externalHostManagementUrl: value };
applyCoreDomainConfig(context);
assert.equal(context.resolved.hachidori.externalHostManagementUrl, '');
assert.equal(warnings[0]?.path, 'hachidori.externalHostManagementUrl');
}
});
+1 -1
View File
@@ -341,7 +341,7 @@ function humanizePath(path: string): string {
}
function categoryAndSection(path: string): { category: ConfigSettingsCategory; section: string } {
if (path === 'dictionaryBackend') {
if (path === 'dictionaryBackend' || path.startsWith('hachidori.')) {
return { category: 'integrations', section: 'Dictionary Lookup' };
}
if (