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"); }); });