video: self-contained video Source section; hide music's server settings on video

Per the desired model: video Settings has its OWN server settings, separate from
music. The 'Video Source' group now holds the Plex/Jellyfin pick AND the Movies/TV
library mapping (moved out of music's Plex panel so it's not coupled to the music
active server). The whole MUSIC 'Server Connections' group is hidden on the video
side. Video reuses the shared Plex/Jellyfin credentials: the picker shows both
servers, the configured ones selectable, the rest 'not connected — set up in Music
settings'. Music settings keep their own server settings, untouched.
This commit is contained in:
BoulderBadgeDad 2026-06-15 15:10:53 -07:00
parent f93c211de3
commit 8f6f992670
3 changed files with 35 additions and 27 deletions

View file

@ -5133,12 +5133,23 @@
<!-- Video API Configuration (placeholders; shown only on the video <!-- Video API Configuration (placeholders; shown only on the video
side in place of the music API services). Same structure as the side in place of the music API services). Same structure as the
music service frames above. --> music service frames above. -->
<!-- Video Source (which Plex/Jellyfin the video side uses) --> <!-- Video Source — the video side's OWN server pick + library
mapping, independent of the music server (it just reuses
the shared Plex/Jellyfin credentials). -->
<div class="settings-group" data-stg="connections" data-video-only> <div class="settings-group" data-stg="connections" data-video-only>
<h3>Video Source</h3> <h3>Video Source</h3>
<div class="vid-source-panel" data-video-source-panel> <div class="vid-source-panel" data-video-source-panel>
<div class="callback-help">Checking…</div> <div class="callback-help">Checking…</div>
</div> </div>
<div class="form-group video-library-selectors" style="margin-top: 16px;">
<label>Movies Library:</label>
<select data-video-lib-select="movies"><option value="">Loading...</option></select>
<label style="margin-top: 12px;">TV Shows Library:</label>
<select data-video-lib-select="tv"><option value="">Loading...</option></select>
<small style="color: #999; font-size: 0.9em; display: block; margin-top: 5px;">
Which libraries the video side scans. <span data-video-lib-status></span>
</small>
</div>
</div> </div>
<div class="settings-group" data-stg="connections" data-video-only> <div class="settings-group" data-stg="connections" data-video-only>
<h3>API Configuration <button class="stg-accordion-toggle" onclick="toggleAllServiceAccordions(this)">Expand All</button></h3> <h3>API Configuration <button class="stg-accordion-toggle" onclick="toggleAllServiceAccordions(this)">Expand All</button></h3>
@ -5300,21 +5311,6 @@
Select which music library to use (doesn't affect config file) Select which music library to use (doesn't affect config file)
</small> </small>
</div> </div>
<!-- Video side: which libraries are Movies / TV (shown only on the
video side; populated + saved by video/video-settings.js). -->
<div class="form-group video-library-selectors" data-video-only>
<label>Movies Library:</label>
<select data-video-lib-select="movies">
<option value="">Loading...</option>
</select>
<label style="margin-top: 12px;">TV Shows Library:</label>
<select data-video-lib-select="tv">
<option value="">Loading...</option>
</select>
<small style="color: #999; font-size: 0.9em; display: block; margin-top: 5px;">
Which libraries the video side scans. <span data-video-lib-status></span>
</small>
</div>
<div class="form-actions"> <div class="form-actions">
<button id="plex-config-action-button" class="detect-button" onclick="clearPlexConfiguration()">Clear Configuration</button> <button id="plex-config-action-button" class="detect-button" onclick="clearPlexConfiguration()">Clear Configuration</button>
</div> </div>

View file

