From 43f433597b7d7bbfbbac5e16f00fbfe85efad698 Mon Sep 17 00:00:00 2001 From: sudipnext Date: Wed, 25 Mar 2026 09:24:00 +0545 Subject: [PATCH] feat: enhance Windows compatibility for LibreOffice checks and subprocess handling --- electron/app/utils/libreoffice-check.ts | 26 +++++++++++++++++++ .../api/v1/ppt/endpoints/pptx_slides.py | 19 +++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/electron/app/utils/libreoffice-check.ts b/electron/app/utils/libreoffice-check.ts index 6b991a52..418030b4 100644 --- a/electron/app/utils/libreoffice-check.ts +++ b/electron/app/utils/libreoffice-check.ts @@ -275,6 +275,12 @@ export async function isLibreOfficeInstalled(): Promise // --- Step 1: check well-known paths synchronously (no exec overhead) --- for (const candidate of getCandidatePaths()) { if (fs.existsSync(candidate)) { + // On Windows, avoid probing with "--version" because some LibreOffice + // builds open a transient console window for this command. + if (process.platform === "win32") { + return { installed: true, path: candidate }; + } + // Binary found at a known location – try to get the version string. try { const quoted = `"${candidate}"`; @@ -291,6 +297,26 @@ export async function isLibreOfficeInstalled(): Promise } // --- Step 2: try the PATH-based command --- + if (process.platform === "win32") { + try { + // Use "where" for PATH detection without launching LibreOffice itself. + const { stdout } = await execAsync("where soffice.exe", { + timeout: 8_000, + windowsHide: true, + }); + const firstPath = stdout + .split(/\r?\n/) + .map((line) => line.trim()) + .find((line) => line.length > 0); + if (firstPath) { + return { installed: true, path: firstPath }; + } + } catch { + // Keep behavior: if PATH lookup fails, report not installed. + } + return { installed: false }; + } + try { const { stdout } = await execAsync("soffice --version", { timeout: 8_000, diff --git a/electron/servers/fastapi/api/v1/ppt/endpoints/pptx_slides.py b/electron/servers/fastapi/api/v1/ppt/endpoints/pptx_slides.py index c57004a3..fd81bfcd 100644 --- a/electron/servers/fastapi/api/v1/ppt/endpoints/pptx_slides.py +++ b/electron/servers/fastapi/api/v1/ppt/endpoints/pptx_slides.py @@ -26,7 +26,23 @@ def _get_soffice_binary() -> str: environment variable. Falling back to the bare ``"soffice"`` command keeps Docker / server deployments working unchanged. """ - return os.environ.get("SOFFICE_PATH") or "soffice" + configured = os.environ.get("SOFFICE_PATH") + if configured: + return configured + return "soffice.exe" if os.name == "nt" else "soffice" + + +def _windows_hidden_subprocess_kwargs() -> Dict[str, object]: + """Return subprocess kwargs that suppress Windows console windows.""" + if os.name != "nt": + return {} + + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + return { + "creationflags": getattr(subprocess, "CREATE_NO_WINDOW", 0), + "startupinfo": startupinfo, + } PPTX_SLIDES_ROUTER = APIRouter(prefix="/pptx-slides", tags=["PPTX Slides"]) @@ -596,6 +612,7 @@ async def _convert_pptx_to_pdf(pptx_path: str, temp_dir: str) -> str: text=True, timeout=500, env=env, + **_windows_hidden_subprocess_kwargs(), ) print(f"LibreOffice PDF conversion output: {result.stdout}")