feat(search): „+ weitere Ergebnisse"-Button für lokale und Web-Suche
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 1m20s
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 1m20s
Die Ergebnislisten waren oft kurz, weil lokale Suche auf LIMIT 30 und die Web-Suche auf die erste SearXNG-Seite beschränkt war. Jetzt lässt sich beides nachladen. - `searchLocal` nimmt jetzt einen `offset` und der `/api/recipes/search`- Endpoint einen `?offset=`-Parameter. - `searchWeb` nimmt jetzt eine `pageno`-Option und reicht sie als `pageno`-Parameter an SearXNG weiter. `pageno=1` wird weggelassen, damit bestehendes Verhalten unverändert bleibt. - `/search` und `/search/web` zeigen unterhalb der Liste einen „+ weitere Ergebnisse"-Button. Beide deduplizieren nachgeladene Hits (ID bzw. URL), weil SearXNG das gleiche Ergebnis auf zwei Seiten liefern kann. Kein Endless-Scroll: expliziter Button ist mobil robuster und spart die teure Thumbnail-Enrichment-Roundtrip-Zeit, die bei jeder neuen Web-Seite anfällt. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -29,7 +29,8 @@ function buildFtsQuery(q: string): string | null {
|
||||
export function searchLocal(
|
||||
db: Database.Database,
|
||||
query: string,
|
||||
limit = 30
|
||||
limit = 30,
|
||||
offset = 0
|
||||
): SearchHit[] {
|
||||
const fts = buildFtsQuery(query);
|
||||
if (!fts) return [];
|
||||
@@ -48,9 +49,9 @@ export function searchLocal(
|
||||
JOIN recipe_fts f ON f.rowid = r.id
|
||||
WHERE recipe_fts MATCH ?
|
||||
ORDER BY bm25(recipe_fts, 10.0, 0.5, 2.0, 5.0)
|
||||
LIMIT ?`
|
||||
LIMIT ? OFFSET ?`
|
||||
)
|
||||
.all(fts, limit) as SearchHit[];
|
||||
.all(fts, limit, offset) as SearchHit[];
|
||||
}
|
||||
|
||||
export function listRecentRecipes(
|
||||
|
||||
@@ -251,7 +251,12 @@ async function enrichAllThumbnails(
|
||||
export async function searchWeb(
|
||||
db: Database.Database,
|
||||
query: string,
|
||||
opts: { searxngUrl?: string; limit?: number; enrichThumbnails?: boolean } = {}
|
||||
opts: {
|
||||
searxngUrl?: string;
|
||||
limit?: number;
|
||||
enrichThumbnails?: boolean;
|
||||
pageno?: number;
|
||||
} = {}
|
||||
): Promise<WebHit[]> {
|
||||
const trimmed = query.trim();
|
||||
if (!trimmed) return [];
|
||||
@@ -260,12 +265,14 @@ export async function searchWeb(
|
||||
|
||||
const searxngUrl = opts.searxngUrl ?? process.env.SEARXNG_URL ?? 'http://localhost:8888';
|
||||
const limit = opts.limit ?? 20;
|
||||
const pageno = Math.max(1, opts.pageno ?? 1);
|
||||
const siteFilter = domains.map((d) => `site:${d}`).join(' OR ');
|
||||
const q = `${trimmed} (${siteFilter})`;
|
||||
const endpoint = new URL('/search', searxngUrl);
|
||||
endpoint.searchParams.set('q', q);
|
||||
endpoint.searchParams.set('format', 'json');
|
||||
endpoint.searchParams.set('language', 'de');
|
||||
if (pageno > 1) endpoint.searchParams.set('pageno', String(pageno));
|
||||
|
||||
const body = await fetchText(endpoint.toString(), {
|
||||
timeoutMs: 15_000,
|
||||
|
||||
Reference in New Issue
Block a user