Fix seasonal playlist track ID for non-spotify/itunes sources, fix polling interval leak

This commit is contained in:
JohnBaumb 2026-04-23 10:26:17 -07:00
parent 85ea2a810f
commit d7e1cdeb83
4 changed files with 40 additions and 5 deletions

View file

@ -371,8 +371,10 @@ class SeasonalDiscoveryService:
config = SEASONAL_CONFIG[season_key]
keywords = config['keywords']
# Use the right track ID column based on source
track_id_col = 'spotify_track_id' if source == 'spotify' else 'itunes_track_id'
# itunes stores IDs in itunes_track_id; all other sources
# (spotify, deezer, discogs, hydrabase, etc.) use spotify_track_id
# as the generic ID column.
track_id_col = 'itunes_track_id' if source == 'itunes' else 'spotify_track_id'
seasonal_tracks = []

View file

@ -44348,7 +44348,10 @@ def get_current_seasonal_playlist():
if not track_ids:
return jsonify({"success": True, "tracks": []})
track_id_col = 'spotify_track_id' if active_source == 'spotify' else 'itunes_track_id'
# itunes stores IDs in itunes_track_id; all other sources
# (spotify, deezer, discogs, hydrabase, etc.) use spotify_track_id
# as the generic ID column.
track_id_col = 'itunes_track_id' if active_source == 'itunes' else 'spotify_track_id'
tracks = []
with database._get_connection() as conn:
cursor = conn.cursor()
@ -44477,8 +44480,10 @@ def get_seasonal_playlist(season_key):
if not track_ids:
return jsonify({"success": True, "tracks": []})
# Use source-appropriate ID column for lookups
track_id_col = 'spotify_track_id' if active_source == 'spotify' else 'itunes_track_id'
# itunes stores IDs in itunes_track_id; all other sources
# (spotify, deezer, discogs, hydrabase, etc.) use spotify_track_id
# as the generic ID column.
track_id_col = 'itunes_track_id' if active_source == 'itunes' else 'spotify_track_id'
# Fetch track details from seasonal tracks or discovery pool (filtered by source)
tracks = []

View file

@ -9332,7 +9332,23 @@ function pollDiscoverSyncFromTab(playlistType, virtualPlaylistId, playlistName)
}
function pollDiscoverBatchFromTab(playlistType, batchId, playlistName) {
// Clear any existing poller for this playlist type
if (discoverSyncPollers[playlistType]) {
clearInterval(discoverSyncPollers[playlistType]);
delete discoverSyncPollers[playlistType];
}
let ticks = 0;
const maxTicks = 600; // 30 min at 3s intervals
const pollInterval = setInterval(async () => {
ticks++;
// Stall guard — stop polling after maxTicks or if the card is no longer in DOM
if (ticks > maxTicks || !document.getElementById(`discover-sync-card-${playlistType}`)) {
clearInterval(pollInterval);
delete discoverSyncPollers[playlistType];
return;
}
try {
const resp = await fetch(`/api/playlists/${batchId}/download_status`);
if (!resp.ok) { clearInterval(pollInterval); return; }
@ -9341,6 +9357,7 @@ function pollDiscoverBatchFromTab(playlistType, batchId, playlistName) {
if (phase === 'complete' || phase === 'error' || phase === 'cancelled') {
clearInterval(pollInterval);
delete discoverSyncPollers[playlistType];
const btn = document.getElementById(`discover-sync-btn-${playlistType}`);
if (btn) { btn.disabled = false; btn.textContent = '\u27f3 Sync Now'; }
@ -9387,8 +9404,12 @@ function pollDiscoverBatchFromTab(playlistType, batchId, playlistName) {
}
} catch (error) {
clearInterval(pollInterval);
delete discoverSyncPollers[playlistType];
}
}, 3000);
// Register so page-leave cleanup can clear it
discoverSyncPollers[playlistType] = pollInterval;
}
/**

View file

@ -2243,6 +2243,13 @@ async function loadPageData(pageId) {
if (typeof _stopNebulaLivePolling === 'function') _stopNebulaLivePolling();
if (pageId !== 'sync') {
cleanupBeatportContent();
// Clear any discover sync tab pollers when leaving the sync page
if (typeof discoverSyncPollers === 'object') {
for (const key of Object.keys(discoverSyncPollers)) {
clearInterval(discoverSyncPollers[key]);
delete discoverSyncPollers[key];
}
}
}
switch (pageId) {
case 'dashboard':