const RenderQueue = { list_items: [], nb_total_render_ms: 0, nb_completed_renders: 0, nb_last_current: 0, list_machine_avgs: [], nb_local_avg_ms: 0, str_hostname: "", init: () => { // Initialized on demand }, build_display: (str_mode, list_cameras) => { RenderQueue.list_items = []; RenderQueue.nb_total_render_ms = 0; RenderQueue.nb_completed_renders = 0; RenderQueue.nb_last_current = 0; RenderQueue.list_machine_avgs = []; RenderQueue.nb_local_avg_ms = 0; RenderQueue.str_hostname = ""; let list_enabled = []; for (let obj_cam of list_cameras) { if (obj_cam.is_enabled) { list_enabled.push(obj_cam); } } if (str_mode === "camera_by_camera") { for (let obj_cam of list_enabled) { let nb_step = obj_cam.nb_frame_step || 1; for (let nb_frame = obj_cam.nb_frame_start; nb_frame <= obj_cam.nb_frame_end; nb_frame += nb_step) { RenderQueue.list_items.push({ str_camera: obj_cam.str_name, nb_frame: nb_frame, str_status: "pending", str_image_path: null, obj_dom_el: null, obj_dom_icon: null, obj_dom_result: null, str_dom_status: null, is_click_bound: false, }); } } } else { let nb_min = Infinity; let nb_max = -Infinity; for (let obj_cam of list_enabled) { if (obj_cam.nb_frame_start < nb_min) { nb_min = obj_cam.nb_frame_start; } if (obj_cam.nb_frame_end > nb_max) { nb_max = obj_cam.nb_frame_end; } } for (let nb_frame = nb_min; nb_frame <= nb_max; nb_frame++) { for (let obj_cam of list_enabled) { let nb_cam_step = obj_cam.nb_frame_step || 1; if (nb_frame >= obj_cam.nb_frame_start && nb_frame <= obj_cam.nb_frame_end && (nb_frame - obj_cam.nb_frame_start) % nb_cam_step === 0) { RenderQueue.list_items.push({ str_camera: obj_cam.str_name, nb_frame: nb_frame, str_status: "pending", str_image_path: null, obj_dom_el: null, obj_dom_icon: null, obj_dom_result: null, str_dom_status: null, is_click_bound: false, }); } } } } let obj_badge = document.getElementById("badge_queue_count"); obj_badge.textContent = String(RenderQueue.list_items.length); RenderQueue._update_time_display(); RenderQueue._create_dom(); }, _create_dom: () => { let obj_container = document.getElementById("container_render_queue"); obj_container.innerHTML = ""; if (RenderQueue.list_items.length === 0) { obj_container.innerHTML = '
File vide
'; return; } let obj_fragment = document.createDocumentFragment(); for (let obj_item of RenderQueue.list_items) { let obj_el = document.createElement("div"); obj_el.classList.add("list-group-item", "bg-dark", "text-light", "border-secondary", "py-1", "px-3", "d-flex", "align-items-center", "gap-2"); let obj_icon = document.createElement("i"); obj_icon.classList.add("mdi", "mdi-clock-outline", "text-muted"); let obj_name = document.createElement("small"); obj_name.classList.add("flex-grow-1"); obj_name.textContent = obj_item.str_camera; let obj_frame = document.createElement("small"); obj_frame.classList.add("text-light-emphasis"); obj_frame.textContent = "F" + obj_item.nb_frame; let obj_result = document.createElement("small"); obj_result.classList.add("text-light-emphasis", "queue-item-result"); obj_result.style.minWidth = "140px"; obj_result.style.textAlign = "right"; obj_result.style.fontSize = "0.75em"; obj_el.appendChild(obj_icon); obj_el.appendChild(obj_name); obj_el.appendChild(obj_frame); obj_el.appendChild(obj_result); obj_item.obj_dom_el = obj_el; obj_item.obj_dom_icon = obj_icon; obj_item.obj_dom_result = obj_result; obj_item.str_dom_status = "pending"; obj_fragment.appendChild(obj_el); } obj_container.appendChild(obj_fragment); }, update_progress: (obj_data) => { let nb_current = obj_data.nb_current || 0; let nb_last_render_ms = obj_data.nb_last_render_ms || 0; let str_last_image_path = obj_data.str_last_image_path || null; let list_skipped = obj_data.list_skipped || []; let list_stopped = obj_data.list_stopped || []; let list_skipped_paths = obj_data.list_skipped_paths || []; let list_rendering_remote = obj_data.list_rendering_remote || []; let list_item_results = obj_data.list_item_results || []; let list_machine_avgs = obj_data.list_machine_avgs || []; RenderQueue.str_hostname = obj_data.str_hostname || ""; RenderQueue.nb_local_avg_ms = obj_data.nb_avg_render_ms || 0; RenderQueue.list_machine_avgs = list_machine_avgs; if (nb_current > RenderQueue.nb_last_current && nb_last_render_ms > 0) { RenderQueue.nb_total_render_ms += nb_last_render_ms; RenderQueue.nb_completed_renders++; } RenderQueue.nb_last_current = nb_current; if (str_last_image_path && nb_current > 0 && nb_current - 1 < RenderQueue.list_items.length) { RenderQueue.list_items[nb_current - 1].str_image_path = str_last_image_path; } if (list_skipped_paths) { for (let obj_sp of list_skipped_paths) { if (obj_sp.nb_index < RenderQueue.list_items.length) { RenderQueue.list_items[obj_sp.nb_index].str_image_path = obj_sp.str_path; } } } // Build result map for quick lookup let map_results = {}; for (let obj_r of list_item_results) { map_results[obj_r.nb_index] = obj_r; } for (let nb_i = 0; nb_i < RenderQueue.list_items.length; nb_i++) { if (list_stopped && list_stopped.indexOf(nb_i) !== -1) { RenderQueue.list_items[nb_i].str_status = "stopped"; } else if (list_rendering_remote && list_rendering_remote.indexOf(nb_i) !== -1) { RenderQueue.list_items[nb_i].str_status = "rendering_remote"; } else if (list_skipped && list_skipped.indexOf(nb_i) !== -1) { RenderQueue.list_items[nb_i].str_status = "skipped"; } else if (nb_i < nb_current) { RenderQueue.list_items[nb_i].str_status = "done"; } else if (nb_i === nb_current) { RenderQueue.list_items[nb_i].str_status = "rendering"; } else { RenderQueue.list_items[nb_i].str_status = "pending"; } // Store result info on item if (map_results[nb_i]) { RenderQueue.list_items[nb_i].obj_result = map_results[nb_i]; } } RenderQueue._update_time_display(); RenderQueue._update_statuses(); }, _update_statuses: () => { let obj_rendering_el = null; for (let obj_item of RenderQueue.list_items) { if (!obj_item.obj_dom_el) { continue; } let is_needs_click = (obj_item.str_status === "done" || obj_item.str_status === "skipped") && obj_item.str_image_path && !obj_item.is_click_bound; let is_status_changed = obj_item.str_status !== obj_item.str_dom_status; if (!is_status_changed && !is_needs_click) { if (obj_item.str_status === "rendering") { obj_rendering_el = obj_item.obj_dom_el; } continue; } let str_icon = "mdi-clock-outline"; let str_color = "text-muted"; if (obj_item.str_status === "rendering") { str_icon = "mdi-loading mdi-spin"; str_color = "text-primary"; obj_rendering_el = obj_item.obj_dom_el; } else if (obj_item.str_status === "done") { str_icon = "mdi-check-circle"; str_color = "text-success"; } else if (obj_item.str_status === "error") { str_icon = "mdi-alert-circle"; str_color = "text-danger"; } else if (obj_item.str_status === "skipped") { str_icon = "mdi-skip-next-circle"; str_color = "text-info"; } else if (obj_item.str_status === "stopped") { str_icon = "mdi-stop-circle"; str_color = "text-warning"; } else if (obj_item.str_status === "rendering_remote") { str_icon = "mdi-desktop-classic"; str_color = "text-warning"; } obj_item.obj_dom_icon.className = "mdi " + str_icon + " " + str_color; // Update result column if (obj_item.obj_dom_result) { RenderQueue._update_result_cell(obj_item); } if (is_needs_click) { obj_item.obj_dom_el.classList.add("queue-item-clickable"); let str_path = obj_item.str_image_path; obj_item.obj_dom_el.addEventListener("click", () => { PreviewPanel.show_image(str_path); }); obj_item.is_click_bound = true; } obj_item.str_dom_status = obj_item.str_status; } if (obj_rendering_el) { obj_rendering_el.scrollIntoView({ behavior: "smooth", block: "center" }); } }, _update_result_cell: (obj_item) => { let obj_r = obj_item.obj_result; if (!obj_r) { obj_item.obj_dom_result.textContent = ""; return; } if (obj_r.str_type === "done") { let str_date = ""; if (obj_r.str_date) { let obj_d = new Date(obj_r.str_date); let str_day = String(obj_d.getDate()).padStart(2, "0"); let str_month = String(obj_d.getMonth() + 1).padStart(2, "0"); let str_hours = String(obj_d.getHours()).padStart(2, "0"); let str_minutes = String(obj_d.getMinutes()).padStart(2, "0"); str_date = str_day + "/" + str_month + " " + str_hours + ":" + str_minutes; } let str_res = obj_r.str_resolution || ""; obj_item.obj_dom_result.textContent = str_date + (str_date && str_res ? " | " : "") + str_res; obj_item.obj_dom_result.className = "text-success queue-item-result"; obj_item.obj_dom_result.style.minWidth = "140px"; obj_item.obj_dom_result.style.textAlign = "right"; obj_item.obj_dom_result.style.fontSize = "0.75em"; } else if (obj_r.str_type === "rendering_remote") { let str_host = obj_r.str_remote_hostname || "?"; let str_avg = ""; if (obj_r.nb_remote_avg_ms > 0) { str_avg = " ~" + RenderQueue._format_duration(obj_r.nb_remote_avg_ms) + "/i"; } obj_item.obj_dom_result.textContent = str_host + str_avg; obj_item.obj_dom_result.className = "text-warning queue-item-result"; obj_item.obj_dom_result.style.minWidth = "140px"; obj_item.obj_dom_result.style.textAlign = "right"; obj_item.obj_dom_result.style.fontSize = "0.75em"; } else { obj_item.obj_dom_result.textContent = ""; } }, mark_existing: (list_existing) => { for (let obj_existing of list_existing) { if (obj_existing.nb_index < RenderQueue.list_items.length) { RenderQueue.list_items[obj_existing.nb_index].str_status = "skipped"; RenderQueue.list_items[obj_existing.nb_index].str_image_path = obj_existing.str_path; } } RenderQueue._update_statuses(); }, _update_time_display: () => { let obj_label = document.getElementById("label_queue_time_estimate"); if (!obj_label) { return; } let nb_local_avg = RenderQueue.nb_local_avg_ms; if (nb_local_avg === 0 && RenderQueue.nb_completed_renders > 0) { nb_local_avg = Math.round(RenderQueue.nb_total_render_ms / RenderQueue.nb_completed_renders); } if (nb_local_avg === 0) { obj_label.innerHTML = ""; return; } let nb_remaining_count = 0; for (let obj_item of RenderQueue.list_items) { if (obj_item.str_status !== "done" && obj_item.str_status !== "skipped" && obj_item.str_status !== "rendering_remote") { nb_remaining_count++; } } // Part 1 : temps moyen machine actuelle /i let str_local_avg = RenderQueue._format_duration(nb_local_avg) + "/i"; // Part 2 : temps restant si machine seule let nb_remaining_solo_ms = nb_local_avg * nb_remaining_count; let str_remaining_solo = RenderQueue._format_duration(nb_remaining_solo_ms); // Part 3 : temps restant multi-machines let list_avgs = RenderQueue.list_machine_avgs; let nb_machines_with_data = 0; let nb_sum_avgs = 0; for (let obj_m of list_avgs) { if (obj_m.nb_avg_ms > 0) { nb_sum_avgs += obj_m.nb_avg_ms; nb_machines_with_data++; } } let str_remaining_multi = ""; if (nb_machines_with_data > 1) { let nb_avg_of_avgs = nb_sum_avgs / nb_machines_with_data; let nb_remaining_multi_ms = (nb_avg_of_avgs * nb_remaining_count) / nb_machines_with_data; str_remaining_multi = RenderQueue._format_duration(nb_remaining_multi_ms); } let str_display = '' + str_local_avg + " | " + str_remaining_solo; if (str_remaining_multi) { str_display += " | " + str_remaining_multi; } obj_label.innerHTML = str_display; }, _format_duration: (nb_ms) => { let nb_total_seconds = Math.ceil(nb_ms / 1000); let nb_days = Math.floor(nb_total_seconds / 86400); nb_total_seconds %= 86400; let nb_hours = Math.floor(nb_total_seconds / 3600); nb_total_seconds %= 3600; let nb_minutes = Math.floor(nb_total_seconds / 60); let nb_seconds = nb_total_seconds % 60; let str_result = ""; if (nb_days > 0) { str_result += nb_days + "j "; } if (nb_hours > 0 || nb_days > 0) { str_result += nb_hours + "h "; } if (nb_minutes > 0 || nb_hours > 0 || nb_days > 0) { str_result += nb_minutes + "m "; } str_result += nb_seconds + "s"; return str_result; }, };