From 377343326fcfdfcf0c39586accfa7414c43e8f09 Mon Sep 17 00:00:00 2001 From: Broque Thomas <26755000+Nezreka@users.noreply.github.com> Date: Wed, 22 Apr 2026 12:59:05 -0700 Subject: [PATCH] Dedupe enhanced-search fetch in widget and page, bump to 2.41 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 2 of the Search/Artists unification: the Search page dropdown and the global spotlight widget both POST to /api/enhanced-search with identical boilerplate. Extracted into enhancedSearchFetch() in search.js (loaded before downloads.js). Both callers migrated. Zero UX change — purely sets up Phase 3 to wire a source picker in one place instead of two. --- web_server.py | 12 +++++++++++- webui/static/downloads.js | 8 +------- webui/static/helper.js | 5 +++++ webui/static/search.js | 27 +++++++++++++++++---------- 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/web_server.py b/web_server.py index 426838c4..d2e879b4 100644 --- a/web_server.py +++ b/web_server.py @@ -37,7 +37,7 @@ _log_dir = Path(_log_path).parent logger = setup_logging(_log_level, _log_path) # App version — single source of truth for backup metadata, version-info endpoint, etc. -_SOULSYNC_BASE_VERSION = "2.40" +_SOULSYNC_BASE_VERSION = "2.41" def _build_version_string(): """Append short commit hash to version when available (e.g. 2.35+abc1234).""" @@ -22809,6 +22809,16 @@ def get_version_info(): "title": "What's New in SoulSync", "subtitle": f"Version {SOULSYNC_VERSION} — Latest Changes", "sections": [ + { + "title": "Shared Enhanced-Search Fetch Helper", + "description": "Internal refactor — the Search page and the global search widget now route through one shared fetch helper, so future source-picker work only needs wiring in one place", + "features": [ + "• New enhancedSearchFetch(query, { source, signal }) in search.js", + "• Both callers (Search page dropdown + global widget) deduplicated — single /api/enhanced-search chokepoint", + "• Accepts the source param added in 2.40, letting future UI wire a picker without touching both callers", + "• Zero UX change — pure plumbing (Phase 2 of the Search/Artists unification project)", + ], + }, { "title": "Explicit Source Selection on Enhanced Search", "description": "The /api/enhanced-search endpoint now accepts an optional `source` parameter so callers can target a single metadata source instead of always fanning out across every provider", diff --git a/webui/static/downloads.js b/webui/static/downloads.js index 3b18282f..8610caeb 100644 --- a/webui/static/downloads.js +++ b/webui/static/downloads.js @@ -5492,13 +5492,7 @@ async function _gsPerformSearch(query) { results.classList.add('visible'); try { - const res = await fetch('/api/enhanced-search', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ query }), - signal: _gsState.abortCtrl.signal, - }); - const data = await res.json(); + const data = await enhancedSearchFetch(query, { signal: _gsState.abortCtrl.signal }); _gsState.data = data; _gsState.activeSource = data.primary_source || 'spotify'; _gsState.sources = {}; diff --git a/webui/static/helper.js b/webui/static/helper.js index b3687b05..eff92aec 100644 --- a/webui/static/helper.js +++ b/webui/static/helper.js @@ -3599,6 +3599,11 @@ function closeHelperSearch() { // ═══════════════════════════════════════════════════════════════════════════ const WHATS_NEW = { + '2.41': [ + // --- April 22, 2026 (late night) --- + { date: 'April 22, 2026 (late night)' }, + { title: 'Shared Enhanced-Search Fetch Helper', desc: 'Internal refactor — the Search page dropdown and the global search widget now route through one shared enhancedSearchFetch helper in search.js, so both callers hit /api/enhanced-search through a single chokepoint. Zero UX change, but it means the upcoming source picker (Phase 3) only needs wiring in one place instead of two. Also lets both surfaces accept the source parameter added in 2.40 (Phase 2 of the Search/Artists unification project)', page: 'downloads' }, + ], '2.40': [ // --- April 22, 2026 (late) --- { date: 'April 22, 2026 (late)' }, diff --git a/webui/static/search.js b/webui/static/search.js index 2931d91b..cbf19504 100644 --- a/webui/static/search.js +++ b/webui/static/search.js @@ -1,6 +1,22 @@ // SEARCH FUNCTIONALITY // =============================== +// Shared enhanced-search fetch used by the Search page and the global widget. +// Pass source to restrict results to a single metadata provider; omit or pass +// null/'auto' to let the backend fan out across all configured sources. +async function enhancedSearchFetch(query, { source = null, signal = null } = {}) { + const body = { query }; + if (source && source !== 'auto') body.source = source; + const res = await fetch('/api/enhanced-search', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(body), + signal: signal || undefined, + }); + if (!res.ok) throw new Error(`Enhanced search failed: ${res.status}`); + return res.json(); +} + function initializeSearch() { // --- FIX: Corrected the element IDs to match the HTML --- const searchInput = document.getElementById('downloads-search-input'); @@ -225,16 +241,7 @@ function initializeSearchModeToggle() { _enhancedSearchData = { db_artists: [], primary_source: null, sources: {}, searchId, query }; try { - const response = await fetch('/api/enhanced-search', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ query }), - signal: abortController.signal - }); - - if (!response.ok) throw new Error('Search failed'); - - const data = await response.json(); + const data = await enhancedSearchFetch(query, { signal: abortController.signal }); console.log('Enhanced results:', data); // Store multi-source state