wacz Reader
Turn a .wacz recording into a local site the user can browse, share, and read together with you.
Inputs to collect
- The
.waczfile path. If the user hasn't given one, search the usual download locations
(~/Downloads, the workspace) for*.waczand ask which one when several match. - An output directory. Default to
<workspace>/docs/course/<archive-name>; the archive name
usually comes from the.waczfilename minus extension.
Procedure
-
If your environment has no skill-loading tool, this file is still the whole procedure —
read it directly and continue. Do not report "cannot execute" for a missing skill tool. -
Check the port is free before starting, so a busy port is not mistaken for a broken server:
powershell
Get-NetTCPConnection -LocalPort 8899 -State Listen # Windows
bash
lsof -i :8899 # macOS / Linux
If it is taken, pick another port and use it consistently in every later command.
- Run the bundled extractor — it already handles WACZ/WARC decoding, the site's article and
comment APIs, the original code-highlight theme, image localization and page rendering:
bash
node <skill-dir>/scripts/wacz_extract.js --wacz "<path.wacz>" --out "<out-dir>" --serve --port 8899
Reason for using the script instead of ad-hoc parsing: the archive format has several traps
(concatenated gzip members, WARC/1.1 headers, chunked/gzip-encoded HTTP bodies) that silently
produce zero records when handled ad hoc, and the comment section only exists in the recorded
API responses, not in the page skeleton.
--serve blocks until the server stops. Two ways to run it, pick one:
- Same command (default): run the command above as a background/backgrounded task. It
extracts and then serves; do not re-run the extractor afterwards.
- Split: run the extractor without --serve first, then start the server alone with
node <skill-dir>/scripts/serve.js "<out-dir>" 8899.
-
Read the console summary before doing anything else. It reports
articles,comments
(top-level + replies, and how many of the articles actually have them),images saved
(URLs saved / URLs needed / unique files on disk) andhljs theme(characters / CSS rules).
These numbers are the verification source — do not claim success without them. Read them
literally: the comment count is articles with comments, not articles queried, and
images savedcounts distinct URLs, which is larger than the number of files because
avatars repeat across comments. The extractor also cross-checks every article's extracted
comment count against the server's owncomment_countand prints
! 评论数不符 article <id>for any mismatch — treat a printed mismatch as a bug, not noise. -
Give the user the entry URL
http://127.0.0.1:<port>/index.html. If you have an in-app
browser, open that URL in it so the user sees the result immediately; otherwise just report
the URL. -
Confirm one article renders correctly before reporting done: open an article URL and check
the title header, one highlighted code block, and the comment section. A green "已复制"
button on click means the copy script is wired up. -
Report: entry URL, article count, comment count, image count, and the output directory.
Mention that the.mdfiles in the same directory carry the comments too — that is the
version to read jointly with the user, while.htmlis for browsing. The.mdcomment
section is plain text (author replies and timestamps only); avatars, like counts and IP
location live in the.htmlonly.
Output contract
<out-dir>/index.html— entry page listing every article.<out-dir>/NN-<title>.html— article page: title/author/date header, body, original
highlight.js theme colors, copy-code button on every code block, comment section with
author replies and localized avatars. Comments whose avatar was not captured in the
recording fall back to a colored initial instead of an image — that is expected, not a bug.<out-dir>/NN-<title>.md— same article as Markdown, including the comment section.<out-dir>/assets/— localized images, avatars, and the extracted theme CSS. Image file
names are derived from the URL plus a hash suffix, so two different URLs never overwrite
each other.<out-dir>/index.json,README.md— machine-readable index and table.
Reading the index
index.json is a JSON array; each record has n, id, title, author, reading_time
(in seconds), comments (number), md, html, chars. There is no comment_count field —
sum comments for the total. Note that PowerShell 5.1's ConvertFrom-Json wraps a top-level
array in one more array, so $j.Count is 1; use $j[0].Count or Node instead.
Failure handling
没有解析到文章means the archive's content is not in recorded API responses of the expected
shape (the extractor targets GeekTime's/serv/v1/article). Say so and stop; do not start
guessing at other endpoints.images saved: X / Ywith X < Y means some images were neither in the recording nor
downloadable (expired CDN links). The pages still work; mention which images are missing.- Port already in use — pick another port and pass it with
--port. - The archive is a plain zip of HTML with no API responses — the extractor will find no
articles. Explain that the recording captured only the shell page and the body text cannot
be recovered from it. - HTML entities:
article_contentandcomment_contentarrive HTML-escaped (&#47;is/).
The extractor unescapes them once. If you post-process the output yourself, do not unescape
a second time or the page will show literal&#47;.
Examples
Input: "帮我把这个 wacz 解析出来离线看"
Output: runs the extractor into docs/course/<name>/, serves it on http://127.0.0.1:8899/index.html,
reports 18 篇文章 / 98 条评论 + 98 条回复(分布在 14 篇)/ 123 个图片 URL 全部本地化(落盘 120 个文件,页面引用 0 缺失).
Input: "朋友发来一个 .wacz,怎么打开?"
Output: same flow, pointing at the received file; the result is a folder the friend can open
with a double click on index.html (the pages also work over file://).
Windows (win32) platform notes
- Requires only Node.js (bundled with most agent tools) — no Python, no
npm install. nodeis the command;python3does not exist on Windows.- Quote every path: wacz names usually contain Chinese characters and spaces.
--serveblocks until the server stops, so run it as a background task; when the server
must outlive the current call, either background the combined command or split extraction
andserve.jsinto two calls.
Notes for extending
See references/geekbang-archive.md for the archive internals (WARC layout, API endpoints,
how the original code-highlight theme is recovered) — read it before changing the extractor or
adapting it to another site.