const App = { str_blend_path: null, str_output_path: null, init: () => { ConsoleLog.init(); RenderSettings.init(); CameraList.init(App._on_camera_select); CollectionList.init(); CameraConfig.init(); RenderQueue.init(); PreviewPanel.init(); ProgressBar.init(); UpdateBanner.init(); BlenderPath.init(); FfmpegPath.init(); NotificationConfig.init(); App._bind_events(); App._bind_render_events(); ConsoleLog.add("Application prete."); }, _bind_events: () => { let obj_btn_blend = document.getElementById("btn_select_blend"); obj_btn_blend.addEventListener("click", () => { App._select_blend_file(); }); let obj_btn_output = document.getElementById("btn_select_output"); obj_btn_output.addEventListener("click", () => { App._select_output_folder(); }); let obj_btn_start = document.getElementById("btn_start"); obj_btn_start.addEventListener("click", () => { App._start_render(); }); let obj_btn_pause = document.getElementById("btn_pause"); obj_btn_pause.addEventListener("click", () => { App._pause_render(); }); let obj_btn_stop = document.getElementById("btn_stop"); obj_btn_stop.addEventListener("click", () => { App._stop_render(); }); let obj_btn_check = document.getElementById("btn_check_queue"); obj_btn_check.addEventListener("click", () => { App._check_queue(); }); let obj_btn_save = document.getElementById("btn_save_config"); obj_btn_save.addEventListener("click", () => { App._save_config(); }); let obj_btn_load = document.getElementById("btn_load_config"); obj_btn_load.addEventListener("click", () => { App._load_config(); }); let obj_radio_subfolder = document.getElementById("radio_output_subfolder"); let obj_radio_prefix = document.getElementById("radio_output_prefix"); let obj_radio_both = document.getElementById("radio_output_both"); let obj_input_frame_prefix = document.getElementById("input_frame_prefix"); let obj_input_frame_padding = document.getElementById("input_frame_padding"); obj_radio_subfolder.addEventListener("change", () => { App._update_output_example(); }); obj_radio_prefix.addEventListener("change", () => { App._update_output_example(); }); obj_radio_both.addEventListener("change", () => { App._update_output_example(); }); obj_input_frame_prefix.addEventListener("input", () => { App._update_output_example(); }); obj_input_frame_padding.addEventListener("input", () => { App._update_output_example(); }); let obj_btn_reset_cols = document.getElementById("btn_reset_collections"); obj_btn_reset_cols.addEventListener("click", () => { CollectionList.reset_to_original(); ConsoleLog.add("Collections restaurees aux valeurs originales."); }); }, _bind_render_events: () => { window.api.on_render_complete((obj_data) => { if (obj_data.is_all_done) { ConsoleLog.add("Tous les rendus sont termines !"); App._set_controls_state("idle"); } }); window.api.on_render_error((obj_data) => { ConsoleLog.add("ERREUR sur " + obj_data.str_camera + " frame " + obj_data.nb_frame + " : " + obj_data.str_error); }); }, _update_output_example: () => { let str_mode = document.querySelector('input[name="output_mode"]:checked').value; let str_prefix = document.getElementById("input_frame_prefix").value || ""; let nb_padding = parseInt(document.getElementById("input_frame_padding").value, 10) || 5; let str_padded = String(1).padStart(nb_padding, "0"); let obj_label = document.getElementById("label_output_example"); if (str_mode === "subfolder") { obj_label.innerHTML = 'Ex: /sortie/Camera.001/' + str_prefix + str_padded + '.png'; } else if (str_mode === "prefix") { obj_label.innerHTML = 'Ex: /sortie/Camera.001_' + str_prefix + str_padded + '.png'; } else { obj_label.innerHTML = 'Ex: /sortie/Camera.001/Camera.001_' + str_prefix + str_padded + '.png'; } }, // ── Actions ──────────────────────────────────────────── _select_blend_file: () => { let obj_btn_blend = document.getElementById("btn_select_blend"); window.api.select_blend_file() .then((str_path) => { if (!str_path) { return; } App.str_blend_path = str_path; document.getElementById("input_blend_path").value = str_path; ConsoleLog.add("Fichier charge : " + str_path); obj_btn_blend.disabled = true; CameraList.show_loading(); return window.api.get_cameras(str_path); }) .then((obj_result) => { obj_btn_blend.disabled = false; if (!obj_result) { return; } CameraList.set_cameras(obj_result.list_cameras, obj_result.obj_scene); CameraConfig.clear(); if (obj_result.obj_render_settings) { RenderSettings.set_from_blend(obj_result.obj_render_settings); } if (obj_result.list_collections) { CollectionList.set_collections(obj_result.list_collections); ConsoleLog.add(obj_result.list_collections.length + " collection(s) trouvee(s)."); } else { CollectionList.clear(); } ConsoleLog.add(obj_result.list_cameras.length + " camera(s) trouvee(s)."); App._update_start_button(); }) .catch((obj_err) => { obj_btn_blend.disabled = false; ConsoleLog.add("Erreur chargement : " + obj_err.message); }); }, _select_output_folder: () => { window.api.select_output_folder() .then((str_path) => { if (!str_path) { return; } App.str_output_path = str_path; document.getElementById("input_output_path").value = str_path; ConsoleLog.add("Dossier de sortie : " + str_path); App._update_start_button(); }) .catch((obj_err) => { ConsoleLog.add("Erreur selection dossier : " + obj_err.message); }); }, _on_camera_select: (obj_camera) => { CameraConfig.show(obj_camera); }, _start_render: () => { let obj_btn_start = document.getElementById("btn_start"); if (obj_btn_start.disabled) { return; } obj_btn_start.disabled = true; if (!App.str_output_path) { ConsoleLog.add("Veuillez selectionner un dossier de sortie."); App._set_controls_state("idle"); return; } let str_mode = document.querySelector('input[name="render_mode"]:checked').value; let str_output_mode = document.querySelector('input[name="output_mode"]:checked').value; let str_overwrite_mode = document.querySelector('input[name="overwrite_mode"]:checked').value; let list_cameras = CameraList.list_cameras; let str_frame_prefix = document.getElementById("input_frame_prefix").value || ""; let nb_frame_padding = parseInt(document.getElementById("input_frame_padding").value, 10) || 5; let obj_config = { str_blend_file: App.str_blend_path, str_render_mode: str_mode, str_output_mode: str_output_mode, str_overwrite_mode: str_overwrite_mode, str_frame_prefix: str_frame_prefix, nb_frame_padding: nb_frame_padding, str_output_path: App.str_output_path, list_cameras: list_cameras, list_collections: CollectionList.get_overrides(), obj_render_settings: RenderSettings.get_settings(), }; RenderQueue.build_display(str_mode, list_cameras); ProgressBar.reset(); window.api.start_render(obj_config) .then(() => { App._set_controls_state("running"); ConsoleLog.add("Rendu lance en mode : " + str_mode); }) .catch((obj_err) => { App._set_controls_state("idle"); ConsoleLog.add("Erreur lancement rendu : " + obj_err.message); }); }, _pause_render: () => { window.api.pause_render() .then(() => { App._set_controls_state("paused"); }) .catch((obj_err) => { ConsoleLog.add("Erreur pause : " + obj_err.message); }); }, _stop_render: () => { window.api.stop_render() .then(() => { App._set_controls_state("idle"); }) .catch((obj_err) => { ConsoleLog.add("Erreur arret : " + obj_err.message); }); }, _check_queue: () => { let obj_btn_check = document.getElementById("btn_check_queue"); if (obj_btn_check.disabled) { return; } if (!App.str_output_path) { ConsoleLog.add("Veuillez selectionner un dossier de sortie."); return; } let str_mode = document.querySelector('input[name="render_mode"]:checked').value; let str_output_mode = document.querySelector('input[name="output_mode"]:checked').value; let list_cameras = CameraList.list_cameras; let str_frame_prefix = document.getElementById("input_frame_prefix").value || ""; let nb_frame_padding = parseInt(document.getElementById("input_frame_padding").value, 10) || 5; let obj_config = { str_blend_file: App.str_blend_path, str_render_mode: str_mode, str_output_mode: str_output_mode, str_frame_prefix: str_frame_prefix, nb_frame_padding: nb_frame_padding, str_output_path: App.str_output_path, list_cameras: list_cameras, list_collections: CollectionList.get_overrides(), }; RenderQueue.build_display(str_mode, list_cameras); obj_btn_check.disabled = true; ConsoleLog.add("Verification des fichiers existants..."); window.api.check_queue(obj_config) .then((obj_result) => { obj_btn_check.disabled = false; RenderQueue.mark_existing(obj_result.list_existing); let nb_existing = obj_result.list_existing.length; let nb_to_render = obj_result.nb_total - nb_existing; ConsoleLog.add("Verification terminee : " + nb_existing + " fichier(s) existant(s), " + nb_to_render + " a rendre."); }) .catch((obj_err) => { obj_btn_check.disabled = false; ConsoleLog.add("Erreur verification : " + obj_err.message); }); }, _save_config: () => { let str_mode = document.querySelector('input[name="render_mode"]:checked').value; let str_output_mode = document.querySelector('input[name="output_mode"]:checked').value; let str_overwrite_mode = document.querySelector('input[name="overwrite_mode"]:checked').value; let str_frame_prefix = document.getElementById("input_frame_prefix").value || ""; let nb_frame_padding = parseInt(document.getElementById("input_frame_padding").value, 10) || 5; let obj_config = { str_blend_file: App.str_blend_path, str_render_mode: str_mode, str_output_mode: str_output_mode, str_overwrite_mode: str_overwrite_mode, str_frame_prefix: str_frame_prefix, nb_frame_padding: nb_frame_padding, str_output_path: App.str_output_path, list_cameras: CameraList.list_cameras, list_collections: CollectionList.list_collections, is_skip_collections: CollectionList.is_skip_collections, obj_render_settings: RenderSettings.get_settings(), }; window.api.save_config(obj_config) .then((obj_result) => { if (obj_result && obj_result.is_success) { ConsoleLog.add("Configuration exportee : " + obj_result.str_path); } }) .catch((obj_err) => { ConsoleLog.add("Erreur sauvegarde : " + obj_err.message); }); }, _load_config: () => { window.api.load_config() .then((obj_config) => { if (!obj_config) { return; } App.str_blend_path = obj_config.str_blend_file; App.str_output_path = obj_config.str_output_path || null; document.getElementById("input_blend_path").value = obj_config.str_blend_file || ""; document.getElementById("input_output_path").value = obj_config.str_output_path || ""; if (obj_config.str_render_mode === "frame_by_frame") { document.getElementById("radio_frame_by_frame").checked = true; } else { document.getElementById("radio_camera_by_camera").checked = true; } if (obj_config.str_output_mode === "prefix") { document.getElementById("radio_output_prefix").checked = true; } else if (obj_config.str_output_mode === "both") { document.getElementById("radio_output_both").checked = true; } else { document.getElementById("radio_output_subfolder").checked = true; } if (obj_config.str_overwrite_mode === "skip") { document.getElementById("radio_skip").checked = true; } else { document.getElementById("radio_overwrite").checked = true; } if (obj_config.str_frame_prefix !== undefined) { document.getElementById("input_frame_prefix").value = obj_config.str_frame_prefix; } if (obj_config.nb_frame_padding !== undefined) { document.getElementById("input_frame_padding").value = obj_config.nb_frame_padding; } App._update_output_example(); RenderSettings.set_from_config(obj_config); if (obj_config.list_cameras && obj_config.list_cameras.length > 0) { CameraList.list_cameras = obj_config.list_cameras; CameraList.str_selected_camera = null; CameraList.render(); let obj_badge = document.getElementById("badge_camera_count"); obj_badge.textContent = String(obj_config.list_cameras.length); } if (obj_config.is_skip_collections !== undefined) { CollectionList.is_skip_collections = obj_config.is_skip_collections; document.getElementById("check_skip_collections").checked = obj_config.is_skip_collections; } if (obj_config.list_collections && obj_config.list_collections.length > 0) { CollectionList.list_collections = obj_config.list_collections; CollectionList.render(); CollectionList._update_panel_state(); let obj_badge_col = document.getElementById("badge_collection_count"); obj_badge_col.textContent = String(obj_config.list_collections.length); } else { CollectionList.clear(); } CameraConfig.clear(); App._update_start_button(); ConsoleLog.add("Configuration importee."); }) .catch((obj_err) => { ConsoleLog.add("Erreur chargement config : " + obj_err.message); }); }, // ── UI State ─────────────────────────────────────────── _set_controls_state: (str_state) => { let obj_btn_start = document.getElementById("btn_start"); let obj_btn_pause = document.getElementById("btn_pause"); let obj_btn_stop = document.getElementById("btn_stop"); let obj_btn_check = document.getElementById("btn_check_queue"); if (str_state === "running") { obj_btn_start.disabled = true; obj_btn_pause.disabled = false; obj_btn_stop.disabled = false; obj_btn_check.disabled = true; } else if (str_state === "paused") { obj_btn_start.disabled = false; obj_btn_pause.disabled = true; obj_btn_stop.disabled = false; obj_btn_check.disabled = true; } else { App._update_start_button(); obj_btn_pause.disabled = true; obj_btn_stop.disabled = true; } }, _update_start_button: () => { let obj_btn_start = document.getElementById("btn_start"); let obj_btn_check = document.getElementById("btn_check_queue"); let is_ready = App.str_blend_path && App.str_output_path && CameraList.get_enabled_cameras().length > 0; obj_btn_start.disabled = !is_ready; obj_btn_check.disabled = !is_ready; }, }; document.addEventListener("DOMContentLoaded", () => { App.init(); });