You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kmftools/bookscraper/static/js/log_view.js

153 lines
4.6 KiB

/* =======================================================================
File: static/js/log_view.js
Purpose:
High-performance rolling log viewer
- efficient delta polling
- append-only mode (no DOM reset)
- rolling limit (prevents memory freeze)
- supports both global logs and per-book logs
======================================================================= */
console.log(">>> log_view.js LOADING…");
/* ---------------------------------------------------------
Global log viewer state
--------------------------------------------------------- */
let LOG_FILTER = "ALL";
let LAST_LOG_INDEX = -1; // delta offset
const MAX_LOG_LINES = 600; // safe rolling window
/* ---------------------------------------------------------
Apply filter on existing log lines
--------------------------------------------------------- */
function applyLogFilter() {
const lines = $$(".log-line");
lines.forEach((line) => {
const text = line.innerText;
const show = LOG_FILTER === "ALL" || (text && text.includes(LOG_FILTER));
line.style.display = show ? "block" : "none";
});
}
/* ---------------------------------------------------------
DOM Ready — bind clear/filter
--------------------------------------------------------- */
document.addEventListener("DOMContentLoaded", () => {
console.log(">>> log_view.js DOMContentLoaded");
const filterSel = $("#log-filter");
const clearBtn = $("#log-clear");
const output = $("#log-output");
if (!output) {
console.log(
">>> log_view.js: No #log-output on this page → viewer disabled"
);
return;
}
console.log(">>> log_view.js: log viewer detected.");
// Filter dropdown (currently disabled in your UI)
// if (filterSel) {
// filterSel.addEventListener("change", () => {
// LOG_FILTER = filterSel.value;
// applyLogFilter();
// });
// }
if (clearBtn) {
clearBtn.addEventListener("click", () => {
console.log(">>> log_view.js: Clear log viewer");
output.innerHTML = "";
LAST_LOG_INDEX = -1; // reset delta polling
});
}
});
/* ---------------------------------------------------------
Append ONE line (smart class assignment)
--------------------------------------------------------- */
function rollingAppend(lineText) {
const output = $("#log-output");
if (!output) return;
const div = document.createElement("div");
div.classList.add("log-line");
// Type detection
if (lineText.includes("[DL]") || lineText.includes("[DOWNLOAD]"))
div.classList.add("dl");
else if (lineText.includes("[PARSE]")) div.classList.add("parse");
else if (lineText.includes("[SAVE]")) div.classList.add("save");
else if (lineText.includes("[AUDIO]")) div.classList.add("audio");
else if (lineText.includes("[CTRL]")) div.classList.add("ctrl");
else if (lineText.includes("[ERROR]")) div.classList.add("error");
else div.classList.add("default");
div.textContent = lineText;
output.appendChild(div);
// Rolling limit
while (output.childNodes.length > MAX_LOG_LINES) {
output.removeChild(output.firstChild);
}
}
/* ---------------------------------------------------------
Primary API entry: updateLogs()
Used by dashboard.js AND delta polling
Accepts:
{ logs: [...], last_index: N }
OR legacy:
{ lines: [...], total: N }
--------------------------------------------------------- */
function updateLogs(packet) {
const output = $("#log-output");
if (!output) return;
if (!packet) return;
// Normalized log arrays
let lines = packet.logs || packet.lines || [];
if (!Array.isArray(lines)) return;
// Append only new lines
lines.forEach((line) => rollingAppend(line));
// Update delta index
if (packet.last_index !== undefined) {
LAST_LOG_INDEX = packet.last_index;
} else if (packet.total !== undefined) {
LAST_LOG_INDEX = packet.total - 1;
}
applyLogFilter();
autoScroll(output);
}
/* ---------------------------------------------------------
Delta polling: ONLY global logs use this
Dashboard overrides logs per book.
--------------------------------------------------------- */
function pollLogs() {
fetch(`/logs?last_index=${LAST_LOG_INDEX}`)
.then((r) => r.json())
.then((data) => {
const lines = data.lines || [];
if (lines.length > 0) {
lines.forEach((line) => logAppend(line));
LAST_LOG_INDEX = data.last; // <-- DE JUISTE INDEX!
}
})
.catch((err) => {
console.warn(">>> log_view.js pollLogs() error:", err);
});
}
setInterval(pollLogs, 2800);
console.log(">>> log_view.js LOADED");