From d672c3f02ddaeadbb5f2a85f2ba345c3f6014176 Mon Sep 17 00:00:00 2001 From: Barely Removable Date: Sun, 30 Aug 2026 08:54:41 -0700 Subject: [PATCH] Show SABnzbd's queue in the header on every page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a live download figure next to the header clock, present on every page (not just Activity/System). It's populated by the same /api/sabnzbd poll those pages already use, extended to run unconditionally and to fill in a new #head-dl span — never a server-rendered fetch, so an unreachable SABnzbd can't add latency to pages that don't otherwise touch it. Quiet ink at "0 IN QUEUE" when idle, live cyan with a speed reading once something's moving. --- static/css/teletext.css | 12 +++++++++++- static/js/service.js | 19 +++++++++++++------ templates/_shell.html | 5 +++++ 3 files changed, 29 insertions(+), 7 deletions(-) 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. -#} +