mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 15:25:46 +00:00
006635de4b
Three domain-eng modules peel ~316 LOC of fetch/mapping out of `api/subsonic.ts`: - `subsonicLibrary.ts` — browse + random + per-song fetch (`getMusicDirectory`, `getMusicIndexes`, `getMusicFolders`, `getRandomAlbums`, `getAlbumList`, `getRandomSongs`, `getRandomSongsFiltered`, `getSong`, `getAlbum`, `filterSongsToActiveLibrary`, `similarSongsRequestCount`, plus the private `albumIdsInActiveLibraryScope` cache). - `subsonicArtists.ts` — artist endpoints (`getArtists`, `getArtist`, `getArtistInfo`, `getTopSongs`, `getSimilarSongs2`, `getSimilarSongs`). Uses Library's `filterSongsToActiveLibrary` and `similarSongsRequestCount` for the per-library scoping fallback. - `subsonicRatings.ts` — `parseSubsonicEntityStarRating` parser plus `prefetchArtistUserRatings` and `prefetchAlbumUserRatings` workers with the shared 7-min cache. Calls back into Library/Artists for the per-id fetch. 51 external call sites migrated to direct imports. No re-export shims in `subsonic.ts`. Statistics endpoints still in `subsonic.ts` keep their `RATING_CACHE_TTL` constant locally (same 7-min window). subsonic.ts: 1078 → 762 LOC (−316).
78 lines
3.2 KiB
TypeScript
78 lines
3.2 KiB
TypeScript
import { useAuthStore } from '../store/authStore';
|
|
import { api, libraryFilterParams } from './subsonicClient';
|
|
import { filterSongsToActiveLibrary, similarSongsRequestCount } from './subsonicLibrary';
|
|
import type {
|
|
SubsonicAlbum,
|
|
SubsonicArtist,
|
|
SubsonicArtistInfo,
|
|
SubsonicSong,
|
|
} from './subsonicTypes';
|
|
|
|
export async function getArtists(): Promise<SubsonicArtist[]> {
|
|
const data = await api<{ artists: { index: any } }>('getArtists.view', {
|
|
...libraryFilterParams(),
|
|
});
|
|
const rawIdx = data.artists?.index;
|
|
const indices = Array.isArray(rawIdx) ? rawIdx : (rawIdx ? [rawIdx] : []);
|
|
const artists: SubsonicArtist[] = [];
|
|
for (const idx of indices) {
|
|
const rawArt = idx.artist;
|
|
const arr = Array.isArray(rawArt) ? rawArt : (rawArt ? [rawArt] : []);
|
|
artists.push(...arr);
|
|
}
|
|
return artists;
|
|
}
|
|
|
|
export async function getArtist(id: string): Promise<{ artist: SubsonicArtist; albums: SubsonicAlbum[] }> {
|
|
const data = await api<{ artist: SubsonicArtist & { album: SubsonicAlbum[] } }>('getArtist.view', { id });
|
|
const { album, ...artist } = data.artist;
|
|
return { artist, albums: album ?? [] };
|
|
}
|
|
|
|
export async function getArtistInfo(id: string, options?: { similarArtistCount?: number }): Promise<SubsonicArtistInfo> {
|
|
const count = options?.similarArtistCount ?? 5;
|
|
const data = await api<{ artistInfo2: SubsonicArtistInfo }>('getArtistInfo2.view', { id, count, ...libraryFilterParams() });
|
|
return data.artistInfo2 ?? {};
|
|
}
|
|
|
|
export async function getTopSongs(artist: string): Promise<SubsonicSong[]> {
|
|
try {
|
|
const { activeServerId, musicLibraryFilterByServer } = useAuthStore.getState();
|
|
const scoped = activeServerId && musicLibraryFilterByServer[activeServerId] && musicLibraryFilterByServer[activeServerId] !== 'all';
|
|
const topCount = scoped ? 20 : 5;
|
|
const data = await api<{ topSongs: { song: SubsonicSong[] } }>('getTopSongs.view', { artist, count: topCount, ...libraryFilterParams() });
|
|
const raw = data.topSongs?.song ?? [];
|
|
const filtered = await filterSongsToActiveLibrary(raw);
|
|
return filtered.slice(0, 5);
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
export async function getSimilarSongs2(id: string, count = 50): Promise<SubsonicSong[]> {
|
|
try {
|
|
const requestCount = similarSongsRequestCount(count);
|
|
const data = await api<{ similarSongs2: { song: SubsonicSong[] } }>('getSimilarSongs2.view', { id, count: requestCount, ...libraryFilterParams() });
|
|
const raw = data.similarSongs2?.song ?? [];
|
|
const filtered = await filterSongsToActiveLibrary(raw);
|
|
return filtered.slice(0, count);
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/** Similar tracks for a song id (Subsonic `getSimilarSongs`) — Navidrome + AudioMuse Instant Mix. */
|
|
export async function getSimilarSongs(id: string, count = 50): Promise<SubsonicSong[]> {
|
|
try {
|
|
const requestCount = similarSongsRequestCount(count);
|
|
const data = await api<{ similarSongs: { song: SubsonicSong | SubsonicSong[] } }>('getSimilarSongs.view', { id, count: requestCount, ...libraryFilterParams() });
|
|
const raw = data.similarSongs?.song;
|
|
if (!raw) return [];
|
|
const list = Array.isArray(raw) ? raw : [raw];
|
|
const filtered = await filterSongsToActiveLibrary(list);
|
|
return filtered.slice(0, count);
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|