Add caching for enhanced search, don't attempt searches with 2 characters or less

This commit is contained in:
Antti Kettunen 2026-04-18 15:01:32 +03:00
parent 688e84ce4d
commit e687486561

View file

@ -2724,6 +2724,63 @@ def add_cache_headers(response, cache_duration=300):
response.headers['Pragma'] = 'cache'
return response
_enhanced_search_cache = collections.OrderedDict()
_enhanced_search_cache_lock = threading.Lock()
_ENHANCED_SEARCH_CACHE_TTL = 600
_ENHANCED_SEARCH_CACHE_MAX_ENTRIES = 100
def _get_enhanced_search_cache_key(query):
"""Build a cache key that follows the current metadata/search configuration."""
normalized_query = (query or '').strip().lower()
try:
active_server = config_manager.get_active_media_server()
except Exception:
active_server = 'unknown'
try:
fallback_source = _get_metadata_fallback_source()
except Exception:
fallback_source = 'unknown'
try:
hydrabase_active = _is_hydrabase_active()
except Exception:
hydrabase_active = False
return (normalized_query, active_server, fallback_source, hydrabase_active)
def _get_cached_enhanced_search_response(cache_key):
"""Return a cached enhanced-search response if it is still fresh."""
now = time.time()
with _enhanced_search_cache_lock:
entry = _enhanced_search_cache.get(cache_key)
if not entry:
return None
if now - entry['timestamp'] < _ENHANCED_SEARCH_CACHE_TTL:
_enhanced_search_cache.move_to_end(cache_key)
return entry['data']
_enhanced_search_cache.pop(cache_key, None)
return None
def _set_cached_enhanced_search_response(cache_key, response_data):
"""Store an enhanced-search response in the short-lived in-memory cache."""
with _enhanced_search_cache_lock:
_enhanced_search_cache[cache_key] = {
'timestamp': time.time(),
'data': response_data,
}
_enhanced_search_cache.move_to_end(cache_key)
while len(_enhanced_search_cache) > _ENHANCED_SEARCH_CACHE_MAX_ENTRIES:
_enhanced_search_cache.popitem(last=False)
# --- Background Download Monitoring (GUI Parity) ---
class WebUIDownloadMonitor:
"""
@ -8474,6 +8531,7 @@ def enhanced_search():
"""
data = request.get_json()
query = data.get('query', '').strip()
cache_key = _get_enhanced_search_cache_key(query)
empty_source = {"artists": [], "albums": [], "tracks": [], "available": False}
@ -8488,6 +8546,11 @@ def enhanced_search():
"metadata_source": "spotify"
})
cached_response = _get_cached_enhanced_search_response(cache_key)
if cached_response is not None:
logger.info(f"Enhanced search cache hit for: '{query}'")
return jsonify(cached_response)
logger.info(f"Enhanced search initiated for: '{query}'")
try:
@ -8507,6 +8570,23 @@ def enhanced_search():
"image_url": image_url
})
# Very short queries are usually broad enough that remote metadata searches
# just add latency without improving the result quality much. Keep them local.
if len(query) < 3:
fb_source = _get_metadata_fallback_source()
response_data = {
"db_artists": db_artists,
"spotify_artists": [],
"spotify_albums": [],
"spotify_tracks": [],
"metadata_source": fb_source,
"primary_source": fb_source,
"alternate_sources": [],
"sources": {},
}
_set_cached_enhanced_search_response(cache_key, response_data)
return jsonify(response_data)
# ── Determine primary source and search it synchronously ──
primary_source = "spotify"
primary_results = empty_source
@ -8575,7 +8655,7 @@ def enhanced_search():
f"{len(primary_results['tracks'])} tracks | "
f"Alt sources available: {alternate_sources}")
return jsonify({
response_data = {
# Backward compat — same shape as before
"db_artists": db_artists,
"spotify_artists": primary_results["artists"],
@ -8585,7 +8665,9 @@ def enhanced_search():
# New multi-source data
"primary_source": primary_source,
"alternate_sources": alternate_sources,
})
}
_set_cached_enhanced_search_response(cache_key, response_data)
return jsonify(response_data)
except Exception as e:
logger.error(f"Enhanced search error: {e}")