Feat: Toggle für Fuzzy-Suche (default OFF), Server respektiert ?fuzzy=1/0
This commit is contained in:
parent
d975114768
commit
62890e0e85
3 changed files with 27 additions and 12 deletions
|
|
@ -432,6 +432,8 @@ app.get('/api/sounds', (req: Request, res: Response) => {
|
||||||
const q = String(req.query.q ?? '').toLowerCase();
|
const q = String(req.query.q ?? '').toLowerCase();
|
||||||
const folderFilter = typeof req.query.folder === 'string' ? (req.query.folder as string) : '__all__';
|
const folderFilter = typeof req.query.folder === 'string' ? (req.query.folder as string) : '__all__';
|
||||||
const categoryFilter = typeof (req.query as any).categoryId === 'string' ? String((req.query as any).categoryId) : undefined;
|
const categoryFilter = typeof (req.query as any).categoryId === 'string' ? String((req.query as any).categoryId) : undefined;
|
||||||
|
const fuzzyParam = String((req.query as any).fuzzy ?? '0');
|
||||||
|
const useFuzzy = fuzzyParam === '1' || fuzzyParam === 'true';
|
||||||
|
|
||||||
const rootEntries = fs.readdirSync(SOUNDS_DIR, { withFileTypes: true });
|
const rootEntries = fs.readdirSync(SOUNDS_DIR, { withFileTypes: true });
|
||||||
const rootFiles = rootEntries
|
const rootFiles = rootEntries
|
||||||
|
|
@ -523,11 +525,15 @@ app.get('/api/sounds', (req: Request, res: Response) => {
|
||||||
|
|
||||||
let filteredItems = itemsByFolder;
|
let filteredItems = itemsByFolder;
|
||||||
if (q) {
|
if (q) {
|
||||||
|
if (useFuzzy) {
|
||||||
const scored = itemsByFolder
|
const scored = itemsByFolder
|
||||||
.map((it) => ({ it, score: fuzzyScore(it.name.toLowerCase(), q) }))
|
.map((it) => ({ it, score: fuzzyScore(it.name.toLowerCase(), q) }))
|
||||||
.filter((x) => x.score > 0)
|
.filter((x) => x.score > 0)
|
||||||
.sort((a, b) => (b.score - a.score) || a.it.name.localeCompare(b.it.name));
|
.sort((a, b) => (b.score - a.score) || a.it.name.localeCompare(b.it.name));
|
||||||
filteredItems = scored.map((x) => x.it);
|
filteredItems = scored.map((x) => x.it);
|
||||||
|
} else {
|
||||||
|
filteredItems = itemsByFolder.filter((s) => s.name.toLowerCase().includes(q));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const total = allItems.length;
|
const total = allItems.length;
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ export default function App() {
|
||||||
const [activeCategoryId, setActiveCategoryId] = useState<string>('');
|
const [activeCategoryId, setActiveCategoryId] = useState<string>('');
|
||||||
const [channels, setChannels] = useState<VoiceChannelInfo[]>([]);
|
const [channels, setChannels] = useState<VoiceChannelInfo[]>([]);
|
||||||
const [query, setQuery] = useState('');
|
const [query, setQuery] = useState('');
|
||||||
|
const [fuzzy, setFuzzy] = useState<boolean>(false);
|
||||||
const [selected, setSelected] = useState<string>('');
|
const [selected, setSelected] = useState<string>('');
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
@ -113,7 +114,7 @@ export default function App() {
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
const folderParam = activeFolder === '__favs__' ? '__all__' : activeFolder;
|
const folderParam = activeFolder === '__favs__' ? '__all__' : activeFolder;
|
||||||
const s = await fetchSounds(query, folderParam, activeCategoryId || undefined);
|
const s = await fetchSounds(query, folderParam, activeCategoryId || undefined, fuzzy);
|
||||||
setSounds(s.items);
|
setSounds(s.items);
|
||||||
setTotal(s.total);
|
setTotal(s.total);
|
||||||
setFolders(s.folders);
|
setFolders(s.folders);
|
||||||
|
|
@ -121,7 +122,7 @@ export default function App() {
|
||||||
setError(e?.message || 'Fehler beim Laden der Sounds');
|
setError(e?.message || 'Fehler beim Laden der Sounds');
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
}, [activeFolder, query, activeCategoryId]);
|
}, [activeFolder, query, activeCategoryId, fuzzy]);
|
||||||
|
|
||||||
// Favoriten aus Cookie laden
|
// Favoriten aus Cookie laden
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -324,6 +325,13 @@ export default function App() {
|
||||||
<button className="bg-gray-700 hover:bg-gray-600 text-white font-bold py-3 px-6 rounded-lg transition duration-300" onClick={async () => {
|
<button className="bg-gray-700 hover:bg-gray-600 text-white font-bold py-3 px-6 rounded-lg transition duration-300" onClick={async () => {
|
||||||
try { const res = await fetch('/api/sounds'); const data = await res.json(); const items = data?.items || []; if (!items.length || !selected) return; const rnd = items[Math.floor(Math.random()*items.length)]; const [guildId, channelId] = selected.split(':'); await playSound(rnd.name, guildId, channelId, volume, rnd.relativePath);} catch {}
|
try { const res = await fetch('/api/sounds'); const data = await res.json(); const items = data?.items || []; if (!items.length || !selected) return; const rnd = items[Math.floor(Math.random()*items.length)]; const [guildId, channelId] = selected.split(':'); await playSound(rnd.name, guildId, channelId, volume, rnd.relativePath);} catch {}
|
||||||
}}>Random</button>
|
}}>Random</button>
|
||||||
|
<button
|
||||||
|
className={`font-bold py-3 px-6 rounded-lg transition duration-300 ${fuzzy ? 'bg-green-600 hover:bg-green-500 text-white' : 'bg-gray-700 hover:bg-gray-600 text-white'}`}
|
||||||
|
onClick={() => setFuzzy((v) => !v)}
|
||||||
|
title="Fuzzy-Suche umschalten"
|
||||||
|
>
|
||||||
|
Fuzzy {fuzzy ? 'ON' : 'OFF'}
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
className={`font-bold py-3 px-6 rounded-lg transition duration-300 ${
|
className={`font-bold py-3 px-6 rounded-lg transition duration-300 ${
|
||||||
chaosMode
|
chaosMode
|
||||||
|
|
@ -440,7 +448,7 @@ export default function App() {
|
||||||
const toDelete = Object.entries(selectedSet).filter(([,v])=>v).map(([k])=>k);
|
const toDelete = Object.entries(selectedSet).filter(([,v])=>v).map(([k])=>k);
|
||||||
await adminDelete(toDelete);
|
await adminDelete(toDelete);
|
||||||
clearSelection();
|
clearSelection();
|
||||||
const resp = await fetchSounds(query, activeFolder === '__favs__' ? '__all__' : activeFolder);
|
const resp = await fetchSounds(query, activeFolder === '__favs__' ? '__all__' : activeFolder, activeCategoryId || undefined, fuzzy);
|
||||||
setSounds(resp.items); setTotal(resp.total); setFolders(resp.folders);
|
setSounds(resp.items); setTotal(resp.total); setFolders(resp.folders);
|
||||||
} catch (e:any) { setError(e?.message||'Löschen fehlgeschlagen'); }
|
} catch (e:any) { setError(e?.message||'Löschen fehlgeschlagen'); }
|
||||||
}}
|
}}
|
||||||
|
|
@ -455,7 +463,7 @@ export default function App() {
|
||||||
try {
|
try {
|
||||||
await adminRename(from, newName);
|
await adminRename(from, newName);
|
||||||
clearSelection();
|
clearSelection();
|
||||||
const resp = await fetchSounds(query, activeFolder === '__favs__' ? '__all__' : activeFolder);
|
const resp = await fetchSounds(query, activeFolder === '__favs__' ? '__all__' : activeFolder, activeCategoryId || undefined, fuzzy);
|
||||||
setSounds(resp.items); setTotal(resp.total); setFolders(resp.folders);
|
setSounds(resp.items); setTotal(resp.total); setFolders(resp.folders);
|
||||||
} catch (e:any) { setError(e?.message||'Umbenennen fehlgeschlagen'); }
|
} catch (e:any) { setError(e?.message||'Umbenennen fehlgeschlagen'); }
|
||||||
}} />
|
}} />
|
||||||
|
|
@ -475,7 +483,7 @@ export default function App() {
|
||||||
if(!assignCategoryId){ setError('Bitte Kategorie wählen'); return; }
|
if(!assignCategoryId){ setError('Bitte Kategorie wählen'); return; }
|
||||||
await assignCategories(files, [assignCategoryId], []);
|
await assignCategories(files, [assignCategoryId], []);
|
||||||
setInfo('Kategorie zugewiesen'); setError(null);
|
setInfo('Kategorie zugewiesen'); setError(null);
|
||||||
const resp = await fetchSounds(query, activeFolder === '__favs__' ? '__all__' : activeFolder, activeCategoryId || undefined);
|
const resp = await fetchSounds(query, activeFolder === '__favs__' ? '__all__' : activeFolder, activeCategoryId || undefined, fuzzy);
|
||||||
setSounds(resp.items); setTotal(resp.total); setFolders(resp.folders);
|
setSounds(resp.items); setTotal(resp.total); setFolders(resp.folders);
|
||||||
}catch(e:any){ setError(e?.message||'Zuweisung fehlgeschlagen'); setInfo(null); }
|
}catch(e:any){ setError(e?.message||'Zuweisung fehlgeschlagen'); setInfo(null); }
|
||||||
}}
|
}}
|
||||||
|
|
@ -490,7 +498,7 @@ export default function App() {
|
||||||
const files = Object.entries(selectedSet).filter(([,v])=>v).map(([k])=>k);
|
const files = Object.entries(selectedSet).filter(([,v])=>v).map(([k])=>k);
|
||||||
await clearBadges(files);
|
await clearBadges(files);
|
||||||
setInfo('Alle Custom-Badges entfernt'); setError(null);
|
setInfo('Alle Custom-Badges entfernt'); setError(null);
|
||||||
const resp = await fetchSounds(query, activeFolder === '__favs__' ? '__all__' : activeFolder, activeCategoryId || undefined);
|
const resp = await fetchSounds(query, activeFolder === '__favs__' ? '__all__' : activeFolder, activeCategoryId || undefined, fuzzy);
|
||||||
setSounds(resp.items); setTotal(resp.total); setFolders(resp.folders);
|
setSounds(resp.items); setTotal(resp.total); setFolders(resp.folders);
|
||||||
}catch(err:any){ setError(err?.message||'Badge-Entfernung fehlgeschlagen'); setInfo(null); }
|
}catch(err:any){ setError(err?.message||'Badge-Entfernung fehlgeschlagen'); setInfo(null); }
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,12 @@ import type { Sound, SoundsResponse, VoiceChannelInfo } from './types';
|
||||||
|
|
||||||
const API_BASE = import.meta.env.VITE_API_BASE_URL || '/api';
|
const API_BASE = import.meta.env.VITE_API_BASE_URL || '/api';
|
||||||
|
|
||||||
export async function fetchSounds(q?: string, folderKey?: string, categoryId?: string): Promise<SoundsResponse> {
|
export async function fetchSounds(q?: string, folderKey?: string, categoryId?: string, fuzzy?: boolean): Promise<SoundsResponse> {
|
||||||
const url = new URL(`${API_BASE}/sounds`, window.location.origin);
|
const url = new URL(`${API_BASE}/sounds`, window.location.origin);
|
||||||
if (q) url.searchParams.set('q', q);
|
if (q) url.searchParams.set('q', q);
|
||||||
if (folderKey !== undefined) url.searchParams.set('folder', folderKey);
|
if (folderKey !== undefined) url.searchParams.set('folder', folderKey);
|
||||||
if (categoryId) url.searchParams.set('categoryId', categoryId);
|
if (categoryId) url.searchParams.set('categoryId', categoryId);
|
||||||
|
if (typeof fuzzy === 'boolean') url.searchParams.set('fuzzy', fuzzy ? '1' : '0');
|
||||||
const res = await fetch(url.toString());
|
const res = await fetch(url.toString());
|
||||||
if (!res.ok) throw new Error('Fehler beim Laden der Sounds');
|
if (!res.ok) throw new Error('Fehler beim Laden der Sounds');
|
||||||
return res.json();
|
return res.json();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue