Fix Tidal playlists showing 0 tracks and broken auto-mirror

The metadata-only optimization broke two things:
1. Cards showed 0 tracks because tracks were no longer in the listing
2. Auto-mirror skipped all playlists because tracks array was empty

Fix: cards render instantly from metadata, then tracks are fetched
per-playlist in the background via /api/tidal/playlist/<id>. As each
playlist's tracks arrive, the card count updates and the playlist
is auto-mirrored. Also tried multiple V2 attribute names for track
count (numberOfTracks, numberOfItems, etc.) and fixed the card DOM
selector for count updates.
This commit is contained in:
Broque Thomas 2026-03-31 09:33:52 -07:00
parent 3154d16cf3
commit 8bb2729dc3
2 changed files with 36 additions and 4 deletions

View file

@ -647,7 +647,14 @@ class TidalClient:
tracks=[], # Empty — fetched on-demand via get_playlist()
)
# Store track count from metadata (no API call needed)
new_playlist.track_count = attributes.get('numberOfTracks', 0)
# V2 API may use different field names depending on version
new_playlist.track_count = (
attributes.get('numberOfTracks') or
attributes.get('numberOfItems') or
attributes.get('totalNumberOfItems') or
attributes.get('nrOfTracks') or
0
)
if image_url:
new_playlist.image_url = image_url

View file

@ -23168,16 +23168,41 @@ async function loadTidalPlaylists() {
console.log(`🎵 Loaded ${tidalPlaylists.length} Tidal playlists`);
// Auto-mirror Tidal playlists that have tracks
tidalPlaylists.forEach(p => {
// Auto-mirror Tidal playlists: fetch tracks in background then mirror
// Cards render instantly from metadata; tracks load per-playlist without blocking UI
for (const p of tidalPlaylists) {
// Skip if already have tracks from a previous load
if (p.tracks && p.tracks.length > 0) {
mirrorPlaylist('tidal', p.id, p.name, p.tracks.map(t => ({
track_name: t.name || '', artist_name: Array.isArray(t.artists) ? t.artists[0] : (t.artists || ''),
album_name: typeof t.album === 'string' ? t.album : '', duration_ms: t.duration_ms || 0,
source_track_id: t.id || ''
})), { owner: p.owner, image_url: p.image_url, description: p.description });
continue;
}
});
// Fetch tracks on-demand for this playlist
try {
const fullResp = await fetch(`/api/tidal/playlist/${p.id}`);
if (fullResp.ok) {
const fullData = await fullResp.json();
if (fullData.tracks && fullData.tracks.length > 0) {
p.tracks = fullData.tracks;
p.track_count = fullData.tracks.length;
// Update card track count in UI
const countEl = document.querySelector(`#tidal-card-${p.id} .playlist-card-track-count`);
if (countEl) countEl.textContent = `${fullData.tracks.length} tracks`;
// Mirror with full track data
mirrorPlaylist('tidal', p.id, p.name, fullData.tracks.map(t => ({
track_name: t.name || '', artist_name: Array.isArray(t.artists) ? t.artists[0] : (t.artists || ''),
album_name: typeof t.album === 'string' ? t.album : '', duration_ms: t.duration_ms || 0,
source_track_id: t.id || ''
})), { owner: p.owner, image_url: p.image_url, description: p.description });
}
}
} catch (e) {
console.warn(`Failed to fetch tracks for Tidal playlist ${p.name}: ${e.message}`);
}
}
// Load and apply saved discovery states from backend (like YouTube)
await loadTidalPlaylistStatesFromBackend();