Files
UHD_Media_Tool/packages/adapters/src/sites/deps.ts
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

32 lines
1004 B
TypeScript

import type { SiteHttpContext } from "./http";
import { createSiteRateLimiter, type SiteRateLimiter } from "./rate-limit";
import type { SecretResolver } from "./types";
export interface SiteAdapterDeps {
secrets: SecretResolver;
fetch?: typeof globalThis.fetch;
/** 同站共享的限流器;不传则按站点定义新建(列表/搜索/详情/下载共享) */
limiter?: SiteRateLimiter;
now?: () => Date;
timeoutMs?: number;
userAgent?: string;
/** 覆盖站点基址(测试指向 mock) */
baseUrl?: string;
}
export function buildHttpContext(
siteId: string,
deps: SiteAdapterDeps,
limiterDefaults: { minIntervalMs: number; burst: number },
): SiteHttpContext {
const ctx: SiteHttpContext = {
siteId,
fetch: deps.fetch ?? globalThis.fetch,
limiter: deps.limiter ?? createSiteRateLimiter(limiterDefaults),
timeoutMs: deps.timeoutMs ?? 30_000,
now: deps.now ?? (() => new Date()),
};
if (deps.userAgent) ctx.userAgent = deps.userAgent;
return ctx;
}