From 0c01d9a77ce609ef792a5b25864e92444c214310 Mon Sep 17 00:00:00 2001 From: meidlinger Date: Thu, 18 Jun 2026 16:49:53 +0800 Subject: [PATCH 1/2] =?UTF-8?q?Update=20plugin=20=E9=9A=90=E9=98=85?= =?UTF-8?q?=E7=9B=92=20v1.3.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - feat: 初始化ZTools插件项目 - feat: 实现隐阅盒阅读器插件 - chore(gitignore): add ignore rules - chore: 相关标识重命名 - chore: add changelog - fix: 修复书架导入书籍异常未捕获、完善本地存储数据兼容逻辑 - docs: 更新README - docs: 重写README - feat: 发布1.1.0版本,新增多项功能并修复多个bug - fix(窗口拖动): 修复阅读窗口拖动拉伸卡顿问题 - chore: bump plugin version to 1.1.1 - chore: 重命名部分称呼 - feat(setting): add plain cover option, remove epub cache storage - feat: 新增MOBI电子书格式支持 - feat: 迁移封面和章节缓存到ztools.db - feat: 新增主题模式切换功能,优化深色主题样式 - chore: release v1.3.0, update plugin info and changelog - style: 优化窗口进度显示 - chore: 发布v1.3.1版本,更新功能与修复问题 - chore: bump plugin version to 1.3.1 - fix: 修复多个已知问题并优化部分功能 - style(settings): 优化设置项的封面提示文案 - fix(bookshelf): 修复纯色封面关闭后MOBI封面未恢复的问题 - docs: 更新README中的截图 - feat(bookshelf): 实现拖拽导入书籍功能 - feat(bookshelf): 增加快捷导入命令 - chore: update gitignore and changelog - feat(tips): 增加提示文本 ,更新版本标识 - feat: 新增多选批量操作、重载元数据和恢复封面功能 - style(plugin.json): 调整插件命令列表的排序顺序 - feat: 新增书籍信息弹窗与阅读数据追踪,优化元数据解析 --- plugins/hushreader/.gitignore | 3 +- plugins/hushreader/CHANGELOG.md | 17 + plugins/hushreader/README.md | 18 +- plugins/hushreader/public/plugin.json | 27 +- plugins/hushreader/src/App.vue | 42 +- .../src/components/Bookshelf/BookCard.vue | 49 +- .../components/Bookshelf/BookInfoModal.vue | 628 ++++++++++++++++++ .../src/components/Bookshelf/ContextMenu.vue | 15 + .../src/components/Bookshelf/index.vue | 598 ++++++++++++++++- .../src/components/Settings/index.vue | 53 +- plugins/hushreader/src/stores/books.ts | 14 +- plugins/hushreader/src/utils/epubParser.ts | 4 +- plugins/hushreader/src/utils/mobiParser.ts | 17 +- 13 files changed, 1434 insertions(+), 51 deletions(-) create mode 100644 plugins/hushreader/src/components/Bookshelf/BookInfoModal.vue diff --git a/plugins/hushreader/.gitignore b/plugins/hushreader/.gitignore index b8b54725..eb8e7331 100644 --- a/plugins/hushreader/.gitignore +++ b/plugins/hushreader/.gitignore @@ -1,3 +1,4 @@ node_modules dist -**/*.zip \ No newline at end of file +**/*.zip +test \ No newline at end of file diff --git a/plugins/hushreader/CHANGELOG.md b/plugins/hushreader/CHANGELOG.md index ccce34d0..15ed646c 100644 --- a/plugins/hushreader/CHANGELOG.md +++ b/plugins/hushreader/CHANGELOG.md @@ -2,6 +2,23 @@ All notable changes to this project will be documented in this file. +## [1.3.2](https://github.com/me1dlinger/hushreader/releases/tag/v1.3.2) - 2026-06-18 + +### Added +- **拖拽导入书籍**:将书籍文件拖入书架界面时,显示拖拽悬停覆盖层提示"导入书籍",松手后弹出确认弹窗列出待导入文件,确认后解析书籍并保存元数据,取消则放弃导入 +- **快捷文件导入**:支持通过 `hushreader-import` 命令从 ztools 快捷导入书籍文件,`onPluginEnter` 触发时自动解析并添加到书架 +- **TXT 章节正则提示气泡**:设置页"TXT 章节识别正则"标签旁新增 ⓘ 提示图标,悬停/聚焦时显示默认规则说明 +- **重载元数据**:右键菜单新增"重载元数据"选项,重新解析书籍的章节、封面、标题、作者等信息并更新,同时清除自定义封面 +- **恢复封面**:右键菜单新增"恢复封面"选项,EPUB/MOBI 删除自定义封面并重新从文件加载封面,TXT 删除自定义封面恢复为纯色封面 +- **多选模式**:书架头部新增多选按钮,点击进入多选模式,可逐个勾选书籍或通过分类栏"全选"按钮批量选中当前分类下所有书籍 +- **批量操作**:多选模式下底部显示操作栏,支持批量重载元数据和批量删除,批量删除前弹出确认弹窗 + +- **书籍信息窗口**:右键菜单新增"书籍信息"选项,打开信息窗口展示封面与标题作者、简介、分类、阅读信息(导入/更新/首次阅读/最近阅读时间、阅读时长、阅读速度);支持编辑模式可上传自定义封面、编辑标题/作者/简介、选择已有分类或新建分类 +- **EPUB/MOBI 简介解析**:导入和重载元数据时从 EPUB metadata.description 和 MOBI EXTH record 101 提取书籍简介 +- **阅读进度追踪**:保存阅读进度时记录首次阅读时间(firstReadAt)、累计阅读时长(readingTimeMs)、阅读速度(readingSpeed) +- **updatedAt 时间戳**:书籍新增时设置 updatedAt = addedAt,编辑元数据或上传封面时更新 updatedAt,分类变更不更新 updatedAt + + ## [1.3.1](https://github.com/me1dlinger/hushreader/releases/tag/v1.3.1) - 2026-06-17 ### Added diff --git a/plugins/hushreader/README.md b/plugins/hushreader/README.md index b7ca6d62..9789cae1 100644 --- a/plugins/hushreader/README.md +++ b/plugins/hushreader/README.md @@ -1,6 +1,8 @@
-# 隐阅盒 · HushReader +![HushReader Logo](public/logo.png) + +# [隐阅盒 · HushReader](https://github.com/me1dlinger/hushreader) 适配 [ZTools](https://github.com/ZToolsCenter/ZTools) 的阅读插件,支持 TXT / EPUB / MOBI 格式 @@ -19,12 +21,14 @@ ## 截图 -
- - - - -
+![书架](https://files.seeusercontent.com/2026/06/17/qvX8/image_86.png) +![暗色模式](https://files.seeusercontent.com/2026/06/17/lu4H/image_85.png) +![书籍信息](https://files.seeusercontent.com/2026/06/18/D9di/image_90.png) +![隐阅窗口设置](https://files.seeusercontent.com/2026/06/17/eCu4/image_89.png) +![功能设置](https://files.seeusercontent.com/2026/06/17/0bqW/image_88.png) +![其他设置](https://files.seeusercontent.com/2026/06/17/y3uD/image_87.png) +![隐阅效果](https://files.seeusercontent.com/2026/06/18/h1Jb/show.gif) + ## 快速开始 diff --git a/plugins/hushreader/public/plugin.json b/plugins/hushreader/public/plugin.json index f3822f18..ffed5746 100644 --- a/plugins/hushreader/public/plugin.json +++ b/plugins/hushreader/public/plugin.json @@ -4,7 +4,7 @@ "title": "隐阅盒", "description": "隐阅盒,ZTools自己的摸鱼阅读,支持TXT/EPUB/MOBI格式,沉浸式阅读", "author": "meidlinger", - "version": "1.3.1", + "version": "1.3.2", "main": "index.html", "preload": "preload/services.js", "logo": "logo.png", @@ -17,11 +17,11 @@ "explain": "打开书架", "icon": "logo.png", "cmds": [ - "yyh", - "摸鱼阅读", "隐阅盒", "书架", - "hushreader" + "摸鱼阅读", + "hushreader", + "yyh" ] }, { @@ -31,6 +31,25 @@ "cmds": [ "开始阅读" ] + }, + { + "code": "hushreader-import", + "explain": "导入本地书籍", + "icon": "logo.png", + "cmds": [ + "导入书籍", + { + "type": "files", + "fileType": "file", + "extensions": [ + "txt", + "epub", + "mobi" + ], + "maxLength": 1, + "label": "导入到 隐阅盒" + } + ] } ], "platform": [ diff --git a/plugins/hushreader/src/App.vue b/plugins/hushreader/src/App.vue index 43c6bc93..f07a3b16 100644 --- a/plugins/hushreader/src/App.vue +++ b/plugins/hushreader/src/App.vue @@ -356,13 +356,43 @@ function closePlugin() { function saveReadingProgress() { const book = bookStore.currentBook if (!book) return - bookStore.updateBook(book.id, { + const now = Date.now() + const updates: Partial = { lastChapter: readerStore.currentChapterIndex, progressIndex: readerStore.progressIndex, - lastReadAt: Date.now(), + lastReadAt: now, totalChapters: readerStore.chapters.length, readingPercent: readerStore.readingPercent - }) + } + if (!book.firstReadAt) { + updates.firstReadAt = now + } + if (book.lastReadAt && book.lastReadAt > 0) { + const elapsed = now - book.lastReadAt + if (elapsed > 0 && elapsed < 30 * 60 * 1000) { + const totalMs = (book.readingTimeMs || 0) + elapsed + updates.readingTimeMs = totalMs + const totalChars = readerStore.chapters.reduce((sum, ch) => sum + ch.content.length, 0) + const currentReadChars = Math.round(totalChars * (readerStore.readingPercent / 100)) + const prevReadChars = book.lastSaveReadChars || 0 + const deltaChars = Math.max(0, currentReadChars - prevReadChars) + updates.lastSaveReadChars = currentReadChars + const elapsedMinutes = elapsed / 60000 + if (elapsedMinutes > 0 && deltaChars > 0) { + const sessionSpeed = deltaChars / elapsedMinutes + const prevSpeed = book.readingSpeed || 0 + if (prevSpeed > 0) { + updates.readingSpeed = Math.round(prevSpeed * 0.6 + sessionSpeed * 0.4) + } else { + updates.readingSpeed = Math.round(sessionSpeed) + } + } + } + } else { + const totalChars = readerStore.chapters.reduce((sum, ch) => sum + ch.content.length, 0) + updates.lastSaveReadChars = Math.round(totalChars * (readerStore.readingPercent / 100)) + } + bookStore.updateBook(book.id, updates) } function getFileModifiedTime(filePath: string): number | null { @@ -624,9 +654,9 @@ watch( } ) -onMounted(() => { - configStore.load() - bookStore.load() +onMounted(async () => { + await configStore.load() + await bookStore.load() ;(window as any).ztools?.onPluginEnter?.((action: any) => { route.value = action.code enterAction.value = action diff --git a/plugins/hushreader/src/components/Bookshelf/BookCard.vue b/plugins/hushreader/src/components/Bookshelf/BookCard.vue index 87b44676..35869d3b 100644 --- a/plugins/hushreader/src/components/Bookshelf/BookCard.vue +++ b/plugins/hushreader/src/components/Bookshelf/BookCard.vue @@ -5,12 +5,15 @@ import type { Book } from '../../stores/books' const props = defineProps<{ book: Book listMode?: boolean + selectionMode?: boolean + selected?: boolean }>() const emit = defineEmits<{ click: [] contextmenu: [e: MouseEvent] 'cover-error': [] + 'toggle-select': [] }>() const imgError = ref(false) @@ -46,10 +49,14 @@ function progressText(book: Book): string {