mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 15:25:46 +00:00
feat(server): capability framework, AudioMuse sonic routing & PsyLab Connections (#1033)
* feat(server): probe AudioMuse via OpenSubsonic and add PsyLab Connections tab Navidrome ≥0.62: detect sonicSimilarity extension for reliable plugin signal; older servers keep the legacy getSimilarSongs probe. PsyLab gets a Connections tab with session, endpoint, and active-server capability details. * feat(psylab): polish Connections tab, admin role probe, and tab bar layout Status badges and Navidrome admin/user validation in Connections; prevent PsyLab tab row from vertically collapsing under the Logs flex layout. * docs: add CHANGELOG and credits for PR #1032 * feat(settings): auto-enable AudioMuse on Navidrome 0.62+ with status indicator Replace the per-server manual toggle with a probe-driven badge when sonicSimilarity is available; pre-0.62 Navidrome keeps the legacy toggle. * feat(server): capability framework with AudioMuse sonic routing Add a declarative server-capability catalog (src/serverCapabilities/) that picks a feature strategy per server generation, runs only the needed probes, and routes API calls. AudioMuse Instant Mix now prefers the OpenSubsonic sonicSimilarity endpoint (getSonicSimilarTracks) on Navidrome 0.62+ and falls back to legacy getSimilarSongs. - catalog/context/resolve: eligibility, detection, activation, call routing - storeView: read facade over the existing per-server probe maps - getSonicSimilarTracks API client + fetchSimilarTracksRouted router - route Instant Mix and Lucky Mix through the resolver - ServersTab + PsyLab Connections read the resolver (auto status vs toggle) - tests: resolve, storeView, router * docs: update CHANGELOG and credits for PR #1033 Renamed branch supersedes PR #1032: point changelog/credits at #1033 and document the server-capability framework, auto-managed AudioMuse indicator, and sonic Instant Mix routing. * refactor(server): address PR #1033 review — idempotent probe, drop dead code - Make scheduleInstantMixProbeForServer idempotent: skip when a definitive result is cached; re-probe only on force (add/edit/test server), a prior error, or a server version/type change (invalidated in setSubsonicServerIdentity). Removes the steady-state 120 s re-probe, the present→probing→present flicker, and the momentary legacy-fallback routing window. - Remove now-dead identity helpers (showAudiomuseNavidromeServerSetting, isAudiomusePluginAutoManaged, isNavidromeSonicSimilarityEligible, resolveAudiomusePluginProbeUiStatus + type) and the superseded probeAudiomusePluginWithCredentials; the catalog is the single source of truth. - Drop the never-emitted 'unsupported' AudiomusePluginProbeResult variant. - Fill audiomuseStatus* keys in all 8 non-en locales. - Tests: probe idempotency + version-change invalidation; retarget OpenSubsonic test to fetchOpenSubsonicExtensionsWithCredentials.
This commit is contained in:
@@ -95,21 +95,28 @@
|
||||
|
||||
.sidebar-perf-modal__tabs {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
flex: 0 0 auto;
|
||||
flex-shrink: 0;
|
||||
gap: 4px;
|
||||
margin: 12px 0 10px;
|
||||
padding: 4px;
|
||||
border-radius: 12px;
|
||||
background: color-mix(in srgb, var(--bg-card, var(--bg-app)) 88%, transparent);
|
||||
border: 1px solid color-mix(in srgb, var(--text-muted) 18%, transparent);
|
||||
overflow-x: auto;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
.sidebar-perf-modal__tab {
|
||||
flex: 1;
|
||||
flex: 0 0 auto;
|
||||
min-width: 4.5rem;
|
||||
min-height: 2.25rem;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
padding: 8px 10px;
|
||||
white-space: nowrap;
|
||||
border: none;
|
||||
border-radius: 9px;
|
||||
background: transparent;
|
||||
@@ -312,6 +319,130 @@
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.perf-metric-section__body {
|
||||
padding: 0 10px 10px;
|
||||
}
|
||||
|
||||
.perf-conn-summary {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
padding: 10px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid color-mix(in srgb, var(--text-muted) 16%, transparent);
|
||||
background: color-mix(in srgb, var(--bg-card, var(--bg-app)) 88%, transparent);
|
||||
}
|
||||
|
||||
.perf-conn-summary__item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 4px;
|
||||
min-width: 88px;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.perf-conn-summary__label {
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
color: color-mix(in srgb, var(--text-muted) 90%, transparent);
|
||||
}
|
||||
|
||||
.perf-status-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 999px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
line-height: 1.35;
|
||||
border: 1px solid transparent;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.perf-status-badge--ok {
|
||||
color: #9ece6a;
|
||||
background: color-mix(in srgb, #9ece6a 14%, transparent);
|
||||
border-color: color-mix(in srgb, #9ece6a 28%, transparent);
|
||||
}
|
||||
|
||||
.perf-status-badge--warn {
|
||||
color: #e0af68;
|
||||
background: color-mix(in srgb, #e0af68 14%, transparent);
|
||||
border-color: color-mix(in srgb, #e0af68 28%, transparent);
|
||||
}
|
||||
|
||||
.perf-status-badge--error {
|
||||
color: #f7768e;
|
||||
background: color-mix(in srgb, #f7768e 14%, transparent);
|
||||
border-color: color-mix(in srgb, #f7768e 28%, transparent);
|
||||
}
|
||||
|
||||
.perf-status-badge--neutral {
|
||||
color: #7aa2f7;
|
||||
background: color-mix(in srgb, #7aa2f7 14%, transparent);
|
||||
border-color: color-mix(in srgb, #7aa2f7 28%, transparent);
|
||||
}
|
||||
|
||||
.perf-status-badge--muted {
|
||||
color: var(--text-muted);
|
||||
background: color-mix(in srgb, var(--text-muted) 10%, transparent);
|
||||
border-color: color-mix(in srgb, var(--text-muted) 20%, transparent);
|
||||
}
|
||||
|
||||
.perf-server-dl {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
font-size: 12px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid color-mix(in srgb, var(--text-muted) 12%, transparent);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.perf-server-dl__row {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(110px, 38%) 1fr;
|
||||
gap: 8px 12px;
|
||||
align-items: center;
|
||||
padding: 8px 10px;
|
||||
border-top: 1px solid color-mix(in srgb, var(--text-muted) 10%, transparent);
|
||||
}
|
||||
|
||||
.perf-server-dl__row:first-child {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.perf-server-dl__row:nth-child(even) {
|
||||
background: color-mix(in srgb, var(--bg-sidebar, var(--bg-app)) 40%, transparent);
|
||||
}
|
||||
|
||||
.perf-server-dl__row dt {
|
||||
margin: 0;
|
||||
color: var(--text-muted);
|
||||
font-weight: 500;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.perf-server-dl__row dd {
|
||||
margin: 0;
|
||||
color: var(--text-primary, var(--text));
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.perf-server-dl__code {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
font-size: 11px;
|
||||
color: color-mix(in srgb, var(--text-primary, var(--text)) 92%, var(--accent));
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.perf-live-poll {
|
||||
margin-bottom: 12px;
|
||||
padding: 10px 12px;
|
||||
@@ -907,6 +1038,7 @@
|
||||
}
|
||||
|
||||
.sidebar-perf-modal__actions {
|
||||
flex-shrink: 0;
|
||||
margin-top: 14px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
Reference in New Issue
Block a user