refactor(random-mix): G.88 — extract panels + dedupe track row (cluster, multi-commit) (#655)

* refactor(random-mix): G.88.1 — extract helpers + AUDIOBOOK_GENRES + filter logic

* refactor(random-mix): G.88.2 — extract RandomMixHeader component

* refactor(random-mix): G.88.3 — extract RandomMixFiltersPanel component

* refactor(random-mix): G.88.4 — extract RandomMixGenrePanel component

* refactor(random-mix): G.88.5 — extract RandomMixTrackRow (dedupe genre + main lists)
This commit is contained in:
Frank Stellmacher
2026-05-13 18:21:50 +02:00
committed by GitHub
parent d4d3b0e53f
commit 40dd0bd100
6 changed files with 646 additions and 468 deletions
+41
View File
@@ -0,0 +1,41 @@
import type { SubsonicSong } from '../api/subsonicTypes';
import { passesMixMinRatings, type MixMinRatingsConfig } from './mixRatingFilter';
export const AUDIOBOOK_GENRES = [
'hörbuch', 'hoerbuch', 'hörspiel', 'hoerspiel',
'audiobook', 'audio book', 'spoken word', 'spokenword',
'podcast', 'kapitel', 'thriller', 'krimi', 'speech',
'fantasy', 'comedy', 'literature',
];
export function formatRandomMixDuration(seconds: number): string {
if (!seconds || isNaN(seconds)) return '0:00';
const m = Math.floor(seconds / 60);
const s = seconds % 60;
return `${m}:${s.toString().padStart(2, '0')}`;
}
interface FilterArgs {
excludeAudiobooks: boolean;
customGenreBlacklist: string[];
mixRatingCfg: MixMinRatingsConfig;
}
export function filterRandomMixSongs(songs: SubsonicSong[], args: FilterArgs): SubsonicSong[] {
const { excludeAudiobooks, customGenreBlacklist, mixRatingCfg } = args;
return songs.filter(song => {
if (!excludeAudiobooks) return true;
const checkText = (text: string) => {
const t = text.toLowerCase();
if (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 (!passesMixMinRatings(song, mixRatingCfg)) return false;
return true;
});
}