mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-09-22 17:16:19 -07:00
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:
+54
@@ -0,0 +1,54 @@
|
||||
// Keep engine-owned backup URLs alive until Chrome finishes saving the file.
|
||||
// Session storage survives service-worker restarts, but is not backup content.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
const KEY = "backupDownloads";
|
||||
const TARGET = "hoshidicts-offscreen";
|
||||
|
||||
export function createBackupDownloads(chrome, relay) {
|
||||
let tail = Promise.resolve();
|
||||
const serialise = job => {
|
||||
const result = tail.then(job, job);
|
||||
tail = result.catch(() => {});
|
||||
return result;
|
||||
};
|
||||
const release = blobUrl => relay({ target: TARGET, type: "hd_backup_release", blobUrl });
|
||||
const read = async () => (await chrome.storage.session.get(KEY))[KEY] ?? {};
|
||||
|
||||
async function finish(id) {
|
||||
const tracked = await read();
|
||||
if (!Object.hasOwn(tracked, id)) return;
|
||||
const [download] = await chrome.downloads.search({ id: Number(id) });
|
||||
if (download?.state === "in_progress") return;
|
||||
const reply = await release(tracked[id]);
|
||||
if (!reply?.ok) throw new Error(reply?.error || "Could not release the saved backup archive.");
|
||||
delete tracked[id];
|
||||
await chrome.storage.session.set({ [KEY]: tracked });
|
||||
}
|
||||
|
||||
return {
|
||||
async download() {
|
||||
const exported = await relay({ target: TARGET, type: "hd_backup_export" });
|
||||
if (!exported?.ok) throw new Error(exported?.error || "Could not create a backup archive.");
|
||||
let id;
|
||||
try {
|
||||
id = await chrome.downloads.download({ url: exported.blobUrl, saveAs: true,
|
||||
filename: `hachidori-backup-${new Date().toISOString().slice(0, 10)}.zip`, conflictAction: "uniquify" });
|
||||
} catch (error) {
|
||||
await serialise(() => release(exported.blobUrl));
|
||||
throw error;
|
||||
}
|
||||
let warning = null;
|
||||
try {
|
||||
await serialise(async () => {
|
||||
await chrome.storage.session.set({ [KEY]: { ...await read(), [id]: exported.blobUrl } });
|
||||
// A small download can complete before its ownership record is written.
|
||||
await finish(id);
|
||||
});
|
||||
} catch (error) {
|
||||
warning = `Download started, but its temporary archive could not be tracked: ${error.message}`;
|
||||
}
|
||||
return { downloadId: id, warning };
|
||||
},
|
||||
changed(id) { return serialise(() => finish(id)); },
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user