Files
ddc/web/static/js/notify.js
T

69 lines
2.0 KiB
JavaScript

const storageKey = "ddc-notifications";
const finishedTitles = {
ready: "Download ready",
completed: "Download moved",
failed: "Download failed",
};
const previousStatuses = new Map();
function notificationsSupported() {
return "Notification" in window;
}
function readPreference() {
try {
return localStorage.getItem(storageKey) === "on";
} catch {
return false;
}
}
function storePreference(enabled) {
try {
localStorage.setItem(storageKey, enabled ? "on" : "off");
} catch {
return;
}
}
export function notificationsEnabled() {
return notificationsSupported() && Notification.permission === "granted" && readPreference();
}
export async function setNotificationsEnabled(enabled) {
if (!enabled) {
storePreference(false);
return;
}
if (!notificationsSupported()) throw new Error("This browser does not support notifications.");
const permission = await Notification.requestPermission();
if (permission !== "granted") throw new Error("Notifications are blocked for this site in the browser settings.");
storePreference(true);
}
export function collectTransitions(jobs) {
const transitions = [];
const seenIds = new Set();
for (const job of jobs) {
seenIds.add(job.id);
const previous = previousStatuses.get(job.id);
if (previous && previous !== job.status) transitions.push({ job, previous });
previousStatuses.set(job.id, job.status);
}
for (const id of previousStatuses.keys()) {
if (!seenIds.has(id)) previousStatuses.delete(id);
}
return transitions;
}
export function notifyTransitions(transitions) {
if (!notificationsEnabled()) return;
for (const { job, previous } of transitions) {
const title = finishedTitles[job.status];
const wasWorking = previous === "queued" || previous === "downloading" || previous === "extracting" || previous === "moving";
if (!title || !wasWorking) continue;
if (job.status === "ready" && previous === "moving") continue;
new Notification(title, { body: job.fileName || job.sourceUrl, tag: `ddc-${job.id}` });
}
}