- sites/spiders: Haidan/HDDolby/RousiPro/SunnyPT/TNode/TorrentLeech/Yema (+mTorrent wrapper), specialized SiteAdapter, indirect download resolved at download time - sites/user-parsers: SiteParserBase + all 20 MP SiteSchema parsers (lxml XPath via xpath+xmldom), refreshSiteUserData with schema fallback - sites/definitions: zod SiteDefinition schemas, 23 MovieClaw v0.27.0 (MIT) definitions via scripts/mp-sync/movieclaw-import.mjs, registry getSiteDefinition/listSiteDefinitions, NOTICE - scripts/mp-sync: ledger.json (upstream sha256), check.mjs, build-ledger.mjs; docs/porting/mp-sync-ledger.md - license-and-provenance: add copied-mit kind, re-anchor MovieClaw rows to v0.27.0 Co-Authored-By: Claude Opus 5.5 <[email protected]>
59 lines
3.1 KiB
TypeScript
59 lines
3.1 KiB
TypeScript
import { createMockFetch, HAIDAN_SEARCH_ERROR, HAIDAN_SEARCH_OK } from "@umt/testkit";
|
|
import { describe, expect, it } from "vitest";
|
|
import { haidanSearchQuery, haidanSpider } from "./haidan.ts";
|
|
import { adapterWith, expectSiteError, testDef, withTorrent } from "./testing.ts";
|
|
|
|
const def = testDef("Haidan", { domain: "https://www.haidan.video/" });
|
|
|
|
describe("HaiDanSpider(MP haidan.py)", () => {
|
|
it("__get_params:isapi/search_area/空关键词/分类逗号拼接", () => {
|
|
expect(haidanSearchQuery(null)).toBe("isapi=1&search_area=0&search=&search_mode=0&cat=");
|
|
expect(haidanSearchQuery("tt1160419", "tv")).toBe(
|
|
"isapi=1&search_area=4&search=tt1160419&search_mode=0&cat=402%2C403%2C404%2C405",
|
|
);
|
|
});
|
|
|
|
it("列表解析:字段映射、分类投影、促销系数表、passkey 脱敏", async () => {
|
|
const m = createMockFetch({ "/torrents.php": { body: HAIDAN_SEARCH_OK } });
|
|
const page = await adapterWith(def, haidanSpider, m.fetch).search("Dune", { mtype: "movie" });
|
|
expect(m.requests[0]!.headers.cookie).toBe("c=COOKIESECRET");
|
|
expect(m.requests[0]!.url.searchParams.get("cat")).toBe("401,404,405");
|
|
const by = Object.fromEntries(page.items.map((i) => [i.siteReleaseId, i]));
|
|
expect(by["30001"]).toMatchObject({
|
|
title: "Dune.Part.Two.2024.2160p.UHD.BluRay.REMUX.HDR.HEVC.Atmos-HDH",
|
|
subtitle: "沙丘2 | 4K 原盘 REMUX",
|
|
category: { id: "401" },
|
|
sizeBytes: 76543210987,
|
|
seeders: 88,
|
|
leechers: 3,
|
|
snatched: 412,
|
|
promotion: { type: "free", downloadFactor: 0, uploadFactor: 1 },
|
|
hr: "unknown",
|
|
uploadedAt: "2024-09-20T00:00:00.000Z",
|
|
detailUrl: "https://www.haidan.video/details.php?group_id=9001&torrent_id=30001",
|
|
raw: expect.objectContaining({ category: "电影" }),
|
|
});
|
|
expect(by["30002"]!.promotion).toMatchObject({ type: "2x50%", downloadFactor: 0.5, uploadFactor: 2 });
|
|
expect(by["30002"]!.raw.category).toBe("电视剧");
|
|
expect(by["30003"]!.raw.category).toBe("音乐");
|
|
expect(JSON.stringify(page)).not.toContain("HDPASSKEY123");
|
|
expect(page.totalPages).toBeNull();
|
|
// 不翻页:第 2 页直接为空
|
|
expect((await adapterWith(def, haidanSpider, m.fetch).list(2)).items).toEqual([]);
|
|
});
|
|
|
|
it("业务错误 / 缺 Cookie / 下载沿用缓存直链带 Cookie", async () => {
|
|
const bad = createMockFetch({ "/torrents.php": { body: HAIDAN_SEARCH_ERROR } });
|
|
await expectSiteError(adapterWith(def, haidanSpider, bad.fetch).list(1), "auth_invalid");
|
|
await expectSiteError(adapterWith(def, haidanSpider, bad.fetch, {}).list(1), "auth_missing");
|
|
const m = createMockFetch({ "/torrents.php": { body: HAIDAN_SEARCH_OK } });
|
|
const t = withTorrent(m.fetch, (u) => u.pathname === "/download.php");
|
|
const a = adapterWith(def, haidanSpider, t.fetch);
|
|
await a.list(1);
|
|
const target = await a.downloadTarget("30001");
|
|
expect(target).toMatchObject({ kind: "torrent", infoHash: t.infoHash });
|
|
expect(t.hits[0]!.url.searchParams.get("passkey")).toBe("HDPASSKEY123");
|
|
expect(t.hits[0]!.headers.get("cookie")).toBe("c=COOKIESECRET");
|
|
});
|
|
});
|