Compare commits

..

4 Commits

Author SHA1 Message Date
Sucukdeluxe
0a7467a8b0 Release v2.0.0-beta.5 2026-03-08 19:39:07 +01:00
Sucukdeluxe
f25e61573d Fix downloads not starting: reset session.running on startup
Root cause: normalizeSessionStatuses() did not reset session.running
to false on startup. If the app was closed/crashed while downloads
were active, session.json retained running=true. On next launch,
start() checked if (this.session.running) return — silently refusing
to start any downloads.

Also improved normalizeSessionStatuses to match the old DM behavior:
- Reset session.running, paused, reconnectUntil, reconnectReason
- Recover cancelled/Gestoppt items back to queued
- Mark extracting/integrity_check items as completed (already downloaded)
- Handle paused and reconnect_wait items
- Cover all transient package statuses

Updated update tests for beta repo name.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 19:38:22 +01:00
Sucukdeluxe
25b7104580 Release v2.0.0-beta.4 2026-03-08 19:19:32 +01:00
Sucukdeluxe
e0eab43763 Fix auto-updater pointing to stable repo instead of beta repo
DEFAULT_UPDATE_REPO was still set to Administrator/real-debrid-downloader
(the stable repo). Changed to Administrator/beta-real-debrid-downloader
so the beta app finds its own releases.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 19:19:01 +01:00
4 changed files with 41 additions and 10 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "real-debrid-downloader-beta", "name": "real-debrid-downloader-beta",
"version": "2.0.0-beta.3", "version": "2.0.0-beta.5",
"description": "Desktop downloader", "description": "Desktop downloader",
"main": "build/main/main/main.js", "main": "build/main/main/main.js",
"author": "Sucukdeluxe", "author": "Sucukdeluxe",

View File

@ -36,7 +36,7 @@ export const MAX_LINK_ARTIFACT_BYTES = 256 * 1024;
export const SPEED_WINDOW_SECONDS = 1; export const SPEED_WINDOW_SECONDS = 1;
export const CLIPBOARD_POLL_INTERVAL_MS = 2000; export const CLIPBOARD_POLL_INTERVAL_MS = 2000;
export const DEFAULT_UPDATE_REPO = "Administrator/real-debrid-downloader"; export const DEFAULT_UPDATE_REPO = "Administrator/beta-real-debrid-downloader";
export function defaultSettings(): AppSettings { export function defaultSettings(): AppSettings {
const baseDir = path.join(os.homedir(), "Downloads", "RealDebrid"); const baseDir = path.join(os.homedir(), "Downloads", "RealDebrid");

View File

@ -1594,16 +1594,47 @@ export class DownloadManager extends EventEmitter {
} }
private normalizeSessionStatuses(): void { private normalizeSessionStatuses(): void {
// Critical: reset session-level running state on startup.
// Without this, if the app crashes while running, session.running stays true
// in the persisted JSON and start() silently returns on next launch.
this.session.running = false;
this.session.paused = false;
this.session.reconnectUntil = 0;
this.session.reconnectReason = "";
for (const item of Object.values(this.session.items)) { for (const item of Object.values(this.session.items)) {
if (item.status === "downloading" || item.status === "validating" || item.status === "integrity_check") { // Items that were stopped mid-run should be re-queued
if (item.status === "cancelled" && item.fullStatus === "Gestoppt") {
item.status = "queued"; item.status = "queued";
item.fullStatus = "Wartet"; item.fullStatus = "Wartet";
item.lastError = "";
item.speedBps = 0;
item.provider = null;
item.updatedAt = nowMs();
continue;
}
// Items that were extracting/checking integrity are already fully downloaded
if (item.status === "extracting" || item.status === "integrity_check") {
item.status = "completed";
item.fullStatus = `Fertig (${humanSize(item.downloadedBytes)})`;
item.speedBps = 0;
item.updatedAt = nowMs();
continue;
}
// Active/paused/reconnecting items → re-queue
if (item.status === "downloading" || item.status === "validating"
|| item.status === "paused" || item.status === "reconnect_wait") {
item.status = "queued";
const pkg = this.session.packages[item.packageId];
item.fullStatus = (pkg && pkg.enabled === false) ? "Paket gestoppt" : "Wartet";
item.speedBps = 0; item.speedBps = 0;
item.updatedAt = nowMs(); item.updatedAt = nowMs();
} }
} }
for (const pkg of Object.values(this.session.packages)) { for (const pkg of Object.values(this.session.packages)) {
if (pkg.status === "downloading" || pkg.status === "validating" || pkg.status === "extracting") { if (pkg.status === "downloading" || pkg.status === "validating"
|| pkg.status === "extracting" || pkg.status === "integrity_check"
|| pkg.status === "paused" || pkg.status === "reconnect_wait") {
pkg.status = "queued"; pkg.status = "queued";
pkg.updatedAt = nowMs(); pkg.updatedAt = nowMs();
} }

View File

@ -46,7 +46,7 @@ afterEach(() => {
describe("update", () => { describe("update", () => {
it("normalizes update repo input", () => { it("normalizes update repo input", () => {
expect(normalizeUpdateRepo("")).toBe("Administrator/real-debrid-downloader"); expect(normalizeUpdateRepo("")).toBe("Administrator/beta-real-debrid-downloader");
expect(normalizeUpdateRepo("owner/repo")).toBe("owner/repo"); expect(normalizeUpdateRepo("owner/repo")).toBe("owner/repo");
expect(normalizeUpdateRepo("https://codeberg.org/owner/repo")).toBe("owner/repo"); expect(normalizeUpdateRepo("https://codeberg.org/owner/repo")).toBe("owner/repo");
expect(normalizeUpdateRepo("https://www.codeberg.org/owner/repo")).toBe("owner/repo"); expect(normalizeUpdateRepo("https://www.codeberg.org/owner/repo")).toBe("owner/repo");
@ -518,14 +518,14 @@ describe("normalizeUpdateRepo extended", () => {
}); });
it("returns default for malformed inputs", () => { it("returns default for malformed inputs", () => {
expect(normalizeUpdateRepo("just-one-part")).toBe("Administrator/real-debrid-downloader"); expect(normalizeUpdateRepo("just-one-part")).toBe("Administrator/beta-real-debrid-downloader");
expect(normalizeUpdateRepo(" ")).toBe("Administrator/real-debrid-downloader"); expect(normalizeUpdateRepo(" ")).toBe("Administrator/beta-real-debrid-downloader");
}); });
it("rejects traversal-like owner or repo segments", () => { it("rejects traversal-like owner or repo segments", () => {
expect(normalizeUpdateRepo("../owner/repo")).toBe("Administrator/real-debrid-downloader"); expect(normalizeUpdateRepo("../owner/repo")).toBe("Administrator/beta-real-debrid-downloader");
expect(normalizeUpdateRepo("owner/../repo")).toBe("Administrator/real-debrid-downloader"); expect(normalizeUpdateRepo("owner/../repo")).toBe("Administrator/beta-real-debrid-downloader");
expect(normalizeUpdateRepo("https://codeberg.org/owner/../../repo")).toBe("Administrator/real-debrid-downloader"); expect(normalizeUpdateRepo("https://codeberg.org/owner/../../repo")).toBe("Administrator/beta-real-debrid-downloader");
}); });
it("handles www prefix", () => { it("handles www prefix", () => {