import { useAuthStore } from '../store/authStore'; import type { AudiomusePluginProbeResult, InstantMixProbeResult, } from '../utils/server/subsonicServerIdentity'; import { buildCapabilityContext } from './context'; import { PROBE_LEGACY_INSTANT_MIX, PROBE_OPENSUBSONIC_EXTENSIONS, SONIC_SIMILARITY_EXTENSION, getCapabilityDefinition, } from './catalog'; import { isCapabilityActive, resolveCallChain, resolveCapability, } from './resolve'; import type { CapabilityCallRoute, ProbeOutcome, ResolvedCapability, } from './types'; /** * Probe results currently live in dedicated per-server store maps. This facade * maps them into the generic `ProbeOutcome` shape the resolver consumes, so the * catalog/resolver/router stay storage-agnostic. */ function pluginProbeToOutcome(probe: AudiomusePluginProbeResult | undefined): ProbeOutcome | undefined { switch (probe) { case 'present': return { status: 'present', extensions: [SONIC_SIMILARITY_EXTENSION] }; case 'absent': return { status: 'present', extensions: [] }; case 'probing': return { status: 'probing' }; case 'error': return { status: 'error' }; default: return undefined; } } function legacyProbeToOutcome(probe: InstantMixProbeResult | undefined): ProbeOutcome | undefined { switch (probe) { case 'ok': return { status: 'present' }; case 'empty': case 'skipped': return { status: 'absent' }; case 'error': return { status: 'error' }; default: return undefined; } } export function buildProbeOutcomesForServer(serverId: string): Record { const s = useAuthStore.getState(); return { [PROBE_OPENSUBSONIC_EXTENSIONS]: pluginProbeToOutcome(s.audiomusePluginProbeByServer[serverId]), [PROBE_LEGACY_INSTANT_MIX]: legacyProbeToOutcome(s.instantMixProbeByServer[serverId]), }; } export function resolveFeatureForServer( serverId: string, feature: string, ): ResolvedCapability | null { const def = getCapabilityDefinition(feature); if (!def) return null; const s = useAuthStore.getState(); const ctx = buildCapabilityContext(s.subsonicServerIdentityByServer[serverId]); return resolveCapability(def, ctx, buildProbeOutcomesForServer(serverId)); } export function isFeatureActiveForServer(serverId: string, feature: string): boolean { const resolved = resolveFeatureForServer(serverId, feature); if (!resolved) return false; const userOptIn = !!useAuthStore.getState().audiomuseNavidromeByServer[serverId]; return isCapabilityActive(resolved, userOptIn); } export function resolveCallRoutesForServer( serverId: string, feature: string, op: string, ): CapabilityCallRoute[] { const def = getCapabilityDefinition(feature); if (!def) return []; const s = useAuthStore.getState(); const ctx = buildCapabilityContext(s.subsonicServerIdentityByServer[serverId]); return resolveCallChain(def, ctx, buildProbeOutcomesForServer(serverId), op); }