mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-09-22 17:16:19 -07:00
- 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
55 lines
2.2 KiB
JavaScript
55 lines
2.2 KiB
JavaScript
// 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)); },
|
|
};
|
|
}
|