From ae8db1ab531bd3fe469a95253688341bd4b0d6f9 Mon Sep 17 00:00:00 2001 From: xxxigm Date: Sat, 20 Jun 2026 14:45:18 +0700 Subject: [PATCH] fix(desktop): mute hidden link-title window so historical links don't autoplay audio Tier-2 link-title resolution loads the URL in an offscreen BrowserWindow to read its when curl can't. That window was never muted, so pages that autoplay media (e.g. YouTube `watch` URLs) leaked ~2s of audio every time a session containing such links was re-rendered. Move the window creation into a dedicated helper that calls `webContents.setAudioMuted(true)` immediately after construction, so the offscreen probe can never emit sound. Fixes #49505 --- apps/desktop/electron/link-title-window.cjs | 42 +++++++++++++++++++++ apps/desktop/electron/main.cjs | 16 +------- 2 files changed, 44 insertions(+), 14 deletions(-) create mode 100644 apps/desktop/electron/link-title-window.cjs diff --git a/apps/desktop/electron/link-title-window.cjs b/apps/desktop/electron/link-title-window.cjs new file mode 100644 index 00000000000..80b3af3976e --- /dev/null +++ b/apps/desktop/electron/link-title-window.cjs @@ -0,0 +1,42 @@ +'use strict' + +// Hidden BrowserWindow used by tier-2 link-title resolution: when curl can't +// read a page <title> (bot walls, JS-rendered pages), we briefly load the URL +// in an offscreen window and read its title. That window loads arbitrary +// user-linked pages — including YouTube/`watch` URLs that autoplay — so it must +// never be allowed to emit sound. + +function linkTitleWindowOptions(partitionSession) { + return { + show: false, + width: 1280, + height: 800, + webPreferences: { + backgroundThrottling: false, + contextIsolation: true, + javascript: true, + nodeIntegration: false, + sandbox: true, + session: partitionSession, + webSecurity: true + } + } +} + +// Create the offscreen title-fetch window and immediately mute it. Without the +// mute, autoplaying media on the loaded page (e.g. a YouTube link) leaks ~2s of +// audio every time a session containing such links is re-rendered. See #49505. +function createLinkTitleWindow(BrowserWindow, partitionSession) { + const window = new BrowserWindow(linkTitleWindowOptions(partitionSession)) + + try { + window.webContents.setAudioMuted(true) + } catch { + // webContents may be unavailable in degraded/headless environments; muting + // is best-effort and the window is destroyed within a few seconds anyway. + } + + return window +} + +module.exports = { createLinkTitleWindow, linkTitleWindowOptions } diff --git a/apps/desktop/electron/main.cjs b/apps/desktop/electron/main.cjs index 0a4f8eec8ad..b4ba88a243c 100644 --- a/apps/desktop/electron/main.cjs +++ b/apps/desktop/electron/main.cjs @@ -34,6 +34,7 @@ const { SESSION_WINDOW_MIN_WIDTH } = require('./session-windows.cjs') const { canImportHermesCli, verifyHermesCli } = require('./backend-probes.cjs') +const { createLinkTitleWindow } = require('./link-title-window.cjs') const { probeGatewayWebSocket } = require('./gateway-ws-probe.cjs') const { adoptServedDashboardToken } = require('./dashboard-token.cjs') const { waitForDashboardPort } = require('./backend-ready.cjs') @@ -2980,20 +2981,7 @@ function runRenderTitleJob(rawUrl) { } try { - window = new BrowserWindow({ - show: false, - width: 1280, - height: 800, - webPreferences: { - backgroundThrottling: false, - contextIsolation: true, - javascript: true, - nodeIntegration: false, - sandbox: true, - session: partitionSession, - webSecurity: true - } - }) + window = createLinkTitleWindow(BrowserWindow, partitionSession) } catch { return finish('') }