From 3d4372b15448f153d005b23cdb53ae64571e46ec Mon Sep 17 00:00:00 2001 From: orfelorfel23 Date: Sun, 13 Sep 2026 01:02:11 +0200 Subject: [PATCH] fix(suggestions): enable combined search, progressive BPM widening, and include db in docker build --- .dockerignore | 1 - Dockerfile | 1 + public/index.html | 16 ++++++++-------- public/search.js | 9 ++++++++- server/db.js | 9 +++++++-- server/routes/suggestions.js | 14 +++++++++++++- 6 files changed, 37 insertions(+), 13 deletions(-) diff --git a/.dockerignore b/.dockerignore index 36920ae..9028996 100644 --- a/.dockerignore +++ b/.dockerignore @@ -3,6 +3,5 @@ node_modules .git .gitignore .env -db docs *.webm diff --git a/Dockerfile b/Dockerfile index 44978ce..ba175b1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,6 +13,7 @@ RUN cd server && npm ci --omit=dev COPY server/ ./server/ COPY public/ ./public/ COPY shared/ ./shared/ +COPY db/ ./db/ # Set ownership and switch to non-root user RUN chown -R node:node /app diff --git a/public/index.html b/public/index.html index d26147c..dac24a8 100644 --- a/public/index.html +++ b/public/index.html @@ -151,14 +151,14 @@ - - - - + + + + - - - - + + + + diff --git a/public/search.js b/public/search.js index 3ea03a9..814bb91 100644 --- a/public/search.js +++ b/public/search.js @@ -134,6 +134,8 @@ async function selectTrack(track) { key = metaJson.data.key; bpm = metaJson.data.bpm; tags = metaJson.data.tags || tags; + document.getElementById('stat-match').textContent = metaJson.data.is_corrected ? '100%' : (metaJson.data.source === 'postgresql' ? '100%' : 'Online'); + document.getElementById('stat-source-sub').textContent = metaJson.data.source === 'postgresql' ? (metaJson.data.is_corrected ? 'PostgreSQL (Fix)' : 'PostgreSQL') : 'PostgreSQL (Neu)'; } } catch (e) { console.warn('[Search] Metadata fetch failed, using fallback', e); @@ -205,7 +207,12 @@ async function renderSuggestions(currentKey, currentBpm = 120, artist = '', titl const res = await fetch(url); const json = await res.json(); - if (json.status !== 'success' || !json.data || json.data.length === 0) { + if (json.status !== 'success') { + sugContainer.innerHTML = `
Fehler beim Laden der Vorschläge: ${escapeHtml(json.error || 'Serverfehler')}
`; + return; + } + + if (!json.data || json.data.length === 0) { sugContainer.innerHTML = '
Keine passenden Tracks in der Datenbank gefunden. Suche weitere Tracks, um deine Library zu erweitern.
'; return; } diff --git a/server/db.js b/server/db.js index 664a901..0fafddb 100644 --- a/server/db.js +++ b/server/db.js @@ -188,7 +188,10 @@ async function searchTracks(queryStr, limit = 10) { const res = await getPool().query( `SELECT id, title, artist, camelot_key, bpm, music_key, cover_url, is_corrected FROM tracks - WHERE LOWER(title) LIKE $1 OR LOWER(artist) LIKE $1 + WHERE LOWER(title) LIKE $1 + OR LOWER(artist) LIKE $1 + OR LOWER(artist || ' ' || title) LIKE $1 + OR LOWER(title || ' ' || artist) LIKE $1 ORDER BY is_corrected DESC, play_count DESC LIMIT $2`, [term, limit] @@ -202,7 +205,9 @@ async function searchTracks(queryStr, limit = 10) { const results = []; const q = queryStr.toLowerCase(); for (const track of memoryTracks.values()) { - if (track.title.toLowerCase().includes(q) || track.artist.toLowerCase().includes(q)) { + const combined1 = `${track.artist} ${track.title}`.toLowerCase(); + const combined2 = `${track.title} ${track.artist}`.toLowerCase(); + if (track.title.toLowerCase().includes(q) || track.artist.toLowerCase().includes(q) || combined1.includes(q) || combined2.includes(q)) { results.push(track); if (results.length >= limit) break; } diff --git a/server/routes/suggestions.js b/server/routes/suggestions.js index e594a10..59d624b 100644 --- a/server/routes/suggestions.js +++ b/server/routes/suggestions.js @@ -26,13 +26,25 @@ router.get('/', async (req, res) => { // 1. Fetch tracks from PostgreSQL within ±6% let tracks = await db.getSuggestions(compatibleKeys, minBpm, maxBpm, 10, artist, title); - // 2. If fewer than 8 tracks, widen BPM range to ±12% to guarantee plenty of suggestions + // 2. If fewer than 8 tracks, widen BPM range to ±12% if (tracks.length < 8) { minBpm = Math.round(currentBpm * 0.88); maxBpm = Math.round(currentBpm * 1.12); tracks = await db.getSuggestions(compatibleKeys, minBpm, maxBpm, 10, artist, title); } + // 3. If fewer than 5 tracks, widen BPM range to ±20% for smaller libraries + if (tracks.length < 5) { + minBpm = Math.round(currentBpm * 0.80); + maxBpm = Math.round(currentBpm * 1.20); + tracks = await db.getSuggestions(compatibleKeys, minBpm, maxBpm, 10, artist, title); + } + + // 4. If still empty, fetch any compatible key track (50-220 BPM) + if (tracks.length === 0) { + tracks = await db.getSuggestions(compatibleKeys, 50, 220, 10, artist, title); + } + // 3. Map tracks with compatibility info and colors const enriched = tracks.map(t => { const ruleIdx = compatibleKeys.indexOf(t.camelot_key);