temps restant + video + download link + left click + show next frame done

This commit is contained in:
sorlinv
2026-03-05 15:43:28 +01:00
parent 9ab59373df
commit b169e69b24
20 changed files with 2128 additions and 30 deletions

161
main.js
View File

@@ -1,4 +1,4 @@
const { app, BrowserWindow, ipcMain, dialog } = require("electron");
const { app, BrowserWindow, ipcMain, dialog, shell, clipboard, nativeImage } = require("electron");
const path = require("path");
const fs = require("fs");
const CameraParser = require("./src/main/CameraParser.js");
@@ -6,12 +6,16 @@ const QueueManager = require("./src/main/QueueManager.js");
const ConfigManager = require("./src/main/ConfigManager.js");
const UpdateManager = require("./src/main/UpdateManager.js");
const PathResolver = require("./src/main/PathResolver.js");
const VideoGenerator = require("./src/main/VideoGenerator.js");
const EmailNotifier = require("./src/main/EmailNotifier.js");
let obj_main_window = null;
let obj_queue_manager = null;
let obj_notification_config = { is_notify_each_image: false, is_notify_all_done: true };
let obj_email_config = { is_enabled: false, str_to: "" };
const STR_NOTIFICATION_CONFIG_FILE = "notification_config.json";
const STR_EMAIL_CONFIG_FILE = "email_config.json";
const _load_notification_config = () => {
let str_config_path = path.join(app.getPath("userData"), STR_NOTIFICATION_CONFIG_FILE);
@@ -34,6 +38,28 @@ const _save_notification_config = () => {
}
};
const _load_email_config = () => {
let str_config_path = path.join(app.getPath("userData"), STR_EMAIL_CONFIG_FILE);
try {
if (fs.existsSync(str_config_path)) {
let str_content = fs.readFileSync(str_config_path, "utf8");
obj_email_config = JSON.parse(str_content);
EmailNotifier.set_config(obj_email_config);
}
} catch (obj_err) {
console.error("Erreur lecture config email :", obj_err.message);
}
};
const _save_email_config = () => {
let str_config_path = path.join(app.getPath("userData"), STR_EMAIL_CONFIG_FILE);
try {
fs.writeFileSync(str_config_path, JSON.stringify(obj_email_config, null, 4), "utf8");
} catch (obj_err) {
console.error("Erreur sauvegarde config email :", obj_err.message);
}
};
const create_window = () => {
obj_main_window = new BrowserWindow({
width: 1400,
@@ -53,13 +79,17 @@ const create_window = () => {
obj_queue_manager = new QueueManager(obj_main_window);
PathResolver.load_saved_path();
PathResolver.load_saved_ffmpeg_path();
_load_notification_config();
_load_email_config();
obj_queue_manager.set_notification_config(obj_notification_config);
obj_queue_manager.set_email_notifier(EmailNotifier);
UpdateManager.init(obj_main_window);
obj_main_window.webContents.on("did-finish-load", () => {
UpdateManager.check_for_updates();
obj_main_window.webContents.send("blender-path-status", PathResolver.get_status());
obj_main_window.webContents.send("ffmpeg-path-status", PathResolver.get_ffmpeg_status());
});
};
@@ -205,6 +235,37 @@ ipcMain.handle("set-blender-path", (event, str_path) => {
return obj_result;
});
ipcMain.handle("get-ffmpeg-path", () => {
return PathResolver.get_ffmpeg_status();
});
ipcMain.handle("set-ffmpeg-path", (event, str_path) => {
let obj_result = PathResolver.set_ffmpeg_path(str_path);
if (obj_result.is_success) {
obj_main_window.webContents.send("ffmpeg-path-status", PathResolver.get_ffmpeg_status());
}
return obj_result;
});
ipcMain.handle("select-ffmpeg-exe", () => {
let str_exe_name = process.platform === "win32" ? "ffmpeg.exe" : "ffmpeg";
let list_filters = process.platform === "win32"
? [{ name: "FFmpeg", extensions: ["exe"] }]
: [{ name: "FFmpeg", extensions: ["*"] }];
return dialog.showOpenDialog(obj_main_window, {
title: "Selectionner l'executable FFmpeg",
filters: list_filters,
properties: ["openFile"],
})
.then((obj_result) => {
if (obj_result.canceled || obj_result.filePaths.length === 0) {
return null;
}
return obj_result.filePaths[0];
});
});
ipcMain.handle("select-blender-exe", () => {
let str_exe_name = process.platform === "win32" ? "blender.exe" : "blender";
let list_filters = process.platform === "win32"
@@ -232,6 +293,15 @@ ipcMain.handle("apply-update", (event, str_tag_name) => {
return UpdateManager.download_and_apply(str_tag_name);
});
ipcMain.handle("generate-preview-video", (event, obj_params) => {
let fn_on_log = (str_msg) => {
if (obj_main_window && !obj_main_window.isDestroyed()) {
obj_main_window.webContents.send("log", "[ffmpeg] " + str_msg);
}
};
return VideoGenerator.generate(obj_params, fn_on_log);
});
ipcMain.handle("select-output-folder", () => {
return dialog.showOpenDialog(obj_main_window, {
title: "Selectionner le dossier de sortie",
@@ -245,6 +315,78 @@ ipcMain.handle("select-output-folder", () => {
});
});
// ── File actions (context menu) ───────────────────────────────
ipcMain.handle("show-item-in-folder", (event, str_path) => {
shell.showItemInFolder(str_path);
return { is_success: true };
});
ipcMain.handle("open-file-default", (event, str_path) => {
return shell.openPath(str_path)
.then((str_error) => {
if (str_error) {
return { is_success: false, str_error: str_error };
}
return { is_success: true };
});
});
ipcMain.handle("delete-rendered-file", (event, str_path) => {
try {
if (fs.existsSync(str_path)) {
fs.unlinkSync(str_path);
return { is_success: true };
}
return { is_success: false, str_error: "Fichier introuvable" };
} catch (obj_err) {
return { is_success: false, str_error: obj_err.message };
}
});
ipcMain.handle("delete-rendered-files", (event, list_paths) => {
let nb_deleted = 0;
let list_errors = [];
for (let str_p of list_paths) {
try {
if (fs.existsSync(str_p)) {
fs.unlinkSync(str_p);
nb_deleted++;
}
} catch (obj_err) {
list_errors.push(str_p + ": " + obj_err.message);
}
}
return { is_success: true, nb_deleted: nb_deleted, list_errors: list_errors };
});
ipcMain.handle("get-file-info", (event, str_path) => {
try {
let obj_stats = fs.statSync(str_path);
return {
is_success: true,
nb_size: obj_stats.size,
str_modified: obj_stats.mtime.toISOString(),
str_created: obj_stats.birthtime.toISOString(),
};
} catch (obj_err) {
return { is_success: false, str_error: obj_err.message };
}
});
ipcMain.handle("copy-image-to-clipboard", (event, str_path) => {
try {
let obj_image = nativeImage.createFromPath(str_path);
if (obj_image.isEmpty()) {
return { is_success: false, str_error: "Image vide ou format non supporte" };
}
clipboard.writeImage(obj_image);
return { is_success: true };
} catch (obj_err) {
return { is_success: false, str_error: obj_err.message };
}
});
// ── Notification Config ───────────────────────────────────────
ipcMain.handle("get-notification-config", () => {
@@ -257,3 +399,20 @@ ipcMain.handle("set-notification-config", (event, obj_config) => {
obj_queue_manager.set_notification_config(obj_notification_config);
return { is_success: true };
});
// ── Email Config ──────────────────────────────────────────────
ipcMain.handle("get-email-config", () => {
return obj_email_config;
});
ipcMain.handle("set-email-config", (event, obj_config) => {
obj_email_config = obj_config;
_save_email_config();
EmailNotifier.set_config(obj_email_config);
return { is_success: true };
});
ipcMain.handle("test-email", (event, obj_config) => {
return EmailNotifier.test(obj_config);
});