const Library = (() => { let dirty = true; let sortMode = localStorage.getItem('libSortMode') || 'added'; let grid, statusEl; const SORTERS = { added: (a, b) => (b.addedAt || 0) - (a.addedAt || 0), title: (a, b) => String(a.title).localeCompare(String(b.title), 'zh'), author: (a, b) => String((a.authors || [])[0] || '').localeCompare(String((b.authors || [])[0] || ''), 'zh') }; function init() { grid = $('libGrid'); statusEl = $('libStatus'); $('addLocalBtn').onclick = addLocal; $('rescanBtn').onclick = rescan; window.api.library.onChanged(() => { dirty = true; refresh(true); }); } async function rescan() { const btn = $('rescanBtn'); btn.disabled = true; btn.textContent = '扫描中...'; const r = await window.api.library.scan(); btn.textContent = r.ok && r.data && r.data.added ? `新增 ${r.data.added} 本 ✓` : '已是最新 ✓'; dirty = true; await refresh(true); setTimeout(() => { btn.textContent = '重新扫描'; btn.disabled = false; }, 2000); } function getSortMode() { return sortMode; } function setSortMode(m) { sortMode = m; localStorage.setItem('libSortMode', m); dirty = true; refresh(true); } async function refresh(force) { if (!force && !dirty) return; const res = await window.api.library.list(); dirty = false; if (!res.ok) { statusEl.textContent = '加载失败:' + res.error; return; } const items = res.data.slice().sort(SORTERS[sortMode] || SORTERS.added); const missingCount = items.filter((it) => it.missing).length; statusEl.textContent = `共 ${items.length} 条` + (missingCount ? `,${missingCount} 条文件缺失` : ''); if (!items.length) { grid.innerHTML = '
确定移除「${escapeHtml(it.title)}」吗?
${hasFile ? '' : ''} `, () => ({ del: !!(document.getElementById('delFiles') || {}).checked })); if (!r) return; await window.api.library.remove(id, r.del); dirty = true; refresh(true); } } async function addLocal() { const r = await window.api.pickFile(); if (!r.ok || !r.data) return; const { path: p, name } = r.data; const res = await openModal('添加本地文件', `文件:${escapeHtml(p)}
`, () => ({ title: (document.getElementById('localTitle').value || name).trim(), author: (document.getElementById('localAuthor').value || '').trim() })); if (!res) return; await window.api.library.add({ title: res.title, authors: res.author ? [res.author] : [], files: [{ path: p, name: p.split(/[\\/]/).pop(), format: (p.split('.').pop() || '').toUpperCase() }] }); dirty = true; refresh(true); } function markDirty() { dirty = true; } return { init, refresh, markDirty, getSortMode, setSortMode }; })(); window.Library = Library;