6 Commits

Author SHA1 Message Date
sorlinv
830ce3d035 chore: release v1.7.0 2026-03-05 16:30:27 +01:00
sorlinv
207846fa04 chore: release v1.6.5 2026-03-05 16:16:30 +01:00
sorlinv
47433f3dc9 add nodemail en commit 2026-03-05 16:16:13 +01:00
sorlinv
5d83212761 chore: release v1.6.4 2026-03-05 16:10:13 +01:00
sorlinv
34306a3d05 fix update 2026-03-05 16:10:02 +01:00
sorlinv
cbd2f676e2 chore: release v1.6.3 2026-03-05 16:09:31 +01:00
5 changed files with 940 additions and 1219 deletions

1976
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{ {
"name": "multi-render-blender", "name": "multi-render-blender",
"version": "1.6.2", "version": "1.7.0",
"description": "Application Electron pour piloter des rendus Blender multi-cameras", "description": "Application Electron pour piloter des rendus Blender multi-cameras",
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {
@@ -11,8 +11,8 @@
"author": "", "author": "",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"electron": "^34.0.0", "electron": "^40.7.0",
"electron-builder": "^25.1.8" "electron-builder": "^26.8.1"
}, },
"build": { "build": {
"appId": "com.multirender.blender", "appId": "com.multirender.blender",

View File

@@ -1,4 +1,16 @@
const nodemailer = require("nodemailer"); let _nodemailer = null;
const _get_nodemailer = () => {
if (!_nodemailer) {
try {
_nodemailer = require("nodemailer");
} catch (_err) {
console.error("[EmailNotifier] nodemailer non disponible :", _err.message);
return null;
}
}
return _nodemailer;
};
const _SMTP = { const _SMTP = {
str_host: "ssl0.ovh.net", str_host: "ssl0.ovh.net",
@@ -28,7 +40,12 @@ const EmailNotifier = {
return; return;
} }
EmailNotifier._obj_transporter = nodemailer.createTransport({ let obj_nm = _get_nodemailer();
if (!obj_nm) {
return;
}
EmailNotifier._obj_transporter = obj_nm.createTransport({
host: _SMTP.str_host, host: _SMTP.str_host,
port: _SMTP.nb_port, port: _SMTP.nb_port,
secure: true, secure: true,
@@ -66,7 +83,12 @@ const EmailNotifier = {
}, },
test: (obj_config) => { test: (obj_config) => {
let obj_transporter = nodemailer.createTransport({ let obj_nm = _get_nodemailer();
if (!obj_nm) {
return Promise.resolve({ is_success: false, str_error: "nodemailer non disponible" });
}
let obj_transporter = obj_nm.createTransport({
host: _SMTP.str_host, host: _SMTP.str_host,
port: _SMTP.nb_port, port: _SMTP.nb_port,
secure: true, secure: true,

View File

@@ -6,12 +6,16 @@ const { app } = require("electron");
const { execFile } = require("child_process"); const { execFile } = require("child_process");
const GITEA_HOST = "git.sorlinv.fr"; const GITEA_HOST = "git.sorlinv.fr";
const REPO_PATH = "/api/v1/repos/sorlinv/multi_render_blender/tags"; const GITEA_BASE = "https://git.sorlinv.fr";
const ARCHIVE_URL_BASE = "https://git.sorlinv.fr/sorlinv/multi_render_blender/archive/"; const REPO_OWNER = "sorlinv";
const REPO_NAME = "multi_render_blender";
const REPO_PATH = "/api/v1/repos/" + REPO_OWNER + "/" + REPO_NAME + "/tags";
const RELEASES_API = "/api/v1/repos/" + REPO_OWNER + "/" + REPO_NAME + "/releases/tags/";
const PRODUCT_NAME = "multi-render-blender";
const NB_TIMEOUT_API = 10000; const NB_TIMEOUT_API = 10000;
const NB_TIMEOUT_DOWNLOAD = 60000; const NB_TIMEOUT_DOWNLOAD = 300000;
const LIST_REQUIRED_FILES = ["main.js", "version.json"]; const LIST_REQUIRED_FILES = ["main.js", "version.json"];
const LIST_TARGETS = ["main.js", "preload.js", "src", "version.json", "package.json"]; const LIST_TARGETS = ["main.js", "preload.js", "src", "version.json", "package.json", "node_modules"];
const UpdateManager = { const UpdateManager = {
obj_window: null, obj_window: null,
@@ -208,9 +212,84 @@ const UpdateManager = {
}); });
}, },
_download_zip: (str_tag_name, str_zip_path) => { _fetch_release_asset_url: (str_tag_name) => {
let str_url = ARCHIVE_URL_BASE + str_tag_name + ".zip"; let str_platform = process.platform === "win32" ? "win-x64" : "linux-x64";
let str_expected_suffix = "-" + str_platform + ".zip";
return new Promise((resolve, reject) => {
let obj_options = {
hostname: GITEA_HOST,
path: RELEASES_API + str_tag_name,
method: "GET",
timeout: NB_TIMEOUT_API,
headers: {
"Accept": "application/json",
"User-Agent": "MultiRenderBlender",
},
};
let obj_req = https.request(obj_options, (obj_res) => {
let str_data = "";
obj_res.on("data", (chunk) => {
str_data += chunk;
});
obj_res.on("end", () => {
if (obj_res.statusCode !== 200) {
reject(new Error("Release API status " + obj_res.statusCode));
return;
}
try {
let obj_release = JSON.parse(str_data);
let list_assets = obj_release.assets || [];
let obj_asset = null;
for (let obj_a of list_assets) {
let str_name = obj_a.name || "";
if (str_name.endsWith(str_expected_suffix)) {
obj_asset = obj_a;
break;
}
}
if (!obj_asset) {
reject(new Error("Asset build introuvable pour " + str_platform + " dans la release " + str_tag_name));
return;
}
let str_url = obj_asset.browser_download_url || "";
if (!str_url) {
str_url = GITEA_BASE + "/" + REPO_OWNER + "/" + REPO_NAME + "/releases/download/" + str_tag_name + "/" + obj_asset.name;
}
resolve(str_url);
} catch (obj_err) {
reject(new Error("Reponse JSON release invalide"));
}
});
});
obj_req.on("timeout", () => {
obj_req.destroy();
reject(new Error("Timeout API release"));
});
obj_req.on("error", (obj_err) => {
reject(obj_err);
});
obj_req.end();
});
},
_download_zip: (str_tag_name, str_zip_path) => {
return UpdateManager._fetch_release_asset_url(str_tag_name)
.then((str_url) => {
return UpdateManager._download_file(str_url, str_zip_path);
});
},
_download_file: (str_url, str_zip_path) => {
let fn_download = (str_download_url, nb_redirects) => { let fn_download = (str_download_url, nb_redirects) => {
if (nb_redirects > 5) { if (nb_redirects > 5) {
return Promise.reject(new Error("Trop de redirections")); return Promise.reject(new Error("Trop de redirections"));
@@ -311,39 +390,41 @@ const UpdateManager = {
_find_extracted_root: (str_temp_dir) => { _find_extracted_root: (str_temp_dir) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let list_entries = fs.readdirSync(str_temp_dir); let fn_find_version_json = (str_dir, nb_depth) => {
let str_root = null; if (nb_depth > 5) {
return null;
}
let str_version_check = path.join(str_dir, "version.json");
if (fs.existsSync(str_version_check)) {
return str_dir;
}
let list_entries;
try {
list_entries = fs.readdirSync(str_dir);
} catch (obj_err) {
return null;
}
for (let str_entry of list_entries) { for (let str_entry of list_entries) {
if (str_entry === "update.zip") { if (str_entry === "update.zip") {
continue; continue;
} }
let str_full = path.join(str_temp_dir, str_entry); let str_full = path.join(str_dir, str_entry);
try {
if (!fs.statSync(str_full).isDirectory()) { if (!fs.statSync(str_full).isDirectory()) {
continue; continue;
} }
} catch (obj_err) {
continue;
}
let str_found = fn_find_version_json(str_full, nb_depth + 1);
if (str_found) {
return str_found;
}
}
return null;
};
let str_version_check = path.join(str_full, "version.json"); let str_root = fn_find_version_json(str_temp_dir, 0);
if (fs.existsSync(str_version_check)) {
str_root = str_full;
break;
}
let list_sub = fs.readdirSync(str_full);
for (let str_sub of list_sub) {
let str_sub_full = path.join(str_full, str_sub);
if (fs.statSync(str_sub_full).isDirectory()) {
let str_nested_check = path.join(str_sub_full, "version.json");
if (fs.existsSync(str_nested_check)) {
str_root = str_sub_full;
break;
}
}
}
if (str_root) {
break;
}
}
if (!str_root) { if (!str_root) {
reject(new Error("Dossier extrait introuvable (version.json absent)")); reject(new Error("Dossier extrait introuvable (version.json absent)"));

View File

@@ -1,3 +1,3 @@
{ {
"str_version": "1.6.2" "str_version": "1.7.0"
} }