import path from 'node:path'; import { spawn } from 'node:child_process'; import { app, dialog } from 'electron'; import { printHelp } from './cli/help'; import { loadRawConfigStrict } from './config/load'; import { configureEarlyAppPaths, normalizeLaunchMpvExtraArgs, normalizeLaunchMpvTargets, normalizeStartupArgv, sanitizeStartupEnv, sanitizeBackgroundEnv, sanitizeHelpEnv, sanitizeLaunchMpvEnv, shouldDetachBackgroundLaunch, shouldHandleHelpOnlyAtEntry, shouldHandleLaunchMpvAtEntry, shouldHandleStatsDaemonCommandAtEntry, } from './main-entry-runtime'; import { requestSingleInstanceLockEarly } from './main/early-single-instance'; import { resolvePackagedFirstRunPluginAssets } from './main/runtime/first-run-setup-plugin'; import { createWindowsMpvLaunchDeps, launchWindowsMpv } from './main/runtime/windows-mpv-launch'; import { parseMpvLaunchMode } from './shared/mpv-launch-mode'; import { runStatsDaemonControlFromProcess } from './stats-daemon-entry'; const DEFAULT_TEXTHOOKER_PORT = 5174; function applySanitizedEnv(sanitizedEnv: NodeJS.ProcessEnv): void { if (sanitizedEnv.NODE_NO_WARNINGS) { process.env.NODE_NO_WARNINGS = sanitizedEnv.NODE_NO_WARNINGS; } if (sanitizedEnv.VK_INSTANCE_LAYERS) { process.env.VK_INSTANCE_LAYERS = sanitizedEnv.VK_INSTANCE_LAYERS; } else { delete process.env.VK_INSTANCE_LAYERS; } } function resolveBundledWindowsMpvPluginEntrypoint(): string | undefined { const assets = resolvePackagedFirstRunPluginAssets({ dirname: __dirname, appPath: app.getAppPath(), resourcesPath: process.resourcesPath, }); if (!assets) { return undefined; } return path.join(assets.pluginDirSource, 'main.lua'); } function readConfiguredWindowsMpvLaunch(configDir: string): { executablePath: string; launchMode: 'normal' | 'maximized' | 'fullscreen'; } { const loadResult = loadRawConfigStrict({ configDir, configFileJsonc: path.join(configDir, 'config.jsonc'), configFileJson: path.join(configDir, 'config.json'), }); if (!loadResult.ok) { return { executablePath: '', launchMode: 'normal', }; } return { executablePath: typeof loadResult.config.mpv?.executablePath === 'string' ? loadResult.config.mpv.executablePath.trim() : '', launchMode: parseMpvLaunchMode(loadResult.config.mpv?.launchMode) ?? 'normal', }; } process.argv = normalizeStartupArgv(process.argv, process.env); applySanitizedEnv(sanitizeStartupEnv(process.env)); const userDataPath = configureEarlyAppPaths(app); if (shouldDetachBackgroundLaunch(process.argv, process.env)) { const child = spawn(process.execPath, process.argv.slice(1), { detached: true, stdio: 'ignore', env: sanitizeBackgroundEnv(process.env), }); child.unref(); process.exit(0); } if (shouldHandleHelpOnlyAtEntry(process.argv, process.env)) { const sanitizedEnv = sanitizeHelpEnv(process.env); process.env.NODE_NO_WARNINGS = sanitizedEnv.NODE_NO_WARNINGS; if (!sanitizedEnv.VK_INSTANCE_LAYERS) { delete process.env.VK_INSTANCE_LAYERS; } printHelp(DEFAULT_TEXTHOOKER_PORT); process.exit(0); } if (shouldHandleLaunchMpvAtEntry(process.argv, process.env)) { const sanitizedEnv = sanitizeLaunchMpvEnv(process.env); applySanitizedEnv(sanitizedEnv); void app.whenReady().then(async () => { const configuredMpvLaunch = readConfiguredWindowsMpvLaunch(userDataPath); const result = await launchWindowsMpv( normalizeLaunchMpvTargets(process.argv), createWindowsMpvLaunchDeps({ getEnv: (name) => process.env[name], showError: (title, content) => { dialog.showErrorBox(title, content); }, }), normalizeLaunchMpvExtraArgs(process.argv), process.execPath, resolveBundledWindowsMpvPluginEntrypoint(), configuredMpvLaunch.executablePath, configuredMpvLaunch.launchMode, ); app.exit(result.ok ? 0 : 1); }); } else if (shouldHandleStatsDaemonCommandAtEntry(process.argv, process.env)) { void app.whenReady().then(async () => { const exitCode = await runStatsDaemonControlFromProcess(app.getPath('userData')); app.exit(exitCode); }); } else { const gotSingleInstanceLock = requestSingleInstanceLockEarly(app); if (!gotSingleInstanceLock) { app.exit(0); } require('./main.js'); }