fix: split multi-artists by • and /, clickable artist/album in playlists and album detail

- components.js: expand artist split regex to handle both ' / ' and '•' separators
- views.js: enable artist+album links in playlist song items (were noArtistLink:true)
- views.js: enable artist links in album detail song items
- views.js: album header artist is now split and renders as clickable links

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Sonnet 4.6 committed 2026-04-28 00:31:48 +02:00
1 parent 51babd9e41
commit e5a80242e9
2 files changed
+8 -5

No files matched your search

+1 -1
View File
@@ -32,7 +32,7 @@ export function makeSongItem(s, idx, list, { noArtistLink = false, noAlbumLink =
if(s.starred && !s._starred) s._starred = true; if(s.starred && !s._starred) s._starred = true;
el.className = 'song-item' + (S.queue[S.qIdx]?.id === s.id ? ' playing' : ''); el.className = 'song-item' + (S.queue[S.qIdx]?.id === s.id ? ' playing' : '');
const cv = coverUrl(s.coverArt, 60); const cv = coverUrl(s.coverArt, 60);
const artistParts = (s.artist || '').split(' / ').filter(Boolean); const artistParts = (s.artist || '').split(/\s*(?:\/|•)\s*/).filter(Boolean);
const artistHtml = artistParts.length const artistHtml = artistParts.length
? artistParts.map((name, i) => { ? artistParts.map((name, i) => {
const aid = i === 0 ? (s.artistId || '') : ''; const aid = i === 0 ? (s.artistId || '') : '';
+7 -4
View File
@@ -422,8 +422,11 @@ export async function loadAlbumDetail(album) {
album._fromArtist ? navigate('artist-detail', album._fromArtist) : navigate('albums'); album._fromArtist ? navigate('artist-detail', album._fromArtist) : navigate('albums');
document.getElementById('album-detail-name').textContent = album.name; document.getElementById('album-detail-name').textContent = album.name;
const artistEl = document.getElementById('album-detail-artist'); const artistEl = document.getElementById('album-detail-artist');
artistEl.textContent = album.artist || ''; const albumArtistParts = (album.artist || '').split(/\s*(?:\/|•)\s*/).filter(Boolean);
artistEl.onclick = () => { if(album.artistId) navigate('artist-detail', {id:album.artistId, name:album.artist}); }; artistEl.innerHTML = albumArtistParts.map((name, i) => {
const aid = i === 0 ? (album.artistId || '') : '';
return `<span class="song-link" onclick="s_goArtist(event,${JSON.stringify(name)},${JSON.stringify(aid)})">${esc(name)}</span>`;
}).join('<span style="color:var(--text3)"> / </span>') || '';
const cw = document.getElementById('album-cover-wrap'); const cw = document.getElementById('album-cover-wrap');
const cv = coverUrl(album.coverArt, 300); const cv = coverUrl(album.coverArt, 300);
cw.innerHTML = cv ? `<img src="${cv}" onerror="this.parentNode.innerHTML='<div class=\\'no-art\\'>💿</div>'">` : '<div class="no-art">💿</div>'; cw.innerHTML = cv ? `<img src="${cv}" onerror="this.parentNode.innerHTML='<div class=\\'no-art\\'>💿</div>'">` : '<div class="no-art">💿</div>';
@@ -440,7 +443,7 @@ export async function loadAlbumDetail(album) {
toast(`⬇ ${songs.length} Titel Download gestartet`); toast(`⬇ ${songs.length} Titel Download gestartet`);
}; };
sl.innerHTML = ''; sl.innerHTML = '';
songs.forEach((s,i) => sl.appendChild(makeSongItem(s, i, songs, { noArtistLink: true, noAlbumLink: true }))); songs.forEach((s,i) => sl.appendChild(makeSongItem(s, i, songs, { noAlbumLink: true })));
} catch(e) { sl.innerHTML = `<p style="color:var(--danger)">${e.message}</p>`; } } catch(e) { sl.innerHTML = `<p style="color:var(--danger)">${e.message}</p>`; }
} }
@@ -492,7 +495,7 @@ export async function loadPlaylistDetail(pl) {
playQueue(shuffled, 0); playQueue(shuffled, 0);
}; };
sl.innerHTML = ''; sl.innerHTML = '';
songs.forEach((s,i) => sl.appendChild(makeSongItem(s, i, songs, { noArtistLink: true }))); songs.forEach((s,i) => sl.appendChild(makeSongItem(s, i, songs)));
} catch(e) { sl.innerHTML = `<p style="color:var(--danger)">${e.message}</p>`; } } catch(e) { sl.innerHTML = `<p style="color:var(--danger)">${e.message}</p>`; }
} }