/api/v1/ai/capabilities now also answers `scan`: 启用 AI and 启用 AI 扫描 on and
Base URL, key and model filled in. 扫描与刮削 shows the AI 扫描 tab only then; while
the answer is unknown there is no tab, a ?tab=ai link falls back to 媒体库扫描,
and a server without the endpoint keeps the tab as before. The answer is
re-asked each time the page opens, so a switch changed in 系统设置 takes effect
on the next visit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reading time is counted by the reader: only while the page is visible and the
reader has turned, scrolled or tapped within three minutes, or while 朗读 plays.
It is kept per book per 15-minute UTC slot and per device install, saved
locally until sent, and stored as MAX(stored, reported) in the new
reading_time table, so a replayed report never counts twice.
Media time is derived on the server from the progress saves the web player and
Android Media3 already send: the smaller of the wall-clock gap and the position
advance between two saves of one session, gaps over 30s ignored. It is stored
in media.db (media_watch_time), so neither client changes.
我的 → 时长统计 shows a stacked bar per day (one month), month (one year) or
year, with a legend that filters by kind, a table view and the works ranked for
the range or the bar picked. Administrators also get every account's totals.
Chart colours are new mode-level tokens (--color-chart-1..4), validated for
colour-vision separation on both surfaces. The React UI review now covers the
page and names the overflowing elements when a screen overflows.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
reading_progress keeps one row per book and last-writer-wins, which answers
"where am I" and loses "where was I": a stale device, a mistapped 目录 entry
or a clock running ahead overwrote the place for good (P0: 进度历史).
Every valid progress write now also lands in reading_progress_history,
including a write that lost the merge. A device reading on through one
chapter updates its latest entry (same chapter, within 5% and 30 minutes)
instead of adding rows; another chapter, a jump, another device or an
out-of-order write is a new entry. The newest 50 per book are kept.
GET /api/v1/sync/progress/:bookId/history lists them, newest first, for the
signed-in account only.
The table is new (CREATE TABLE IF NOT EXISTS), so the schema change is
additive and older builds sharing the database ignore it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The top bar always drew AI 总结, although AI is off by default, so most
readers pressed it only to be told AI_DISABLED (ui.md §4/§5: a control the
reader cannot use is not drawn). GET /api/v1/ai/capabilities tells any signed-in
account whether chapter summaries are enabled and configured, without exposing
the configuration; the reader asks once per book and leaves the button out
when the answer is no. Against an older server (404) the button stays.
The busy line while a summary is generated is a global notice like every other
one, instead of a hand-drawn .floating-notice.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Remove .cnb.yml and CNB references in the Dockerfile and Compose file; the
Compose default image is hectorqin/reader-pro:latest.
- Rename the Android applicationId/namespace and Kotlin package from
cool.cnb.reader to com.htmake.readerpro (shortcuts, ProGuard, shell check).
Installs under the old package are a different app and are not migrated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- browse move/rename/mkdir/delete/metadata now require an administrator
(403 ADMIN_REQUIRED for members).
- Members may upload, but only add books: unsupported formats are skipped,
zip/cbz are stored as comic archives rather than unpacked, and overwrite is
refused. The new business setting library.memberUpload (default on) turns
member uploads off (403 UPLOAD_DISABLED); GET /library/upload reports
`allowed`.
- The library page shows 上传书籍 to members when uploads are allowed.
- Shelf tests read user_books for the owner only, now that a second user exists.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Server: user_books gains reading_status. The shelf list computes each
book's readingState — an explicit 在读/已读 mark wins, otherwise progress
decides (>=99% 已读, started 在读), and 想读 gives way once reading starts —
filters by ?status=, and PUT /api/v1/books/:id/reading-status sets or
clears the mark.
Client: chips 全部/在读/想读/已读 and 分组 (a series or a tag from the
shelf's facets) above the toolbar, all kept in the URL; a state label on
each cover; the ⋯ menu marks 想读/在读/已读, clears the mark, or takes the
book off the shelf.
Docs: API, UI and media user guide for this and the other V3.1 gaps.
Server:
- Scan jobs record the number of files listed (total), so a running scan
can report a real percentage.
- New 扫描设置 business settings, shown as the page's 扫描与元数据 card:
自动扫描新文件 (hourly rescan of every library, default on),
刮削封面与简介 (after a completed scan, scrape items that have no online
metadata and were never attempted, with the first configured provider;
default off), 读取内嵌字幕与歌词 (default on; off hides embedded subtitle
streams and lyrics tags), 扫描隐藏文件夹 (default off: names starting
with '.' are skipped, e.g. ._film.mp4 resource forks).
- MediaAutomation runs the scheduled scans and post-scan scraping as the
first active administrator; MediaScanner gains onFinished/isScanning.
Client:
- Each library card shows its latest scan: 上次扫描 今天 09:12 beside
重新扫描; 正在扫描 · 已处理 62% with a progress bar and 取消; or the
failure (路径不可访问…) with 重试 and 查看详情 (the tasks page).
Starting or cancelling a scan now stays on the page; scan-jobs is polled.
- 扫描与元数据 card beside the list saves each switch with the settings
revision, and hides itself on servers without these settings.
Unify media secondary page chrome, loading states, playback controls, favorites filtering, and source/library screens with the legacy reader experience.
Align the React media detail, player, history, queue, shelf, and resource flows with the legacy UX. Refresh the migration validation record and add focused route, resource, and shelf parity coverage.
Support local and OpenList libraries, metadata, independent media navigation, themes, and audio/video playback. Preserve approved v2 prototypes and current documentation; archive superseded review artifacts and keep generated validation output outside version control.