import { afterEach, describe, expect, it, vi } from "vitest"; import { checkDdownloadOnline, checkOneFichierLinks, extractDdownloadFilenameFromHtml, filenameFromDdownloadUrlPath, isDdownloadLink, isOneFichierLink, parseDdownloadFileSize } from "../src/main/debrid"; import { extractHosterFromUrl } from "../src/shared/hoster"; import { formatHosterLabel } from "../src/renderer/download-format"; const originalFetch = globalThis.fetch; afterEach(() => { globalThis.fetch = originalFetch; vi.useRealTimers(); }); describe("1Fichier public metadata", () => { it("normalizes supported domains and resolves exact metadata in batches of 100", async () => { vi.useFakeTimers(); const links = Array.from({ length: 101 }, (_unused, index) => `https://1fichier.com/?id${String(index).padStart(5, "0")}`); const batchSizes: number[] = []; globalThis.fetch = vi.fn(async (_input: RequestInfo | URL, init?: RequestInit) => { const body = init?.body instanceof URLSearchParams ? init.body : new URLSearchParams(String(init?.body || "")); const requested = body.getAll("links[]"); batchSizes.push(requested.length); return new Response(requested.map((link, index) => `${link};Archive.${batchSizes.length}.${index}.7z;${1000 + index}`).join("\n"), { status: 200 }); }) as typeof fetch; const pending = checkOneFichierLinks(links); await vi.advanceTimersByTimeAsync(1000); const results = await pending; expect(batchSizes).toEqual([100, 1]); expect(results.get(links[0])).toEqual({ online: true, fileName: "Archive.1.0.7z", fileSizeBytes: 1000, accessRestricted: false }); expect(results.get(links[100])).toEqual({ online: true, fileName: "Archive.2.0.7z", fileSizeBytes: 1000, accessRestricted: false }); expect(isOneFichierLink("https://desfichiers.net/?abc12345")).toBe(true); expect(isOneFichierLink("https://piecejointe.net/?abc12345")).toBe(true); expect(extractHosterFromUrl("https://dl4free.com/?abc12345")).toBe("1fichier"); expect(formatHosterLabel("1fichier")).toEqual({ compact: "1F", title: "1Fichier" }); }); it("distinguishes online, missing and private links without inventing metadata", async () => { const online = "https://1fichier.com/?online123"; const missing = "https://1fichier.com/?gone12345"; const privateLink = "https://1fichier.com/?priv12345"; globalThis.fetch = vi.fn(async () => new Response([ `${online};Movie&Bonus.mkv;734003200`, `${missing};;;NOT FOUND`, `${privateLink};;;PRIVATE` ].join("\n"), { status: 200 })) as typeof fetch; const results = await checkOneFichierLinks([online, missing, privateLink]); expect(results.get(online)).toEqual({ online: true, fileName: "Movie&Bonus.mkv", fileSizeBytes: 734003200, accessRestricted: false }); expect(results.get(missing)).toEqual({ online: false, fileName: "", fileSizeBytes: null, accessRestricted: false }); expect(results.get(privateLink)).toEqual({ online: true, fileName: "", fileSizeBytes: null, accessRestricted: true }); }); }); describe("DDownload public metadata", () => { it("normalizes domains and parses public filename and size", () => { const html = '

Show.S01E02.German.DL.part02.rar

502.00 MB

'; expect(isDdownloadLink("https://ddownload.com/ntwscdw62gyb")).toBe(true); expect(isDdownloadLink("https://ddl.to/ntwscdw62gyb/Archive.part02.rar")).toBe(true); expect(isDdownloadLink("https://ddownload.com/login.html")).toBe(false); expect(filenameFromDdownloadUrlPath("https://ddl.to/ntwscdw62gyb/Archive.part02.rar")).toBe("Archive.part02.rar"); expect(filenameFromDdownloadUrlPath("https://ddownload.com/ntwscdw62gyb")).toBe(""); expect(extractDdownloadFilenameFromHtml(html)).toBe("Show.S01E02.German.DL.part02.rar"); expect(parseDdownloadFileSize("502.00 MB")).toBe(526_385_152); expect(extractHosterFromUrl("https://ddl.to/ntwscdw62gyb/Archive.part02.rar")).toBe("ddownload"); expect(formatHosterLabel("ddownload")).toEqual(expect.objectContaining({ compact: "DD", title: "DDownload" })); expect(extractDdownloadFilenameFromHtml('

Release.Notes.pdf

')).toBe("Release.Notes.pdf"); }); it("returns online and offline metadata while keeping challenge pages unknown", async () => { const responses = [ new Response('

Show.S01E02.mkv

840.02 MB

', { status: 200, headers: { "Content-Type": "text/html" } }), new Response("

File Not Found

", { status: 200, headers: { "Content-Type": "text/html" } }), new Response("Just a moment...", { status: 200, headers: { "Content-Type": "text/html" } }) ]; globalThis.fetch = vi.fn(async () => responses.shift() || new Response("", { status: 500 })) as typeof fetch; await expect(checkDdownloadOnline("https://ddownload.com/online1234")).resolves.toEqual({ online: true, fileName: "Show.S01E02.mkv", fileSizeBytes: 880_824_812 }); await expect(checkDdownloadOnline("https://ddownload.com/missing1234")).resolves.toEqual({ online: false, fileName: "", fileSizeBytes: null }); await expect(checkDdownloadOnline("https://ddownload.com/unknown1234")).resolves.toBeNull(); }); it("does not follow redirects outside the supported DDownload domains", async () => { globalThis.fetch = vi.fn(async (_input: RequestInfo | URL, init?: RequestInit) => { if (init?.redirect === "follow") { return new Response('

Internal.Secret.txt

1 KB

', { status: 200, headers: { "Content-Type": "text/html" } }); } return new Response(null, { status: 302, headers: { Location: "http://127.0.0.1/private" } }); }) as typeof fetch; await expect(checkDdownloadOnline("https://ddownload.com/redirect123")).resolves.toBeNull(); }); it("rejects redirects that change the file code or downgrade HTTPS", async () => { globalThis.fetch = vi.fn(async (input: RequestInfo | URL) => { const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url; if (url === "https://ddownload.com/original123") return new Response(null, { status: 302, headers: { Location: "https://ddl.to/different456/Other.rar" } }); if (url === "https://ddownload.com/secure123") return new Response(null, { status: 302, headers: { Location: "http://ddownload.com/secure123/File.rar" } }); return new Response('

Wrong.Target.rar

1 MB

', { status: 200, headers: { "Content-Type": "text/html" } }); }) as typeof fetch; await expect(checkDdownloadOnline("https://ddownload.com/original123")).resolves.toBeNull(); await expect(checkDdownloadOnline("https://ddownload.com/secure123")).resolves.toBeNull(); }); it("prefers concrete file markers over unrelated offline text in a valid page", async () => { globalThis.fetch = vi.fn(async () => new Response([ '

Still.Online.mkv

', '

10 MB

', '' ].join(""), { status: 200, headers: { "Content-Type": "text/html" } })) as typeof fetch; await expect(checkDdownloadOnline("https://ddownload.com/online5678")).resolves.toEqual({ online: true, fileName: "Still.Online.mkv", fileSizeBytes: 10_485_760 }); }); });