diff --git a/README.md b/README.md index 0b9cdd1..b3875f6 100644 --- a/README.md +++ b/README.md @@ -287,7 +287,7 @@ src/data/reading.json src/components/bookshelf-content.astro ``` -- 刷新数据:`pnpm reading`(失败会明确报错并 exit 1);`pnpm reading --top 12` 可改抓取条数(默认 8) +- 刷新数据:`pnpm reading`(失败会明确报错并 exit 1)。默认抓**整架**(1 + N 个请求,书架几十本完全够用);想只抓最近动过的几本就 `pnpm reading --top 12` - **`pnpm build` 会自动先跑一次抓取,但用 `--soft` 模式**:微信读书挂了 / Key 过期 / 断网时,保留上一次的 `reading.json` 继续构建,**不会阻塞部署** - `src/data/reading.json` 是数据快照,**要提交进 git**,这样 CI 或新克隆的仓库没 Key 也能构建 - Key 申请: 扫码,拿到 `wrk-` 开头的串,写进 `.env` 的 `WEREAD_API_KEY`(`.env` 已 gitignore)。**只在本地构建**时用得上 —— `deploy.sh` 是本地构建再 rsync,凭据不会上传服务器;如果另外接了 Vercel / GitHub Actions 构建,要在那边单独配 secret @@ -302,7 +302,14 @@ src/components/bookshelf-content.astro - `category` 是 `文学-外国文学` 这种「大类-子类」复合串 - 时间戳统一按 `YYYY-MM-DD` 展示(官方硬性要求),顺带避开「N 天前」在静态站上会随构建时间变旧 -展示逻辑:过滤掉私密阅读(`secret === 1`)和从没打开过的书;读完的照常显示,标「已读完」;0% 标「还没开始」;有声书不管。 +展示逻辑: + +| 归到哪 | 条件 | +|---|---| +| 最近在读 | `progress < 100`(含 0%,标「还没开始」) | +| 书籍 → 「微信读书 · 已读完」分组 | `progress === 100` | + +这一组混在「书籍」区的网格里,卡片结构和手工书单一致,但没有书评/简介,所以点击是直接跳微信读书而不是弹窗。它们带 `data-weread-card` 和 `data-category="微信读书"`,所以搜索框和「领域」筛选同样作用得到(领域里会多出一个「微信读书」选项)。过滤掉的:私密阅读(`secret === 1`)、从没打开过的书;有声书不处理。 **2. 书籍** —— 来自 `public/data/books.json`,由 `bookshelf-content.astro` 在构建时 import(文件必须存在)。另外两个文件 `papers.json` / `comics.json` 对应的漫画、论文分类已经移除,文件保留但不再被引用。 diff --git a/docs/操作指南.md b/docs/操作指南.md index 7bb0d32..e8970cc 100644 --- a/docs/操作指南.md +++ b/docs/操作指南.md @@ -203,7 +203,9 @@ pnpm preview # 本地预览构建产物(搜索功能只有这里才生效 pnpm reading ``` -会打印抓到的每本书和进度。想看更多本就 `pnpm reading --top 12`(默认 8 本)。 +会打印抓到的每本书和进度。**默认抓整架**;想只抓最近动过的几本就 `pnpm reading --top 12`。 + +读完的书会自动出现在「书籍」区底部的「微信读书 · 已读完」分组里,不用手工搬。 **平时不用管**:`pnpm build` 和 `./deploy.sh` 都会自动先抓一次。抓不到就沿用上一次的数据,**不会让部署失败**。 diff --git a/scripts/fetch-reading.mjs b/scripts/fetch-reading.mjs index 43c8a75..0914ef1 100644 --- a/scripts/fetch-reading.mjs +++ b/scripts/fetch-reading.mjs @@ -2,7 +2,7 @@ * * 用法: * pnpm reading 手动刷新(失败会 exit 1,明确报错) - * pnpm reading --top 12 抓前 12 本,默认 8 + * pnpm reading --top 12 只抓最近动过的 12 本;不加则整架都抓(默认不限) * node scripts/fetch-reading.mjs --soft 失败时保留旧数据并 exit 0(构建流程用) * * 接口是腾讯官方的微信读书 Agent Gateway: @@ -25,14 +25,15 @@ const ENDPOINT = "https://i.weread.qq.com/api/agent/gateway" /** 与官方 SKILL.md 顶部的 version 保持一致;服务端会用它对版本 */ const SKILL_VERSION = "1.0.4" const OUT_FILE = "src/data/reading.json" -const DEFAULT_TOP = 8 +/** 0 = 不限制,整架都抓。书架一般也就几十本,1+N 个请求完全够用 */ +const DEFAULT_TOP = 0 const REQUEST_TIMEOUT_MS = 15_000 const DELAY_BETWEEN_CALLS_MS = 150 const args = process.argv.slice(2) const SOFT = args.includes("--soft") const topIndex = args.indexOf("--top") -const TOP_N = topIndex >= 0 ? Number(args[topIndex + 1]) || DEFAULT_TOP : DEFAULT_TOP +const TOP_N = topIndex >= 0 ? Number(args[topIndex + 1]) || DEFAULT_TOP : DEFAULT_TOP // 0 = 不限 // .env 已 gitignore;Node 22 自带 loadEnvFile,不需要 dotenv try { @@ -78,13 +79,15 @@ async function call(apiName, params = {}) { async function fetchReading() { const shelf = await call("/shelf/sync") - const candidates = (shelf.books ?? []) + const sorted = (shelf.books ?? []) // 私密阅读(secret=1)不要发到公开网站上 .filter((book) => book.secret !== 1) // readUpdateTime 为 0 表示从没打开过,不算「在读」 .filter((book) => Number(book.readUpdateTime) > 0) .sort((a, b) => Number(b.readUpdateTime) - Number(a.readUpdateTime)) - .slice(0, TOP_N) + + // TOP_N 为 0 时整架都取;页面再按「读完 / 在读」自己分组 + const candidates = TOP_N > 0 ? sorted.slice(0, TOP_N) : sorted if (candidates.length === 0) { return { books: [], note: "书架里没有可展示的阅读记录" } diff --git a/src/components/bookshelf-content.astro b/src/components/bookshelf-content.astro index d7856a2..07bf98e 100644 --- a/src/components/bookshelf-content.astro +++ b/src/components/bookshelf-content.astro @@ -5,10 +5,17 @@ import { cn } from "@/lib/utils" import booksData from "../../public/data/books.json" import { formatReadingDate, getReadingData } from "@/lib/reading" -// 微信读书「最近在读」。数据缺失时 reading 为 null,页面退化成空态,不报错。 +// 微信读书数据。数据缺失时 reading 为 null,页面退化成空态,不报错。 const reading = getReadingData() const readingBooks = reading?.books ?? [] -const readingCount = readingBooks.length + +// 读完的挪到「书籍」区,剩下的才留在「最近在读」 +const inProgressReading = readingBooks.filter((book) => !book.finished) +const finishedReading = readingBooks.filter((book) => book.finished) +const readingCount = inProgressReading.length + +/** 「书籍」区里给微信读书已读书记一个分类名,同时作为可筛选的领域 */ +const WEREAD_CATEGORY = "微信读书" // ---- Types @@ -41,7 +48,7 @@ const booksByCategory = allBooks.reduce>((acc, book return acc }, {}) -const bookCategories = ["全部", ...Object.keys(booksByCategory)] +const bookCategories = ["全部", ...Object.keys(booksByCategory), ...(finishedReading.length > 0 ? [WEREAD_CATEGORY] : [])] const bookStatuses = ["全部", "推荐", "中庸", "不行"] const bookStats = { @@ -151,9 +158,9 @@ const recommendBadge = (status?: string) => { ) : null} - {readingBooks.length > 0 ? ( + {inProgressReading.length > 0 ? (
- {readingBooks.map((book) => ( + {inProgressReading.map((book) => ( {
))} + + {/* 微信读书里已读完的书,并入「书籍」区。 + 卡片结构和上面的书一样,但没有书评/简介,所以点击直接跳微信读书,不弹窗。 + data-weread-card 让搜索框和领域/评价筛选同样作用于这一组。 */} + {finishedReading.length > 0 && ( +
+
+ )} {/* Empty state (shared, shown when filters return nothing) */} @@ -466,7 +528,7 @@ const recommendBadge = (status?: string) => { const applyBooks = () => { const q = state.query.trim().toLowerCase(); - const cards = document.querySelectorAll("[data-book-card]"); + const cards = document.querySelectorAll("[data-book-card], [data-weread-card]"); let totalVisible = 0; cards.forEach((card) => { const cat = card.getAttribute("data-category") || ""; @@ -481,7 +543,7 @@ const recommendBadge = (status?: string) => { if (show) totalVisible++; }); document.querySelectorAll("[data-books-section]").forEach((section) => { - const visible = Array.from(section.querySelectorAll("[data-book-card]")).filter((c) => !c.classList.contains("hidden")).length; + const visible = Array.from(section.querySelectorAll("[data-book-card], [data-weread-card]")).filter((c) => !c.classList.contains("hidden")).length; const countEl = section.querySelector("[data-books-count]"); if (countEl) countEl.textContent = `(${visible})`; section.classList.toggle("hidden", visible === 0); diff --git a/src/data/reading.json b/src/data/reading.json index 4b35ea7..bf92071 100644 --- a/src/data/reading.json +++ b/src/data/reading.json @@ -1,5 +1,5 @@ { - "updatedAt": "2026-09-15T02:39:58.551Z", + "updatedAt": "2026-09-15T02:45:18.862Z", "source": "weread", "books": [ { @@ -89,6 +89,204 @@ "finished": false, "lastReadAt": "2026-06-10T16:13:58.000Z", "deepLink": "https://weread.qq.com/book-detail?type=1&v=32f329e0813aba1d3g018fee" + }, + { + "bookId": "3300053824", + "title": "改变世界的17个方程", + "author": "伊恩·斯图尔特", + "category": "科学技术-自然科学", + "cover": "https://cdn.weread.qq.com/weread/cover/94/cpplatform_wxkigsn3nwuexqw4pspab6/t6_cpplatform_wxkigsn3nwuexqw4pspab61679905263.jpg", + "progress": 100, + "finished": true, + "lastReadAt": "2026-06-07T10:50:15.000Z", + "deepLink": "https://weread.qq.com/book-detail?type=1&v=fb8320d0813ab7b86g01401c" + }, + { + "bookId": "3300028287", + "title": "羊道·深山夏牧场(羊道终章,游牧生活的漫长告别)", + "author": "李娟", + "category": "精品小说-社会小说", + "cover": "https://cdn.weread.qq.com/weread/cover/82/cpPlatform_kz1K9Wo8Sh3FUsdhx8eckN/t6_cpPlatform_kz1K9Wo8Sh3FUsdhx8eckN.jpg", + "progress": 5, + "finished": false, + "lastReadAt": "2026-06-07T05:15:01.000Z", + "deepLink": "https://weread.qq.com/book-detail?type=1&v=ec0325c0813ab718cg017a62" + }, + { + "bookId": "3300201219", + "title": "AI 时代的认知觉醒", + "author": "知识重构者", + "category": "心理-认知与行为", + "cover": "https://cdn.weread.qq.com/weread/cover/46/cpplatform_t658eoeazmalyo2rw3pskp/t6_cpplatform_t658eoeazmalyo2rw3pskp1776046889.jpg", + "progress": 16, + "finished": false, + "lastReadAt": "2026-06-06T18:14:57.000Z", + "deepLink": "https://weread.qq.com/book-detail?type=1&v=ec332c80813abb519g019b32" + }, + { + "bookId": "38894307", + "title": "谈美", + "author": "朱光潜", + "category": "哲学宗教-美学", + "cover": "https://cdn.weread.qq.com/weread/cover/48/YueWen_38894307/t6_YueWen_38894307.jpg", + "progress": 3, + "finished": false, + "lastReadAt": "2026-06-01T17:12:29.000Z", + "deepLink": "https://weread.qq.com/book-detail?type=1&v=da032ef072517ae3da039f2" + }, + { + "bookId": "27126747", + "title": "杜邦安全管理", + "author": "崔政斌 张美元 周礼庆编著", + "category": "经济理财-管理", + "cover": "https://cdn.weread.qq.com/weread/cover/98/YueWen_27126747/t6_YueWen_27126747.jpg", + "progress": 10, + "finished": false, + "lastReadAt": "2026-05-13T00:11:25.000Z", + "deepLink": "https://weread.qq.com/book-detail?type=1&v=a3d32d20719debdba3d5de1" + }, + { + "bookId": "674073", + "title": "沧浪之水", + "author": "阎真", + "category": "精品小说-影视原著", + "cover": "https://cdn.weread.qq.com/weread/cover/49/yuewen_674073/t6_yuewen_6740731774011595.jpg", + "progress": 1, + "finished": false, + "lastReadAt": "2026-04-19T15:00:03.000Z", + "deepLink": "https://weread.qq.com/book-detail?type=1&v=7c632ef05a49197c62b53f0" + }, + { + "bookId": "26943492", + "title": "每天5分钟玩转Docker容器技术", + "author": "CloudMan", + "category": "计算机-计算机综合", + "cover": "https://cdn.weread.qq.com/weread/cover/41/YueWen_26943492/t6_YueWen_26943492.jpg", + "progress": 4, + "finished": false, + "lastReadAt": "2026-04-18T15:44:35.000Z", + "deepLink": "https://weread.qq.com/book-detail?type=1&v=93d325a0719b200493d5ba9" + }, + { + "bookId": "40055543", + "title": "置身事内:中国政府与经济发展", + "author": "兰小欢", + "category": "经济理财-财经", + "cover": "https://cdn.weread.qq.com/weread/cover/52/YueWen_40055543/t6_YueWen_40055543.jpg", + "progress": 13, + "finished": false, + "lastReadAt": "2026-03-28T10:03:33.000Z", + "deepLink": "https://weread.qq.com/book-detail?type=1&v=2a332d10726332f72a34943" + }, + { + "bookId": "41100356", + "title": "挽救计划(同名电影原著)", + "author": "[美]安迪·威尔", + "category": "精品小说-科幻小说", + "cover": "https://cdn.weread.qq.com/weread/cover/0/yuewen_41100356/t6_yuewen_411003561772520377.jpg", + "progress": 100, + "finished": true, + "lastReadAt": "2026-03-28T10:01:44.000Z", + "deepLink": "https://weread.qq.com/book-detail?type=1&v=6d232640727324446d2e978" + }, + { + "bookId": "31515008", + "title": "消失的13级台阶", + "author": "高野和明", + "category": "精品小说-悬疑推理", + "cover": "https://wfqqreader-1252317822.image.myqcloud.com/cover/8/31515008/t6_31515008.jpg", + "progress": 100, + "finished": true, + "lastReadAt": "2026-03-25T17:32:16.000Z", + "deepLink": "https://weread.qq.com/book-detail?type=1&v=8033247071e0e1808035ab9" + }, + { + "bookId": "3300175025", + "title": "此刻是春天(微信读书特别版)", + "author": "卢思浩", + "category": "精品小说-治愈小说", + "cover": "https://cdn.weread.qq.com/weread/cover/4/cpplatform_3hsoybvrwapq1efqha1mvz/t6_cpplatform_3hsoybvrwapq1efqha1mvz1762325065.jpg", + "progress": 4, + "finished": false, + "lastReadAt": "2026-01-11T10:35:21.000Z", + "deepLink": "https://weread.qq.com/book-detail?type=1&v=b0b32630813abaadeg0157d1" + }, + { + "bookId": "39280063", + "title": "博弈论:每个人都能成为决策高手(《人民日报》推荐)", + "author": "蒋文华", + "category": "经济理财-财经", + "cover": "https://cdn.weread.qq.com/weread/cover/77/YueWen_39280063/t6_YueWen_39280063.jpg", + "progress": 0, + "finished": false, + "lastReadAt": "2025-10-29T00:43:47.000Z", + "deepLink": "https://weread.qq.com/book-detail?type=1&v=5d332c2072575dbf5d33fe2" + }, + { + "bookId": "721367", + "title": "白说", + "author": "白岩松", + "category": "文学-散文杂著", + "cover": "https://wfqqreader-1252317822.image.myqcloud.com/cover/367/721367/t6_721367.jpg", + "progress": 100, + "finished": true, + "lastReadAt": "2025-10-29T00:43:35.000Z", + "deepLink": "https://weread.qq.com/book-detail?type=1&v=4e3321805b01d74e3fa7481" + }, + { + "bookId": "3300024284", + "title": "毛泽东选集(全四卷)", + "author": "", + "category": "政治军事-政治", + "cover": "https://cdn.weread.qq.com/weread/cover/84/3300024284/t6_3300024284.jpg", + "progress": 1, + "finished": false, + "lastReadAt": "2025-10-18T09:21:26.000Z", + "deepLink": "https://weread.qq.com/book-detail?type=1&v=2bb32ff0813ab6ffcg014315" + }, + { + "bookId": "3300120749", + "title": "不被大风吹倒(莫言陪女儿高考也这样! )", + "author": "莫言", + "category": "文学-散文杂著", + "cover": "https://cdn.weread.qq.com/weread/cover/60/cpplatform_n3ezmfhymkjcbuuszk8bgy/t6_cpplatform_n3ezmfhymkjcbuuszk8bgy1731488438.jpg", + "progress": 10, + "finished": false, + "lastReadAt": "2024-12-21T00:51:54.000Z", + "deepLink": "https://weread.qq.com/book-detail?type=1&v=2c032e80813ab95aag019524" + }, + { + "bookId": "673157", + "title": "浴血荣光(同名电视剧原著)", + "author": "金一南", + "category": "文学-纪实文学", + "cover": "https://cdn.weread.qq.com/weread/cover/25/YueWen_673157/t6_YueWen_673157.jpg", + "progress": 6, + "finished": false, + "lastReadAt": "2020-04-09T07:29:49.000Z", + "deepLink": "https://weread.qq.com/book-detail?type=1&v=814322405a4585814beb03d" + }, + { + "bookId": "807264", + "title": "微纪元", + "author": "刘慈欣", + "category": "精品小说-科幻小说", + "cover": "https://wfqqreader-1252317822.image.myqcloud.com/cover/264/807264/t6_807264.jpg", + "progress": 100, + "finished": true, + "lastReadAt": "2019-10-15T15:30:42.000Z", + "deepLink": "https://weread.qq.com/book-detail?type=1&v=770328405c5160770c987ae" + }, + { + "bookId": "812443", + "title": "白鹿原", + "author": "陈忠实", + "category": "精品小说-年代小说", + "cover": "https://cdn.weread.qq.com/weread/cover/78/YueWen_812443/t6_YueWen_812443.jpg", + "progress": 0, + "finished": false, + "lastReadAt": "2017-05-30T00:49:56.000Z", + "deepLink": "https://weread.qq.com/book-detail?type=1&v=47532ac05c659b47554a825" } ] }