This commit is contained in:
douboer 2025-09-07 13:10:52 +08:00
parent 2f26e95052
commit 227c7f806f
1 changed files with 64 additions and 64 deletions

128
readme.md
View File

@ -41,9 +41,33 @@
---
## 3. 主要数据结构
## 3. UML 图Mermaid
### 3.1 booksnote
> 注:使用 Mermaid 语法,支持在支持渲染的 Markdown 查看。类之间仅展示主要依赖/调用,非完整字段集合。
### 3.1 类图(核心模块)
![img](uml/iShot_2025-09-07_12.55.41.png)
### 3.2 时序图:应用启动
![img](uml/iShot_2025-09-07_12.56.27.png)
### 3.3 时序图:选择书籍 + AI 简评
![img](uml/iShot_2025-09-07_12.56.00.png)
### 3.4 时序图:导出 Markdown
![img](uml/iShot_2025-09-07_12.57.06.png)
### 3.5 时序图:已读书籍网格刷新
![img](uml/iShot_2025-09-07_12.57.19.png)
### 3.6 时序图:点击已读封面跳转
![img](uml/iShot_2025-09-07_12.57.28.png)
---
## 4. 主要数据结构
### 4.1 booksnote
```python
booksnote = {
@ -63,20 +87,20 @@ booksnote = {
---
## 4. 主要流程
## 5. 主要流程
### 4.1 数据同步
### 5.1 数据同步
- 自动将 iBooks 的数据库和 plist 文件复制到本地 `data/` 目录,便于后续处理。
### 4.2 构建 booksnote
### 5.2 构建 booksnote
- 通过 `get_annotations` 解析 SQLite 笔记数据库,获取所有笔记。
- 通过 `parse_books_plist` 解析书籍元数据,获取书名、路径等信息。
- 遍历每本书的所有笔记结合OPF、NCX文件和HTML 文件,定位章节名。
- 若无法通过目录文件定位章节,则尝试通过笔记选中文本在 HTML 文件中查找章节,否则标记为“未找到章节”。
### 4.3 交互式选择书籍
### 5.3 交互式选择书籍
- 读取 Books.plist 获取所有书籍元数据。
- 读取 BKLibrary.sqlite获取每本书的最近打开时间last_open苹果时间戳基准2001-01-01
@ -84,7 +108,7 @@ booksnote = {
- 按 last_open 时间戳降序排列,菜单显示“书名 [时间戳]”,时间戳为 last_open 字段。
- 使用 InquirerPy 提供模糊搜索交互界面,供用户选择要导出的书籍。
### 4.4 导出 Markdown
### 5.4 导出 Markdown
- 仅导出用户选择的书籍。
- Markdown 格式如下:
@ -101,15 +125,15 @@ booksnote = {
---
## 5. 关键函数说明
## 6. 关键函数说明
### 5.1 build_booksnote
### 6.1 build_booksnote
- 输入:注释数据库路径、书籍 plist 路径
- 输出:结构化的 booksnote 字典
- 逻辑:遍历所有笔记,结合书籍元数据和目录信息,归类到章节下
### 5.2 export_booksnote_to_md
### 6.2 export_booksnote_to_md
- 输入booksnote、booksinfo、导出路径
- 输出Markdown 字符串,并写入文件
@ -117,7 +141,7 @@ booksnote = {
---
## 6. 交互与用户体验
## 7. 交互与用户体验
- 通过命令行交互,用户可模糊搜索并选择要导出的书籍。
- 若无可导出的笔记,程序自动退出并提示。
@ -125,9 +149,9 @@ booksnote = {
---
## 7. 代码片段示例
## 8. 代码片段示例
### 7.1 书名处理逻辑
### 8.1 书名处理逻辑
```python
name = info.get('displayname') or info.get('itemname') or assetid
@ -135,7 +159,7 @@ name = info.get('displayname') or info.get('itemname') or assetid
if '-' in name: name = name.split('-', 1)[0].strip()
```
### 7.2 交互式选择与排序
### 8.2 交互式选择与排序
```python
from booklist_parse import get_books_last_open
@ -156,7 +180,7 @@ answer = inquirer.fuzzy(
---
## 8. 依赖说明
## 9. 依赖说明
- Python 3
- 主要依赖库:`InquirerPy`, `bs4`, `shutil`, `os`, `datetime`, `sqlite3`
@ -164,7 +188,7 @@ answer = inquirer.fuzzy(
---
## 9. 目录结构
## 10. 目录结构
- `data/`:存放同步下来的数据库和 plist 文件(含 AEAnnotation.sqlite、Books.plist、BKLibrary.sqlite 等)
- `notes/`:导出的 Markdown 文件
@ -172,9 +196,9 @@ answer = inquirer.fuzzy(
---
## 10. 主要代码文件说明(细化)
## 11. 主要代码文件说明(细化)
### 10.1 exportbooknotes.py
### 11.1 exportbooknotes.py
- 采用 OOP 设计,核心类为 `BookNotesExporter`
- `build_booksnote(bookid=None)`:构建结构化笔记数据。
@ -185,7 +209,7 @@ answer = inquirer.fuzzy(
- 只处理用户选中书籍的笔记,按章节分组导出 Markdown。
- 依赖核心解析模块,负责主流程调度。
### 10.2 annotationdata.py
### 11.2 annotationdata.py
- OOP 设计,核心类为 `AnnotationManager`
- `get_annotations(bookid=None)`:返回所有或指定 assetid 的笔记。
@ -193,7 +217,7 @@ answer = inquirer.fuzzy(
- 解析 AEAnnotation.sqlite提取所有或指定 assetid 的笔记。
- 支持苹果时间戳转换,结构化输出。
### 10.3 booklist_parse.py
### 11.3 booklist_parse.py
- OOP 设计,核心类为 `BookListManager`
- `get_books_info()`:获取书籍元数据。
@ -201,13 +225,13 @@ answer = inquirer.fuzzy(
- 解析 Books.plist获取书籍元数据书名、作者、路径、时间等
- 解析 BKLibrary.sqlite获取每本书的最近打开时间。
### 10.4 opf_parse.py
### 11.4 opf_parse.py
- OOP 设计,核心类为 `OPFParser`
- `parse_opf(filepath)`:静态方法,返回 id->href 映射。
- 解析 epub 的 OPF 文件获取章节与文件映射关系idref -> href
### 10.5 toc_parse.py
### 11.5 toc_parse.py
- OOP 设计,核心类为 `TOCParser`
- `parse_navpoints(navpoints)`:递归解析 navPoint 节点。
@ -216,13 +240,13 @@ answer = inquirer.fuzzy(
- `parse_html_title(html_path)`:解析 html 文件标题。
- 解析 NCX 目录文件,递归构建章节树结构。
### 10.6 backup/booksnote.py
### 11.6 backup/booksnote.py
- 历史/备份脚本,辅助数据迁移或格式转换。
---
## 11. 扩展与维护建议
## 12. 扩展与维护建议
- 可扩展支持多本书批量导出
- 可增加导出格式(如 HTML、PDF
@ -235,9 +259,9 @@ answer = inquirer.fuzzy(
---
## 12. GUI 架构与模块调用关系2025 拆分后更新)
## 13. GUI 架构与模块调用关系2025 拆分后更新)
### 12.1 模块职责概览
### 13.1 模块职责概览
| 模块 | 主要类/函数 | 职责 | 关键依赖 |
|------|-------------|------|----------|
@ -252,7 +276,7 @@ answer = inquirer.fuzzy(
| `opf_parse.py` | `OPFParser` | 解析 OPF 获取 manifest 映射 | OPF XML |
| `charts.py` | 图表组件 | 周 / 月 / 年 / 气泡指标可视化 | `BookListManager` 汇总数据 |
### 12.2 运行时对象关系(简化 UML 文本表示)
### 13.2 运行时对象关系(简化 UML 文本表示)
```
IBookExportApp
├── BookListManager (数据/统计)
@ -268,7 +292,7 @@ IBookExportApp
2. 网格构建 -> `FinishedBooksMixin._populate_finished_books_grid`
3. AI 简评 -> `BookReviewWorker` 发起,完成后回调 `_on_review_finished`
### 12.3 启动序列Startup Sequence
### 13.3 启动序列Startup Sequence
1. 用户运行 `ibook_export_app.py` → 创建 `QApplication`
2. `IBookExportApp.__init__`
- 加载 `.ui`
@ -281,14 +305,14 @@ IBookExportApp
- 安排延迟 `_relayout_finished_grid()` 确保初次布局正确
3. 主窗口显示;用户可交互。
### 12.4 书籍切换流程Selecting a Book
### 13.4 书籍切换流程Selecting a Book
1. 用户在列表中选中条目 → `currentRowChanged``update_book_info(row)`
2. 刷新右侧三张封面(当前 + 后两本轮播预览)
3. 构建基础信息 `_base_info_cache`
4. 若 `bookintro.json` 已有简评 → 直接渲染;否则启动新 `BookReviewWorker` → 占位“简评获取中...”
5. 线程完成 → 通过信号调用 `_on_review_finished` → 更新 HTML。
### 12.5 AI 简评线程生命周期
### 13.5 AI 简评线程生命周期
1. 实例化 `BookReviewWorker(bookname, prompt, json_path)`
2. 连接 `finished` 信号到:
- `_on_review_finished`
@ -296,7 +320,7 @@ IBookExportApp
3. `worker.start()` → 线程内部:调用 `DashScopeChatClient.ask()`;写入/更新 `bookintro.json`;发送 `finished` 信号。
4. 主线程根据 `_current_bookname` 校验是否仍是当前书,防止串写。
### 12.6 已读书籍网格刷新逻辑
### 13.6 已读书籍网格刷新逻辑
事件触发:
1. 程序启动初次调用 `_populate_finished_books_grid()`
2. Tab 切换到“已读书籍”标签 → `_on_main_tab_changed()` → 若命中,立即 `_relayout_finished_grid()` 并延迟一次;(后续可扩展为定期重新查询)
@ -307,26 +331,26 @@ IBookExportApp
- 将 Apple epoch(2001) 秒转为 `datetime`,过滤 `year==当前年`
- 返回列表后排序(时间倒序)
### 12.7 封面加载与缩放流程
### 13.7 封面加载与缩放流程
1. `_load_initial()` / `update_book_info()` 内调用 `find_book_cover()` 获取路径
2. 原图 QPixmap 存入 `_cover_pixmaps_original`
3. `_apply_cover_scale()` 使用当前 `cover_ratio`(默认 1.2)和弹性策略计算目标高度
4. 固定宽 180px受硬上限 400px 与(可选)文本区 45% 限制
5. 非弹性模式忽略文本高度,仅 ratio + 硬上限。
### 12.8 导出流程Export Notes
### 13.8 导出流程Export Notes
1. 用户点击“导出”按钮 → `export_notes()`
2. 取当前行 assetid → `BookNotesExporter.build_booksnote(bookid)`
3. 组装单书字典 → `export_booksnote_to_md()` 输出 Markdown 到 `notes/` 目录
4. 弹窗提示路径。
### 12.9 统计图表流程
### 13.9 统计图表流程
1. 启动后调用 `_init_charts()`(懒加载)
2. 获取周 / 月 / 年聚合数据及总指标
3. 构造原生自绘组件 `BarChartWidget` / `ScatterChartWidget` / `BubbleMetricsWidget`
4. 添加到对应 Layout。
### 12.10 关键调用关系(摘要)
### 13.10 关键调用关系(摘要)
```
update_book_info -> find_book_cover (CoverMixin)
update_book_info -> BookReviewWorker.start -> _on_review_finished
@ -336,7 +360,7 @@ export_notes -> BookNotesExporter.build_booksnote -> export_booksnote_to_md
_init_charts -> manager.get_total_readtime* 系列函数
```
### 12.11 数据流摘要
### 13.11 数据流摘要
```
iBooks 原始文件 -> sync_source_files -> data/*.sqlite / Books.plist
└─ BookListManager 载入 -> booksinfo / open_times / 阅读统计
@ -349,7 +373,7 @@ iBooks 原始文件 -> sync_source_files -> data/*.sqlite / Books.plist
AI 请求 -> BookReviewWorker -> DashScopeChatClient.ask -> bookintro.json -> _on_review_finished 渲染
```
### 12.12 扩展点与建议
### 13.12 扩展点与建议
1. 已读书籍:增加“显示全部年份 / 仅今年”开关;提供手动“刷新”按钮。
2. 封面缓存:引入 LRU (assetid -> QPixmap) 降低重复磁盘扫描。
3. AI 简评:加速策略(本地缓存 TTL、批量预取前 N 本)。
@ -361,7 +385,7 @@ AI 请求 -> BookReviewWorker -> DashScopeChatClient.ask -> bookintro.json -> _o
6. 性能:大书量时(>1000列表初始化可用分页或懒加载。
7. 打包:后续可用 `PyInstaller`将可执行与资源icons、ui整合。
### 12.13 风险与缓解
### 13.13 风险与缓解
| 风险 | 描述 | 缓解 |
|------|------|------|
| 数据不同步 | data/ 下 sqlite 未更新导致已读缺失 | 提供“重新同步”按钮;比对文件修改时间 |
@ -373,32 +397,6 @@ AI 请求 -> BookReviewWorker -> DashScopeChatClient.ask -> bookintro.json -> _o
(本节为 2025-09 结构化重构新增)
## 13. UML 图Mermaid
> 注:使用 Mermaid 语法,支持在支持渲染的 Markdown 查看。类之间仅展示主要依赖/调用,非完整字段集合。
### 13.1 类图(核心模块)
![img](uml/iShot_2025-09-07_12.55.41.png)
### 13.2 时序图:应用启动
![img](uml/iShot_2025-09-07_12.56.27.png)
### 13.3 时序图:选择书籍 + AI 简评
![img](uml/iShot_2025-09-07_12.56.00.png)
### 13.4 时序图:导出 Markdown
![img](uml/iShot_2025-09-07_12.57.06.png)
### 13.5 时序图:已读书籍网格刷新
![img](uml/iShot_2025-09-07_12.57.19.png)
### 13.6 时序图:点击已读封面跳转
![img](uml/iShot_2025-09-07_12.57.28.png)
---
## 14. 书籍阅读时长统计与可视化
### 14.1 阅读时长统计逻辑
@ -470,3 +468,5 @@ AI 请求 -> BookReviewWorker -> DashScopeChatClient.ask -> bookintro.json -> _o
- 气泡图支持动画过渡或改为雷达/仪表盘形式;“已读”气泡可按年份切换(未来提供年份选择器)。
- 增加刷新按钮与 Esc 退出全屏逻辑。
---