Fix [object Object] in discovery live-update paths (bulletproof pass)

The previous commit only fixed the INITIAL-render transform for
Spotify/Tidal/Deezer discovery rows. User confirmed [object Object]
still appeared after discovery completed — because there are two
additional update paths that do their own row-transform:

- WebSocket live-update handler (populates rows as discovery progresses)
- Poll-based fallback (same shape, runs when socket is disconnected)

Both had the same naive `.artists.join(', ')` on potentially-object
arrays. The poll and socket handlers exist for each of Spotify Public,
Tidal, and Deezer — six occurrences total across three platforms, all
with the same bug class. Now all use the object-aware map-and-join
pattern consistent with the initial-render fix.

Also fixes two more spots in openDiscoveryFixModal that the earlier
sweep missed:
- Missing spotify_public branch in the apply-selected-match handler:
  after user picks a replacement track, state lookup failed, the local
  row wouldn't refresh even though the backend had succeeded.
- Same artist-join bug in the same handler (track.artists from the
  fix-modal search results could be array-of-objects).

Full suite stays at 263 passed. Ruff clean.
This commit is contained in:
Broque Thomas 2026-04-21 16:14:36 -07:00
parent 891b18540b
commit fadbb286b7

View file

@ -19758,6 +19758,8 @@ async function selectDiscoveryFixTrack(track) {
state = listenbrainzPlaylistStates[identifier];
} else if (platform === 'mirrored') {
state = youtubePlaylistStates[identifier];
} else if (platform === 'spotify_public') {
state = youtubePlaylistStates[identifier];
}
// Support both camelCase and snake_case
@ -19770,7 +19772,12 @@ async function selectDiscoveryFixTrack(track) {
result.status = '✅ Found';
result.status_class = 'found';
result.spotify_track = track.name;
result.spotify_artist = Array.isArray(track.artists) ? track.artists.join(', ') : track.artists;
result.spotify_artist = Array.isArray(track.artists)
? track.artists
.map(a => (typeof a === 'object' && a !== null) ? (a.name || '') : a)
.filter(Boolean)
.join(', ') || '-'
: (track.artists || '-');
result.spotify_album = track.album;
result.spotify_id = track.id;
result.duration = formatDuration(track.duration_ms);
@ -27238,7 +27245,14 @@ function startTidalDiscoveryPolling(fakeUrlHash, playlistId) {
status: isWingIt ? '🎯 Wing It' : (isFound ? '✅ Found' : '❌ Not Found'),
status_class: isWingIt ? 'wing-it' : (isFound ? 'found' : 'not-found'),
spotify_track: r.spotify_data ? r.spotify_data.name : (r.spotify_track || '-'),
spotify_artist: r.spotify_data && r.spotify_data.artists ? (Array.isArray(r.spotify_data.artists) ? r.spotify_data.artists.join(', ') : r.spotify_data.artists) : (r.spotify_artist || '-'),
spotify_artist: r.spotify_data && r.spotify_data.artists
? (Array.isArray(r.spotify_data.artists)
? (r.spotify_data.artists
.map(a => (typeof a === 'object' && a !== null) ? (a.name || '') : a)
.filter(Boolean)
.join(', ') || '-')
: r.spotify_data.artists)
: (r.spotify_artist || '-'),
spotify_album: r.spotify_data ? (typeof r.spotify_data.album === 'object' ? r.spotify_data.album.name : r.spotify_data.album) : (r.spotify_album || '-'),
spotify_data: r.spotify_data, spotify_id: r.spotify_id, manual_match: r.manual_match,
wing_it_fallback: isWingIt
@ -27301,8 +27315,14 @@ function startTidalDiscoveryPolling(fakeUrlHash, playlistId) {
status: isFound ? '✅ Found' : '❌ Not Found',
status_class: isFound ? 'found' : 'not-found',
spotify_track: result.spotify_data ? result.spotify_data.name : (result.spotify_track || '-'),
spotify_artist: result.spotify_data && result.spotify_data.artists ?
(Array.isArray(result.spotify_data.artists) ? result.spotify_data.artists.join(', ') : result.spotify_data.artists) : (result.spotify_artist || '-'),
spotify_artist: result.spotify_data && result.spotify_data.artists
? (Array.isArray(result.spotify_data.artists)
? (result.spotify_data.artists
.map(a => (typeof a === 'object' && a !== null) ? (a.name || '') : a)
.filter(Boolean)
.join(', ') || '-')
: result.spotify_data.artists)
: (result.spotify_artist || '-'),
spotify_album: result.spotify_data ? (typeof result.spotify_data.album === 'object' ? result.spotify_data.album.name : result.spotify_data.album) : (result.spotify_album || '-'),
spotify_data: result.spotify_data, // Pass through
spotify_id: result.spotify_id, // Pass through
@ -28693,7 +28713,14 @@ function startDeezerDiscoveryPolling(fakeUrlHash, playlistId) {
status: isWingIt ? '🎯 Wing It' : (isFound ? '✅ Found' : '❌ Not Found'),
status_class: isWingIt ? 'wing-it' : (isFound ? 'found' : 'not-found'),
spotify_track: r.spotify_data ? r.spotify_data.name : (r.spotify_track || '-'),
spotify_artist: r.spotify_data && r.spotify_data.artists ? (Array.isArray(r.spotify_data.artists) ? r.spotify_data.artists.join(', ') : r.spotify_data.artists) : (r.spotify_artist || '-'),
spotify_artist: r.spotify_data && r.spotify_data.artists
? (Array.isArray(r.spotify_data.artists)
? (r.spotify_data.artists
.map(a => (typeof a === 'object' && a !== null) ? (a.name || '') : a)
.filter(Boolean)
.join(', ') || '-')
: r.spotify_data.artists)
: (r.spotify_artist || '-'),
spotify_album: r.spotify_data ? (typeof r.spotify_data.album === 'object' ? r.spotify_data.album.name : r.spotify_data.album) : (r.spotify_album || '-'),
spotify_data: r.spotify_data, spotify_id: r.spotify_id, manual_match: r.manual_match,
wing_it_fallback: isWingIt
@ -28755,8 +28782,14 @@ function startDeezerDiscoveryPolling(fakeUrlHash, playlistId) {
status: isFound ? '✅ Found' : '❌ Not Found',
status_class: isFound ? 'found' : 'not-found',
spotify_track: result.spotify_data ? result.spotify_data.name : (result.spotify_track || '-'),
spotify_artist: result.spotify_data && result.spotify_data.artists ?
(Array.isArray(result.spotify_data.artists) ? result.spotify_data.artists.join(', ') : result.spotify_data.artists) : (result.spotify_artist || '-'),
spotify_artist: result.spotify_data && result.spotify_data.artists
? (Array.isArray(result.spotify_data.artists)
? (result.spotify_data.artists
.map(a => (typeof a === 'object' && a !== null) ? (a.name || '') : a)
.filter(Boolean)
.join(', ') || '-')
: result.spotify_data.artists)
: (result.spotify_artist || '-'),
spotify_album: result.spotify_data ? (typeof result.spotify_data.album === 'object' ? result.spotify_data.album.name : result.spotify_data.album) : (result.spotify_album || '-'),
spotify_data: result.spotify_data,
spotify_id: result.spotify_id,
@ -32586,7 +32619,14 @@ function startSpotifyPublicDiscoveryPolling(fakeUrlHash, urlHash) {
status: isWingIt ? '🎯 Wing It' : (isFound ? '✅ Found' : '❌ Not Found'),
status_class: isWingIt ? 'wing-it' : (isFound ? 'found' : 'not-found'),
spotify_track: r.spotify_data ? r.spotify_data.name : (r.spotify_track || '-'),
spotify_artist: r.spotify_data && r.spotify_data.artists ? (Array.isArray(r.spotify_data.artists) ? r.spotify_data.artists.join(', ') : r.spotify_data.artists) : (r.spotify_artist || '-'),
spotify_artist: r.spotify_data && r.spotify_data.artists
? (Array.isArray(r.spotify_data.artists)
? (r.spotify_data.artists
.map(a => (typeof a === 'object' && a !== null) ? (a.name || '') : a)
.filter(Boolean)
.join(', ') || '-')
: r.spotify_data.artists)
: (r.spotify_artist || '-'),
spotify_album: r.spotify_data ? (typeof r.spotify_data.album === 'object' ? r.spotify_data.album.name : r.spotify_data.album) : (r.spotify_album || '-'),
spotify_data: r.spotify_data, spotify_id: r.spotify_id, manual_match: r.manual_match,
wing_it_fallback: isWingIt
@ -32648,8 +32688,14 @@ function startSpotifyPublicDiscoveryPolling(fakeUrlHash, urlHash) {
status: isFound ? '✅ Found' : '❌ Not Found',
status_class: isFound ? 'found' : 'not-found',
spotify_track: result.spotify_data ? result.spotify_data.name : (result.spotify_track || '-'),
spotify_artist: result.spotify_data && result.spotify_data.artists ?
(Array.isArray(result.spotify_data.artists) ? result.spotify_data.artists.join(', ') : result.spotify_data.artists) : (result.spotify_artist || '-'),
spotify_artist: result.spotify_data && result.spotify_data.artists
? (Array.isArray(result.spotify_data.artists)
? (result.spotify_data.artists
.map(a => (typeof a === 'object' && a !== null) ? (a.name || '') : a)
.filter(Boolean)
.join(', ') || '-')
: result.spotify_data.artists)
: (result.spotify_artist || '-'),
spotify_album: result.spotify_data ? (typeof result.spotify_data.album === 'object' ? result.spotify_data.album.name : result.spotify_data.album) : (result.spotify_album || '-'),
spotify_data: result.spotify_data,
spotify_id: result.spotify_id,