fix(suggestions): enable combined search, progressive BPM widening, and include db in docker build

This commit is contained in:
Jannik committed 2026-09-13 01:02:11 +02:00
1 parent 8b917c78ad
commit 3d4372b154
6 files changed
+37 -13

No files matched your search

-1
View File
@@ -3,6 +3,5 @@ node_modules
.git
.gitignore
.env
db
docs
*.webm
+1
View File
@@ -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
+8 -8
View File
@@ -151,14 +151,14 @@
</div>
</div>
<script src="../shared/mixing-rules.js"></script>
<script src="../shared/color-matrix.js"></script>
<script src="../shared/camelot-angle.js"></script>
<script src="../shared/camelot-to-musickey.js"></script>
<script src="/shared/mixing-rules.js?v=2.0.1"></script>
<script src="/shared/color-matrix.js?v=2.0.1"></script>
<script src="/shared/camelot-angle.js?v=2.0.1"></script>
<script src="/shared/camelot-to-musickey.js?v=2.0.1"></script>
<script src="wheel.js"></script>
<script src="cover.js"></script>
<script src="search.js"></script>
<script src="app.js"></script>
<script src="wheel.js?v=2.0.1"></script>
<script src="cover.js?v=2.0.1"></script>
<script src="search.js?v=2.0.1"></script>
<script src="app.js?v=2.0.1"></script>
</body>
</html>
+8 -1
View File
@@ -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 = `<div style="color:#D62828;font-size:12px;font-family:monospace;">Fehler beim Laden der Vorschläge: ${escapeHtml(json.error || 'Serverfehler')}</div>`;
return;
}
if (!json.data || json.data.length === 0) {
sugContainer.innerHTML = '<div style="color:var(--text-dim);font-size:12px;font-family:monospace;">Keine passenden Tracks in der Datenbank gefunden. Suche weitere Tracks, um deine Library zu erweitern.</div>';
return;
}
+7 -2
View File
@@ -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;
}
+13 -1
View File
@@ -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);