diff --git a/static/css/teletext.css b/static/css/teletext.css
index 69eb404..a424731 100644
--- a/static/css/teletext.css
+++ b/static/css/teletext.css
@@ -33,7 +33,6 @@
text-transform: uppercase;
}
.tt-head-clock {
- margin-left: auto;
color: var(--live);
white-space: nowrap;
min-width: 0;
@@ -45,6 +44,16 @@
letter-spacing: 0.3em;
}
.tt-entry[hidden] { display: none; }
+/* SABnzbd's queue, live on every page — filled in by service.js, empty
+ (and so invisible) until its first poll returns. Quiet ink when
+ idle; the live colour only while something is actually moving. */
+.tt-head-dl {
+ margin-left: auto;
+ color: var(--ink-dim);
+ white-space: nowrap;
+ min-width: 0;
+}
+.tt-head-dl.live { color: var(--live); }
/* ── Page ───────────────────────────────────────────────
One measure for every page in the service. Nothing is ever
@@ -602,6 +611,7 @@ a.tt-row:focus-visible .tt-row-sub { color: var(--tt-black); }
.tt-row-title { white-space: normal; }
.tt-row-val { margin-left: auto; white-space: normal; }
.tt-head-name { letter-spacing: 0.12em; }
+ .tt-head-dl { margin-left: 0; flex-basis: 100%; }
.tt-head-clock { margin-left: 0; flex-basis: 100%; }
/* The System disk table swaps for its row reflow here — see the
diff --git a/static/js/service.js b/static/js/service.js
index f7e71fc..475dfcd 100644
--- a/static/js/service.js
+++ b/static/js/service.js
@@ -160,14 +160,15 @@
The queue and the active streams are the only two numbers
that must be accurate to the second, so they are the only
two that poll. Everything else is cached server-side and
- arrives with the page. */
+ arrives with the page. The queue also drives the header's
+ download row, present on every page, so it polls
+ unconditionally rather than only where #sab-queue exists. */
function setText(id, value) {
var el = document.getElementById(id);
if (el) el.textContent = value;
}
function pollSab() {
- if (!document.getElementById('sab-queue')) return;
fetch(BASE + '/api/sabnzbd')
.then(function (r) { return r.json(); })
.then(function (d) {
@@ -175,6 +176,14 @@
setText('sab-queue', d.queue_count);
setText('sab-speed', d.speed || '0');
setText('sab-remaining', d.sizeleft || '—');
+ var dl = document.getElementById('head-dl');
+ if (dl) {
+ var active = d.queue_count > 0;
+ dl.textContent = active
+ ? d.queue_count + ' IN QUEUE · ' + (d.speed || '0')
+ : '0 IN QUEUE';
+ dl.classList.toggle('live', active);
+ }
})
.catch(function () { /* offline is the dev baseline, not an error */ });
}
@@ -190,10 +199,8 @@
.catch(function () { /* as above */ });
}
- if (document.getElementById('sab-queue')) {
- pollSab();
- setInterval(pollSab, 5000);
- }
+ pollSab();
+ setInterval(pollSab, 5000);
if (document.getElementById('tt-streams')) {
pollTautulli();
setInterval(pollTautulli, 15000);
diff --git a/templates/_shell.html b/templates/_shell.html
index 2509aa4..ba4430f 100644
--- a/templates/_shell.html
+++ b/templates/_shell.html
@@ -42,6 +42,11 @@ provenance.
P{{ here[1] }}
{{ here[2] }}
+ {#- SABnzbd's queue, on every page — the same live /api/sabnzbd poll
+ Activity and System already use, not a server-rendered fetch, so
+ an unreachable SABnzbd never adds latency to a page that doesn't
+ otherwise need it. Starts blank and fills in within a second. -#}
+