Skip to content

v0.1.4

Choose a tag to compare

@github-actions github-actions released this 12 Sep 13:10
· 55 commits to main since this release

下载与安装

本页为 Android 安装包,按设备 CPU 架构拆分为 4 个 APK,选择匹配的一个下载即可:

  • arm64-v8a:近几年的主流手机 / 平板(64 位),绝大多数设备选这个
  • armeabi-v7a:仅支持 32 位应用的老设备
  • x86_64 / x86:Android 模拟器(分别对应 64 / 32 位镜像)

系统要求 Android 7.0(API 24)及以上。

直接覆盖安装即可升级,书架、书源、设置等数据保留在设备本地,不受影响。

使用中遇到问题欢迎到 Issues 反馈,请附上设备型号与 Android 版本。

以下为本版本更新内容:

Added

  • 书源编辑页重排为常驻三 Tab(书源信息 / JS代码 / 测试):切 Tab 不丢草稿,
    页头保存按钮与 Tab 栏始终在位,长表单(信息 / 测试)在各自 Tab 内滚动;
    • JS代码:编辑器占满整页剩余空间,带行号槽与语法高亮(关键字 / 字符串 /
      模板串与 ${} 插值 / 正则 / 数字 / 注释 / 书源宿主 API http·html·util·
      base64·cryptoUtil·webview·console 单独配色);长行横向滚动不折行,
      滚动时行号与高亮层同步,配色随浅色 / 深色 / 护眼主题切换;
      输入层是原生输入框,中文输入法与长按选词照常;
    • 「填入模板」在已有代码时需再点一次确认,避免一键抹掉正在写的内容;
    • 入口函数与测试参数在切 Tab 后仍保留(不会切走再切回就被重置)。
  • 处理不了的异常会明确提示用户(不再只写日志 / 控制台):
    • Rust 侧任何漏网的 panic(书源引擎、第三方解析库、命令线程……)都会经 panic hook
      以 readerx-internal-error 事件推给前端,弹出错误提示条并附「消息 + 位置」,停留 8 秒;
    • 前端接管全局未捕获异常(window.onerror)与未处理的 Promise 拒绝(unhandledrejection);
    • 后端读写本地设置 / 书籍 / 书源列表 / 正文拉取 / 登录状态清除等原先只 console.error
      后静默降级的路径,改为把真实原因提示给用户(相同文案去重并按重复次数退避,
      批量下载 / 持续写盘失败不会刷屏);
    • 「本地设置载入失败」「书库载入失败」也会提示,同时仍以内置默认值继续渲染,不再出现
      「数据凭空没了但没有任何说明」的情况;
    • 网页登录的 Cookie 持久化失败不再只写日志:登录提示会说明「Cookie 保存失败(重启后需重新登录)」。
  • 书源支持网络导入:书源管理页右上角新增「链接」图标(空列表时也有「从网址导入」按钮),
    粘贴一个指向书源 JSON(单个或数组)的 http/https 网址即可拉取并进入原有「确认导入」流程
    (冲突覆盖逐条可选、含免责声明),无需先下载到本地再选文件;网址不合法 / 拉取失败 /
    内容无法解析时会就地提示原因。
  • 在线书「书籍详情」页右上角新增刷新按钮(仅在线书显示):可随时重新拉取书籍信息——重调书源 bookDetail 取回最新简介与封面(封面仍经书源会话下载压缩成缩略图落盘),书源在详情里新补充 / 更新的简介与封面无需重新入架即可同步;刷新中按钮转圈禁用,结果以轻提示反馈。
  • 标签可点击触发「发现」快速搜索:书籍详情页(/detail/:id)与发现页在线书详情抽屉里的只读标签点击后,会切到发现页「搜索」模式并以该标签为关键词自动跑一次全源搜索(从详情页进入时跳转 /discover?q=标签),方便按题材/关键词找同类书;编辑态带移除按钮的标签不受影响。
  • 书源封面(BookItem.cover 可选字段,自动兜底):书源在 searchBook / discoverBooks / bookDetail 里返回书籍封面绝对地址后,「发现」的搜索结果 / 分类发现列表行与「书籍详情」预览会展示真实封面;「加入书架」时应用经该书源会话(Cookie / UA / 默认请求头,Referer 取书页地址 bookUrl)下载封面并压缩为缩略图随书保存,书架与书籍详情页显示真实封面——带防盗链或需登录的图站同样适用。书源未返回封面、地址非法或下载失败时自动回退书名首字渐变占位封面,不影响搜索 / 预览 / 入架;列表行封面采用「滚入视口附近才下载」的懒加载,封面下载并发受全局「书源并发」设置约束,同一封面一次会话内复用下载结果。
  • 在线书「书籍详情」页新增「书源地址」行(仅在线书展示):显示该书在书源网站的书页 URL,点击该行即用系统浏览器打开书源原网页(Tauri 端走系统默认浏览器,网页预览下退化为新标签页),便于到书源站点核对正版页面与更新。
  • 书源新增「自动网页认证」(书源 JSON autoAuth,默认开启,编辑页「网页登录」卡片内可单独关闭):
    http.* 请求命中 Cloudflare 人机挑战(或 cf_clearance 令牌过期后再次挑战)时,引擎在 Android 端
    自动拉起应用内 WebView 完成认证、覆盖式刷新并按书源持久化 Cookie,然后自动重试原请求一次
    (书源代码无需改动,普通 http.get 即可);两次自动弹窗间约 45s 全局冷却,避免批量下载/并发搜索
    连环弹窗。未弹窗/被取消/刷新后仍被拦截时,原挑战响应带 cf 字段(auto:disabled/unsupported/
    cooldown/cancelled/stale)返回;书源代码显式 webview.login(url) 也受该书源 autoAuth 开关
    约束(关闭时返回 ok:false),编辑页手动「网页登录」不受影响。桌面/iOS/浏览器预览不支持时静默降级,
    详见 docs/cloudflare.md 与 docs/book-source-api.md。
  • 书源作品信息支持 tags 标签字段(searchBook / discoverBooks / bookDetail 返回的 BookItem 可带 tags 字符串数组,自动去重去空白,单个 ≤ 24 字、至多 30 个):发现页点击结果弹出的「书籍详情」预览会展示标签,「加入书架」时随书保存;所有书籍(含在线书)都可在书籍详情页查看,并通过右上角「编辑」增删标签(本地导入的书同样适用)。
  • 在线书正文图片改为阅读时按需下载(新增 src/lib/chapterImages.ts):拉取章节正文只解析并保存图片地址,正文立刻落盘、拉取速度与纯文字章一致;用户读到该章时才经书源会话逐张取回并写回本地章节(离线可读、本次运行内不重复请求,下载并发受「书源并发」约束、最多 4 路)。分页排版先等本章图片就绪(最多 8s,超时先按占位把正文给用户、图片到位后再排一次),避免先按占位高度排一遍、图片到位后又整章跳动;等待期间覆盖层显示「正在获取图片 x / y」。
  • 在线书图片缺失可再次尝试获取:下载失败的图片在正文里显示带「重试」按钮的占位框(点一下忽略冷却立即重取,成功后本章按真实尺寸重排);同一张图再次读到本章时也会自动再试一次,两次自动尝试之间约 4s 冷却,避免连环打图站。
  • 「下载剩余全部」改为正文与图片分两趟:先把所有章节正文下完,再单独过一遍图片(不与获取章节同时取图),下载面板分别显示两阶段进度与失败张数;图片失败不影响章节正文的下载结果。
  • 简繁转换(新增 src/lib/hanConvert.ts 与 src/lib/hanDisplay.ts):设置页「阅读」区块与阅读器「阅读设置」面板都可一键切换「关闭 / 简→繁 / 繁→简」,选定后应用内书籍文字自动换成对应字形 —— 书名、作者、简介、标签、目录章节名、阅读页正文与页眉页脚、书架卡片、书籍详情、发现页的搜索结果与分类列表、在线书详情预览(简介 / 目录 / 标签)、书架搜索一并生效;听书朗读与全书搜索读到的也是转换后的同一份文字。
    转换只作用于展示副本:书库原文、书源返回的数据、入架落盘内容与用户手输内容(书籍编辑表单、文本替换规则)都不受影响,随时切回「关闭」即可还原。词典来自 opencc-js(OpenCC 的纯 JS 实现,MIT / Apache-2.0),简→繁约 1.1 MB、繁→简约 110 KB,按方向动态加载,未开启的用户不下载也不解析;章节正文按需惰性转换(读到哪一章才转哪一章),打开大书不会先卡一次,目录、听书、全书搜索也都只转换真正访问到的章节。

