Add package and item link export
This commit is contained in:
@@ -6890,6 +6890,40 @@ describe("download manager", () => {
|
||||
expect(() => manager.importQueue("{not-json")).toThrow(/Ungultige Queue-Datei/i);
|
||||
});
|
||||
|
||||
it("imports structured text exports and preserves package names and file hints", () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), "rd-dm-"));
|
||||
tempDirs.push(root);
|
||||
|
||||
const manager = new DownloadManager(
|
||||
{
|
||||
...defaultSettings(),
|
||||
token: "rd-token",
|
||||
outputDir: path.join(root, "downloads"),
|
||||
extractDir: path.join(root, "extract")
|
||||
},
|
||||
emptySession(),
|
||||
createStoragePaths(path.join(root, "state"))
|
||||
);
|
||||
|
||||
const result = manager.importQueue([
|
||||
"# rd-link-export: 1",
|
||||
"# package: Dave Staffel 1",
|
||||
"# file: Dave.S01E01.rar",
|
||||
"https://example.com/e01",
|
||||
"# file: Dave.S01E02.rar",
|
||||
"https://example.com/e02"
|
||||
].join("\n"));
|
||||
|
||||
expect(result).toEqual({ addedPackages: 1, addedLinks: 2 });
|
||||
|
||||
const snapshot = manager.getSnapshot();
|
||||
const packageId = snapshot.session.packageOrder[0];
|
||||
const pkg = snapshot.session.packages[packageId];
|
||||
expect(pkg?.name).toBe("Dave Staffel 1");
|
||||
const importedItems = pkg?.itemIds.map((itemId) => snapshot.session.items[itemId]);
|
||||
expect(importedItems?.map((item) => item?.fileName)).toEqual(["Dave.S01E01.rar", "Dave.S01E02.rar"]);
|
||||
});
|
||||
|
||||
it("applies global speed limit path when global mode is enabled", async () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), "rd-dm-"));
|
||||
tempDirs.push(root);
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { buildLinkExportSelection, serializeLinkExportText } from "../src/main/link-export";
|
||||
import { parseCollectorInput } from "../src/main/link-parser";
|
||||
import type { UiSnapshot } from "../src/shared/types";
|
||||
|
||||
function buildSnapshot(): UiSnapshot {
|
||||
return {
|
||||
settings: {} as UiSnapshot["settings"],
|
||||
session: {
|
||||
version: 1,
|
||||
packageOrder: ["pkg-1", "pkg-2"],
|
||||
packages: {
|
||||
"pkg-1": {
|
||||
id: "pkg-1",
|
||||
name: "Dave Staffel 1",
|
||||
outputDir: "C:\\Downloads\\Dave Staffel 1",
|
||||
extractDir: "C:\\Extract\\Dave Staffel 1",
|
||||
status: "queued",
|
||||
itemIds: ["item-1", "item-2"],
|
||||
cancelled: false,
|
||||
enabled: true,
|
||||
priority: "normal",
|
||||
createdAt: 1,
|
||||
updatedAt: 1
|
||||
},
|
||||
"pkg-2": {
|
||||
id: "pkg-2",
|
||||
name: "Andere Staffel",
|
||||
outputDir: "C:\\Downloads\\Andere Staffel",
|
||||
extractDir: "C:\\Extract\\Andere Staffel",
|
||||
status: "queued",
|
||||
itemIds: ["item-3"],
|
||||
cancelled: false,
|
||||
enabled: true,
|
||||
priority: "normal",
|
||||
createdAt: 1,
|
||||
updatedAt: 1
|
||||
}
|
||||
},
|
||||
items: {
|
||||
"item-1": {
|
||||
id: "item-1",
|
||||
packageId: "pkg-1",
|
||||
url: "https://example.com/e01",
|
||||
provider: null,
|
||||
status: "queued",
|
||||
retries: 0,
|
||||
speedBps: 0,
|
||||
downloadedBytes: 0,
|
||||
totalBytes: null,
|
||||
progressPercent: 0,
|
||||
fileName: "Dave.S01E01.rar",
|
||||
targetPath: "",
|
||||
resumable: true,
|
||||
attempts: 0,
|
||||
lastError: "",
|
||||
fullStatus: "Wartet",
|
||||
createdAt: 1,
|
||||
updatedAt: 1
|
||||
},
|
||||
"item-2": {
|
||||
id: "item-2",
|
||||
packageId: "pkg-1",
|
||||
url: "https://example.com/e02",
|
||||
provider: null,
|
||||
status: "queued",
|
||||
retries: 0,
|
||||
speedBps: 0,
|
||||
downloadedBytes: 0,
|
||||
totalBytes: null,
|
||||
progressPercent: 0,
|
||||
fileName: "Dave.S01E02.rar",
|
||||
targetPath: "",
|
||||
resumable: true,
|
||||
attempts: 0,
|
||||
lastError: "",
|
||||
fullStatus: "Wartet",
|
||||
createdAt: 1,
|
||||
updatedAt: 1
|
||||
},
|
||||
"item-3": {
|
||||
id: "item-3",
|
||||
packageId: "pkg-2",
|
||||
url: "https://example.com/other",
|
||||
provider: null,
|
||||
status: "queued",
|
||||
retries: 0,
|
||||
speedBps: 0,
|
||||
downloadedBytes: 0,
|
||||
totalBytes: null,
|
||||
progressPercent: 0,
|
||||
fileName: "Andere.S01E01.rar",
|
||||
targetPath: "",
|
||||
resumable: true,
|
||||
attempts: 0,
|
||||
lastError: "",
|
||||
fullStatus: "Wartet",
|
||||
createdAt: 1,
|
||||
updatedAt: 1
|
||||
}
|
||||
},
|
||||
runStartedAt: 0,
|
||||
totalDownloadedBytes: 0,
|
||||
summaryText: "",
|
||||
reconnectUntil: 0,
|
||||
reconnectReason: "",
|
||||
paused: false,
|
||||
running: false,
|
||||
updatedAt: 1
|
||||
},
|
||||
summary: null,
|
||||
stats: {
|
||||
totalDownloaded: 0,
|
||||
totalDownloadedAllTime: 0,
|
||||
totalFilesSession: 0,
|
||||
totalFilesAllTime: 0,
|
||||
totalPackages: 2,
|
||||
sessionStartedAt: 0
|
||||
},
|
||||
speedText: "",
|
||||
etaText: "",
|
||||
canStart: true,
|
||||
canStop: false,
|
||||
canPause: false,
|
||||
clipboardActive: false,
|
||||
reconnectSeconds: 0,
|
||||
packageSpeedBps: {}
|
||||
};
|
||||
}
|
||||
|
||||
describe("link-export", () => {
|
||||
it("keeps original package names when exporting selected items", () => {
|
||||
const selection = buildLinkExportSelection(buildSnapshot(), [], ["item-1", "item-3"]);
|
||||
expect(selection.packageCount).toBe(2);
|
||||
expect(selection.linkCount).toBe(2);
|
||||
expect(selection.packages.map((pkg) => pkg.name)).toEqual(["Dave Staffel 1", "Andere Staffel"]);
|
||||
});
|
||||
|
||||
it("roundtrips exported text back into parsed package inputs", () => {
|
||||
const selection = buildLinkExportSelection(buildSnapshot(), [], ["item-1", "item-2"]);
|
||||
const text = serializeLinkExportText(selection.packages);
|
||||
const reparsed = parseCollectorInput(text, "");
|
||||
|
||||
expect(reparsed).toHaveLength(1);
|
||||
expect(reparsed[0]?.name).toBe("Dave Staffel 1");
|
||||
expect(reparsed[0]?.links).toEqual(["https://example.com/e01", "https://example.com/e02"]);
|
||||
expect(reparsed[0]?.fileNames).toEqual(["Dave.S01E01.rar", "Dave.S01E02.rar"]);
|
||||
});
|
||||
});
|
||||
@@ -33,6 +33,18 @@ describe("link-parser", () => {
|
||||
// "Valid?Name*" becomes "Valid Name " -> trimmed to "Valid Name"
|
||||
expect(result.map(p => p.name).sort()).toEqual(["Valid Name", "Valid_Name"]);
|
||||
});
|
||||
|
||||
it("preserves file name hints when merging packages", () => {
|
||||
const input = [
|
||||
{ name: "Package A", links: ["http://link1", "http://link2"], fileNames: ["one.rar", "two.rar"] },
|
||||
{ name: "Package A", links: ["http://link3", "http://link1"], fileNames: ["three.rar", "ignored.rar"] }
|
||||
];
|
||||
|
||||
const result = mergePackageInputs(input);
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0]?.links).toEqual(["http://link1", "http://link2", "http://link3"]);
|
||||
expect(result[0]?.fileNames).toEqual(["one.rar", "two.rar", "three.rar"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("parseCollectorInput", () => {
|
||||
|
||||
@@ -40,6 +40,28 @@ describe("utils", () => {
|
||||
expect(parsed[1].name).toBe("B");
|
||||
});
|
||||
|
||||
it("parses optional file markers for roundtrip imports", () => {
|
||||
const parsed = parsePackagesFromLinksText(
|
||||
"# rd-link-export: 1\n# package: Dave Staffel 1\n# file: Folge 001.rar\nhttps://a.com/1\n# file: Folge 002.rar\nhttps://a.com/2\n",
|
||||
"Default"
|
||||
);
|
||||
expect(parsed).toHaveLength(1);
|
||||
expect(parsed[0].name).toBe("Dave Staffel 1");
|
||||
expect(parsed[0].links).toEqual(["https://a.com/1", "https://a.com/2"]);
|
||||
expect(parsed[0].fileNames).toEqual(["Folge 001.rar", "Folge 002.rar"]);
|
||||
});
|
||||
|
||||
it("does not carry a file marker across package boundaries", () => {
|
||||
const parsed = parsePackagesFromLinksText(
|
||||
"# package: Dave Staffel 1\n# file: Folge 001.rar\n# package: Dave Staffel 2\nhttps://a.com/2\n",
|
||||
"Default"
|
||||
);
|
||||
expect(parsed).toHaveLength(1);
|
||||
expect(parsed[0].name).toBe("Dave Staffel 2");
|
||||
expect(parsed[0].links).toEqual(["https://a.com/2"]);
|
||||
expect(parsed[0].fileNames).toBeUndefined();
|
||||
});
|
||||
|
||||
it("formats eta", () => {
|
||||
expect(formatEta(-1)).toBe("--");
|
||||
expect(formatEta(65)).toBe("01:05");
|
||||
|
||||
Reference in New Issue
Block a user