import { search, searchSongsPaged } from '../api/subsonicSearch'; import React, { useCallback, useEffect, useRef, useState } from 'react'; import { useSearchParams } from 'react-router-dom'; import { Search } from 'lucide-react'; import type { SearchResults as ISearchResults } from '../api/subsonicTypes'; import AlbumRow from '../components/AlbumRow'; import ArtistRow from '../components/ArtistRow'; import SongRow, { SongListHeader } from '../components/SongRow'; import { useTranslation } from 'react-i18next'; import { useAuthStore } from '../store/authStore'; const SONGS_INITIAL = 50; const SONGS_PAGE_SIZE = 50; export default function SearchResults() { const { t } = useTranslation(); const [params] = useSearchParams(); const query = params.get('q') ?? ''; const [results, setResults] = useState(null); const [loading, setLoading] = useState(false); const [songsServerOffset, setSongsServerOffset] = useState(0); const [songsHasMore, setSongsHasMore] = useState(false); const [loadingMoreSongs, setLoadingMoreSongs] = useState(false); const songsSentinelRef = useRef(null); const musicLibraryFilterVersion = useAuthStore(s => s.musicLibraryFilterVersion); useEffect(() => { setSongsServerOffset(0); setSongsHasMore(false); if (!query.trim()) { setResults(null); return; } setLoading(true); search(query, { artistCount: 20, albumCount: 20, songCount: SONGS_INITIAL }) .then(r => { setResults(r); setSongsServerOffset(r.songs.length); setSongsHasMore(r.songs.length === SONGS_INITIAL); }) .finally(() => setLoading(false)); }, [query, musicLibraryFilterVersion]); const loadMoreSongs = useCallback(async () => { if (loadingMoreSongs || !songsHasMore || !query.trim()) return; setLoadingMoreSongs(true); try { const page = await searchSongsPaged(query.trim(), SONGS_PAGE_SIZE, songsServerOffset); setResults(prev => prev ? { ...prev, songs: [...prev.songs, ...page] } : prev); setSongsServerOffset(o => o + page.length); if (page.length < SONGS_PAGE_SIZE) setSongsHasMore(false); } catch { setSongsHasMore(false); } finally { setLoadingMoreSongs(false); } }, [loadingMoreSongs, songsHasMore, query, songsServerOffset]); useEffect(() => { const el = songsSentinelRef.current; if (!el) return; const obs = new IntersectionObserver(entries => { if (entries[0]?.isIntersecting) loadMoreSongs(); }, { rootMargin: '600px' }); obs.observe(el); return () => obs.disconnect(); }, [loadMoreSongs]); const hasResults = results && (results.artists.length || results.albums.length || results.songs.length); return (

{query ? t('search.resultsFor', { query }) : t('search.title')}

{loading && (
)} {!loading && query && !hasResults && (
{t('search.noResults', { query })}
)} {!loading && results && ( <> {results.artists.length > 0 && ( )} {results.albums.length > 0 && ( )} {results.songs.length > 0 && (

{t('search.songs')}

{results.songs.map(song => ( ))} {songsHasMore && (
{loadingMoreSongs &&
}
)}
)} )}
); }