feat: PeopleLib 开放文献客户端,集成 Z-Library 与 LibGen 等多源检索
Electron 桌面客户端,聚合多个开放获取文献源的搜索、详情与下载。 新增数据源: - Z-Library:邮箱登录(凭据本地存储),会话失效自动重登 - LibGen:适配新版 libgen.ac 前端(旧版 search.php 镜像已全部下线) - Memory of the World、Sci-Hub、Anna's Archive 基础设施: - mirror.js:镜像故障转移,支持串行优先与并发竞速两种策略, 失效镜像 5 分钟冷却后自动重试,避免站点恢复后被永久跳过 - http.js:统一 15 秒请求超时,防止单个卡死镜像拖垮整次搜索 - settings.js:全局代理配置持久化,经 Electron net.fetch 生效于所有请求 Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
commit
1a1288ce18
@@ -0,0 +1,61 @@
|
||||
window.$ = (id) => document.getElementById(id);
|
||||
|
||||
window.escapeHtml = (s) => String(s == null ? '' : s).replace(/[&<>"']/g, (c) => ({
|
||||
'&': '&', '<': '<', '>': '>', '"': '"', "'": '''
|
||||
}[c]));
|
||||
|
||||
window.coverStyle = (cover) => {
|
||||
if (!cover) return '';
|
||||
const url = /^(https?:|data:)/.test(cover) ? cover : 'file:///' + String(cover).replace(/\\/g, '/');
|
||||
return `background-image:url('${url.replace(/'/g, "\\'")}')`;
|
||||
};
|
||||
|
||||
window.copyText = async (btn, text) => {
|
||||
await window.api.copy(text);
|
||||
const orig = btn.textContent;
|
||||
btn.textContent = '已复制 ✓';
|
||||
btn.classList.add('copied');
|
||||
setTimeout(() => { btn.textContent = orig; btn.classList.remove('copied'); }, 1500);
|
||||
};
|
||||
|
||||
window.formatDate = (ts) => {
|
||||
if (!ts) return '';
|
||||
const d = new Date(ts);
|
||||
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
|
||||
};
|
||||
|
||||
window.getEnabledSources = () => {
|
||||
let ids = null;
|
||||
try {
|
||||
const raw = localStorage.getItem('enabledSources');
|
||||
if (raw) ids = JSON.parse(raw);
|
||||
} catch (e) { /* ignore */ }
|
||||
return ids;
|
||||
};
|
||||
|
||||
window.setEnabledSources = (ids) => {
|
||||
localStorage.setItem('enabledSources', JSON.stringify(ids));
|
||||
};
|
||||
|
||||
// 通用弹窗: 返回 Promise<{ok, values}|null>
|
||||
window.openModal = (title, bodyHtml, onOk) => {
|
||||
const modal = $('modal');
|
||||
$('modalTitle').textContent = title;
|
||||
$('modalBody').innerHTML = bodyHtml;
|
||||
modal.classList.remove('hidden');
|
||||
return new Promise((resolve) => {
|
||||
const close = (result) => {
|
||||
modal.classList.add('hidden');
|
||||
$('modalOk').onclick = null;
|
||||
$('modalCancel').onclick = null;
|
||||
resolve(result);
|
||||
};
|
||||
$('modalCancel').onclick = () => close(null);
|
||||
$('modalOk').onclick = async () => {
|
||||
const r = onOk ? await onOk() : true;
|
||||
if (r !== false) close(r);
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
window.confirmModal = (title, text) => window.openModal(title, `<p>${escapeHtml(text)}</p>`);
|
||||
Reference in New Issue
Block a user