Fixed

  • 有章节在下载时,批量下载 / 重新加载本章不会被挡住:正文拉取从「每本书同一时刻只允许一个任务」
    改为各自独立、可并存,冲突一律以用户操作为准:

    • 下载面板的「下载剩余全部」随时可点:开始后后台窗口预取让位(它覆盖的窗口章节本就在批量目标里,
      且批量下载继续按「阅读焦点」优先取回正在读的那一章),不再出现按钮显示「下载中…」点不动的情况;
    • 「重新加载本章」在窗口预取 / 批量下载进行中同样可用(同一章正在重载时不重复发起);正在重载的
      那一章其余任务跳过,重载结果也不会被随后返回的旧拉取覆盖;
    • 「检查书籍更新」不再要求先停下下载:末尾追加照常执行;结构冲突选「覆盖更新」时自动停掉在跑的
      章节拉取,并让已发出、随后才回来的正文回写作废(不会写到重排后的错位章节上);
    • 书籍详情页「重新拉取书籍信息」同样不再被章节下载拦住(它只改元信息,不影响正文);
    • 底层配套:同一本书的写盘按书 id 排队串行(Rust 侧章节回写与元信息补丁都是「读文件 → 改 →
      整本写回」,并发执行会互相丢掉对方刚写好的内容),且每笔写在队列内基于最新缓存 + 最新目录
      复核后再套用补丁;正文回写改为先到先得,只有用户显式「重新加载本章」才覆盖已有正文,
      图片本地副本的回写改为与最新正文合并(与重载并发时不会拿旧正文覆盖新正文)。
  • 修复「图片多的在线书加载时应用直接崩溃」:此前正文图片下载后是以 data URL(base64)写进书籍
    JSON
    的,同一张图会同时存在于磁盘 JSON、Rust 解析出的字符串、IPC 报文、WebView 的 JS 字符串,
    并在排版时被逐张解码 —— 一章几百张图时内存成倍膨胀(一本书的 JSON 甚至能到几百 MB),
    打开书 / 应用启动扫描书库时会直接被系统杀掉。现在改为:

    • 图片字节由 Rust 写成本地图片文件(应用数据目录 images/<书籍id>_<地址哈希>.<扩展名>),
      章节块只保留文件名引用,书籍 JSON 与 IPC 报文都只带少量文本,内存占用与图片数量解耦;
    • 渲染经应用内自定义协议 readerx-img 直接从文件读取(离线可读),图片按 loading="lazy"
      惰性解码,图片被重新下载时才重新请求;
    • 排版所需的图片尺寸由 Rust 读文件头解析(JPEG / PNG / GIF / BMP / WebP),不再为了量尺寸把
      整章图片解码一遍;只有尺寸确实未知的图(老 data URL / SVG)才退回解码,且限 3 路并发;
    • 书库元数据扫描跳过图片载荷(流式解析),应用启动不再为书库里的图片字节分配内存;
    • 旧数据自动迁移:已存在的书籍(含 EPUB 插图)在打开 / 回写时把章节里的 data URL 图片抽成文件,
      超大书籍文件走流式重写(内存占用只与单张图片同级),迁移失败则原样保留、不丢图;
    • 顺带修复:Rust 侧回写书籍时会丢掉图片块的 remote 字段(导致下载过的图无法重试);
      书籍文件改为「先写临时文件再原子替换」,写到一半崩溃不会再留下半截书文件。
  • Rust 端不再「直接抛异常」把应用打崩:全面梳理了会 panic 的路径,改为返回可读错误或安全兜底 ——
    远端响应头 Content-Type 含非 ASCII 字符(如 İcharset=)时,旧实现拿 to_lowercase 得到的下标去切原串,
    会越界 panic(任何站点都能触发),现改为等长的 ASCII 小写匹配;HTTP 方法解析、书源 HTML 转纯文本
    等所有可能越界的切片都改成安全取值。书源 JS 执行线程与全部 IPC 命令统一加了 panic 兜底
    (release 由 panic = "abort" 改为 unwind + catch_unwind):引擎 / 第三方解析库万一 panic,
    也只让这一次调用失败并把 …内部异常: 原因 回传前端,其它章节、其它书源不受影响;
    同时安装 panic hook,把「消息 + 位置」打到 logcat 并推给前端提示(见上「Added」)。

  • 书源死循环 / 无限递归不再卡死界面:Boa 引擎增加单个函数帧的循环次数上限(约 1 亿次),并把引擎的
    运行时限制翻译成中文原因 —— while (true) {} 这类规则现在返回「循环次数超出上限(书源代码可能存在死循环)」,
    而不是让引擎线程被永久占住、界面一直转圈(说明同步更新到 docs/book-source-spec.md 与 docs/book-source-api.md)。

  • 无 charset 的短响应体不再整段乱码:响应解码「合法 UTF-8 优先」的判断里,替代符计数被 max(1) 固定,
    导致长度不足约 334 字符的无 charset 响应(返回中文书名的 JSON 接口 / 小页面很常见)被误判成 GB18030;
    现在只要整段是合法 UTF-8 就直接按 UTF-8 解码,与文档描述一致。

  • 批量拉正文时单个 worker 异常不再让整批结果丢失:未领取的章节交给其它 worker 继续处理,最终没有写回结果的
    章节会带上真实原因,而不是笼统的「未知错误」。

  • 应用启动明显提速:此前首帧必须等 Rust 把整座书库的完整正文(每本书的全部章节 + 在线书内嵌 data URL 大图)读出来并整体搬进 WebView 才渲染,启动耗时随书库总字节数增长。现在启动只拉书库「元数据」(章节标题 + 每章字符数),外壳立即渲染、书库后台载入;书架 / 搜索 / 详情等页面直接消费元数据展示封面与进度,单本正文在打开阅读页时才按需读取。Rust 侧新增 readerx_book_list_meta / readerx_book_get / readerx_book_patch_meta:元数据只带章节头,正文按需单本读取,分组 / 书名 / 封面等编辑在磁盘就地打补丁,正文不再整本经 IPC 往返。

  • 修复新增 / 改动书源后不立即生效、必须重启软件的问题:书源管理页的「启停开关」与「JSON 导入(新增 / 覆盖)」此前直接写入后端文件,却没有同步进程内的书源清单(该清单只在应用启动时加载一次),导致改动要重启后才在「书源管理 / 发现」页体现。现在每次启停、导入完成后都会立即重拉书源清单,新增、覆盖、停用的书源无需重启即时生效。

  • Android 端禁用 WebView 页面手势缩放:双指捏合 / 双击不再把整页放大错乱(首页 viewport meta 增加 maximum-scale=1, user-scalable=no),阅读字号仍由应用内设置调节。

  • tts悬浮球播放键图标异常。

  • 「重新加载本章」现在全过程可见:此前点下去没有任何反馈(设置面板收起、正文照旧),用户无法判断是否在加载 —— 现在阅读区立即盖上「正在重新加载本章…」覆盖层(带取消入口,覆盖期间不翻页 / 不误呼菜单),设置面板里的该行也同步转圈并显示「正在重新加载本章…」;加载成功提示「已重新加载「章节名」」,失败则回退到重载前的阅读进度(分页页码与段落文字偏移双保险)并提示失败原因,不再静默停在原位。

  • 在线书下载正文时阅读页不再高频闪烁:此前阅读器读的是整本书对象,后台每落盘一章都会换掉整本书 → 阅读区重新测量尺寸并写入一个新的面积对象 → 排版参数失效 → 当前章整章重新分页(页面闪断、偶发「正在加载」),批量下载时尤其明显。现在阅读视图只读取「当前章 ±1 章」这份窗口视图(src/lib/renderWindow.ts):窗口内三章与书籍元信息都没变时沿用上一次的书对象引用,章节内容、分页、进度百分比、面积测量整条渲染链路全部跳过;面积测量也改为尺寸没变就不写信号。目录 / 下载面板 / 全书搜索 / 听书引擎仍读实时书库,下载状态与跨章朗读不受影响。

  • 章节头与每章字符数改为按章节对象缓存复用(未变章节保持同一引用),正文回写对书架可见元数据的发布按 ~250ms 合并、可见数据没变时整次跳过 —— 此前每落盘一章都要按全书正文重算一遍字数并发布一次整本书库清单。阅读器的显示级文本替换同样按章节缓存,下载期间不再反复重跑全书替换规则。

  • 修复阅读页正文加载期间点屏幕中间呼不出菜单:正文未就绪时盖在阅读区上的两层覆盖层(大章节「正在加载…」与在线书「正在获取章节正文…」)会吞掉按下 / 抬起事件,等待期间菜单完全无法呼出 —— 而在抓正文往往要等几秒,菜单正是这段时间里看目录 / 下载 / 改设置或返回的唯一入口。现在覆盖层不再拦截手势,翻页约束改由手势判定承担:正文未就绪时点中间照常呼出菜单,左右区域与横向滑动翻页仍按原门闩语义被挡住(正文没就绪时自绘选区引擎本就停用,不会误起选)。

  • 在线书读到哪一章就先出哪一章:此前阅读窗口预取(当前章 ±5 章)把整个窗口一次性交给书源引擎取回,要等窗口内所有章节都拉回来才开始写回书库,正在读的这一章因此必须陪跑其余章节的预取(跳章后尤其明显)。现在当前阅读章单独请求、取回即落盘,阅读器拿到本章正文直接显示,其余窗口章节随后按小批(约 2×书源并发)后台补齐、逐章落盘;拉取任务在跑时切章也不用等它跑完 —— 窗口预取会在下一批之后改以新章为中心先取本章,批量下载也会把正在阅读的未缓存章节提前单独取回。

