fix: duplicate rows in artist "Top Songs" when a track exists twice in the library
Navidrome can hold the same track twice (downloaded as a single AND as an album track), so
getTopSongs returned two identical rows ("PIXELATED KISSES" x2). Collapse the top-songs list
by title+album for display (keeps the highest play count) on web + Android. SW ns-v59.
Note: this is a display fix — the underlying duplicate files remain a library-cleanup matter.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
fbee695aad
commit
b3cf01dd3b
3 files changed
+12
-3
No files matched your search
@@ -84,7 +84,9 @@ class ArtistViewModel(app: Application, savedState: SavedStateHandle) : AndroidV
|
|||||||
val info = infoDef.await()
|
val info = infoDef.await()
|
||||||
|
|
||||||
val topDef = async { runCatching { repo.getTopSongs(artist.name) }.getOrDefault(emptyList()) }
|
val topDef = async { runCatching { repo.getTopSongs(artist.name) }.getOrDefault(emptyList()) }
|
||||||
val top = topDef.await()
|
// Navidrome can hold the same track twice (single + album track) → duplicate top-song
|
||||||
|
// rows ("PIXELATED KISSES" x2). Collapse by title+album (keeps the highest play count).
|
||||||
|
val top = topDef.await().distinctBy { "${it.title}|${it.album}".lowercase() }
|
||||||
|
|
||||||
_state.value = ArtistUiState(
|
_state.value = ArtistUiState(
|
||||||
artist = artist, info = info, topSongs = top,
|
artist = artist, info = info, topSongs = top,
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
const CACHE = 'ns-v58';
|
const CACHE = 'ns-v59';
|
||||||
const PRECACHE = ['/', 'index.html', 'manifest.json', 'icon.svg'];
|
const PRECACHE = ['/', 'index.html', 'manifest.json', 'icon.svg'];
|
||||||
const SKIP_PATHS = ['/rest/stream', '/rest/download', '/config.js'];
|
const SKIP_PATHS = ['/rest/stream', '/rest/download', '/config.js'];
|
||||||
// Auth token params stripped from cache keys so artwork survives across sessions/token refreshes.
|
// Auth token params stripped from cache keys so artwork survives across sessions/token refreshes.
|
||||||
|
|||||||
+8
-1
@@ -219,7 +219,14 @@ export async function loadArtistDetail(artist) {
|
|||||||
|
|
||||||
// ── Top Songs ──
|
// ── Top Songs ──
|
||||||
const ndAlbums = _ndArtist?.album || [];
|
const ndAlbums = _ndArtist?.album || [];
|
||||||
const topSongs = topRes.status === 'fulfilled' ? (topRes.value?.topSongs?.song || []) : [];
|
// Navidrome can hold the same track twice (e.g. downloaded as a single AND as an album track),
|
||||||
|
// so getTopSongs returns duplicate rows ("PIXELATED KISSES" x2). Collapse by title+album for display.
|
||||||
|
const _rawTop = topRes.status === 'fulfilled' ? (topRes.value?.topSongs?.song || []) : [];
|
||||||
|
const _seenTop = new Set();
|
||||||
|
const topSongs = _rawTop.filter(s => {
|
||||||
|
const k = `${s.title}|${s.album}`.toLowerCase().replace(/[^a-z0-9|]/g, '');
|
||||||
|
return _seenTop.has(k) ? false : (_seenTop.add(k), true);
|
||||||
|
});
|
||||||
const iTracks = iTracksRes.status === 'fulfilled' ? (iTracksRes.value || []).filter(t => t.wrapperType === 'track') : [];
|
const iTracks = iTracksRes.status === 'fulfilled' ? (iTracksRes.value || []).filter(t => t.wrapperType === 'track') : [];
|
||||||
const iAlbums = iAlbumsRes.status === 'fulfilled' ? (iAlbumsRes.value || []) : [];
|
const iAlbums = iAlbumsRes.status === 'fulfilled' ? (iAlbumsRes.value || []) : [];
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user