From f9bc96bd9050c050d6e4e1125d4f4a5ebb65b88b Mon Sep 17 00:00:00 2001 From: BoulderBadgeDad Date: Sat, 30 May 2026 15:07:31 -0700 Subject: [PATCH] Player: 'Playing from' context header (Radio / Radio) Spotify-style context line above the track title. npSetPlayContext(text) shows/ hides it; set to 'Radio' when radio mode turns on, ' Radio' from playArtistRadio (specific label wins over generic), cleared on stop/clearTrack and when radio mode is turned off. Accent-colored name, uppercase label. Frontend-only; JS + CSS clean. --- webui/index.html | 4 ++++ webui/static/media-player.js | 23 +++++++++++++++++++++++ webui/static/stats-automations.js | 3 +++ webui/static/style.css | 12 ++++++++++++ 4 files changed, 42 insertions(+) diff --git a/webui/index.html b/webui/index.html index bdef4cfa..ca63d727 100644 --- a/webui/index.html +++ b/webui/index.html @@ -7033,6 +7033,10 @@
+
No track
Unknown Artist
Unknown Album
diff --git a/webui/static/media-player.js b/webui/static/media-player.js index 23072eab..b030f509 100644 --- a/webui/static/media-player.js +++ b/webui/static/media-player.js @@ -222,6 +222,7 @@ function clearTrack() { // Clear track state currentTrack = null; isPlaying = false; + npSetPlayContext(''); // hide "Playing from" when nothing's playing const trackTitleElement = document.getElementById('track-title'); trackTitleElement.innerHTML = 'No track'; @@ -1466,6 +1467,13 @@ function npSetRadioMode(enabled, options = {}) { if (toast) { showToast(npRadioMode ? 'Radio mode on - similar tracks will auto-queue' : 'Radio mode off', 'success'); } + // Context label: only set the generic "Radio" if a more specific one (e.g. + // " Radio") wasn't already set by the caller. + if (npRadioMode) { + if (!npPlayContext || !/radio/i.test(npPlayContext)) npSetPlayContext('Radio'); + } else if (/radio/i.test(npPlayContext)) { + npSetPlayContext(''); + } if (npRadioMode && fetchIfNeeded && currentTrack && currentTrack.id && !npLoadingQueueItem && !npQueueHasNext()) { npEnsureCurrentTrackInQueue(); npFetchRadioTracks(); @@ -2114,6 +2122,21 @@ function handleNpRepeat() { // QUEUE MANAGEMENT // =============================== +// "Playing from" context shown above the track title (Spotify-style). +let npPlayContext = ''; +function npSetPlayContext(text) { + npPlayContext = text || ''; + const box = document.getElementById('np-play-context'); + const nameEl = document.getElementById('np-play-context-name'); + if (!box || !nameEl) return; + if (npPlayContext) { + nameEl.textContent = npPlayContext; + box.classList.remove('hidden'); + } else { + box.classList.add('hidden'); + } +} + function addToQueue(track) { npQueue.push(track); showToast('Added to queue', 'success'); diff --git a/webui/static/stats-automations.js b/webui/static/stats-automations.js index 37f1d51d..b46cbd1c 100644 --- a/webui/static/stats-automations.js +++ b/webui/static/stats-automations.js @@ -4757,6 +4757,9 @@ async function playArtistRadio() { // Enable radio mode + immediately seed the queue with similar tracks — // same path the modal's Radio button uses (fetchIfNeeded also adds the // current track to the queue first). + if (typeof npSetPlayContext === 'function') { + npSetPlayContext(`${artistName || 'Artist'} Radio`); + } if (typeof npSetRadioMode === 'function') { npSetRadioMode(true, { toast: false, fetchIfNeeded: true }); } else { diff --git a/webui/static/style.css b/webui/static/style.css index 7ee3be99..020a9264 100644 --- a/webui/static/style.css +++ b/webui/static/style.css @@ -48664,6 +48664,18 @@ textarea.enhanced-meta-field-input { box-shadow: 0 30px 92px rgba(0,0,0,0.66), 0 12px 40px rgba(var(--accent-rgb),0.28) !important; } +/* ── "Playing from" context label (above the title) ── */ +.np-play-context { display: flex; align-items: center; gap: 7px; margin-bottom: 10px; } +.np-play-context.hidden { display: none; } +.np-play-context-label { + font-size: 10px; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; + color: rgba(255,255,255,0.32); +} +.np-play-context-name { + font-size: 12px; font-weight: 700; color: rgb(var(--accent-light-rgb)); + white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 220px; +} + /* ── Track meta ── */ .np-track-info { text-align: left !important; } .np-track-title { font-size: 28px !important; font-weight: 800 !important; letter-spacing: -0.02em !important; line-height: 1.1 !important; }