From 99481a02324e9618969fd1ad5072aceb1b60e573 Mon Sep 17 00:00:00 2001 From: Broque Thomas <26755000+Nezreka@users.noreply.github.com> Date: Thu, 19 Mar 2026 08:23:19 -0700 Subject: [PATCH] Fix Track Match search ignoring Track/Artist fields and low result limit - Frontend was concatenating Track and Artist inputs into a single query string, causing Spotify to return mixed results matching either word in any field. Now sends track and artist as separate params; backend builds field-filtered query (track:X artist:Y). - Result limit was silently capped at 10 in spotify_client.search_tracks via min(limit, 10). Raised to respect requested limit up to Spotify's API max of 50. - iTunes fallback endpoint updated with same field-specific params. - Legacy ?query= param still supported for backward compatibility. Fixes #194 --- core/spotify_client.py | 7 ++++--- web_server.py | 33 +++++++++++++++++++++++++++++---- webui/static/script.js | 24 ++++++++++++++++++------ 3 files changed, 51 insertions(+), 13 deletions(-) diff --git a/core/spotify_client.py b/core/spotify_client.py index f06ff955..aee617a5 100644 --- a/core/spotify_client.py +++ b/core/spotify_client.py @@ -955,7 +955,8 @@ class SpotifyClient: if use_spotify: # Check Spotify cache - cached_results = cache.get_search_results('spotify', 'track', query, min(limit, 10)) + effective_limit = min(limit, 50) # Spotify API max is 50 + cached_results = cache.get_search_results('spotify', 'track', query, effective_limit) if cached_results is not None: tracks = [] for raw in cached_results: @@ -967,7 +968,7 @@ class SpotifyClient: return tracks try: - results = self.sp.search(q=query, type='track', limit=min(limit, 10)) + results = self.sp.search(q=query, type='track', limit=effective_limit) tracks = [] raw_items = results['tracks']['items'] @@ -979,7 +980,7 @@ class SpotifyClient: entries = [(td.get('id'), td) for td in raw_items if td.get('id')] if entries: cache.store_entities_bulk('spotify', 'track', entries) - cache.store_search_results('spotify', 'track', query, min(limit, 10), + cache.store_search_results('spotify', 'track', query, effective_limit, [td.get('id') for td in raw_items if td.get('id')]) return tracks diff --git a/web_server.py b/web_server.py index 0f5ad099..d89a706a 100644 --- a/web_server.py +++ b/web_server.py @@ -25069,10 +25069,23 @@ def search_spotify_tracks(): return jsonify({"error": "Spotify not authenticated."}), 401 try: - query = request.args.get('query', '').strip() + # Support field-specific search params (track, artist) or legacy combined query + track_q = request.args.get('track', '').strip() + artist_q = request.args.get('artist', '').strip() + legacy_query = request.args.get('query', '').strip() limit = int(request.args.get('limit', 20)) - if not query: + # Build Spotify field-filtered query + if track_q or artist_q: + parts = [] + if track_q: + parts.append(f'track:{track_q}') + if artist_q: + parts.append(f'artist:{artist_q}') + query = ' '.join(parts) + elif legacy_query: + query = legacy_query + else: return jsonify({"error": "Query parameter is required"}), 400 if use_hydrabase: @@ -25101,10 +25114,22 @@ def search_spotify_tracks(): def search_itunes_tracks(): """Search for tracks on iTunes - used by discovery fix modal when iTunes is the source""" try: - query = request.args.get('query', '').strip() + # Support field-specific search params or legacy combined query + track_q = request.args.get('track', '').strip() + artist_q = request.args.get('artist', '').strip() + legacy_query = request.args.get('query', '').strip() limit = int(request.args.get('limit', 20)) - if not query: + if track_q or artist_q: + parts = [] + if track_q: + parts.append(track_q) + if artist_q: + parts.append(artist_q) + query = ' '.join(parts) + elif legacy_query: + query = legacy_query + else: return jsonify({"error": "Query parameter is required"}), 400 use_hydrabase = _is_hydrabase_active() diff --git a/webui/static/script.js b/webui/static/script.js index 8991af5b..803abeeb 100644 --- a/webui/static/script.js +++ b/webui/static/script.js @@ -15392,12 +15392,19 @@ async function searchDiscoveryFix() { resultsContainer.innerHTML = `