fix(search): hide search3 artists with zero albums (#697)

* fix(search): hide search3 artists with zero albums

* docs: changelog and credits for search zero-album filter (PR #697)
This commit is contained in:
cucadmuh
2026-05-14 22:17:26 +03:00
committed by GitHub
parent 3cc172723d
commit 5d53a63553
4 changed files with 40 additions and 1 deletions
+7
View File
@@ -255,6 +255,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Fixed
### Search — hide duplicate artist hits with zero albums
**By [@cucadmuh](https://github.com/cucadmuh), thanks to zunoz for the report on the Psysonic Discord, PR [#697](https://github.com/Psychotoxical/psysonic/pull/697)**
* Subsonic **`search3`** sometimes returns extra **artist** rows that duplicate a real name but list **0 albums** (server-side indexing noise). **`search()`** now strips artists whose **`albumCount` is exactly `0`**. Rows with **no** `albumCount` field are kept so strict or legacy servers are unchanged.
* Applies everywhere **`search()`** is used: header live search, mobile overlay, search results page, advanced search free-text query, and hooks that call **`search()`** (e.g. similarity fallbacks).
### Offline downloads — the cancel button works again + the sidebar toast keeps its size
**By [@Psychotoxical](https://github.com/Psychotoxical), PR [#694](https://github.com/Psychotoxical/psysonic/pull/694)**
+18
View File
@@ -0,0 +1,18 @@
import { describe, expect, it } from 'vitest';
import { filterSearchArtistsWithNoAlbums } from './subsonicSearch';
import type { SubsonicArtist } from './subsonicTypes';
describe('filterSearchArtistsWithNoAlbums', () => {
it('removes artists with albumCount 0', () => {
const artists: SubsonicArtist[] = [
{ id: '1', name: 'Real', albumCount: 2 },
{ id: '2', name: 'Ghost', albumCount: 0 },
];
expect(filterSearchArtistsWithNoAlbums(artists)).toEqual([artists[0]]);
});
it('keeps artists when albumCount is omitted', () => {
const artists: SubsonicArtist[] = [{ id: '1', name: 'Unknown count' }];
expect(filterSearchArtistsWithNoAlbums(artists)).toEqual(artists);
});
});
+14 -1
View File
@@ -6,6 +6,15 @@ import type {
SubsonicSong,
} from './subsonicTypes';
/**
* search3 sometimes returns duplicate or junk artist rows with **zero** albums (e.g. Navidrome indexing).
* Drop only rows that explicitly report `albumCount === 0`; keep artists when the field is absent.
* Thanks to zunoz for the report on the Psysonic Discord.
*/
export function filterSearchArtistsWithNoAlbums(artists: SubsonicArtist[]): SubsonicArtist[] {
return artists.filter((a) => a.albumCount !== 0);
}
export async function search(query: string, options?: { albumCount?: number; artistCount?: number; songCount?: number }): Promise<SearchResults> {
if (!query.trim()) return { artists: [], albums: [], songs: [] };
const data = await api<{
@@ -22,7 +31,11 @@ export async function search(query: string, options?: { albumCount?: number; art
...libraryFilterParams(),
});
const r = data.searchResult3 ?? {};
return { artists: r.artist ?? [], albums: r.album ?? [], songs: r.song ?? [] };
return {
artists: filterSearchArtistsWithNoAlbums(r.artist ?? []),
albums: r.album ?? [],
songs: r.song ?? [],
};
}
/**
+1
View File
@@ -106,6 +106,7 @@ export const CONTRIBUTORS = [
'Analysis queue control: prune stale http-backfill / cpu-seed jobs when tracks leave the playback queue, cap loudness backfill warmup to current + next 5 tracks, plus debug counters for diagnostics (PR #480)',
'CachedImage / useCachedUrl: blob URL only for matching cacheKey, layout load reset on key change; fixes broken player cover flash on track switch (#606) (PR #695)',
'OpenSubsonic albumArtists in album header; track artists in player bar, mobile, mini + songToTrack (#552) (PR #696)',
'Search: filter search3 artist rows with zero albums (report: zunoz on Psysonic Discord) (PR #697)',
],
},
{