diff --git a/src/main/realdebrid-web.ts b/src/main/realdebrid-web.ts index 7054e41..a78b26e 100644 --- a/src/main/realdebrid-web.ts +++ b/src/main/realdebrid-web.ts @@ -135,6 +135,8 @@ export class RealDebridWebFallback { private onClosed?: () => void; + private interactiveLoginDismissed = false; + private persistentPartition: string; private transientPartition: string; @@ -176,7 +178,8 @@ export class RealDebridWebFallback { public async openLoginWindow(): Promise { this.throwIfDisposed(); - const window = await this.ensureLoginWindow(); + this.interactiveLoginDismissed = false; + const window = await this.ensureLoginWindow(); if (window.isMinimized()) { window.restore(); } @@ -340,6 +343,7 @@ export class RealDebridWebFallback { let closingTokenProbe: Promise = Promise.resolve(); window.on("close", () => { if (!this.programmaticClosures.has(window)) { + this.interactiveLoginDismissed = true; closingTokenProbe = this.primeTokenFromWindow(window, windowGeneration); } }); @@ -372,6 +376,7 @@ export class RealDebridWebFallback { const changed = token !== this.cachedToken; this.cachedToken = token; this.cachedTokenAt = Date.now(); + this.interactiveLoginDismissed = false; if (changed && this.onAuthenticated) { void Promise.resolve().then(() => this.onAuthenticated?.()); } @@ -581,8 +586,11 @@ export class RealDebridWebFallback { throw new Error("Real-Debrid Web: Unrestrict fehlgeschlagen"); } - private async waitForLoginAndGenerate(link: string, signal?: AbortSignal): Promise { - const window = await this.ensureLoginWindow(); + private async waitForLoginAndGenerate(link: string, signal?: AbortSignal): Promise { + if (this.interactiveLoginDismissed) { + throw new Error("Real-Debrid Web-Login abgebrochen"); + } + const window = await this.ensureLoginWindow(); if (window.isMinimized()) { window.restore(); } @@ -596,11 +604,12 @@ export class RealDebridWebFallback { throw new Error("Real-Debrid Web-Login abgebrochen"); } - const outcome = await this.generate(link, signal); - if (outcome.kind === "success") { - if (!window.isDestroyed()) { - window.close(); - } + const outcome = await this.generate(link, signal); + if (outcome.kind === "success") { + if (!window.isDestroyed()) { + this.programmaticClosures.add(window); + window.close(); + } return outcome.value; } diff --git a/tests/realdebrid-web.test.ts b/tests/realdebrid-web.test.ts index 883be55..4895cc5 100644 --- a/tests/realdebrid-web.test.ts +++ b/tests/realdebrid-web.test.ts @@ -197,6 +197,30 @@ describe("realdebrid-web", () => { ); }); + it("does not reopen an automatically required login after the user closed it", async () => { + mockExecuteJavaScript.mockResolvedValue(""); + mockSessionFetch.mockImplementation(async () => new Response("login", { status: 200 })); + const fallback = new RealDebridWebFallback("persist:realdebrid-web-rdw_dismissed", () => true); + + await fallback.openLoginWindow(); + mockBrowserWindow.close(); + + await expect(fallback.unrestrict("https://rapidgator.net/file/first")).rejects.toThrow("abgebrochen"); + await expect(fallback.unrestrict("https://rapidgator.net/file/second")).rejects.toThrow("abgebrochen"); + expect(mockBrowserWindowCtor).toHaveBeenCalledTimes(1); + }); + + it("allows an explicitly requested login after the user closed the previous window", async () => { + mockExecuteJavaScript.mockResolvedValue(""); + const fallback = new RealDebridWebFallback("persist:realdebrid-web-rdw_reopen", () => true); + + await fallback.openLoginWindow(); + mockBrowserWindow.close(); + await fallback.openLoginWindow(); + + expect(mockBrowserWindowCtor).toHaveBeenCalledTimes(2); + }); + it("notifies the controller when a new browser token is detected", async () => { mockExecuteJavaScript.mockResolvedValue("new-browser-token"); const onAuthenticated = vi.fn();