* fix(route/zhihu): obtain __zse_ck from a browser session
`__zse_ck` is computed at runtime by Zhihu's JS from the device fingerprint
and `d_c0`, rotates every few days, and is cross-checked against `d_c0` by
the backend, so it has to come from a real browser session. Drive a browser
seeded with the configured cookies (including the `z_c0` login cookie that
most endpoints now require) to compute a fresh, consistent `__zse_ck`,
harvest the cookie jar, and cache it for 30 minutes so it is refreshed
automatically.
Recommended ZHIHU_COOKIES: "d_c0=...; z_c0=..." (omit `__zse_ck`).
* fix(route/zhihu): fetch posts profile via API instead of HTML
The user's HTML homepage (www.zhihu.com/people/:id) is now rate-limited
(403) more aggressively than the API, which broke /zhihu/posts on the
profile fetch even though the article-list API works. Read the profile
(name, headline, avatar) from /api/v4/members/:id instead.
* fix(route/zhihu): generate __zse_ck with JSDOM
* fix(route/zhihu): use members API for org posts
---------
Co-authored-by: DzmingLi <news@dzming.li>
The /xueqiu/today route requested statuses/hot/listV2.json on xueqiu.com,
which the Alibaba Cloud WAF blocks (returns a challenge page instead of
JSON), so response.data.items was undefined and the route threw 503.
Switch the endpoint to api.xueqiu.com, which serves the same JSON without
the WAF challenge. Also mark antiCrawler: true.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The /xueqiu/user route drove a headless browser (Patchright) to load the
profile page and navigate to each status for full text. The user timeline
is public, so the data can be fetched directly from api.xueqiu.com once the
WAF challenge cookie is obtained.
- replace the browser navigation with direct ofetch calls to
api.xueqiu.com/v4/statuses/user_timeline.json and statuses/show.json
- requirePuppeteer: false (no longer drives a browser); antiCrawler: true
- pass source=买卖 for the 交易 (type 11) tab so it filters correctly
- skip the show.json detail request when legal_user_visible is true
- inline images and the retweeted status into the description
- derive screen_name and the avatar image from the timeline response
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(route): refactor to adapt to new web design
* fix:reduce complexity
* fix: update CSS selector for xingnew and xwzt
* fix: update selectors
* fix:update hideBoxes
* fix: replace for with find
- Update route name from 'User' to 'Stories'
- Rename parameter 'user' to 'value' for clarity
- Document all available sections (index, newest, ask, show, jobs, over, threads, submitted)
- Document type parameter options (sources, comments, comments_list)
- Clarify 'over' section uses points threshold instead of user ID
- Document value's general ?id=<value> behavior for other sections
- Add usage examples (HN100, user submitted, threads, comments_list)
comicat.org now fronts every page with a fake JS "captcha" (/public/html/start/)
that redirects back only after setting a `visitor_test=human` cookie. A bare request
302s to that page, so #listTable and the detail selectors match nothing (empty feed).
Send the cookie directly on both the search listing and the per-item detail fetches.
* fix(route/makerworld): bypass Cloudflare challenge and adapt to new API shape
makerworld.com now sits behind a Cloudflare bot-management challenge that
fingerprints the TLS/HTTP client rather than just headers, so plain fetch
requests get a 403 even with a browser-like User-Agent. Fall back to a
stealth Playwright page load when that happens.
The trending page's data shape also changed: designs moved from
`pageProps.popularDesignsData` to `pageProps.v2Props.foryouData.hits[].design`,
mixed in with non-design promo/community entries, and `tags`/`startTime` were
replaced by `createTime` (no tags exposed on this endpoint anymore).
* fix(route/makerworld): always fetch via browser instead of trying ofetch first
Cloudflare's challenge fingerprints the client itself, so the plain fetch
attempt was guaranteed to always fail with a 403 first. Go straight to the
Playwright fallback instead of paying for a request known to fail.
* route: add 中国地质大学(北京)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat(route): add channel icon for 中国地质大学(北京)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(route): use official crest favicon as 中国地质大学(北京)feed icon
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(route): use official high-res crest for 中国地质大学(北京)feed icon
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* perf: use only one WASM alloc for xxhash
* perf(deps): lazy load mercury-parser and use googleapis/youtube instead of heavy googleapis
* perf(dx): lazy load dev registry
speed up npm dev script
* perf: close playwright browser on destroy
* fix: show exception msg in prod
* revert: "perf: use only one WASM alloc for xxhash"
This reverts commit 01ecdd48d09a046dce05f440814dcbec0323a7de.
* perf: use only one WASM alloc for xxhash
* test: add claim for worker
* fix: missing piece from 8dd9c9a
* feat: add namespace to the chunkfilename
* fix: keep var naming
* fix: remove the src attribute of atom:content
The src attribute is to replace the inner content, not to mark its source.
RFC4287:
> 4.1.3.2. The "src" Attribute
>
> atom:content MAY have a "src" attribute, whose value MUST be an IRI
> reference [RFC3987]. If the "src" attribute is present, atom:content
> MUST be empty. Atom Processors MAY use the IRI to retrieve the
> content and MAY choose to ignore remote content or to present it in a
> different manner than local content.
>
> If the "src" attribute is present, the "type" attribute SHOULD be
> provided and MUST be a MIME media type [MIMEREG], rather than "text",
> "html", or "xhtml". The value is advisory; that is to say, when the
> corresponding URI (mapped from an IRI, if necessary) is dereferenced,
> if the server providing that content also provides a media type, the
> server-provided media type is authoritative.
* fix: move <language> to xml:lang
* fix: remove <webMaster> in atom
* fix: use ISO format to display date in atom & always have <updated>
* fix: use ISO date for feed <updated> in atom
* fix: add <link rel=self> for atom
* feat(route): add Zhejiang Museum temporary exhibition route
* fix: fix the radar source and target
* fix:fix location with null
* fix: only remove the faulty x448
The /xueqiu/stock_info route was broken by Alibaba Cloud WAF: the cookie
acquisition could not pass the challenge, and the data request was sent
to xueqiu.com which the WAF blocks for these endpoints.
- cookies.ts: allow the `script` resource type in the page.route filter
so the WAF challenge scripts can execute, enabling cookie extraction
via Patchright
- stock-info.ts: request data from api.xueqiu.com instead of xueqiu.com
to bypass the WAF
- stock-info.ts: align the supported types with the tabs on the stock
page (all / discuss / trans / news / announcement). all / discuss /
trans use the symbol search endpoint; news / announcement use the
stock timeline endpoint. The previously broken research type is removed
- stock-info.ts: fetch the stock name from the lightweight quote API
since it is rendered client-side and cannot be scraped from the HTML
- stock-info.ts: throw InvalidParameterError for unsupported types
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>