Skip to content

Update plugin 隐阅盒 v1.3.0#266

Merged
lzx8589561 merged 4 commits into
ZToolsCenter:mainfrom
me1dlinger:plugin/hushreader
Jun 17, 2026
Merged

Update plugin 隐阅盒 v1.3.0#266
lzx8589561 merged 4 commits into
ZToolsCenter:mainfrom
me1dlinger:plugin/hushreader

Conversation

@me1dlinger

@me1dlinger me1dlinger commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

插件信息

  • 名称: 隐阅盒
  • 插件ID: hushreader
  • 版本: 1.3.1
  • 描述: 隐阅盒,ZTools自己的摸鱼阅读,支持TXT/EPUB/MOBI格式,沉浸式阅读
  • 作者: meidlinger
  • 类型: 更新

本次变更

1.3.1 - 2026-06-17

Added

  • 窗口大小锁定开关:功能设置中新增"窗口大小锁定"开关,开启后窗口不允许拉伸调整大小

Fixed

  • 窗口可拖动开关生效:修复关闭"窗口可拖动"后窗口仍可拖动的问题,关闭后拖动区域 cursor 变为 default
  • ThemeToggle 主题未随配置加载更新:改用 watch + immediate: true 替代直接调用 applyTheme(),确保配置异步加载后主题也能正确应用
  • 纯色封面时误清章节缓存:开启"显示纯色封面"时仅清除封面和自定义封面缓存,不再误删章节缓存
  • MOBI 导入 coverUrl 未赋值:MOBI 解析成功后将 coverUrl 赋值给 coverImage
  • MOBI recordOffsets 边界检查:增加 firstRecordOffset + 16 > data.length 检查,防止格式损坏文件导致越界
  • MOBI firstImageIndex 为 0xffffffff 时封面索引错误:在 extractCoverUrl 中判断 firstImageIndex 无效值,避免错误计算封面记录索引
  • HTML 实体解码 fromCharCode → fromCodePoint&#xxx;&#xHH; 解码改用 String.fromCodePoint,parseInt 增加 radix 参数,支持 BMP 外字符
  • 纯色封面关闭后 MOBI 封面未恢复:新增 resolveMobiCovers() 函数,关闭纯色封面时同步恢复 MOBI 书籍封面(此前仅恢复 EPUB 封面)

Removed

  • 固定行数分页模式:移除分页模式中的"固定行数"选项,统一使用自适应模式

1.3.0 - 2026-06-17

Added

  • MOBI 格式支持:新增 MOBI 电子书格式的解析和阅读功能
  • 主题模式切换:新增"主题模式"切换

Changed

  • 封面和章节内容缓存迁移至 ztools.db 数据库:封面和章节内容不再每次实时解析,改为存到 ztools.db 数据库,提升书架加载和打开书籍的速度
    • 封面图(coverImage/customCoverImage)存入数据库文档 cover_{bookId} / custom_cover_{bookId},书架加载时从数据库恢复
    • 章节内容存入数据库文档 chapters_{bookId},打开书籍时优先从数据库加载,文件修改后自动重新解析并更新缓存
    • 删除书籍时同步清理数据库中对应的封面和章节文档
    • 开启"显示纯色封面"时清除数据库中的封面数据
    • dbStorage 中仅保留轻量数据:书籍列表(不含封面)、阅读进度、配置

截图 / 演示

自检清单

  • plugin.json 的 name / title / version / description / author 字段均已检查
  • 已移除调试日志、未使用文件、敏感信息(.env、token、密钥等)
  • 本次 PR 的 diff 仅涉及 plugins/hushreader/ 目录
  • 已在本地 ZTools 客户端实际加载并测试过此插件,主要功能正常
  • 同意以仓库声明的开源协议发布此插件

此 PR 由 ztools-plugin-cli 自动管理:每次 ztools publish 在分支上追加一个 commit,PR 链接保持不变。

- 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
@me1dlinger me1dlinger marked this pull request as ready for review June 17, 2026 08:02

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for the MOBI ebook format, including PalmDOC decompression, DRM detection, and cover extraction. It also migrates cover images and chapter content caching to a database (ztools.db) to improve performance and prevent storage overflow, and adds a theme toggle component for dark mode support. Feedback on these changes highlights several issues: MOBI covers are not saved during import, the theme toggle does not watch for configuration changes, and toggling the plain-text cover option accidentally deletes chapter caches. Additionally, the MOBI parser lacks boundary checks on record offsets, does not handle cases where firstImageIndex is 0xffffffff, and uses String.fromCharCode instead of String.fromCodePoint for HTML entity decoding.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +327 to +328
title = result.title || title
author = result.author || ''

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

在导入 MOBI 格式书籍时,解析得到的 result.coverUrl 没有赋值给 coverImage。这会导致导入的 MOBI 书籍无法提取并保存封面。建议在解析成功后,且未开启“显示纯色封面”时,将封面 URL 赋值给 coverImage

          title = result.title || title
          author = result.author || ''
          if (result.coverUrl && !configStore.config.other.plainTextCover) coverImage = result.coverUrl

Comment on lines +1 to +18
<script setup lang="ts">
import { computed } from 'vue'
import { useConfigStore } from '../../stores/config'

