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

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:
hsiegeln
2026-04-17 21:58:47 +02:00
parent b4a7355b24
commit a62b32aa1e
8 changed files with 184 additions and 8 deletions

View File

@@ -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,