fix(library): scoped live search FTS, race, and multi-server advanced search (#868)

* fix(library): scoped live search FTS, race, and multi-server advanced search

Scope track_fts live search to active server_id so multi-server libraries
no longer show empty or wrong-server hits. Match Navidrome-style any-word
prefix matching and GROUP BY artist/album dedupe on track_fts only.

Frontend: parallel local vs search3 race (empty waits, 8s network timeout),
merge supplemental hits after both settle, debug via Settings → Logging →
Debug (frontend_debug_log). Advanced Search FTS subqueries use the same
server scope fix.

* docs: CHANGELOG and credits for PR #868 live search fix
This commit is contained in:
cucadmuh
2026-05-25 04:20:02 +03:00
committed by GitHub
parent bc85065316
commit 91e7195e0f
13 changed files with 839 additions and 207 deletions
+21
View File
@@ -1,8 +1,10 @@
import { describe, expect, it } from 'vitest';
import { onInvoke } from '@/test/mocks/tauri';
import type { SearchResults } from '../../api/subsonicTypes';
import { useAuthStore } from '@/store/authStore';
import {
liveSearchQueryTooShort,
mergeLiveSearchResults,
runLocalLiveSearch,
} from './liveSearchLocal';
@@ -96,3 +98,22 @@ describe('liveSearchQueryTooShort', () => {
expect(liveSearchQueryTooShort('ab')).toBe(false);
});
});
describe('mergeLiveSearchResults', () => {
it('keeps local order and fills gaps from network', () => {
const local: SearchResults = {
artists: [{ id: 'a1', name: 'Local' }],
albums: [],
songs: [{ id: 's1', title: 'Song', artist: 'A', album: 'Al', albumId: 'al0', duration: 1 }],
};
const network: SearchResults = {
artists: [{ id: 'a2', name: 'Net' }],
albums: [{ id: 'al1', name: 'Album', artist: 'A', artistId: 'a2', songCount: 1, duration: 100 }],
songs: [{ id: 's2', title: 'Other', artist: 'B', album: 'Bl', albumId: 'al1', duration: 2 }],
};
const merged = mergeLiveSearchResults(local, network);
expect(merged.artists.map(a => a.id)).toEqual(['a1', 'a2']);
expect(merged.albums.map(a => a.id)).toEqual(['al1']);
expect(merged.songs.map(s => s.id)).toEqual(['s1', 's2']);
});
});