fix(composers): hide performer-only artists with zero composer credits (#963)

* fix(composers): drop Navidrome role rows with zero composer albums

Navidrome can list performer-only artists under role=composer with
stats.composer.albumCount 0; filter them out of the Composers catalog
so search no longer surfaces ghost entries like Apollo 440.

* docs(changelog): credit zunoz on Psysonic Discord for PR #963
This commit is contained in:
cucadmuh
2026-06-03 22:45:52 +03:00
committed by GitHub
parent c683b5e37b
commit be21f7834f
4 changed files with 36 additions and 1 deletions
+7
View File
@@ -443,6 +443,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Multi-select rings on Artists, All Albums, Playlists, and related card grids use an inset `::after` overlay (same approach as card focus rings) instead of `outline` on `overflow: hidden` tiles — fixes top-row clipping and the ~1px gap vs the inner border on Wayland/WebKitGTK.
### Composers — hide performer-only artists from role catalog
**By [@cucadmuh](https://github.com/cucadmuh), reported by zunoz on the Psysonic Discord, PR [#963](https://github.com/Psychotoxical/psysonic/pull/963)**
* Navidrome's composer role list can include artists with zero composer album credits (e.g. Apollo 440 with performer albums only). Composers browse/search now drops rows where `stats.composer.albumCount` is zero so ghost composer cards no longer appear.
### In-page browse — virtual scroll and cover-art priority
**By [@cucadmuh](https://github.com/cucadmuh), PR [#783](https://github.com/Psychotoxical/psysonic/pull/783)**
+2 -1
View File
@@ -19,6 +19,7 @@ import { useNavigateToComposer } from '../hooks/useNavigateToComposer';
import { peekComposerBrowseScrollRestore } from '../store/composerBrowseSessionStore';
import { useScopedBrowseSearchQuery } from '../store/liveSearchScopeStore';
import { readComposerBrowseRestore } from '../utils/navigation/albumDetailNavigation';
import { filterArtistsWithRoleAlbumCredits } from '../utils/library/composerBrowse';
import { usePerfProbeFlags } from '../utils/perf/perfFlags';
import { VirtualCardGrid } from '../components/VirtualCardGrid';
import OverlayScrollArea from '../components/OverlayScrollArea';
@@ -153,7 +154,7 @@ export default function Composers() {
ndListArtistsByRole('composer', 0, 10000)
.then(data => {
if (cancelled) return;
setComposers(data);
setComposers(filterArtistsWithRoleAlbumCredits(data));
setLoading(false);
})
.catch(err => {
+17
View File
@@ -0,0 +1,17 @@
import { describe, expect, it } from 'vitest';
import { filterArtistsWithRoleAlbumCredits } from './composerBrowse';
describe('filterArtistsWithRoleAlbumCredits', () => {
it('removes artists with zero role-scoped album count', () => {
const artists = [
{ id: '1', name: 'Bach', albumCount: 12 },
{ id: '2', name: 'Apollo 440', albumCount: 0 },
];
expect(filterArtistsWithRoleAlbumCredits(artists)).toEqual([artists[0]]);
});
it('removes artists when role album count is missing', () => {
const artists = [{ id: '1', name: 'Ghost', albumCount: undefined }];
expect(filterArtistsWithRoleAlbumCredits(artists)).toEqual([]);
});
});
+10
View File
@@ -0,0 +1,10 @@
import type { SubsonicArtist } from '../../api/subsonicTypes';
/**
* Navidrome's `/api/artist?role=composer` can include artists whose
* `stats.composer.albumCount` is zero (performer-only credits with no composer
* tags). Drop them from the Composers browse catalog.
*/
export function filterArtistsWithRoleAlbumCredits(artists: SubsonicArtist[]): SubsonicArtist[] {
return artists.filter(a => (a.albumCount ?? 0) > 0);
}