fix(random-mix): keyword blocks and scoped genre list on Build a Mix (#965)

* fix(random-mix): honor keyword blocks and scope genre list to library

Keyword filter was gated behind the audiobook exclusion checkbox, so
blocked artists still appeared after Remix. Genre Mix now loads genres
via fetchGenreCatalog (scoped index / library filter) instead of raw
getGenres; show empty state when all tracks are filtered out.

* docs(changelog): credit zunoz on Psysonic Discord for PR #965
This commit is contained in:
cucadmuh
2026-06-03 23:06:50 +03:00
committed by GitHub
parent e76dac87ae
commit 5990d84f5a
14 changed files with 86 additions and 29 deletions
@@ -32,4 +32,14 @@ describe('filterRandomMixSongs', () => {
expect(kept).toHaveLength(1);
expect(kept[0].id).toBe('2');
});
it('applies keyword blacklist even when audiobook exclusion is off', () => {
const blocked = { ...song('1'), artist: '[Unknown Artist]' };
const out = filterRandomMixSongs([blocked, song('2')], {
excludeAudiobooks: false,
customGenreBlacklist: ['[Unknown Artist]'],
mixRatingCfg: { enabled: false, minSong: 0, minAlbum: 0, minArtist: 0 },
});
expect(out).toEqual([song('2')]);
});
});
@@ -25,17 +25,16 @@ export function filterRandomMixSongs(songs: SubsonicSong[], args: FilterArgs): S
const { excludeAudiobooks, customGenreBlacklist, mixRatingCfg } = args;
return songs.filter(song => {
if (!passesMixMinRatings(song, mixRatingCfg)) return false;
if (!excludeAudiobooks) return true;
const checkText = (text: string) => {
const matchesExcludedText = (text: string) => {
const t = text.toLowerCase();
if (AUDIOBOOK_GENRES.some(ag => t.includes(ag))) return true;
if (excludeAudiobooks && AUDIOBOOK_GENRES.some(ag => t.includes(ag))) return true;
if (customGenreBlacklist.some(bg => t.includes(bg.toLowerCase()))) return true;
return false;
};
if (song.genre && checkText(song.genre)) return false;
if (song.title && checkText(song.title)) return false;
if (song.album && checkText(song.album)) return false;
if (song.artist && checkText(song.artist)) return false;
if (song.genre && matchesExcludedText(song.genre)) return false;
if (song.title && matchesExcludedText(song.title)) return false;
if (song.album && matchesExcludedText(song.album)) return false;
if (song.artist && matchesExcludedText(song.artist)) return false;
return true;
});
}