fix(collector): restore direct DLC drag imports

Resolve dropped file paths through Electron webUtils, send dragged DLC containers directly to Downloads, and keep explicit collector imports bounded so metadata enrichment cannot leave the interface permanently busy.
This commit is contained in:
Sucukdeluxe
2026-08-22 20:17:58 +02:00
parent 340d6597cc
commit 2f031dc350
9 changed files with 128 additions and 12 deletions
+12 -2
View File
@@ -4,7 +4,8 @@ import type { ElectronApi } from "../src/shared/preload-api";
const electron = vi.hoisted(() => ({
api: undefined as ElectronApi | undefined,
invoke: vi.fn<(...args: unknown[]) => Promise<unknown>>(async () => undefined)
invoke: vi.fn<(...args: unknown[]) => Promise<unknown>>(async () => undefined),
getPathForFile: vi.fn(() => "C:\\Imports\\dropped.dlc")
}));
vi.mock("electron", () => ({
@@ -18,7 +19,8 @@ vi.mock("electron", () => ({
on: vi.fn(),
removeListener: vi.fn(),
send: vi.fn()
}
},
webUtils: { getPathForFile: electron.getPathForFile }
}));
describe("account preload contract", () => {
@@ -122,4 +124,12 @@ describe("account preload contract", () => {
[IPC_CHANNELS.INSPECT_COLLECTOR_CONTAINERS, ["C:\\Imports\\sample.dlc"], 5678]
]);
});
it("resolves dropped files through Electron webUtils without IPC", () => {
const file = { name: "dropped.dlc" } as File;
expect(electron.api?.getPathForDroppedFile(file)).toBe("C:\\Imports\\dropped.dlc");
expect(electron.getPathForFile).toHaveBeenCalledWith(file);
expect(electron.invoke).not.toHaveBeenCalled();
});
});
+35
View File
@@ -0,0 +1,35 @@
import { describe, expect, it, vi } from "vitest";
import { importDroppedDlcFiles, resolveDroppedDlcPaths } from "../src/renderer/collector-drop";
describe("collector DLC drop", () => {
it("resolves DLC paths through the preload bridge instead of File.path", () => {
const first = { name: "first.dlc" } as File;
const ignored = { name: "notes.txt" } as File;
const second = { name: "SECOND.DLC" } as File;
const getPath = vi.fn((file: File) => file === first ? "C:\\Drops\\first.dlc" : "C:\\Drops\\second.dlc");
expect(resolveDroppedDlcPaths([first, ignored, second], getPath)).toEqual([
"C:\\Drops\\first.dlc",
"C:\\Drops\\second.dlc"
]);
expect(getPath.mock.calls.map(([file]) => file)).toEqual([first, second]);
});
it("ignores files whose native path cannot be resolved", () => {
const file = { name: "broken.dlc" } as File;
expect(resolveDroppedDlcPaths([file], () => "")).toEqual([]);
expect(resolveDroppedDlcPaths([file], () => { throw new Error("unavailable"); })).toEqual([]);
});
it("imports dropped DLC files directly into Downloads without collector analysis", async () => {
const file = { name: "package.dlc" } as File;
const addContainers = vi.fn(async () => ({ addedPackages: 2, addedLinks: 16 }));
await expect(importDroppedDlcFiles([file], () => "C:\\Drops\\package.dlc", addContainers)).resolves.toEqual({
addedPackages: 2,
addedLinks: 16
});
expect(addContainers).toHaveBeenCalledWith(["C:\\Drops\\package.dlc"]);
});
});
+15
View File
@@ -100,6 +100,21 @@ describe("collector inspection", () => {
}));
});
it("returns visible unknown links when metadata analysis reaches its deadline", async () => {
const link = "https://1fichier.com/?slow123";
const result = await inspectCollectorText({ rawText: link, addedAt: 3200 }, defaultSettings(), {
checkOneFichier: async () => new Promise(() => {}),
inspectionTimeoutMs: 10
});
expect(result.packages).toHaveLength(1);
expect(result.packages[0].links).toEqual([expect.objectContaining({
url: link,
availability: "unknown",
status: "unknown"
})]);
});
it("resolves DDownload metadata before grouping without using a debrid account", async () => {
const link = "https://ddownload.com/ntwscdw62gyb";
let genericResolverCalls = 0;
+1
View File
@@ -61,6 +61,7 @@ export function createVisualElectronApi(
addContainers: async () => ({ addedPackages: 0, addedLinks: 0 }),
inspectCollectorText: async () => clone(fixture.collector),
inspectCollectorContainers: async () => clone(fixture.collector),
getPathForDroppedFile: () => "",
getStartConflicts: async () => [],
resolveStartConflict: async (_packageId, policy) => ({
skipped: policy === "skip",