// src/main/utils/paths.ts // dev vs production 경로 자동 감지 유틸 import path from 'path' import { app } from 'electron' import { existsSync } from 'fs' /** * 앱이 패키징되었는지 여부. * electron-builder로 빌드 후 실행하면 app.isPackaged = true. */ function isPackaged(): boolean { return app.isPackaged } /** * 프로젝트 루트 경로. * - dev: 프로젝트 디렉토리 (D:/workspace/D3ROVoice) * - production: process.resourcesPath (app.asar.unpacked 포함) */ function getProjectRoot(): string { return isPackaged() ? process.resourcesPath : app.getAppPath() } /** * SoX 실행 파일 경로. * - dev: resources/sox/sox.exe (있으면) 또는 시스템 PATH의 sox * - production: resources/sox/sox.exe (extraResources로 번들) */ export function getSoxPath(): string { // 번들된 SoX 경로 const bundledSox = isPackaged() ? path.join(process.resourcesPath, 'sox', 'sox.exe') : path.join(app.getAppPath(), 'resources', 'sox', 'sox.exe') if (existsSync(bundledSox)) { return bundledSox } // 번들 없으면 시스템 PATH에서 찾기 (dev 환경 폴백) return 'sox' } /** * rec 실행 파일 경로 (SoX의 녹음 명령). * node-record-lpcm16은 rec를 사용한다. */ export function getRecPath(): string { const bundledRec = isPackaged() ? path.join(process.resourcesPath, 'sox', 'rec.exe') : path.join(app.getAppPath(), 'resources', 'sox', 'rec.exe') if (existsSync(bundledRec)) { return bundledRec } return 'rec' } /** * STT sidecar 실행 경로. * - dev: python sidecar/main.py * - production: sidecar/sidecar.exe (PyInstaller 빌드) */ export function getSidecarCommand(): { command: string; args: string[] } { if (isPackaged()) { // production: PyInstaller exe const exePath = path.join(process.resourcesPath, 'sidecar', 'sidecar.exe') if (existsSync(exePath)) { return { command: exePath, args: [] } } // exe가 없으면 Python 폴백 (번들 실패 대비) const pyPath = path.join(process.resourcesPath, 'sidecar', 'main.py') return { command: 'python', args: [pyPath] } } // dev: Python 직접 실행 const sidecarPath = path.join(app.getAppPath(), 'sidecar', 'main.py') const pythonCmd = process.platform === 'win32' ? 'python' : 'python3' return { command: pythonCmd, args: [sidecarPath] } } /** * 효과음 파일 경로. */ export function getSoundPath(filename: string): string { if (isPackaged()) { return path.join(process.resourcesPath, 'sounds', filename) } return path.join(app.getAppPath(), 'resources', 'sounds', filename) } /** * 사용자 데이터 경로 (DB, 로그 등). */ export function getUserDataPath(): string { return app.getPath('userData') }