[feat](trx-rds,trx-frontend-http): expand rds metadata display

Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
2026-02-28 15:27:26 +01:00
parent 8827131264
commit cf8d0743ce
5 changed files with 244 additions and 4 deletions
@@ -3227,6 +3227,21 @@ function formatOverlayPty(pty, ptyName) {
return pty != null ? String(pty) : "--";
}
function overlayTrafficFlagHtml(label, active) {
const stateClass = active === true ? "rds-flag-active" : "rds-flag-inactive";
return `<span class="rds-flag ${stateClass}">${label}</span>`;
}
function formatRdsFlag(value, yes = "Yes", no = "No") {
if (value == null) return "--";
return value ? yes : no;
}
function formatRdsAudio(value) {
if (value == null) return "--";
return value ? "Music" : "Speech";
}
async function copyRdsPsToClipboard() {
const rds = lastSpectrumData?.rds;
const ps = rds?.program_service;
@@ -3276,9 +3291,17 @@ function updateRdsPsOverlay(rds) {
const metaText = hasPs
? `${formatOverlayPi(rds?.pi)} · ${formatOverlayPty(rds?.pty, rds?.pty_name)}`
: (rds?.pty_name ?? (rds?.pty != null ? String(rds.pty) : ""));
const trafficFlags =
`<span class="rds-ps-flags">` +
`${overlayTrafficFlagHtml("TP", rds?.traffic_program)}` +
`${overlayTrafficFlagHtml("TA", rds?.traffic_announcement)}` +
`</span>`;
rdsPsOverlay.innerHTML =
`<span class="${mainClass}">${escapeMapHtml(mainText)}</span>` +
`<span class="rds-ps-meta">${escapeMapHtml(metaText)}</span>`;
`<span class="rds-ps-meta">` +
`<span class="rds-ps-meta-text">${escapeMapHtml(metaText)}</span>` +
`${trafficFlags}` +
`</span>`;
positionRdsPsOverlay();
rdsPsOverlay.style.display = "flex";
} else {
@@ -3294,6 +3317,15 @@ function updateRdsPsOverlay(rds) {
const psEl = document.getElementById("rds-ps");
const ptyEl = document.getElementById("rds-pty");
const ptyNameEl = document.getElementById("rds-pty-name");
const ptynEl = document.getElementById("rds-ptyn");
const tpEl = document.getElementById("rds-tp");
const taEl = document.getElementById("rds-ta");
const musicEl = document.getElementById("rds-music");
const stereoEl = document.getElementById("rds-stereo");
const compEl = document.getElementById("rds-compressed");
const headEl = document.getElementById("rds-artificial-head");
const dynPtyEl = document.getElementById("rds-dynamic-pty");
const rtEl = document.getElementById("rds-radio-text");
const rawEl = document.getElementById("rds-raw");
if (!statusEl) return;
@@ -3309,6 +3341,15 @@ function updateRdsPsOverlay(rds) {
psEl.textContent = "--";
ptyEl.textContent = "--";
ptyNameEl.textContent = "--";
if (ptynEl) ptynEl.textContent = "--";
if (tpEl) tpEl.textContent = "--";
if (taEl) taEl.textContent = "--";
if (musicEl) musicEl.textContent = "--";
if (stereoEl) stereoEl.textContent = "--";
if (compEl) compEl.textContent = "--";
if (headEl) headEl.textContent = "--";
if (dynPtyEl) dynPtyEl.textContent = "--";
if (rtEl) rtEl.textContent = "--";
if (rawEl && lastSpectrumData) {
const { bins: _b, ...rest } = lastSpectrumData;
rawEl.textContent = JSON.stringify(rest, null, 2);
@@ -3322,6 +3363,15 @@ function updateRdsPsOverlay(rds) {
psEl.textContent = rds.program_service ?? "--";
ptyEl.textContent = rds.pty_name ?? (rds.pty != null ? String(rds.pty) : "--");
ptyNameEl.textContent = rds.pty != null ? String(rds.pty) : "--";
if (ptynEl) ptynEl.textContent = rds.program_type_name_long ?? "--";
if (tpEl) tpEl.textContent = formatRdsFlag(rds.traffic_program);
if (taEl) taEl.textContent = formatRdsFlag(rds.traffic_announcement);
if (musicEl) musicEl.textContent = formatRdsAudio(rds.music);
if (stereoEl) stereoEl.textContent = formatRdsFlag(rds.stereo);
if (compEl) compEl.textContent = formatRdsFlag(rds.compressed);
if (headEl) headEl.textContent = formatRdsFlag(rds.artificial_head);
if (dynPtyEl) dynPtyEl.textContent = formatRdsFlag(rds.dynamic_pty);
if (rtEl) rtEl.textContent = rds.radio_text ?? "--";
rawEl.textContent = JSON.stringify(rds, null, 2);
}
@@ -279,6 +279,15 @@
<div class="rds-field"><span class="rds-label">PS</span><span id="rds-ps" class="rds-value rds-ps">--</span></div>
<div class="rds-field"><span class="rds-label">PTY</span><span id="rds-pty" class="rds-value">--</span></div>
<div class="rds-field"><span class="rds-label">PTY Code</span><span id="rds-pty-name" class="rds-value">--</span></div>
<div class="rds-field"><span class="rds-label">PTYN</span><span id="rds-ptyn" class="rds-value">--</span></div>
<div class="rds-field"><span class="rds-label">TP</span><span id="rds-tp" class="rds-value">--</span></div>
<div class="rds-field"><span class="rds-label">TA</span><span id="rds-ta" class="rds-value">--</span></div>
<div class="rds-field"><span class="rds-label">Audio</span><span id="rds-music" class="rds-value">--</span></div>
<div class="rds-field"><span class="rds-label">Stereo</span><span id="rds-stereo" class="rds-value">--</span></div>
<div class="rds-field"><span class="rds-label">Compressed</span><span id="rds-compressed" class="rds-value">--</span></div>
<div class="rds-field"><span class="rds-label">Artificial Head</span><span id="rds-artificial-head" class="rds-value">--</span></div>
<div class="rds-field"><span class="rds-label">Dynamic PTY</span><span id="rds-dynamic-pty" class="rds-value">--</span></div>
<div class="rds-field"><span class="rds-label">RadioText</span><span id="rds-radio-text" class="rds-value rds-text">--</span></div>
</div>
<div class="rds-raw-label">Raw JSON (last spectrum frame)</div>
<pre id="rds-raw" class="rds-raw">--</pre>
@@ -496,13 +496,46 @@ small { color: var(--text-muted); }
white-space: nowrap;
}
.rds-ps-meta {
display: block;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.4rem;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: clamp(0.58rem, 1.1vw, 0.78rem);
letter-spacing: 0.04em;
color: var(--text-muted);
white-space: nowrap;
}
.rds-ps-meta-text {
display: inline-block;
}
.rds-ps-flags {
display: inline-flex;
align-items: center;
gap: 0.25rem;
}
.rds-flag {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 1.9em;
padding: 0.05rem 0.35rem;
border-radius: 999px;
border: 1px solid color-mix(in srgb, var(--border-light) 72%, transparent);
font-size: 0.92em;
font-weight: 700;
letter-spacing: 0.03em;
}
.rds-flag-active {
color: #ffd7d7;
background: color-mix(in srgb, #b31217 68%, transparent);
border-color: color-mix(in srgb, #ff7b7b 46%, transparent);
box-shadow: 0 0 10px color-mix(in srgb, #b31217 28%, transparent);
}
.rds-flag-inactive {
color: var(--text-muted);
background: color-mix(in srgb, var(--card-bg) 62%, transparent);
}
.overview-toolbar {
display: flex;
align-items: center;
@@ -778,6 +811,7 @@ small { color: var(--text-muted); }
.rds-label { color: var(--text-muted); font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.06em; white-space: nowrap; }
.rds-value { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 0.95rem; color: var(--text); }
.rds-ps { font-size: 1.1rem; font-weight: 600; letter-spacing: 0.08em; color: var(--accent-green); }
.rds-text { white-space: normal; overflow-wrap: anywhere; line-height: 1.35; }
.rds-no-signal { color: var(--text-muted); }
.rds-decoding { color: var(--accent-green); }
.rds-raw-label { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); margin-bottom: 0.3rem; }