feat: better first time downloading, feat: more logging
Build and Publish Container / Publish Linux container (push) Successful in 4m59s

This commit is contained in:
2026-10-05 14:23:25 -04:00
parent fa6eb856dc
commit 86b8ab9c75
14 changed files with 504 additions and 70 deletions
+24 -4
View File
@@ -108,9 +108,19 @@ function renderServiceState(data) {
const ready = Number(data.totals?.ready_mods || 0);
element.className = "service-state";
if (data.scheduler?.running) {
const progress = data.scheduler?.progress || {};
const progressPercent = Number(progress.percent || 0);
if (data.scheduler?.initial_download) {
element.classList.add("working");
label.textContent = "Updating now";
label.textContent = progress.total_mods
? `Downloading first-time mods · ${Math.round(progressPercent)}%`
: "Downloading first-time mods";
} else if (data.scheduler?.running) {
element.classList.add("working");
label.textContent = progress.total_mods
? `Updating now · ${Math.round(progressPercent)}%`
: "Updating now";
} else if (data.latest_run?.status === "failed") {
element.classList.add("failed");
label.textContent = "Update needs attention";
@@ -166,12 +176,22 @@ function renderDashboard(data) {
}
const updatedAt = data.rml_updated_at;
$("#last-updated").textContent = data.scheduler?.running ? "Updating now" : formatRelativeDate(updatedAt);
const progress = data.scheduler?.progress || {};
const initialDownload = Boolean(data.scheduler?.initial_download);
$("#last-updated").textContent = initialDownload
? `Downloading ${Math.round(Number(progress.percent || 0))}%`
: (data.scheduler?.running ? "Updating now" : formatRelativeDate(updatedAt));
$("#last-updated").title = formatDate(updatedAt);
state.rmlReady = total > 0 && ready === total && !data.scheduler?.running;
const nextRefresh = data.scheduler?.next_refresh_at;
if (data.scheduler?.running) {
if (initialDownload) {
const completed = Number(progress.completed_mods || 0).toLocaleString();
const target = Number(progress.total_mods || 0).toLocaleString();
$("#update-detail").textContent = progress.total_mods
? `First-time download: ${completed} of ${target} mods. Hourly checks begin after it finishes.`
: "Preparing the first-time Workshop download. Hourly checks are paused.";
} else if (data.scheduler?.running) {
$("#update-detail").textContent = "The hourly Workshop refresh is currently running.";
} else if (!state.rmlReady) {
$("#update-detail").textContent = "The current RML is being prepared from the latest Workshop data.";
+5 -6
View File
@@ -90,14 +90,13 @@
</main>
<footer>
<div class="footer-meta">
<span id="footer-status">Workshop data refreshed every hour</span>
<span id="footer-status">Workshop data refreshed every hour</span>
<div class="footer-credits">
<span class="art-credit">Art by Ferny</span>
<a class="hr-link" href="https://hudsonriggs.systems" target="_blank" rel="noopener noreferrer" aria-label="Visit Hudson Riggs Systems">
<img src="/art/hudsonriggssystems.png" alt="Hudson Riggs Systems">
</a>
</div>
<a class="hr-link" href="https://hudsonriggs.systems" target="_blank" rel="noopener noreferrer" aria-label="Visit Hudson Riggs Systems">
<span>Hudson Riggs Systems</span>
<img src="/art/hudsonriggssystems.png" alt="">
</a>
</footer>
</div>
+32 -15
View File
@@ -48,18 +48,28 @@
html { min-width: 320px; background: var(--bg); }
body {
position: relative;
min-width: 320px;
min-height: 100vh;
margin: 0;
background:
radial-gradient(circle at 85% 8%, rgba(84, 114, 79, .12), transparent 27rem),
linear-gradient(180deg, #171717 0, #101214 100%);
background: #0b0b0c url("/art/Desolation.png") center / cover fixed no-repeat;
color: var(--text);
font-family: var(--font-ui);
font-size: 16px;
line-height: 1.5;
}
body::before {
content: "";
position: fixed;
z-index: 0;
inset: 0;
pointer-events: none;
background:
radial-gradient(circle at center, rgba(21, 21, 21, .08), rgba(21, 21, 21, .76) 72%),
linear-gradient(rgba(21, 21, 21, .36), rgba(21, 21, 21, .66));
}
button, input { font: inherit; }
button { color: inherit; }
img { display: block; max-width: 100%; }
@@ -117,6 +127,8 @@ h1, h2, p { margin: 0; }
.is-ready .intro { opacity: 0; visibility: hidden; }
.page-shell {
position: relative;
z-index: 1;
width: min(1220px, calc(100% - 48px));
margin: 0 auto;
padding-bottom: 26px;
@@ -146,9 +158,13 @@ h1, h2, p { margin: 0; }
font-size: .78rem;
font-weight: 800;
letter-spacing: .08em;
line-height: 1.3;
text-align: right;
text-transform: uppercase;
}
.service-state span:last-child { max-width: 300px; }
.state-dot {
width: 8px;
height: 8px;
@@ -352,20 +368,22 @@ footer {
font-size: .76rem;
}
.footer-meta { display: flex; align-items: center; gap: 10px; }
.footer-credits { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.art-credit { padding: 4px 8px; border: 1px solid #484848; border-radius: 999px; color: #999; font-family: var(--font-serif); font-style: italic; }
.hr-link {
display: inline-flex;
width: 42px;
height: 42px;
display: block;
align-items: center;
gap: 10px;
color: #f16365;
flex: 0 0 auto;
text-decoration: none;
transition: color .16s ease, transform .16s ease;
transition: transform .16s ease, filter .16s ease;
}
.hr-link:hover { color: #ff7b7d; transform: translateY(-1px); }
.hr-link img { width: 42px; height: 42px; object-fit: contain; }
.hr-link:hover { transform: translateY(-1px); filter: brightness(1.12); }
.hr-link:focus-visible { outline: 3px solid rgba(241, 99, 101, .28); outline-offset: 3px; border-radius: 5px; }
.hr-link img { width: 100%; height: 100%; object-fit: contain; }
.wizard {
width: min(820px, calc(100% - 30px));
@@ -578,9 +596,9 @@ footer {
@media (max-width: 700px) {
.page-shell { width: min(calc(100% - 24px), 1220px); }
.site-header { min-height: 78px; }
.brand { width: min(67vw, 330px); }
.service-state { font-size: 0; }
.site-header { min-height: 78px; gap: 12px; }
.brand { width: min(59vw, 330px); }
.service-state { max-width: 36vw; font-size: .62rem; }
.hero { grid-template-columns: 1fr; }
.hero-copy { padding: 30px 24px; }
.hero-art { min-height: 180px; border-top: 1px solid rgba(255,255,255,.09); border-left: 0; }
@@ -588,7 +606,6 @@ footer {
.freshness { grid-template-columns: 1fr; }
.freshness small { grid-column: auto; }
footer { align-items: flex-start; gap: 10px; }
.hr-link span { display: none; }
.wizard { width: min(100% - 18px, 820px); max-height: 94vh; }
.wizard-header { min-height: 66px; padding-left: 18px; }
.wizard-progress { padding: 16px 16px 14px; }
@@ -611,7 +628,7 @@ footer {
.count-grid { grid-template-columns: 1fr; }
.count-card { min-height: 100px; }
.start-button { min-height: 78px; padding-left: 16px; }
.footer-meta { align-items: flex-start; flex-direction: column; gap: 5px; }
.footer-credits { gap: 6px; }
.wizard-actions { display: grid; grid-template-columns: 1fr 1.5fr; }
.button, .button-download { min-width: 0; }
}