Replace Enhanced/Basic toggle with source picker, bump to 2.42
Phase 3 of the Search/Artists unification. The Search page's two-mode toggle is replaced by a single 'Search from' dropdown: All sources (Auto), Spotify, Apple Music, Deezer, Discogs, Hydrabase, MusicBrainz, or Soulseek (raw files). Auto keeps today's fan-out behavior for backwards compatibility; picking a specific source hits only that provider. 'Soulseek' routes to the raw-file basic section, so one picker covers both old modes. Loading text and the enhanced fetch now respect the selected source. Zero API changes — uses the source param added in 2.40 and the shared fetch helper from 2.41.
This commit is contained in:
parent
377343326f
commit
68d46c5aba
5 changed files with 135 additions and 41 deletions
|
|
@ -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.41"
|
||||
_SOULSYNC_BASE_VERSION = "2.42"
|
||||
|
||||
def _build_version_string():
|
||||
"""Append short commit hash to version when available (e.g. 2.35+abc1234)."""
|
||||
|
|
@ -22809,6 +22809,19 @@ def get_version_info():
|
|||
"title": "What's New in SoulSync",
|
||||
"subtitle": f"Version {SOULSYNC_VERSION} — Latest Changes",
|
||||
"sections": [
|
||||
{
|
||||
"title": "Search Source Picker — Pick Where You're Searching",
|
||||
"description": "The Search page's Enhanced/Basic toggle is replaced by a single 'Search from' dropdown so you can explicitly pick which source to query instead of fanning out to every provider",
|
||||
"features": [
|
||||
"• Choose from: All sources (Auto), Spotify, Apple Music, Deezer, Discogs, Hydrabase, MusicBrainz, or Soulseek (raw files)",
|
||||
"• Auto keeps today's multi-source fan-out behavior — no change if you want the current results",
|
||||
"• Picking a specific source hits only that provider — no more surprise Spotify rate-limit hits from flows that didn't need Spotify",
|
||||
"• 'Soulseek' routes to the raw-file search (what 'Basic' used to do) — one picker now covers both modes",
|
||||
"• Loading text shows the selected source (e.g., 'Searching across Apple Music and your library...')",
|
||||
"• Phase 3 of the Search/Artists unification project — builds on the shared fetch helper from 2.41",
|
||||
],
|
||||
"usage_note": "Sidebar → Search → pick a source in the 'Search from' dropdown above the search bar."
|
||||
},
|
||||
{
|
||||
"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",
|
||||
|
|
|
|||
|
|
@ -1869,18 +1869,21 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Search Mode Toggle -->
|
||||
<div class="search-mode-toggle-container">
|
||||
<div class="search-mode-toggle" data-active="enhanced">
|
||||
<button class="search-mode-btn active" data-mode="enhanced">
|
||||
<span class="mode-icon">✨</span>
|
||||
<span class="mode-label">Enhanced Search</span>
|
||||
</button>
|
||||
<button class="search-mode-btn" data-mode="basic">
|
||||
<span class="mode-icon">🔍</span>
|
||||
<span class="mode-label">Basic Search</span>
|
||||
</button>
|
||||
<div class="toggle-slider"></div>
|
||||
<!-- Search Source Picker (replaces Enhanced/Basic toggle) -->
|
||||
<div class="search-source-picker-container">
|
||||
<label for="search-source-select" class="search-source-picker-label">Search from</label>
|
||||
<div class="search-source-picker-wrapper">
|
||||
<select id="search-source-select" class="search-source-picker-select">
|
||||
<option value="auto" selected>All sources (Auto)</option>
|
||||
<option value="spotify">Spotify</option>
|
||||
<option value="itunes">Apple Music</option>
|
||||
<option value="deezer">Deezer</option>
|
||||
<option value="discogs">Discogs</option>
|
||||
<option value="hydrabase">Hydrabase</option>
|
||||
<option value="musicbrainz">MusicBrainz</option>
|
||||
<option value="soulseek">Soulseek (raw files)</option>
|
||||
</select>
|
||||
<span class="search-source-picker-caret">▾</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -3599,6 +3599,11 @@ function closeHelperSearch() {
|
|||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
const WHATS_NEW = {
|
||||
'2.42': [
|
||||
// --- April 23, 2026 ---
|
||||
{ date: 'April 23, 2026' },
|
||||
{ title: 'Search Source Picker — Pick Where You\'re Searching', desc: 'The Search page\'s Enhanced/Basic toggle is replaced by a single "Search from" dropdown at the top. Choose All sources (Auto — keeps today\'s multi-source fan-out), Spotify, Apple Music, Deezer, Discogs, Hydrabase, MusicBrainz, or Soulseek (raw files). Picking a specific source hits only that provider — no more surprise Spotify rate-limit hits from flows that didn\'t need Spotify. "Soulseek" routes to the raw-file search (what "Basic" used to do), so one picker now covers both modes. Loading text reflects the selected source (e.g., "Searching across Apple Music..."). Phase 3 of the Search/Artists unification project', page: 'downloads' },
|
||||
],
|
||||
'2.41': [
|
||||
// --- April 22, 2026 (late night) ---
|
||||
{ date: 'April 22, 2026 (late night)' },
|
||||
|
|
|
|||
|
|
@ -56,41 +56,38 @@ function initializeSearchModeToggle() {
|
|||
return;
|
||||
}
|
||||
|
||||
const toggleContainer = document.querySelector('.search-mode-toggle');
|
||||
const modeBtns = document.querySelectorAll('.search-mode-btn');
|
||||
const sourceSelect = document.getElementById('search-source-select');
|
||||
const basicSection = document.getElementById('basic-search-section');
|
||||
const enhancedSection = document.getElementById('enhanced-search-section');
|
||||
|
||||
if (!toggleContainer || !modeBtns.length || !basicSection || !enhancedSection) {
|
||||
console.warn('Search mode toggle elements not found');
|
||||
if (!sourceSelect || !basicSection || !enhancedSection) {
|
||||
console.warn('Search source picker elements not found');
|
||||
return;
|
||||
}
|
||||
|
||||
searchModeToggleInitialized = true;
|
||||
console.log('✅ Initializing search mode toggle (first time only)');
|
||||
console.log('✅ Initializing search source picker (first time only)');
|
||||
|
||||
modeBtns.forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
const mode = btn.dataset.mode;
|
||||
// Current source selection — 'auto' (fan-out) by default. Soulseek routes
|
||||
// to the raw-file basic search; everything else routes to enhanced.
|
||||
let currentSearchSource = sourceSelect.value || 'auto';
|
||||
|
||||
// Update button active states
|
||||
modeBtns.forEach(b => b.classList.remove('active'));
|
||||
btn.classList.add('active');
|
||||
const applySourceSelection = (value) => {
|
||||
currentSearchSource = value;
|
||||
if (value === 'soulseek') {
|
||||
basicSection.classList.add('active');
|
||||
enhancedSection.classList.remove('active');
|
||||
} else {
|
||||
basicSection.classList.remove('active');
|
||||
enhancedSection.classList.add('active');
|
||||
}
|
||||
};
|
||||
|
||||
// Update toggle slider position
|
||||
toggleContainer.setAttribute('data-active', mode);
|
||||
applySourceSelection(currentSearchSource);
|
||||
|
||||
// Toggle sections
|
||||
if (mode === 'basic') {
|
||||
basicSection.classList.add('active');
|
||||
enhancedSection.classList.remove('active');
|
||||
console.log('Switched to basic search mode');
|
||||
} else {
|
||||
basicSection.classList.remove('active');
|
||||
enhancedSection.classList.add('active');
|
||||
console.log('Switched to enhanced search mode');
|
||||
}
|
||||
});
|
||||
sourceSelect.addEventListener('change', (e) => {
|
||||
applySourceSelection(e.target.value);
|
||||
console.log('Search source →', currentSearchSource);
|
||||
});
|
||||
|
||||
// Initialize enhanced search
|
||||
|
|
@ -221,7 +218,14 @@ function initializeSearchModeToggle() {
|
|||
showDropdown();
|
||||
const loadingText = document.getElementById('enhanced-loading-text');
|
||||
if (loadingText) {
|
||||
loadingText.textContent = `Searching across ${currentMusicSourceName} and your library...`;
|
||||
const _sourceLabelMap = {
|
||||
spotify: 'Spotify', itunes: 'Apple Music', deezer: 'Deezer',
|
||||
discogs: 'Discogs', hydrabase: 'Hydrabase', musicbrainz: 'MusicBrainz',
|
||||
};
|
||||
const _sourceName = currentSearchSource && currentSearchSource !== 'auto'
|
||||
? (_sourceLabelMap[currentSearchSource] || currentSearchSource)
|
||||
: currentMusicSourceName;
|
||||
loadingText.textContent = `Searching across ${_sourceName} and your library...`;
|
||||
}
|
||||
loadingState.classList.remove('hidden');
|
||||
emptyState.classList.add('hidden');
|
||||
|
|
@ -241,7 +245,10 @@ function initializeSearchModeToggle() {
|
|||
_enhancedSearchData = { db_artists: [], primary_source: null, sources: {}, searchId, query };
|
||||
|
||||
try {
|
||||
const data = await enhancedSearchFetch(query, { signal: abortController.signal });
|
||||
const data = await enhancedSearchFetch(query, {
|
||||
source: currentSearchSource,
|
||||
signal: abortController.signal,
|
||||
});
|
||||
console.log('Enhanced results:', data);
|
||||
|
||||
// Store multi-source state
|
||||
|
|
|
|||
|
|
@ -32832,10 +32832,76 @@ div.artist-hero-badge {
|
|||
}
|
||||
|
||||
/* ========================================= */
|
||||
/* SEARCH MODE TOGGLE SYSTEM */
|
||||
/* ========================================= */
|
||||
/* SEARCH SOURCE PICKER (replaces Enhanced/Basic toggle) */
|
||||
/* ========================================= */
|
||||
|
||||
/* Toggle Container */
|
||||
.search-source-picker-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.search-source-picker-label {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
font-family: 'Segoe UI', sans-serif;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
.search-source-picker-wrapper {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.search-source-picker-select {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
background: rgba(30, 30, 30, 0.8);
|
||||
border: 1px solid rgba(64, 64, 64, 0.4);
|
||||
border-radius: 10px;
|
||||
color: #ffffff;
|
||||
padding: 10px 40px 10px 16px;
|
||||
font-family: 'Segoe UI', sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
min-width: 220px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.search-source-picker-select:hover {
|
||||
border-color: rgba(138, 43, 226, 0.6);
|
||||
}
|
||||
|
||||
.search-source-picker-select:focus {
|
||||
outline: none;
|
||||
border-color: rgba(138, 43, 226, 0.9);
|
||||
box-shadow: 0 2px 10px rgba(138, 43, 226, 0.35);
|
||||
}
|
||||
|
||||
.search-source-picker-select option {
|
||||
background: #1e1e1e;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.search-source-picker-caret {
|
||||
position: absolute;
|
||||
right: 14px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
pointer-events: none;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Legacy toggle (kept for any other references, but unused by the Search page) */
|
||||
.search-mode-toggle-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
|
|
|||
Loading…
Reference in a new issue