aboutsummaryrefslogtreecommitdiff
path: root/castle-search/src/engines.ts
diff options
context:
space:
mode:
Diffstat (limited to 'castle-search/src/engines.ts')
-rw-r--r--castle-search/src/engines.ts13
1 files changed, 12 insertions, 1 deletions
diff --git a/castle-search/src/engines.ts b/castle-search/src/engines.ts
index 76716c6..fb07649 100644
--- a/castle-search/src/engines.ts
+++ b/castle-search/src/engines.ts
@@ -45,6 +45,12 @@ export type ExtractionConfig = {
mode: "items" | "headings";
/** Results container candidates, first match wins. */
roots: string[];
+ /**
+ * Present only on the engine's own "nothing matched" page. Without it a page
+ * that genuinely has zero hits is indistinguishable from broken markup, and
+ * the error blames the extractor for what is just an over-narrow query.
+ */
+ emptyMarker?: string;
/** "items" mode: one result. */
item?: string;
/** Anchor carrying the outbound link, relative to the item. */
@@ -124,6 +130,9 @@ const DUCKDUCKGO: EngineDefinition = {
extraction: {
mode: "items",
roots: [".results", "#links"],
+ // Seen 2026-11-06: `<div class="result results_links no-results">` — it is
+ // itself a `.result`, which is why the extractor finds a container and no hits.
+ emptyMarker: ".no-results",
item: ".result",
link: "a.result__a[href]",
title: "a.result__a",
@@ -187,7 +196,9 @@ const BRAVE: EngineDefinition = {
},
extraction: {
mode: "items",
- roots: ["#results"],
+ // `#results` is gone from the live page (2026-11-06); `#main` and `main`
+ // wrap the results. Left first so the older layout still matches.
+ roots: ["#results", "#main", "main"],
// data-type="web" excludes the AI summariser, video and news cards, which
// share the .snippet class but are not ranked web results.
item: '.snippet[data-type="web"]',