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
+38
View File
@@ -18,6 +18,44 @@
import { clipboard, contextBridge, ipcRenderer, IpcRendererEvent, webUtils } from 'electron';
import { resolveOverlayLayerFromArgv } from './preload-args';
import {
DICTIONARY_EXTERNAL_LINK_CHANNEL,
parseDictionaryExternalUrl,
} from './shared/dictionary-external-link';
window.addEventListener('hachidori-open-external', (event) => {
if (!(event instanceof CustomEvent)) return;
const detail: unknown = event.detail;
if (
!detail ||
typeof detail !== 'object' ||
!('requestId' in detail) ||
typeof detail.requestId !== 'string' ||
!('url' in detail)
)
return;
const requestId = detail.requestId;
void Promise.resolve()
.then(() =>
ipcRenderer.invoke(DICTIONARY_EXTERNAL_LINK_CHANNEL, parseDictionaryExternalUrl(detail.url)),
)
.then(() => {
window.dispatchEvent(
new CustomEvent('hachidori-open-external-result', { detail: { requestId, ok: true } }),
);
})
.catch((error: unknown) => {
window.dispatchEvent(
new CustomEvent('hachidori-open-external-result', {
detail: {
requestId,
ok: false,
error: error instanceof Error ? error.message : String(error),
},
}),
);
});
});
import type {
SubtitleData,
SubtitlePosition,