From e92cf59d86f8c2665e97a6178729aa51a82ef69c Mon Sep 17 00:00:00 2001 From: Sucukdeluxe Date: Fri, 6 Mar 2026 16:43:49 +0100 Subject: [PATCH] Release v1.6.82 --- package-lock.json | 4 ++-- package.json | 2 +- src/main/main.ts | 2 +- src/main/update.ts | 17 +++++++++++------ src/renderer/App.tsx | 2 +- tests/update.test.ts | 36 +++++++++++++++++++++++++++++++++++- 6 files changed, 51 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index da7748d..39841de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "real-debrid-downloader", - "version": "1.6.81", + "version": "1.6.82", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "real-debrid-downloader", - "version": "1.6.81", + "version": "1.6.82", "license": "MIT", "dependencies": { "adm-zip": "^0.5.16", diff --git a/package.json b/package.json index 062a6d7..ed15968 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "real-debrid-downloader", - "version": "1.6.81", + "version": "1.6.82", "description": "Desktop downloader", "main": "build/main/main/main.js", "author": "Sucukdeluxe", diff --git a/src/main/main.ts b/src/main/main.ts index 737f95d..cb9df97 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -245,7 +245,7 @@ function registerIpcHandlers(): void { if (result.started) { updateQuitTimer = setTimeout(() => { app.quit(); - }, 2500); + }, 900); } return result; }); diff --git a/src/main/update.ts b/src/main/update.ts index 9686011..a282d0c 100644 --- a/src/main/update.ts +++ b/src/main/update.ts @@ -2,7 +2,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import crypto from "node:crypto"; -import { spawn } from "node:child_process"; +import * as childProcess from "node:child_process"; import { APP_VERSION, DEFAULT_UPDATE_REPO } from "./constants"; import { UpdateCheckResult, UpdateInstallProgress, UpdateInstallResult } from "../shared/types"; import { compactErrorText, humanSize } from "./utils"; @@ -51,6 +51,10 @@ type ReleaseAsset = { type UpdateProgressCallback = (progress: UpdateInstallProgress) => void; +export function buildInstallerLaunchArgs(): string[] { + return ["/S", "--updated", "--force-run"]; +} + function safeEmitProgress(onProgress: UpdateProgressCallback | undefined, progress: UpdateInstallProgress): void { if (!onProgress) { return; @@ -1129,11 +1133,12 @@ export async function installLatestUpdate( percent: 100, downloadedBytes: 0, totalBytes: null, - message: "Starte Update-Installer" + message: "Starte stille Update-Installation" }); - const child = spawn(targetPath, [], { + const child = childProcess.spawn(targetPath, buildInstallerLaunchArgs(), { detached: true, - stdio: "ignore" + stdio: "ignore", + windowsHide: true }); child.once("error", (spawnError) => { logger.error(`Update-Installer Start fehlgeschlagen: ${compactErrorText(spawnError)}`); @@ -1144,9 +1149,9 @@ export async function installLatestUpdate( percent: 100, downloadedBytes: 0, totalBytes: null, - message: "Update-Installer gestartet" + message: "Update wird im Hintergrund installiert und danach neu gestartet" }); - return { started: true, message: "Update-Installer gestartet" }; + return { started: true, message: "Stille Update-Installation gestartet" }; } catch (error) { try { await fs.promises.rm(targetPath, { force: true }); diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index e81ffdf..6dfb51e 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -1115,7 +1115,7 @@ export function App(): ReactElement { if (!mountedRef.current) { return; } - if (install.started) { showToast("Updater gestartet - App wird geschlossen", 2600); return; } + if (install.started) { showToast("Stilles Update gestartet - App wird neu gestartet", 2600); return; } setUpdateInstallProgress({ stage: "error", percent: null, diff --git a/tests/update.test.ts b/tests/update.test.ts index dc8767f..2953f02 100644 --- a/tests/update.test.ts +++ b/tests/update.test.ts @@ -1,7 +1,28 @@ import fs from "node:fs"; import crypto from "node:crypto"; import { afterEach, describe, expect, it, vi } from "vitest"; -import { checkGitHubUpdate, installLatestUpdate, isRemoteNewer, normalizeUpdateRepo, parseVersionParts } from "../src/main/update"; + +const { spawnMock, unrefMock, onceMock } = vi.hoisted(() => { + const unref = vi.fn(); + const once = vi.fn((_event: string, _handler: (...args: unknown[]) => void) => ({ + unref + })); + const spawn = vi.fn(() => ({ + once, + unref + })); + return { + spawnMock: spawn, + unrefMock: unref, + onceMock: once + }; +}); + +vi.mock("node:child_process", () => ({ + spawn: spawnMock +})); + +import { buildInstallerLaunchArgs, checkGitHubUpdate, installLatestUpdate, isRemoteNewer, normalizeUpdateRepo, parseVersionParts } from "../src/main/update"; import { APP_VERSION } from "../src/main/constants"; import { UpdateCheckResult, UpdateInstallProgress } from "../src/shared/types"; @@ -17,6 +38,9 @@ function sha512Hex(buffer: Buffer): string { afterEach(() => { globalThis.fetch = originalFetch; + spawnMock.mockClear(); + unrefMock.mockClear(); + onceMock.mockClear(); vi.restoreAllMocks(); }); @@ -84,6 +108,10 @@ describe("update", () => { expect(result.setupAssetName).toBe("Real-Debrid-Downloader Setup 9.9.9.exe"); }); + it("uses silent NSIS install flags with auto-run after update", () => { + expect(buildInstallerLaunchArgs()).toEqual(["/S", "--updated", "--force-run"]); + }); + it("falls back to alternate download URL when setup asset URL returns 404", async () => { const executablePayload = fs.readFileSync(process.execPath); const executableDigest = sha256Hex(executablePayload); @@ -464,6 +492,12 @@ describe("update", () => { }); expect(result.started).toBe(true); + expect(spawnMock).toHaveBeenCalledWith(expect.any(String), ["/S", "--updated", "--force-run"], expect.objectContaining({ + detached: true, + stdio: "ignore", + windowsHide: true + })); + expect(unrefMock).toHaveBeenCalledTimes(1); expect(progressEvents.some((entry) => entry.stage === "starting")).toBe(true); expect(progressEvents.some((entry) => entry.stage === "downloading")).toBe(true); expect(progressEvents.some((entry) => entry.stage === "verifying")).toBe(true);