@ -28,24 +28,27 @@
.then(function (d) { renderServer(host, d || {}); }) .then(function (d) { renderServer(host, d || {}); })
.catch(function () { renderServer(host, {}); }); .catch(function () { renderServer(host, {}); });
} }
function srvBtn(id, label, active) { function srvOpt(id, label, configured, selected) {
return '<button class="vid-source-btn' + (id === active ? ' active' : '') + if (!configured) {
return '<button class="vid-source-btn vid-source-btn--off" type="button" disabled ' +
'title="Not connected — set it up in Music settings">' + label +
' <span class="vid-source-off">(not connected)</span></button>';
}
return '<button class="vid-source-btn' + (id === selected ? ' active' : '') +
'" type="button" data-video-server-pick="' + id + '">' + label + '</button>'; '" type="button" data-video-server-pick="' + id + '">' + label + '</button>';
} }
function renderServer(host, d) { function renderServer(host, d) {
var plex = !!d.plex, jelly = !!d.jellyfin; var plex = !!d.plex, jelly = !!d.jellyfin;
var html = '<div class="vid-source-pick">' +
srvOpt('plex', 'Plex', plex, d.server) + srvOpt('jellyfin', 'Jellyfin', jelly, d.server) + '</div>';
if (!plex && !jelly) { if (!plex && !jelly) {
host.innerHTML = '<div class="vid-source-none">No video server connected. ' + html += '<div class="callback-help">Neither is connected yet. Set up Plex or Jellyfin in ' +
'Connect <strong>Plex</strong> or <strong>Jellyfin</strong> under <em>Server Connections</em> ' + '<strong>Music &rarr; Settings &rarr; Server Connections</strong> — the video side reuses those credentials.</div>';
'below to scan and browse your video library. <em>(Navidrome and Standalone are music-only.)</em></div>';
} else if (plex && jelly) {
host.innerHTML = '<div class="vid-source-pick">' +
srvBtn('plex', 'Plex', d.server) + srvBtn('jellyfin', 'Jellyfin', d.server) + '</div>' +
'<div class="callback-help">Both are connected — pick which one the video side uses.</div>';
} else { } else {
host.innerHTML = '<div class="vid-source-using"><span class="vid-source-check">✓</span> ' + html += '<div class="callback-help">The video side uses this server, independent of Music. ' +
'Video uses <strong>' + (plex ? 'Plex' : 'Jellyfin') + '</strong></div>'; 'Greyed-out options aren\'t connected — set them up in Music settings.</div>';
} }
host.innerHTML = html;
} }
function pickServer(id) { function pickServer(id) {
fetch(SERVER_URL, { fetch(SERVER_URL, {

View file

@ -140,6 +140,12 @@ body[data-side="video"] [data-music-only] {
body[data-side="video"] [data-stg="library"]:not([data-video-only]) { body[data-side="video"] [data-stg="library"]:not([data-video-only]) {
display: none !important; display: none !important;
} }
/* The video side has its OWN server section (Video Source above) and reuses the
shared Plex/Jellyfin credentials so hide music's Server Connections group
entirely on the video side. Video never configures or selects the MUSIC server. */
body[data-side="video"] .settings-group[data-stg="connections"]:not([data-video-only]) {
display: none !important;
}
/* ── Dashboard header: match music, minus the sweep animation ──────────── */ /* ── Dashboard header: match music, minus the sweep animation ──────────── */
/* The header reuses music's .dashboard-header markup/CSS for an identical look; /* The header reuses music's .dashboard-header markup/CSS for an identical look;
@ -1479,6 +1485,9 @@ a.vd-guest:hover .vd-guest-name { color: rgb(var(--vd-accent-rgb)); }
} }
.vid-source-btn:hover { background: rgba(255, 255, 255, 0.12); color: #fff; } .vid-source-btn:hover { background: rgba(255, 255, 255, 0.12); color: #fff; }
.vid-source-btn.active { background: rgba(56, 189, 248, 0.9); border-color: transparent; color: #fff; } .vid-source-btn.active { background: rgba(56, 189, 248, 0.9); border-color: transparent; color: #fff; }
.vid-source-btn--off { opacity: 0.45; cursor: not-allowed; }
.vid-source-btn--off:hover { background: rgba(255, 255, 255, 0.06); color: rgba(255, 255, 255, 0.8); }
.vid-source-off { font-size: 11px; opacity: 0.85; }
/* library: no-server gate banner */ /* library: no-server gate banner */
.video-noserver { .video-noserver {