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;
},
};