const path = require("path"); const fs = require("fs"); const { app } = require("electron"); const { execFileSync } = require("child_process"); const STR_EXE_NAME = process.platform === "win32" ? "blender.exe" : "blender"; const STR_CONFIG_FILE = "blender_path.json"; const PathResolver = { _str_blender_path: null, _is_found: false, load_saved_path: () => { let str_config_path = PathResolver._get_config_path(); try { if (fs.existsSync(str_config_path)) { let str_content = fs.readFileSync(str_config_path, "utf8"); let obj_data = JSON.parse(str_content); if (obj_data.str_path && fs.existsSync(obj_data.str_path)) { PathResolver._str_blender_path = obj_data.str_path; PathResolver._is_found = true; return; } } } catch (obj_err) { console.error("PathResolver: impossible de lire la config :", obj_err.message); } let str_detected = PathResolver.auto_detect(); if (str_detected) { PathResolver._str_blender_path = str_detected; PathResolver._is_found = true; } else { PathResolver._str_blender_path = "blender"; PathResolver._is_found = false; } }, get_blender_path: () => { if (!PathResolver._str_blender_path) { PathResolver.load_saved_path(); } return PathResolver._str_blender_path; }, is_found: () => { return PathResolver._is_found; }, set_blender_path: (str_path) => { if (!str_path || !fs.existsSync(str_path)) { return { is_success: false, str_error: "Fichier introuvable : " + str_path }; } PathResolver._str_blender_path = str_path; PathResolver._is_found = true; let str_config_path = PathResolver._get_config_path(); try { let str_dir = path.dirname(str_config_path); if (!fs.existsSync(str_dir)) { fs.mkdirSync(str_dir, { recursive: true }); } fs.writeFileSync(str_config_path, JSON.stringify({ str_path: str_path }, null, 4), "utf8"); } catch (obj_err) { console.error("PathResolver: impossible de sauvegarder :", obj_err.message); } return { is_success: true, str_path: str_path }; }, auto_detect: () => { if (process.platform === "win32") { return PathResolver._auto_detect_windows(); } return PathResolver._auto_detect_linux(); }, get_status: () => { return { str_path: PathResolver._str_blender_path || "blender", is_found: PathResolver._is_found, }; }, // ── Private ────────────────────────────────────────────── _get_config_path: () => { return path.join(app.getPath("userData"), STR_CONFIG_FILE); }, _auto_detect_linux: () => { let LIST_PATHS = [ "/usr/bin/blender", "/snap/bin/blender", "/usr/local/bin/blender", "/opt/blender/blender", ]; try { let str_result = execFileSync("which", ["blender"], { encoding: "utf8", timeout: 5000 }).trim(); if (str_result && fs.existsSync(str_result)) { return str_result; } } catch (obj_err) { // which not found or blender not in PATH } for (let str_path of LIST_PATHS) { if (fs.existsSync(str_path)) { return str_path; } } return null; }, _auto_detect_windows: () => { try { let str_result = execFileSync("where", ["blender.exe"], { encoding: "utf8", timeout: 5000 }).trim(); let str_first = str_result.split("\n")[0].trim(); if (str_first && fs.existsSync(str_first)) { return str_first; } } catch (obj_err) { // where not found or blender not in PATH } let LIST_BASES = [ process.env.PROGRAMFILES || "C:\\Program Files", process.env["PROGRAMFILES(X86)"] || "C:\\Program Files (x86)", ]; for (let str_base of LIST_BASES) { let str_foundation = path.join(str_base, "Blender Foundation"); if (!fs.existsSync(str_foundation)) { continue; } try { let list_dirs = fs.readdirSync(str_foundation); for (let str_dir of list_dirs) { let str_exe = path.join(str_foundation, str_dir, STR_EXE_NAME); if (fs.existsSync(str_exe)) { return str_exe; } } } catch (obj_err) { // permission denied or similar } } return null; }, }; module.exports = PathResolver;