diff --git a/src/main/download-manager.ts b/src/main/download-manager.ts index 5ab9fd1..eb0756f 100644 --- a/src/main/download-manager.ts +++ b/src/main/download-manager.ts @@ -5504,23 +5504,25 @@ export class DownloadManager extends EventEmitter { const pkg = this.session.packages[packageId]; if (!pkg) return; if (priority !== "high" && priority !== "normal" && priority !== "low") return; + if ((pkg.priority || "normal") === priority) return; pkg.priority = priority; pkg.updatedAt = nowMs(); - if (priority === "high") { - const order = this.session.packageOrder; - const idx = order.indexOf(packageId); - if (idx > 0) { - order.splice(idx, 1); - let insertAt = 0; - for (let i = 0; i < order.length; i++) { - const p = this.session.packages[order[i]]; - if (p && p.priority === "high") { - insertAt = i + 1; - } + const order = this.session.packageOrder; + const currentIndex = order.indexOf(packageId); + if (currentIndex >= 0) { + order.splice(currentIndex, 1); + const priorityRank: Record = { high: 0, normal: 1, low: 2 }; + let insertAt = order.length; + for (let index = 0; index < order.length; index += 1) { + const other = this.session.packages[order[index]]; + const otherPriority = other?.priority || "normal"; + if (priorityRank[otherPriority] > priorityRank[priority]) { + insertAt = index; + break; } - order.splice(insertAt, 0, packageId); } + order.splice(insertAt, 0, packageId); } this.persistSoon(); diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index fa36604..c1ba912 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -6114,7 +6114,7 @@ export function App(): ReactElement { const label = p === "high" ? "Hoch" : p === "low" ? "Niedrig" : "Standard"; const pkgIds = selectedPackageIds; const allMatch = pkgIds.every((id) => (snapshot.session.packages[id]?.priority || "normal") === p); - return ; + return ; })} diff --git a/tests/download-manager.test.ts b/tests/download-manager.test.ts index 8302b80..48bfba0 100644 --- a/tests/download-manager.test.ts +++ b/tests/download-manager.test.ts @@ -13785,3 +13785,86 @@ describe("mega-debrid api/web resolution overlap gate", () => { expect((manager as any).shouldDelayStartForItem(candidate)).toBe(true); }); }); + +describe("package priority ordering", () => { + function buildPriorityManager(priorities: Array<[string, "high" | "normal" | "low"]>): { + manager: DownloadManager; + session: ReturnType; + } { + const root = fs.mkdtempSync(path.join(os.tmpdir(), "rd-priority-order-")); + tempDirs.push(root); + const session = emptySession(); + const createdAt = Date.now(); + for (const [id, priority] of priorities) { + session.packageOrder.push(id); + session.packages[id] = { + id, + name: id, + outputDir: path.join(root, "downloads", id), + extractDir: path.join(root, "extract", id), + status: "queued", + itemIds: [], + cancelled: false, + enabled: true, + priority, + createdAt, + updatedAt: createdAt + }; + } + return { + manager: new DownloadManager(defaultSettings(), session, createStoragePaths(path.join(root, "state"))), + session + }; + } + + it("moves a package set to low priority behind every normal package", () => { + const { manager, session } = buildPriorityManager([ + ["high-a", "high"], + ["target", "normal"], + ["normal-b", "normal"], + ["low-a", "low"] + ]); + + manager.setPackagePriority("target", "low"); + + expect(session.packageOrder).toEqual(["high-a", "normal-b", "low-a", "target"]); + }); + + it("moves a package set to high priority ahead of every normal package", () => { + const { manager, session } = buildPriorityManager([ + ["high-a", "high"], + ["normal-a", "normal"], + ["target", "normal"], + ["low-a", "low"] + ]); + + manager.setPackagePriority("target", "high"); + + expect(session.packageOrder).toEqual(["high-a", "target", "normal-a", "low-a"]); + }); + + it("moves a package returned to normal between high and low priority groups", () => { + const { manager, session } = buildPriorityManager([ + ["high-a", "high"], + ["normal-a", "normal"], + ["low-a", "low"], + ["target", "low"] + ]); + + manager.setPackagePriority("target", "normal"); + + expect(session.packageOrder).toEqual(["high-a", "normal-a", "target", "low-a"]); + }); + + it("keeps an unchanged priority in place", () => { + const { manager, session } = buildPriorityManager([ + ["high-a", "high"], + ["high-b", "high"], + ["normal-a", "normal"] + ]); + + manager.setPackagePriority("high-a", "high"); + + expect(session.packageOrder).toEqual(["high-a", "high-b", "normal-a"]); + }); +}); diff --git a/tests/downloads-view.test.tsx b/tests/downloads-view.test.tsx index ee37c08..24fa585 100644 --- a/tests/downloads-view.test.tsx +++ b/tests/downloads-view.test.tsx @@ -1171,6 +1171,12 @@ describe("downloads view", () => { }); describe("downloads App integration", () => { + it("keeps the priority menu open when the selected priority is already active", () => { + const source = readFileSync(new URL("../src/renderer/App.tsx", import.meta.url), "utf8").replaceAll("\r\n", "\n"); + + expect(source).toMatch(/disabled=\{allMatch\}[\s\S]{0,260}window\.rd\.setPackagePriority/); + }); + it("updates the clipboard checkbox optimistically before IPC reconciliation", () => { const source = readFileSync(new URL("../src/renderer/App.tsx", import.meta.url), "utf8").replaceAll("\r\n", "\n");