263 lines
8.5 KiB
JavaScript
263 lines
8.5 KiB
JavaScript
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 STR_FFMPEG_CONFIG_FILE = "ffmpeg_path.json";
|
|
|
|
const PathResolver = {
|
|
_str_blender_path: null,
|
|
_is_found: false,
|
|
_str_ffmpeg_path: null,
|
|
_is_ffmpeg_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,
|
|
};
|
|
},
|
|
|
|
// ── FFmpeg ───────────────────────────────────────────────
|
|
|
|
load_saved_ffmpeg_path: () => {
|
|
let str_config_path = PathResolver._get_ffmpeg_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_ffmpeg_path = obj_data.str_path;
|
|
PathResolver._is_ffmpeg_found = true;
|
|
return;
|
|
}
|
|
}
|
|
} catch (obj_err) {
|
|
console.error("PathResolver: impossible de lire la config ffmpeg :", obj_err.message);
|
|
}
|
|
|
|
let str_detected = PathResolver._auto_detect_ffmpeg();
|
|
if (str_detected) {
|
|
PathResolver._str_ffmpeg_path = str_detected;
|
|
PathResolver._is_ffmpeg_found = true;
|
|
} else {
|
|
PathResolver._str_ffmpeg_path = "ffmpeg";
|
|
PathResolver._is_ffmpeg_found = false;
|
|
}
|
|
},
|
|
|
|
get_ffmpeg_path: () => {
|
|
if (!PathResolver._str_ffmpeg_path) {
|
|
PathResolver.load_saved_ffmpeg_path();
|
|
}
|
|
return PathResolver._str_ffmpeg_path;
|
|
},
|
|
|
|
set_ffmpeg_path: (str_path) => {
|
|
if (!str_path || !fs.existsSync(str_path)) {
|
|
return { is_success: false, str_error: "Fichier introuvable : " + str_path };
|
|
}
|
|
|
|
PathResolver._str_ffmpeg_path = str_path;
|
|
PathResolver._is_ffmpeg_found = true;
|
|
|
|
let str_config_path = PathResolver._get_ffmpeg_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 ffmpeg :", obj_err.message);
|
|
}
|
|
|
|
return { is_success: true, str_path: str_path };
|
|
},
|
|
|
|
get_ffmpeg_status: () => {
|
|
return {
|
|
str_path: PathResolver._str_ffmpeg_path || "ffmpeg",
|
|
is_found: PathResolver._is_ffmpeg_found,
|
|
};
|
|
},
|
|
|
|
_auto_detect_ffmpeg: () => {
|
|
let str_cmd = process.platform === "win32" ? "where" : "which";
|
|
let str_exe = process.platform === "win32" ? "ffmpeg.exe" : "ffmpeg";
|
|
|
|
try {
|
|
let str_result = execFileSync(str_cmd, [str_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) {
|
|
// not in PATH
|
|
}
|
|
|
|
if (process.platform !== "win32") {
|
|
let LIST_PATHS = [
|
|
"/usr/bin/ffmpeg",
|
|
"/usr/local/bin/ffmpeg",
|
|
"/snap/bin/ffmpeg",
|
|
];
|
|
for (let str_p of LIST_PATHS) {
|
|
if (fs.existsSync(str_p)) {
|
|
return str_p;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
},
|
|
|
|
// ── Private ──────────────────────────────────────────────
|
|
|
|
_get_config_path: () => {
|
|
return path.join(app.getPath("userData"), STR_CONFIG_FILE);
|
|
},
|
|
|
|
_get_ffmpeg_config_path: () => {
|
|
return path.join(app.getPath("userData"), STR_FFMPEG_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;
|