import { defineStore } from 'pinia'; import { ref } from 'vue'; type ProgressLike = { Completed?: number; Total?: number; IsDecryption?: boolean; Percentage?: number; Title?: string; StatusText?: string; FileName?: string; filename?: string; }; type Info = ProgressLike & { Id: string; Closer?: ReturnType | null; LastUpdated?: number; }; export const useDownloadStore = defineStore('download', () => { const infos = ref([]); let bc: BroadcastChannel | null = null; let _initialized = false; function initCrossTab() { if (_initialized) return; _initialized = true; bc = new BroadcastChannel('downloads'); bc.onmessage = (ev: MessageEvent) => { const msg = ev.data; if (!msg || !msg.type) return; if (msg.type === 'dl:start') upsert(msg.info); else if (msg.type === 'dl:update') upsert(msg.info); else if (msg.type === 'dl:finish') finish(msg.id); }; } function upsert(info: any) { const id = String(info.Id ?? info.id); const i = infos.value.findIndex((x) => x.Id === id); const completed = Number(info.Completed ?? 0); const total = Number(info.Total ?? 0); const pct = total > 0 ? (completed / total) * 100 : Number(info.Percentage ?? 0); const now = Date.now(); const next: Info = { ...(infos.value[i] ?? {}), ...info, Id: id, Completed: completed, Total: total, Percentage: pct, LastUpdated: now, }; if (i >= 0) infos.value[i] = next; else infos.value.push(next); } function finish(id: string) { const i = infos.value.findIndex((x) => x.Id === String(id)); if (i >= 0) { infos.value[i].LastUpdated = Date.now(); if (infos.value[i].Closer) clearTimeout(infos.value[i].Closer!); infos.value[i].Closer = setTimeout(() => { const idx = infos.value.findIndex((x) => x.Id === String(id)); if (idx >= 0) infos.value.splice(idx, 1); }, 3000); } } function touch(id: string) { const i = infos.value.findIndex((x) => x.Id === String(id)); if (i >= 0) infos.value[i].LastUpdated = Date.now(); } function requestPause(id: string) { bc?.postMessage({ type: 'dl:pause', id }); } function requestResume(id: string) { bc?.postMessage({ type: 'dl:resume', id }); } function requestCancel(id: string) { bc?.postMessage({ type: 'dl:cancel', id }); } return { infos, initCrossTab, requestPause, requestResume, requestCancel, touch, }; });