feat: 内置阅读器、批注笔记与 AI 助手,发布 1.3.0

新增 PDF/EPUB/MOBI/AZW 内置阅读器,PDF 分段读取支持超大文件,
批注、读书与画布笔记、封面生成与本地导入。AI 助手支持三种协议、
图像上下文与安全 Markdown 渲染,上下文范围改为 选中/当前页/全文,
页面与全文无需选中文本即可发送,全文会提示可能超出模型限制。

便携版输出目录固定为 PeopleLib-windows-x64,不再随版本号变化,
避免升级后 data/ 被遗留在旧目录。

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
This commit is contained in:
lofyer
2026-08-03 12:13:02 +08:00
co-authored by factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
parent b8c8d24107
commit 3ccd044527
307 changed files with 98477 additions and 1148 deletions
+154 -10
View File
@@ -3,20 +3,36 @@
<head>
<meta charset="UTF-8" />
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https: http: data: file:; style-src 'self' 'unsafe-inline';" />
<title>PeopleLib 文献库</title>
<title>PeopleLib</title>
<link rel="stylesheet" href="style.css" />
<link rel="stylesheet" href="vendor/quill/quill.snow.css" />
<link rel="stylesheet" href="rich-note.css" />
</head>
<body>
<div class="titlebar">
<div class="titlebar-left">
<span class="brand">PeopleLib <span class="brand-sub">开放文献库</span></span>
<span class="brand">
<img class="brand-logo brand-logo-dark" src="../../icons/dist/dark/icon-32.png" alt="" />
<img class="brand-logo brand-logo-light" src="../../icons/dist/light/icon-32.png" alt="" />
<span>人民阅读器</span>
<span class="brand-sub">PeopleLib</span>
</span>
</div>
<nav class="tabs">
<button class="tab active" data-tab="library">我的书库</button>
<button class="tab" data-tab="notes">我的笔记</button>
<button class="tab" data-tab="browse">检索</button>
</nav>
<div class="titlebar-spacer"></div>
<div class="titlebar-controls">
<button id="uiThemeBtn" class="win-btn ui-theme-btn" title="切换到明亮主题" aria-label="切换到明亮主题">
<svg class="titlebar-icon ui-theme-sun" viewBox="0 0 24 24" aria-hidden="true">
<circle cx="12" cy="12" r="4"></circle><path d="M12 2v2M12 20v2M4.93 4.93l1.42 1.42M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.42-1.42M17.66 6.34l1.41-1.41"></path>
</svg>
<svg class="titlebar-icon ui-theme-moon" viewBox="0 0 24 24" aria-hidden="true">
<path d="M20 15.5A8.5 8.5 0 0 1 8.5 4 8.5 8.5 0 1 0 20 15.5Z"></path>
</svg>
</button>
<button class="win-btn tab" data-tab="settings" title="设置">&#9881;</button>
<button id="minBtn" class="win-btn" title="最小化">&#9472;</button>
<button id="maxBtn" class="win-btn" title="最大化">&#9633;</button>
@@ -27,13 +43,74 @@
<main id="main">
<!-- 我的书库 -->
<section id="libraryTab" class="tab-panel">
<div class="toolbar">
<span id="libStatus" class="status-bar"></span>
<div class="spacer"></div>
<button id="rescanBtn" class="tb-btn ghost">重新扫描</button>
<button id="addLocalBtn" class="tb-btn">+ 添加本地文件</button>
<div class="library-page">
<aside class="library-sidebar">
<div class="library-sidebar-head">
<h2>书架</h2>
<button id="addShelfBtn" class="notes-icon-btn" title="新建书架" aria-label="新建书架">+</button>
</div>
<button class="library-filter active" data-shelf="">全部书籍</button>
<button class="library-filter" data-shelf="__uncategorized__">未分类</button>
<div id="libraryShelfList"></div>
<div class="library-sidebar-section">
<div class="library-sidebar-section-head">
<h3>标签</h3>
<button id="addTagBtn" class="notes-icon-btn" title="新建标签" aria-label="新建标签">+</button>
</div>
<div id="libraryTagList" class="library-tag-list"></div>
</div>
</aside>
<div class="library-content">
<div class="toolbar">
<div class="library-search" role="search">
<input id="librarySearchInput" type="search" placeholder="搜索标题或作者..." autocomplete="off" />
<button id="librarySearchBtn" class="tb-btn">搜索</button>
<button id="libraryClearSearchBtn" class="tb-btn ghost hidden">清除</button>
</div>
<span id="libStatus" class="status-bar"></span>
<div class="spacer"></div>
<button id="rescanBtn" class="tb-btn ghost">重新扫描</button>
<button id="addLocalBtn" class="tb-btn">+ 添加本地</button>
</div>
<div id="libGrid" class="grid"></div>
</div>
</div>
</section>
<!-- 我的笔记 -->
<section id="notesTab" class="tab-panel hidden">
<div class="notes-page">
<aside class="notes-sidebar">
<div class="notes-sidebar-head">
<h2>笔记本</h2>
<button id="addCollectionBtn" class="notes-icon-btn" title="新建笔记本" aria-label="新建笔记本">+</button>
</div>
<button class="notes-collection active" data-collection="">全部笔记</button>
<button class="notes-collection" data-collection="__uncategorized__">未分类</button>
<div id="notesCollectionList"></div>
</aside>
<div class="notes-content">
<div class="notes-toolbar">
<div class="notes-search">
<input id="notesSearchInput" type="search" placeholder="搜索笔记、摘录或书名..." autocomplete="off" />
<button id="notesSearchBtn" class="tb-btn">搜索</button>
<button id="notesClearSearchBtn" class="tb-btn ghost hidden">清除</button>
</div>
<select id="notesSourceSelect" class="source-select" aria-label="按来源筛选">
<option value="">全部来源</option>
</select>
<button id="addGlobalNoteBtn" class="tb-btn">+ 新建笔记</button>
</div>
<div id="notesTypeTabs" class="notes-type-tabs" role="tablist" aria-label="笔记类型">
<button class="notes-type-tab active" data-note-type="" role="tab" aria-selected="true">全部</button>
<button class="notes-type-tab" data-note-type="canvas" role="tab" aria-selected="false">画布笔记</button>
<button class="notes-type-tab" data-note-type="reading" role="tab" aria-selected="false">读书笔记</button>
</div>
<div id="notesTagFilters" class="notes-tag-filters hidden"></div>
<div id="notesStatus" class="status-bar"></div>
<div id="notesList" class="notes-list"></div>
</div>
</div>
<div id="libGrid" class="grid"></div>
</section>
<!-- 检索 -->
@@ -106,6 +183,7 @@
<div class="settings-item-desc">控制书库条目的排列顺序</div>
</div>
<select id="sortSelect" class="source-select">
<option value="recent">最近阅读</option>
<option value="added">添加时间</option>
<option value="title">标题</option>
<option value="author">作者</option>
@@ -118,7 +196,7 @@
<div class="settings-item-label">网络代理</div>
<div class="settings-item-desc">对所有数据源与下载统一生效;访问 LibGen / Z-Library 通常需要代理(留空表示直连)</div>
</div>
<input id="proxyInput" type="text" placeholder="留空表示直连,例如 http://localhost:7897" style="width:220px;padding:6px;background:#222;border:1px solid #444;color:#eee;border-radius:4px;" />
<input id="proxyInput" class="settings-input" type="text" placeholder="留空表示直连,例如 http://localhost:7897" />
<button id="proxySaveBtn" class="tb-btn">保存</button>
</div>
</div>
@@ -133,6 +211,46 @@
<button id="semanticKeyClearBtn" class="tb-btn ghost hidden">清除</button>
</div>
</div>
<div class="settings-group">
<div class="settings-item settings-item-block">
<div class="settings-item-info">
<div class="settings-item-label">阅读器 AI 助手</div>
<div class="settings-item-desc" id="aiStatus">未配置</div>
</div>
<div class="ai-form">
<label class="ai-row">
<span>接口类型</span>
<select id="aiProtocol" class="settings-input ai-protocol">
<option value="anthropic">Anthropic 接口(/v1/messages</option>
<option value="openai-responses">OpenAI 接口(/v1/responses</option>
<option value="chat-completions">OpenAI 兼容接口(/v1/chat/completions</option>
</select>
</label>
<label class="ai-row">
<span>接口地址</span>
<input id="aiBaseUrl" class="settings-input" type="text" placeholder="https://api.openai.com/v1" autocomplete="off" />
</label>
<label class="ai-row">
<span>模型名称</span>
<input id="aiModel" class="settings-input" type="text" placeholder="gpt-4o-mini" autocomplete="off" />
</label>
<label class="ai-row">
<span>API Key</span>
<input id="aiKey" class="settings-input" type="password" placeholder="本地模型可留空" autocomplete="off" />
</label>
<label class="ai-row ai-vision-row">
<span>图像输入</span>
<input id="aiVision" type="checkbox" />
<small>仅在模型明确支持图片时开启</small>
</label>
<div class="ai-row ai-actions">
<span id="aiProtocolHint" class="ai-hint">服务地址填写到版本根路径,PeopleLib 会按接口类型调用对应端点。</span>
<button id="aiSaveBtn" class="tb-btn">保存</button>
<button id="aiClearBtn" class="tb-btn ghost hidden">清除</button>
</div>
</div>
</div>
</div>
<div class="settings-group">
<div class="settings-item">
<div class="settings-item-info">
@@ -161,6 +279,27 @@
</label>
</div>
</div>
<div class="settings-group" aria-label="关于 PeopleLib">
<div class="settings-item settings-item-block">
<div class="settings-item-info">
<div class="settings-item-label">关于 PeopleLib</div>
<div class="settings-item-desc">人民阅读器支持的本地图书格式</div>
</div>
<div class="about-formats">
<div>
<span class="about-format-label">内置阅读</span>
<span>PDF、EPUB、MOBI、AZW、AZW3</span>
</div>
<div>
<span class="about-format-label">书库导入与管理</span>
<span>PDF、EPUB、MOBI、AZW、AZW3、TXT、DJVU、FB2、CBZ、CBR</span>
</div>
<div class="settings-item-desc">
MOBI、AZW 与 AZW3 由 Foliate 解析,支持无 DRM 的 MOBI/KF7/KF8 内容;DRM、KFX 与损坏文件可改用系统应用打开。
</div>
</div>
</div>
</div>
</div>
</section>
</main>
@@ -171,7 +310,7 @@
<div id="modalTitle" class="modal-title"></div>
<div id="modalBody" class="modal-body"></div>
<div class="modal-actions">
<button id="modalCancel" class="page-btn">取消</button>
<button id="modalCancel" class="tb-btn ghost">取消</button>
<button id="modalOk" class="tb-btn">确定</button>
</div>
</div>
@@ -180,6 +319,11 @@
<script src="util.js"></script>
<script src="views/browse.js"></script>
<script src="views/library.js"></script>
<script src="vendor/quill/quill.js"></script>
<script src="vendor/jspdf.umd.min.js"></script>
<script src="rich-note.js"></script>
<script src="mixed-note.js"></script>
<script src="views/notes.js"></script>
<script src="app.js"></script>
</body>
</html>