const configStore = useConfigStore()
const isDark = computed(() => configStore.config.other.theme === 'dark')

function toggle() {
configStore.config.other.theme = isDark.value ? 'light' : 'dark'
applyTheme()
configStore.save()
}

function applyTheme() {
document.documentElement.setAttribute('data-theme', configStore.config.other.theme)
}

applyTheme()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

在组件初始化时,applyTheme() 会立即执行,但此时 configStore.load() 尚未在父组件中完成调用,因此获取到的是默认的 light 主题。此外,由于没有对 configStore.config.other.theme 进行监听,当配置从数据库加载完成后,主题也无法自动应用。建议引入 watch 并开启 immediate: true,这样既能保证初始应用,也能在配置加载或切换时自动更新 DOM 的 data-theme 属性。

<script setup lang="ts">
import { computed, watch } from 'vue'
import { useConfigStore } from '../../stores/config'

const configStore = useConfigStore()
const isDark = computed(() => configStore.config.other.theme === 'dark')

function toggle() {
  configStore.config.other.theme = isDark.value ? 'light' : 'dark'
  configStore.save()
}

watch(
  () => configStore.config.other.theme,
  (newTheme) => {
    if (newTheme) {
      document.documentElement.setAttribute('data-theme', newTheme)
    }
  },
  { immediate: true }
)

b.customCoverImage = undefined
})
}
await Promise.allSettled(bookStore.books.map(b => removeBookData(b.id)))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

当开启“显示纯色封面”时,调用 removeBookData(b.id) 会同时清除数据库中的封面和章节内容(chapters_{bookId})。这会导致所有书籍的章节缓存被意外清空,下次打开书籍时需要重新解析,降低了加载速度。建议仅清除封面和自定义封面数据,保留章节内容缓存。

    await Promise.allSettled(
      bookStore.books.flatMap(b => [
        removeCover(b.id),
        removeCustomCover(b.id)
      ])
    )

Comment on lines +398 to +400
const firstRecordOffset = recordOffsets[0]
const palmDocHeader = parsePalmDocHeader(data, firstRecordOffset)
const mobiHeader = parseMobiHeader(data, firstRecordOffset)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

在解析 MOBI 文件时,直接将 recordOffsets[0] 作为 firstRecordOffset 传入 parsePalmDocHeader,但未校验该偏移量加上头部大小后是否超出了文件总长度。如果文件损坏或偏移量异常,可能会导致越界读取。建议在解析前添加边界检查,确保文件长度足够。

Suggested change
const firstRecordOffset = recordOffsets[0]
const palmDocHeader = parsePalmDocHeader(data, firstRecordOffset)
const mobiHeader = parseMobiHeader(data, firstRecordOffset)
const firstRecordOffset = recordOffsets[0]
if (firstRecordOffset + 16 > data.length) {
return { title: '', author: '', chapters: [], error: 'MOBI文件格式损坏或记录偏移越界' }
}
const palmDocHeader = parsePalmDocHeader(data, firstRecordOffset)
const mobiHeader = parseMobiHeader(data, firstRecordOffset)

Comment on lines +227 to +230
const coverRecord = findExthRecord(exthRecords, 201)
if (!coverRecord) return undefined

const coverRecordIndex = firstImageIndex + exthRawToUint(coverRecord.raw)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

如果 MOBI 文件中没有图片,firstImageIndex 的值通常为 0xffffffff(即 -1)。此时直接进行加法运算 firstImageIndex + exthRawToUint(...) 会导致计算出错误的索引。建议在提取封面时,先判断 firstImageIndex 是否为 0xffffffff,若是则直接返回 undefined

Suggested change
const coverRecord = findExthRecord(exthRecords, 201)
if (!coverRecord) return undefined
const coverRecordIndex = firstImageIndex + exthRawToUint(coverRecord.raw)
const coverRecord = findExthRecord(exthRecords, 201)
if (!coverRecord) return undefined
if (firstImageIndex === 0xffffffff) return undefined
const coverRecordIndex = firstImageIndex + exthRawToUint(coverRecord.raw)

Comment on lines +310 to +311
.replace(/&#(\d+);/gi, (_, code) => String.fromCharCode(parseInt(code)))
.replace(/&#x([0-9a-fA-F]+);/gi, (_, hex) => String.fromCharCode(parseInt(hex, 16)))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

在解码 HTML 实体字符时,使用 String.fromCharCode 无法正确处理 Unicode 码点大于 0xFFFF 的字符(例如部分 Emoji 或生僻字),会导致字符截断或乱码。建议使用 ES6 的 String.fromCodePoint 代替 String.fromCharCode

Suggested change
.replace(/&#(\d+);/gi, (_, code) => String.fromCharCode(parseInt(code)))
.replace(/&#x([0-9a-fA-F]+);/gi, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
.replace(/&#(\\d+);/gi, (_, code) => String.fromCodePoint(parseInt(code, 10)))
.replace(/&#x([0-9a-fA-F]+);/gi, (_, hex) => String.fromCodePoint(parseInt(hex, 16)))

- 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
- 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: 修复多个已知问题并优化部分功能
- 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封面未恢复的问题
@lzx8589561 lzx8589561 merged commit ffdb37d into ZToolsCenter:main Jun 17, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants