Fix enrichment widget showing Running when rate limited (#217)
The tooltip only checked paused/authenticated/idle/running states. When Spotify was rate limited or daily budget exhausted, the worker thread was still alive (sleeping in guards) so it showed "Running" with no current item and stale 0% progress. Now checks rate_limited and daily_budget.exhausted before running: - Rate limited: "Rate Limited — Waiting Xm for rate limit to clear" - Budget exhausted: "Daily Limit Reached — Resets in Xh Xm" - No current item: "Waiting for next item..." instead of blank Also adds rate_limit info object to get_stats() response for the countdown display.
This commit is contained in:
parent
59587162cd
commit
7133595e0d
4 changed files with 30 additions and 0 deletions
|
|
@ -107,11 +107,13 @@ class SpotifyWorker:
|
|||
# every 60 seconds indefinitely, wasting API quota and risking rate limits.
|
||||
# Instead, use sp presence as a lightweight proxy for "configured".
|
||||
rate_limited = self.client.is_rate_limited()
|
||||
rate_limit_info = self.client.get_rate_limit_info() if rate_limited else None
|
||||
in_cooldown = self.client.get_post_ban_cooldown_remaining() > 0
|
||||
authenticated = self.client.sp is not None
|
||||
except Exception:
|
||||
authenticated = False
|
||||
rate_limited = False
|
||||
rate_limit_info = None
|
||||
in_cooldown = False
|
||||
|
||||
return {
|
||||
|
|
@ -121,6 +123,7 @@ class SpotifyWorker:
|
|||
'idle': is_idle,
|
||||
'authenticated': authenticated,
|
||||
'rate_limited': rate_limited,
|
||||
'rate_limit': rate_limit_info,
|
||||
'daily_budget': self._get_daily_budget_info(),
|
||||
'current_item': self.current_item,
|
||||
'stats': self.stats.copy(),
|
||||
|
|
|
|||
|
|
@ -19071,6 +19071,15 @@ def get_version_info():
|
|||
"title": "What's New in SoulSync",
|
||||
"subtitle": f"Version {SOULSYNC_VERSION} — Latest Changes",
|
||||
"sections": [
|
||||
{
|
||||
"title": "🔧 Fix Enrichment Widget Showing 'Running' When Rate Limited",
|
||||
"description": "Enrichment tooltip now shows Rate Limited or Daily Limit Reached instead of stuck on Running",
|
||||
"features": [
|
||||
"• Shows 'Rate Limited' with countdown when Spotify rate limit is active",
|
||||
"• Shows 'Daily Limit Reached' with reset time when daily budget is exhausted",
|
||||
"• Shows 'Waiting for next item...' instead of blank when no current item"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "🧹 Metadata Cache Maintenance",
|
||||
"description": "The cache evictor now runs four maintenance phases to keep the metadata cache clean",
|
||||
|
|
|
|||
|
|
@ -3403,6 +3403,7 @@ function closeHelperSearch() {
|
|||
const WHATS_NEW = {
|
||||
'2.1': [
|
||||
// Newest features first
|
||||
{ title: 'Fix Enrichment Status Widget', desc: 'Enrichment tooltip now shows Rate Limited or Daily Limit instead of stuck on Running' },
|
||||
{ title: 'Cache Maintenance', desc: 'Cache evictor now cleans junk entities, orphaned searches, and stale MusicBrainz nulls' },
|
||||
{ title: 'Fix Wishlist Download Selection', desc: 'Download Selection now only downloads checked tracks instead of the entire category' },
|
||||
{ title: 'Fix Tidal OAuth in Docker', desc: 'Tidal redirect URI now uses configured setting instead of Docker container hostname' },
|
||||
|
|
|
|||
|
|
@ -54012,12 +54012,16 @@ function updateSpotifyEnrichmentStatusFromData(data) {
|
|||
if (!button) return;
|
||||
|
||||
const notAuthenticated = data.authenticated === false;
|
||||
const isRateLimited = data.rate_limited === true;
|
||||
const budgetExhausted = data.daily_budget && data.daily_budget.exhausted;
|
||||
|
||||
button.classList.remove('active', 'paused', 'complete', 'no-auth');
|
||||
if (data.paused) {
|
||||
button.classList.add('paused');
|
||||
} else if (notAuthenticated) {
|
||||
button.classList.add('no-auth');
|
||||
} else if (isRateLimited || budgetExhausted) {
|
||||
button.classList.add('paused');
|
||||
} else if (data.idle) {
|
||||
button.classList.add('complete');
|
||||
} else if (data.running && !data.paused) {
|
||||
|
|
@ -54031,6 +54035,8 @@ function updateSpotifyEnrichmentStatusFromData(data) {
|
|||
if (tooltipStatus) {
|
||||
if (data.paused) { tooltipStatus.textContent = 'Paused'; }
|
||||
else if (notAuthenticated) { tooltipStatus.textContent = 'Not Authenticated'; }
|
||||
else if (isRateLimited) { tooltipStatus.textContent = 'Rate Limited'; }
|
||||
else if (budgetExhausted) { tooltipStatus.textContent = 'Daily Limit Reached'; }
|
||||
else if (data.idle) { tooltipStatus.textContent = 'Complete'; }
|
||||
else if (data.running) { tooltipStatus.textContent = 'Running'; }
|
||||
else { tooltipStatus.textContent = 'Idle'; }
|
||||
|
|
@ -54041,10 +54047,21 @@ function updateSpotifyEnrichmentStatusFromData(data) {
|
|||
tooltipCurrent.textContent = notAuthenticated ? 'Connect Spotify in Settings to enrich' : 'Click to resume';
|
||||
} else if (notAuthenticated) {
|
||||
tooltipCurrent.textContent = 'Connect Spotify in Settings to enrich';
|
||||
} else if (isRateLimited) {
|
||||
const info = data.rate_limit || {};
|
||||
const remaining = info.remaining_seconds || 0;
|
||||
tooltipCurrent.textContent = remaining > 0 ? `Waiting ${Math.ceil(remaining / 60)}m for rate limit to clear` : 'Waiting for rate limit to clear';
|
||||
} else if (budgetExhausted) {
|
||||
const resets = data.daily_budget.resets_in_seconds || 0;
|
||||
const hours = Math.floor(resets / 3600);
|
||||
const mins = Math.floor((resets % 3600) / 60);
|
||||
tooltipCurrent.textContent = `Resets in ${hours}h ${mins}m`;
|
||||
} else if (data.idle) {
|
||||
tooltipCurrent.textContent = 'All items processed';
|
||||
} else if (data.current_item && data.current_item.name) {
|
||||
tooltipCurrent.textContent = `Now: ${data.current_item.name}`;
|
||||
} else {
|
||||
tooltipCurrent.textContent = 'Waiting for next item...';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue