diff --git a/web_server.py b/web_server.py index 7e2cd7e0..c95a1f54 100644 --- a/web_server.py +++ b/web_server.py @@ -5718,27 +5718,42 @@ def auth_tidal(): return f"

Tidal Authentication Error

{str(e)}

", 500 -def _spotify_auth_success_page(detail_text: str) -> str: - """Return the post-auth success page and notify the opener.""" +def _spotify_auth_result_page(detail_text: str, authenticated: bool = True) -> str: + """Return the post-auth page and notify the opener.""" + title = "Spotify Authentication Successful" if authenticated else "Spotify Authentication Completed" + heading = title + close_script = """ + setTimeout(() => window.close(), 300); + """ if authenticated else """ + const closeBtn = document.getElementById('close-window-btn'); + if (closeBtn) { + closeBtn.addEventListener('click', () => window.close()); + } + """ return f""" - Spotify Authentication Successful + {title} -

Spotify Authentication Successful

+

{heading}

{detail_text}

+ {'' if not authenticated else ''} @@ -5803,10 +5818,22 @@ def spotify_callback(): ) token_info = auth_manager.get_access_token(auth_code) if token_info: - # Invalidate cached profile client so it gets recreated with new tokens metadata_registry.clear_cached_profile_spotify_client(profile_id_from_state) - add_activity_item("", "Spotify Auth Complete", f"Profile {profile_id_from_state} authenticated with Spotify", "Now") - return _spotify_auth_success_page("Your personal Spotify account is now connected. You can close this window.") + profile_client = metadata_registry.get_spotify_client_for_profile(profile_id_from_state) + profile_authenticated = bool(profile_client and profile_client.is_spotify_authenticated()) + if profile_authenticated: + if profile_client: + profile_client._invalidate_auth_cache() + add_activity_item("", "Spotify Auth Complete", f"Profile {profile_id_from_state} authenticated with Spotify", "Now") + return _spotify_auth_result_page("Your personal Spotify account is now connected. You can close this window.", authenticated=True) + if profile_client: + profile_client._invalidate_auth_cache() + _status_cache_timestamps['spotify'] = 0 + add_activity_item("", "Spotify Auth Warning", f"Profile {profile_id_from_state} completed OAuth but Spotify did not confirm an authenticated session", "Now") + return _spotify_auth_result_page( + "Spotify authorization completed, but SoulSync could not confirm an authenticated Spotify session for this profile. You can close this window and try Authenticate again.", + authenticated=False, + ) else: raise Exception("Failed to exchange authorization code for access token") @@ -5843,9 +5870,16 @@ def spotify_callback(): spotify_enrichment_worker.client.reload_config() spotify_enrichment_worker.client._invalidate_auth_cache() add_activity_item("", "Spotify Auth Complete", "Successfully authenticated with Spotify", "Now") - return _spotify_auth_success_page("You can close this window.") + return _spotify_auth_result_page("You can close this window.", authenticated=True) else: - raise Exception("Token exchange succeeded but authentication validation failed") + logger.warning("Spotify OAuth token exchange succeeded but authentication validation failed") + spotify_client._invalidate_auth_cache() + _status_cache_timestamps['spotify'] = 0 + add_activity_item("", "Spotify Auth Warning", "OAuth completed, but Spotify did not confirm an authenticated session", "Now") + return _spotify_auth_result_page( + "Spotify authorization completed, but SoulSync could not confirm an authenticated Spotify session. You can close this window and try Authenticate again.", + authenticated=False, + ) else: raise Exception("Failed to exchange authorization code for access token") except Exception as e: @@ -31989,9 +32023,19 @@ def start_oauth_callback_servers(): self.send_response(200) self.send_header('Content-type', 'text/html') self.end_headers() - self.wfile.write(_spotify_auth_success_page("You can close this window.").encode("utf-8")) + self.wfile.write(_spotify_auth_result_page("You can close this window.", authenticated=True).encode("utf-8")) else: - raise Exception("Token exchange succeeded but authentication validation failed") + _oauth_logger.warning("Spotify token exchange succeeded but authentication validation failed") + spotify_client._invalidate_auth_cache() + _status_cache_timestamps['spotify'] = 0 + add_activity_item("", "Spotify Auth Warning", "OAuth completed, but Spotify did not confirm an authenticated session", "Now") + self.send_response(200) + self.send_header('Content-type', 'text/html') + self.end_headers() + self.wfile.write(_spotify_auth_result_page( + "Spotify authorization completed, but SoulSync could not confirm an authenticated Spotify session. You can close this window and try Authenticate again.", + authenticated=False, + ).encode("utf-8")) else: raise Exception("Failed to exchange authorization code for access token") except Exception as e: diff --git a/webui/static/shared-helpers.js b/webui/static/shared-helpers.js index 92e5246b..6cad27f8 100644 --- a/webui/static/shared-helpers.js +++ b/webui/static/shared-helpers.js @@ -3121,6 +3121,12 @@ function initializeSpotifyAuthCompletionListener() { try { window._spotifyAuthWindow = null; await _forceServiceStatusRefresh(); + if (event.data.authenticated === false) { + showToast( + event.data.detail || 'Spotify authorization completed, but no authenticated session was detected.', + 'warning' + ); + } } catch (error) { console.warn('Could not refresh Spotify status after auth completion:', error); }