Files
UHD_Media_Tool/packages/testkit/src/rss/README.md
T
rootandClaude Fable 5.1 a6d049db81 feat(adapters): RSS and PT site adapters ported from MoviePilot v3 + mocks (W1-3b)
- rss: port of MP RssHelper._parse_impl/get_rss_link semantics with safe
  XML (entities off, DTD/ENTITY rejected, size/item caps), ETag/Last-Modified,
  backoff + Retry-After, circuit breaker with manual reset, passkey redaction,
  overlap-window GUID+digest dedupe
- sites/spider: TS port of MP SiteSpider (indexer schema, search URL builder,
  field DSL, filters, Jinja templates via nunjucks, login-page detection);
  audiences definition hand-written as JSON; raw category id preserved;
  shared per-site token bucket
- sites/mteam: port of MP MTorrentSpider (params, result mapping, promo
  factors, genDlToken flow) without embedding the API key in enclosures;
  business code/message checks
- testkit: mock RSS server, mock NexusPHP site, mock M-Team API
- docs: W1-3b migration mapping appended to porting ledger

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-27 18:10:34 +08:00

805 B

testkit/rss

mock RSS/Atom 服务器(127.0.0.1 随机端口,node:http,无外部依赖)。

const feed = await createMockRssServer({ items, passkey: "pk", format: "rss" | "atom" });
feed.feedUrl;              // 带 ?passkey= 的完整 URL
feed.addItem(item);        // 新条目置前
feed.updateItem(guid, {title});  // 同 GUID 内容变化
feed.pinItem(guid); feed.shuffle(seed);  // 置顶 / 乱序
feed.failNext(2, { status: 503, retryAfter: "120" });
feed.setRawBody(maliciousXml);   // DTD/XXE/超大响应样本;null 恢复
feed.setConditional(false);      // 关闭 ETag/Last-Modified
feed.requests; feed.notModifiedCount;
await feed.close();

ETag 随内容与版本变化;If-None-Match 命中或 If-Modified-Since 不早于最后修改时间返回 304。passkey 错误返回 403。