mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 15:25:46 +00:00
c37d5f7389
The connection-reachability + Subsonic network-guard helpers were pinned low by four lib/api consumers (subsonicLibrary/Playlists/Ratings/Scrobble) yet ran two lower-layer→feature inversions. Both removed without a registry: - devOfflineBrowseStore is a self-contained DEV-only toggle with zero offline- feature coupling — it was only colocated there. Relocated features/offline/store → store/ (global). The @/features/offline barrel re-exports it so feature/UI consumers are unchanged; the three lower-layer readers (subsonicNetworkGuard, activeServerReachability, useConnectionStatus) now import it from @/store directly. - subsonicNetworkGuard's only other feature dep was playback's resolvePlaybackUrl, used solely for the psysonic-local:// skip check. Added hasLocalPlaybackUrl to the existing M4 substrate store/localPlaybackResolve — it mirrors resolvePlaybackUrl's local-source branch exactly (same profile resolution; the empty-serverId playback fallback never applies in the guard), so the skip stays bit-identical. network/ (subsonicNetworkGuard + activeServerReachability + tests) → lib/network, now @/features-free. useConnectionStatus is now iron-rule-clean and stays in hooks/ (cross-cutting). Test mocks retargeted to the new seam modules. Behavior-adjacent (covered by suite; default paths identical): the local-bytes skip helper — flag for offline-playback runtime QA alongside the M4 media-resolver seam.
47 lines
2.0 KiB
TypeScript
47 lines
2.0 KiB
TypeScript
import { useAuthStore } from '@/store/authStore';
|
|
import { hasLocalPlaybackUrl } from '@/store/localPlaybackResolve';
|
|
import { isDevOfflineBrowseForced } from '@/store/devOfflineBrowseStore';
|
|
import { resolveServerIdForIndexKey } from '@/lib/server/serverLookup';
|
|
import { isActiveServerReachable } from '@/lib/network/activeServerReachability';
|
|
|
|
function isSameServerProfile(a: string, b: string): boolean {
|
|
if (!a || !b) return false;
|
|
if (a === b) return true;
|
|
return resolveServerIdForIndexKey(a) === resolveServerIdForIndexKey(b);
|
|
}
|
|
|
|
/**
|
|
* Whether `serverId` is worth a best-effort Subsonic call while the browser is
|
|
* online. The active profile uses the connection-status probe; other profiles
|
|
* (e.g. queue playback while browsing another server) attempt optimistically.
|
|
*/
|
|
export function isSubsonicServerReachable(serverId: string): boolean {
|
|
if (!serverId) return false;
|
|
if (isDevOfflineBrowseForced()) return false;
|
|
if (typeof navigator !== 'undefined' && !navigator.onLine) return false;
|
|
const activeId = useAuthStore.getState().activeServerId;
|
|
if (!activeId || isSameServerProfile(serverId, activeId)) {
|
|
return isActiveServerReachable();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Whether a Subsonic API call for `serverId` is worth attempting.
|
|
* Skips when the browser or target server is down, or when the track already
|
|
* plays from a local `psysonic-local://` URL (offline / favorite-auto bytes).
|
|
*/
|
|
export function shouldAttemptSubsonicForServer(serverId: string, trackId?: string): boolean {
|
|
if (!serverId) return false;
|
|
if (isDevOfflineBrowseForced()) return false;
|
|
if (typeof navigator !== 'undefined' && !navigator.onLine) return false;
|
|
if (trackId && hasLocalPlaybackUrl(trackId, serverId)) return false;
|
|
return isSubsonicServerReachable(serverId);
|
|
}
|
|
|
|
/** Convenience for call sites that only know the active server id. */
|
|
export function shouldAttemptSubsonicForActiveServer(): boolean {
|
|
const activeId = useAuthStore.getState().activeServerId;
|
|
return activeId ? shouldAttemptSubsonicForServer(activeId) : false;
|
|
}
|