From e04980626d97e2d03ee9bc3df8a179cf78b6ab70 Mon Sep 17 00:00:00 2001 From: Frank Stellmacher <171614930+Psychotoxical@users.noreply.github.com> Date: Wed, 13 May 2026 01:08:48 +0200 Subject: [PATCH] =?UTF-8?q?refactor(api):=20F.52=20=E2=80=94=20move=20cred?= =?UTF-8?q?ential=20helpers=20to=20subsonicClient=20(#617)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move `apiWithCredentials` + `restBaseFromUrl` from `api/subsonic.ts` into `api/subsonicClient.ts` where the other token-auth primitives already live. They are the credential-bearing variants of `api`, sitting in the same client module is the natural home. `api/subsonic.ts` now holds only the connection-probing domain: `ping`, `pingWithCredentials`, `probeInstantMixWithCredentials`, `scheduleInstantMixProbeForServer`. Clear, cohesive, stable import path for the call sites that still use it. Pure code-move. subsonic.ts: 144 → 119 LOC. Total Phase F journey: 1333 → 119 LOC (~91% reduction). --- src/api/subsonic.ts | 27 +-------------------------- src/api/subsonicClient.ts | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/api/subsonic.ts b/src/api/subsonic.ts index f58a7c47..16bd33ad 100644 --- a/src/api/subsonic.ts +++ b/src/api/subsonic.ts @@ -9,7 +9,7 @@ import { import { SUBSONIC_CLIENT, api, - getAuthParams, + apiWithCredentials, secureRandomSalt, } from './subsonicClient'; import type { PingWithCredentialsResult, SubsonicSong } from './subsonicTypes'; @@ -53,31 +53,6 @@ export async function pingWithCredentials( } } -function restBaseFromUrl(serverUrl: string): string { - const base = serverUrl.startsWith('http') ? serverUrl.replace(/\/$/, '') : `http://${serverUrl.replace(/\/$/, '')}`; - return `${base}/rest`; -} - -async function apiWithCredentials( - serverUrl: string, - username: string, - password: string, - endpoint: string, - extra: Record = {}, - timeout = 15000, -): Promise { - const params = { ...getAuthParams(username, password), ...extra }; - const resp = await axios.get(`${restBaseFromUrl(serverUrl)}/${endpoint}`, { - params, - paramsSerializer: { indexes: null }, - timeout, - }); - const data = resp.data?.['subsonic-response']; - if (!data) throw new Error('Invalid response from server (possibly not a Subsonic server)'); - if (data.status !== 'ok') throw new Error(data.error?.message ?? 'Subsonic API error'); - return data as T; -} - const INSTANT_MIX_PROBE_RANDOM_SIZE = 8; const INSTANT_MIX_PROBE_SIMILAR_COUNT = 12; const INSTANT_MIX_PROBE_MAX_TRACKS = 4; diff --git a/src/api/subsonicClient.ts b/src/api/subsonicClient.ts index 32bda47a..7b000ced 100644 --- a/src/api/subsonicClient.ts +++ b/src/api/subsonicClient.ts @@ -17,6 +17,31 @@ export function getAuthParams(username: string, password: string) { return { u: username, t: token, s: salt, v: '1.16.1', c: SUBSONIC_CLIENT, f: 'json' }; } +export function restBaseFromUrl(serverUrl: string): string { + const base = serverUrl.startsWith('http') ? serverUrl.replace(/\/$/, '') : `http://${serverUrl.replace(/\/$/, '')}`; + return `${base}/rest`; +} + +export async function apiWithCredentials( + serverUrl: string, + username: string, + password: string, + endpoint: string, + extra: Record = {}, + timeout = 15000, +): Promise { + const params = { ...getAuthParams(username, password), ...extra }; + const resp = await axios.get(`${restBaseFromUrl(serverUrl)}/${endpoint}`, { + params, + paramsSerializer: { indexes: null }, + timeout, + }); + const data = resp.data?.['subsonic-response']; + if (!data) throw new Error('Invalid response from server (possibly not a Subsonic server)'); + if (data.status !== 'ok') throw new Error(data.error?.message ?? 'Subsonic API error'); + return data as T; +} + export function getClient() { const { getBaseUrl, getActiveServer } = useAuthStore.getState(); const server = getActiveServer();