Show "Running (Spotify Free)" instead of "rate limited" while the worker bridges
#798 follow-up. When the real Spotify API is banned but the worker keeps matching via the no-creds Spotify Free source, every status surface still read the literal rate_limited=True flag and showed "Rate Limited / waiting Nm" — so the dashboard bubble looked paused/stuck even though the worker (visible in Manage Workers) was actively matching. - spotify_worker.get_stats() adds a `using_free` flag: rate_limited AND is_spotify_metadata_available(). Computed ONLY when rate-limited, where is_spotify_authenticated() returns False without an API probe, so the 2s status loop pays no quota cost. - Dashboard bubble (enrichment.js): when using_free, the bubble is 'active', the tooltip says "Running (Spotify Free)" and "Now: X (via Spotify Free)" instead of "Rate Limited / Waiting Nm". Clicking it pauses (works) rather than hitting the resume-blocked toast. - Manage Workers (enrichment-manager.js): status pill shows "Running (Spotify Free)"; the warning banner is replaced with a calm "matching via Spotify Free until the ban lifts" note. The flag flows through both feeds (the /api/enrichment/spotify/status poll and the WebSocket enrichment:* push) since both serialize get_stats(). Genuinely-stuck (no-free) workers still show "Rate Limited".
This commit is contained in:
parent
12038bde08
commit
3fcfa900bd
3 changed files with 25 additions and 3 deletions
|
|
@ -126,11 +126,19 @@ class SpotifyWorker:
|
|||
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
|
||||
# Is the worker still serving via the no-creds Spotify Free source
|
||||
# despite the real-API ban? Only check WHEN rate-limited: during a
|
||||
# ban is_spotify_authenticated() returns False without an API probe,
|
||||
# so is_spotify_metadata_available() reduces to "is free available"
|
||||
# (no quota cost). Lets the UI show "via Spotify Free" instead of a
|
||||
# misleading "rate limited / waiting" while the worker keeps matching.
|
||||
using_free = bool(rate_limited and self.client.is_spotify_metadata_available())
|
||||
except Exception:
|
||||
authenticated = False
|
||||
rate_limited = False
|
||||
rate_limit_info = None
|
||||
in_cooldown = False
|
||||
using_free = False
|
||||
|
||||
return {
|
||||
'enabled': True,
|
||||
|
|
@ -139,6 +147,7 @@ class SpotifyWorker:
|
|||
'idle': is_idle,
|
||||
'authenticated': authenticated,
|
||||
'rate_limited': rate_limited,
|
||||
'using_free': using_free,
|
||||
'rate_limit': rate_limit_info,
|
||||
'daily_budget': self._get_daily_budget_info(),
|
||||
'current_item': self.current_item,
|
||||
|
|
|
|||
|
|
@ -274,6 +274,9 @@ async function _emPollSelected() {
|
|||
|
||||
function _emStatusInfo(status) {
|
||||
if (!status || !status.enabled) return { cls: 'disabled', label: 'Disabled' };
|
||||
// Rate-limited on the real API but still matching via the no-creds Spotify
|
||||
// Free source — show as running, not stuck (#798 bridge).
|
||||
if (status.using_free) return { cls: 'running', label: 'Running (Spotify Free)' };
|
||||
if (status.rate_limited) return { cls: 'ratelimited', label: 'Rate-limited' };
|
||||
if (status.paused) return { cls: 'paused', label: 'Paused' };
|
||||
if (status.idle) return { cls: 'idle', label: 'Idle' };
|
||||
|
|
@ -709,6 +712,9 @@ function _emUpdateHeaderLive() {
|
|||
cls += ' em-banner--warn';
|
||||
html = '⚙️ This source isn’t configured — add its credentials in Settings. '
|
||||
+ 'Browsing works, but matches and retries won’t run until it’s set up.';
|
||||
} else if (status && status.using_free) {
|
||||
// Real API banned but bridging via the no-creds Spotify Free source.
|
||||
html = '✓ Spotify is rate-limited — matching via Spotify Free until the ban lifts.';
|
||||
} else if (status && status.rate_limited) {
|
||||
cls += ' em-banner--warn';
|
||||
const rl = status.rate_limit || {};
|
||||
|
|
|
|||
|
|
@ -457,6 +457,10 @@ function updateSpotifyEnrichmentStatusFromData(data) {
|
|||
|
||||
const notAuthenticated = data.authenticated === false;
|
||||
const isRateLimited = data.rate_limited === true;
|
||||
// The real API is banned but the worker is still matching via the no-creds
|
||||
// Spotify Free source — treat it as running, not stuck (#798 bridge).
|
||||
const bridgingFree = data.using_free === true;
|
||||
const rateLimitedStuck = isRateLimited && !bridgingFree;
|
||||
const budgetExhausted = data.daily_budget && data.daily_budget.exhausted;
|
||||
|
||||
button.classList.remove('active', 'paused', 'complete', 'no-auth');
|
||||
|
|
@ -464,7 +468,7 @@ function updateSpotifyEnrichmentStatusFromData(data) {
|
|||
button.classList.add('paused');
|
||||
} else if (notAuthenticated) {
|
||||
button.classList.add('no-auth');
|
||||
} else if (isRateLimited || budgetExhausted) {
|
||||
} else if (rateLimitedStuck || budgetExhausted) {
|
||||
button.classList.add('paused');
|
||||
} else if (data.idle) {
|
||||
button.classList.add('complete');
|
||||
|
|
@ -479,7 +483,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 (rateLimitedStuck) { tooltipStatus.textContent = 'Rate Limited'; }
|
||||
else if (bridgingFree) { tooltipStatus.textContent = 'Running (Spotify Free)'; }
|
||||
else if (budgetExhausted) { tooltipStatus.textContent = 'Daily Limit Reached'; }
|
||||
else if (data.idle) { tooltipStatus.textContent = 'Complete'; }
|
||||
else if (data.running) { tooltipStatus.textContent = 'Running'; }
|
||||
|
|
@ -491,10 +496,12 @@ 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) {
|
||||
} else if (rateLimitedStuck) {
|
||||
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 (bridgingFree && data.current_item && data.current_item.name) {
|
||||
tooltipCurrent.textContent = `Now: ${data.current_item.name} (via Spotify Free)`;
|
||||
} else if (budgetExhausted) {
|
||||
const resets = data.daily_budget.resets_in_seconds || 0;
|
||||
const hours = Math.floor(resets / 3600);
|
||||
|
|
|
|||
Loading…
Reference in a new issue