Files
NewBlog/src/lib/reading.ts
T
dsh 95dd0d9552 书架页新增「最近在读」:构建时抓微信读书,顺带移除漫画/论文
数据链路
- scripts/fetch-reading.mjs:调腾讯官方 Agent Gateway
  (POST https://i.weread.qq.com/api/agent/gateway,Bearer wrk-...),
  /shelf/sync 拿书架,再对前 N 本调 /book/getprogress 拿进度,
  写出 src/data/reading.json
- src/lib/reading.ts:读 JSON + 按 YYYY-MM-DD 格式化(官方硬性要求),
  文件缺失返回 null 让页面走空态而不是构建报错
- src/components/bookshelf-content.astro:只渲染,页面本身不发请求

接口实测得到的几个结论(都写进脚本注释和 README 了)
- skill_version 必填,业务参数平铺顶层
- /shelf/sync 一次给全封面/书名/作者/分类/最近阅读时间/deepLink,
  只有进度要额外请求,所以请求数 = 1 + N
- progress 是 0-100 整数,只有 100 算读完
- recordReadingTime 恒为 0,所以卡片不做「累计时长」
- deepLink 实测是普通 https,浏览器能直接打开

失败兜底(这次最关键的一条)
- pnpm reading:失败 exit 1,明确报错
- pnpm build:串的是 `fetch-reading.mjs --soft`,Key 失效/断网/接口挂了
  都保留上一次的 reading.json 并 exit 0,不会阻塞部署
- 实测:错误 Key 时 pnpm reading exit 1;pnpm build 完整跑通 exit 0 且
  reading.json 未被改动;不设 Key 也 exit 0
- process.loadEnvFile 不覆盖已存在的环境变量,所以 CI 设的 Key 优先于 .env

Key 安全
- 只写进 .env(gitignore,权限 600),已确认 git status 里没有它
- deploy.sh 是本地构建再 rsync,凭据不会上传服务器
- .env.example 补了占位和申请地址

书架页改版
- 移除漫画/论文两个分类:删掉 tab 切换、两个视图、对应筛选和 JS,
  956 行 -> 620 行;sidebar 的 tab 按钮改成 #reading / #books 页内锚点
- 新增「最近在读」区块置顶(Collection · 01),书籍顺延为 02
- 卡片:封面(hot-link 腾讯 CDN,referrerpolicy=no-referrer)+ 书名 +
  作者 · 分类 + 进度条 + 最近阅读日期,整卡跳 weread.qq.com
- 读完标「已读完」,0% 标「还没开始」
- 过滤私密阅读(secret=1)和从没打开过的书;有声书不处理

静态验证(dist/bookshelf/index.html)
- 8 张在读卡片,链接均指向 weread.qq.com/book-detail
- 8 条进度条宽度 30/0/77/100/28/13/97/0,与脚本输出一致
- 8 张封面全部 hot-link,无本地副本
- 漫画/论文/comics/papers/data-type-btn/switchType 均已从产物消失
- 其他页面(首页/时间线/关于/文章页)不含该区块,未受影响
2026-09-15 10:40:11 +08:00

63 lines
1.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import fs from "node:fs"
import path from "node:path"
/**
* 微信读书「最近在读」的数据读取与展示格式化。
*
* 数据由 `scripts/fetch-reading.mjs` 在构建前抓到 `src/data/reading.json`,
* 这个模块只读文件,不发任何网络请求 —— 页面是纯静态的。
*
* 只允许在 `.astro` 的 frontmatter 里用(依赖 node:fs,不能在客户端组件里 import)。
*/
export type ReadingBook = {
bookId: string
title: string
author: string
/** 微信读书的分类是「大类-子类」复合串,如 `文学-外国文学` */
category: string
cover: string
/** 0-100 的整数;null 表示这次没取到进度(单本失败) */
progress: number | null
finished: boolean
/** ISO 字符串 */
lastReadAt: string
/** 微信读书的跳转链接,实测是普通 https,浏览器能直接打开 */
deepLink: string
}
export type ReadingData = {
updatedAt: string
source: string
books: ReadingBook[]
}
const DATA_FILE = path.join(process.cwd(), "src/data/reading.json")
/** 读不到或格式不对时返回 null,调用方按空态处理,不要抛错。 */
export function getReadingData(): ReadingData | null {
try {
const parsed = JSON.parse(fs.readFileSync(DATA_FILE, "utf-8")) as ReadingData
if (!parsed || !Array.isArray(parsed.books)) return null
return parsed
} catch {
return null
}
}
/**
* 微信读书的时间戳统一按 `YYYY-MM-DD` 展示(官方 Skill 文档的硬性要求),
* 顺带避开「N 天前」这类文案在静态站上会随构建时间变旧的问题。
*/
export function formatReadingDate(iso: string | null | undefined): string {
if (!iso) return ""
const date = new Date(iso)
if (Number.isNaN(date.getTime())) return ""
return new Intl.DateTimeFormat("en-CA", {
timeZone: "Asia/Shanghai",
year: "numeric",
month: "2-digit",
day: "2-digit",
}).format(date)
}