91 lines
3.2 KiB
JavaScript
91 lines
3.2 KiB
JavaScript
(() => {
|
|
const strip = document.querySelector("[data-story-intelligence-global-strip]");
|
|
if (!strip || !window.signalR) {
|
|
return;
|
|
}
|
|
|
|
const title = strip.querySelector("[data-story-intelligence-global-title]");
|
|
const detail = strip.querySelector("[data-story-intelligence-global-detail]");
|
|
const bar = strip.querySelector("[data-story-intelligence-global-bar]");
|
|
const readNumber = (value) => {
|
|
const parsed = Number.parseInt(value || "", 10);
|
|
return Number.isInteger(parsed) ? parsed : null;
|
|
};
|
|
|
|
const trackedBookId = readNumber(strip.dataset.bookId);
|
|
const trackedProjectId = readNumber(strip.dataset.projectId);
|
|
const formatCount = (value) => new Intl.NumberFormat().format(Math.max(0, value || 0));
|
|
const estimateRemaining = (elapsedMs, completed, total) => {
|
|
if (!total || !completed) {
|
|
return "Calculating";
|
|
}
|
|
|
|
if (completed >= total) {
|
|
return "Finalising";
|
|
}
|
|
|
|
const remainingMs = (elapsedMs / completed) * (total - completed);
|
|
const remainingSeconds = Math.max(1, Math.round(remainingMs / 1000));
|
|
if (remainingSeconds >= 60) {
|
|
return `${Math.max(1, Math.round(remainingSeconds / 60))} min`;
|
|
}
|
|
|
|
return `${remainingSeconds} sec`;
|
|
};
|
|
|
|
const update = (progress) => {
|
|
if (!progress) {
|
|
return;
|
|
}
|
|
|
|
const bookId = readNumber(progress.bookID ?? progress.bookId);
|
|
const projectId = readNumber(progress.projectID ?? progress.projectId);
|
|
if (trackedBookId && bookId && trackedBookId !== bookId) {
|
|
return;
|
|
}
|
|
|
|
if (!trackedBookId && trackedProjectId && projectId && trackedProjectId !== projectId) {
|
|
return;
|
|
}
|
|
|
|
const status = progress.status || progress.Status || "";
|
|
const total = readNumber(progress.totalDetectedScenes ?? progress.TotalDetectedScenes) || 0;
|
|
const completed = readNumber(progress.completedScenes ?? progress.CompletedScenes) || 0;
|
|
const failed = readNumber(progress.failedScenes ?? progress.FailedScenes) || 0;
|
|
const elapsedMs = readNumber(progress.totalDurationMs ?? progress.TotalDurationMs) || 0;
|
|
const percent = total > 0 ? Math.max(0, Math.min(100, Math.round((completed / total) * 100))) : 0;
|
|
|
|
if (bar) {
|
|
bar.style.width = `${percent}%`;
|
|
}
|
|
|
|
if (detail) {
|
|
const remaining = estimateRemaining(elapsedMs, completed, total);
|
|
detail.textContent = `${formatCount(completed)} of ${formatCount(total)} scenes analysed \u00b7 ${remaining} remaining`;
|
|
}
|
|
|
|
if (title && status) {
|
|
if (status === "Failed") {
|
|
title.textContent = "Story Intelligence needs attention";
|
|
} else if (status === "Cancelled") {
|
|
title.textContent = "Story Intelligence cancelled";
|
|
} else if (status === "Completed" || status === "CompletedWithWarnings") {
|
|
title.textContent = failed > 0 ? "Story Intelligence completed with notes" : "Story Intelligence complete";
|
|
window.setTimeout(() => {
|
|
strip.hidden = true;
|
|
}, 10000);
|
|
}
|
|
}
|
|
};
|
|
|
|
const connection = new signalR.HubConnectionBuilder()
|
|
.withUrl("/hubs/story-intelligence")
|
|
.withAutomaticReconnect()
|
|
.build();
|
|
|
|
connection.on("StoryIntelligenceRunProgressChanged", update);
|
|
connection.start().catch(() => {
|
|
strip.dataset.connection = "offline";
|
|
});
|
|
})();
|