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/templates/result.html

240 lines
6.2 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html>
<html lang="nl">
<head>
<meta charset="UTF-8" />
<title>BookScraper Resultaat</title>
<style>
body {
font-family: Arial, sans-serif;
padding: 30px;
max-width: 900px;
margin: auto;
}
h1 {
margin-bottom: 10px;
}
.box {
padding: 15px;
border: 1px solid #ddd;
background: #f8f8f8;
border-radius: 6px;
margin-bottom: 20px;
}
.logbox {
background: #000;
color: #0f0;
padding: 12px;
height: 70vh;
overflow-y: auto;
font-family: monospace;
border-radius: 6px;
font-size: 13px;
}
/* NEW: Clear button */
#clearLogBtn {
margin-bottom: 10px;
padding: 8px 16px;
background: #777;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
}
#clearLogBtn:hover {
background: #555;
}
#abortBtn {
padding: 12px 20px;
background: #d9534f;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
margin-top: 10px;
}
#abortBtn:hover {
background: #c9302c;
}
#statusLine {
font-size: 18px;
font-weight: bold;
}
.hidden {
display: none;
}
</style>
</head>
<body>
<a href="/">&larr; Terug</a>
<h1>Scrape Resultaat--</h1>
{% if error %}
<div
class="box"
style="background: #ffdddd; border-left: 5px solid #ff4444"
>
<strong>Fout:</strong> {{ error }}
</div>
{% endif %} {% if message %}
<div class="box">{{ message }}</div>
{% endif %}
<!-- COVER -->
{% if book_title %}
<div class="box">
<strong>Cover:</strong><br />
<img
src="/output/{{ book_title }}/cover.jpg"
alt="Cover"
style="
margin-top: 10px;
max-width: 250px;
border: 1px solid #ccc;
border-radius: 4px;
"
onerror="this.style.display='none'"
/>
</div>
{% endif %}
<div id="statusBox" class="box hidden">
<div id="statusLine">Status: bezig…</div>
<div id="progressText"></div>
<button id="abortBtn" class="hidden">ABORT</button>
</div>
<!-- FAILED LIST -->
<div
id="failedBox"
class="box hidden"
style="background: #ffefef; border-left: 5px solid #cc0000"
>
<strong>Failed chapters:</strong>
<ul id="failedList" style="margin-top: 10px"></ul>
</div>
<div class="box">
<strong>Live log:</strong><br />
<!-- NEW BUTTON -->
<button id="clearLogBtn" onclick="clearLogs()">Clear logs</button>
<div id="logbox" class="logbox"></div>
</div>
<script>
const scrapingTaskId = "{{ scraping_task_id or '' }}";
let bookId = null;
let polling = true;
if (scrapingTaskId) pollForBookId();
function pollForBookId() {
fetch(`/celery-result/${scrapingTaskId}`)
.then((r) => r.json())
.then((data) => {
if (data.ready && data.result && data.result.book_id) {
bookId = data.result.book_id;
startLiveUI();
} else setTimeout(pollForBookId, 800);
})
.catch(() => setTimeout(pollForBookId, 1200));
}
function startLiveUI() {
document.getElementById("statusBox").classList.remove("hidden");
document.getElementById("abortBtn").classList.remove("hidden");
document.getElementById("abortBtn").onclick = () => {
fetch(`/abort/${bookId}`, { method: "POST" });
};
pollProgress();
pollLogs();
}
function pollProgress() {
if (!bookId) return;
fetch(`/progress/${bookId}`)
.then((r) => r.json())
.then((p) => {
const done = p.completed || 0;
const total = p.total || 0;
document.getElementById(
"progressText"
).innerText = `Completed: ${done} / ${total} | Skipped: ${
p.skipped || 0
} | Failed: ${p.failed || 0}`;
const failedBox = document.getElementById("failedBox");
const failedList = document.getElementById("failedList");
if (p.failed_list && p.failed_list.length > 0) {
failedBox.classList.remove("hidden");
failedList.innerHTML = "";
p.failed_list.forEach((entry) => {
const li = document.createElement("li");
li.textContent = entry;
failedList.appendChild(li);
});
}
if (p.abort) {
document.getElementById("statusLine").innerText = "ABORTED";
polling = false;
} else if (done >= total && total > 0) {
document.getElementById("statusLine").innerText = "KLAAR ✔";
polling = false;
} else {
document.getElementById("statusLine").innerText = "Bezig…";
}
if (polling) setTimeout(pollProgress, 1000);
})
.catch(() => {
if (polling) setTimeout(pollProgress, 1500);
});
}
function pollLogs() {
if (!polling) return;
fetch(`/logs`)
.then((r) => r.json())
.then((data) => {
const logbox = document.getElementById("logbox");
logbox.innerHTML = "";
data.logs.forEach((line) => {
const div = document.createElement("div");
div.textContent = line;
logbox.appendChild(div);
});
logbox.scrollTop = logbox.scrollHeight;
setTimeout(pollLogs, 1000);
})
.catch(() => setTimeout(pollLogs, 1500));
}
// =========================================================
// NEW: Clear logs button handler
// =========================================================
function clearLogs() {
fetch("/clear-logs", { method: "POST" })
.then(() => {
document.getElementById("logbox").innerHTML = "";
})
.catch((e) => console.error("Clear logs failed:", e));
}
</script>
</body>
</html>