mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-10-25 11:35:25 -07:00
feat(dictionary): add Hachidori backend support (#266)
This commit is contained in:
1 parent
e690ffba07
commit
cbaa4626e1
143 files changed
+5564
-305
No files matched your search
@@ -0,0 +1,69 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { createHash } from 'node:crypto';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const source = path.join(repoRoot, 'vendor', 'hachidori');
|
||||
const output = path.join(repoRoot, 'build', 'hachidori');
|
||||
const provenance = JSON.parse(fs.readFileSync(path.join(source, 'SOURCE.json'), 'utf8'));
|
||||
|
||||
// Upstream commits the engine binaries. Verify the pinned bytes before staging
|
||||
// so ordinary app builds need neither Emscripten nor network access.
|
||||
for (const [file, expected] of Object.entries(provenance.artifacts)) {
|
||||
const actual = createHash('sha256')
|
||||
.update(fs.readFileSync(path.join(source, file)))
|
||||
.digest('hex');
|
||||
if (actual !== expected) throw new Error(`Hachidori artifact checksum mismatch: ${file}`);
|
||||
}
|
||||
const extension = path.join(source, 'extension');
|
||||
const manifest = JSON.parse(fs.readFileSync(path.join(extension, 'manifest.json'), 'utf8'));
|
||||
for (const file of [
|
||||
manifest.options_page,
|
||||
manifest.background.service_worker,
|
||||
'offscreen.html',
|
||||
...manifest.content_scripts.flatMap(({ js, css }) => [...js, ...css]),
|
||||
]) {
|
||||
if (!fs.existsSync(path.join(extension, file)))
|
||||
throw new Error(`Missing Hachidori asset: ${file}`);
|
||||
}
|
||||
fs.rmSync(output, { recursive: true, force: true });
|
||||
fs.mkdirSync(output, { recursive: true });
|
||||
fs.cpSync(extension, output, { recursive: true });
|
||||
// Host configuration belongs in the staged copy, leaving the fork usable in Chrome.
|
||||
const hostConfiguration = {
|
||||
'overlay-mode.js': [
|
||||
['export const OVERLAY_MODE = false;', 'export const OVERLAY_MODE = true;'],
|
||||
['customJavaScript: true,', 'customJavaScript: false,'],
|
||||
],
|
||||
// Overlay hosts seed the lookup highlight off because their Anki screenshot is
|
||||
// the see-through viewport. SubMiner captures media from mpv, and without the
|
||||
// highlight the sidebar shows nothing for the word being looked up.
|
||||
'setup-state.js': [
|
||||
[
|
||||
'lookupMode: "hover",\n sourceHighlightEnabled: false,',
|
||||
'lookupMode: "hover",\n sourceHighlightEnabled: true,',
|
||||
],
|
||||
],
|
||||
};
|
||||
for (const [file, replacements] of Object.entries(hostConfiguration)) {
|
||||
const filePath = path.join(output, file);
|
||||
let text = fs.readFileSync(filePath, 'utf8');
|
||||
for (const [original, replacement] of replacements) {
|
||||
if (!text.includes(original))
|
||||
throw new Error(`Hachidori host configuration changed upstream: ${original}`);
|
||||
text = text.replace(original, replacement);
|
||||
}
|
||||
fs.writeFileSync(filePath, text);
|
||||
}
|
||||
manifest.permissions = manifest.permissions.filter((permission) => permission !== 'userScripts');
|
||||
// A fixed key pins the extension ID, so Hachidori's storage origin (dictionaries,
|
||||
// settings, setup state) survives userData path changes. Electron otherwise
|
||||
// derives the ID from the unpacked directory path.
|
||||
manifest.key =
|
||||
'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA40zTTbhCbrKnDOqj17tosDChP60VXuuMjR0tFFR/kAet21jrYn0JKPzqqNpXMGaJsx1chnuMOgaP0zuOT+gv9DNVV83wGLhQL7cC4LCoGN648WqnE2jYqBPj6hdD5A/N3uPeKFRAHkiC9HKoj2Et6sYZFTqag79QqQkkUz17X2VpjuTGmTP3lvhyEwhJWQKzOU0k6dTn6fKB2ZSqTebpw/JS2G8jf58vHlQOcfLhIiolKCG9DfMuo11aoG1s3AsFmQmw9VVyp4wgyQ80UI4lyBdqboanJxEiZ211+HKWPEgtG6VML1+Uo59qWS3uBU1apxE1+7E51UBEHaTsxajFIQIDAQAB';
|
||||
fs.writeFileSync(path.join(output, 'manifest.json'), JSON.stringify(manifest, null, 2) + '\n');
|
||||
for (const file of ['LICENSE', 'SOURCE.json', 'README.md']) {
|
||||
fs.copyFileSync(path.join(source, file), path.join(output, file));
|
||||
}
|
||||
process.stdout.write(`Hachidori ${provenance.revision} staged in ${output}\n`);
|
||||
Reference in new issue
Block a user