Changed

  • 发现页搜索「出一个书源显示一个」:此前要等所有书源跑完(Promise.all + 末尾按书源名排序)才一次性列出结果,慢源 / 超时源会拖住全部结果。现在每个书源一返回就把它的结果追加到列表上屏,搜索进度条与结果同屏共存(有结果时缩短为一行),底部计数显示「已找到 N 条 · 仍在搜索其他书源…」;列表顺序即书源返回顺序,不再在结束时重排,避免结果行在用户点击时跳动。同时新增搜索开始清空上一次结果、被新搜索接管后旧书源的回包直接丢弃。
  • 在线书的两级窗口明确分工:预取窗口保持「当前章 ±5 章」(后台提前抓 11 章落盘,顺序阅读与听书跨章不断档),渲染窗口为「当前章 ±1 章」(阅读视图实际读取的范围)。窗口外的正文回写只落盘、不惊动前端渲染。
  • 在线书章节 img 块新增可选字段 local(本地副本文件名):图片字节改为存在应用数据目录的
    images/ 下,章节只留引用(src 保持原始网络地址、remote 保持图片身份),渲染由
    readerx-img 自定义协议直读文件;旧数据启动后首次打开 / 回写时自动迁移,书源 schemaVersion 不变。
  • 在线书章节 img 块新增可选字段 remote(图片原始网络地址):src 仍是可直接渲染的地址(未下载时即网络地址),阅读时下载 / 重试 / 本地副本对应一律以 remote 为准,旧数据(只有 src)按原逻辑直接渲染,书源 schemaVersion 不变。