#!/usr/bin/env bash # Searches with ddgs and writes the results as JSON to standard output. # # scripts/search-ddgs.sh "" [number of results] # # ddgs queries several engines (DuckDuckGo, Brave, Mojeek, Startpage…) with no # key needed. This script exists so the assistant configuration does not have # to know anything about uv or Python environments: a usable ddgs is found # here and the output is normalized. # # Beware of two things that look equivalent and are not: # · `curl` against html.duckduckgo.com returns HTTP 202 with an anti-bot # page and no results. Measured, not assumed. # · The keyless api.duckduckgo.com API (Instant Answer) returns nothing for # almost anything that is not an encyclopedia entity. # The ddgs library does work because it rotates engines and headers. set -euo pipefail QUERY="${1:?usage: search-ddgs.sh \"\" [n]}" MAX="${2:-5}" PROGRAM=$(cat <<'PY' import json, sys from ddgs import DDGS query, max_results = sys.argv[1], int(sys.argv[2]) try: rows = DDGS().text(query, max_results=max_results) except Exception as e: # noqa: BLE001 print(json.dumps({"error": f"{type(e).__name__}: {e}"}), file=sys.stderr) raise SystemExit(1) print(json.dumps(rows, ensure_ascii=False)) PY ) # 1) The `uv tool install ddgs` environment: the fast path, since the package # does not have to be resolved on every search. TOOL_PY="$HOME/.local/share/uv/tools/ddgs/bin/python" if [ -x "$TOOL_PY" ]; then exec "$TOOL_PY" -c "$PROGRAM" "$QUERY" "$MAX" fi # 2) A system Python that already has ddgs installed. if python3 -c "import ddgs" >/dev/null 2>&1; then exec python3 -c "$PROGRAM" "$QUERY" "$MAX" fi # 3) uvx, which downloads it on the fly. Works without installing anything, # but adds several seconds to every search: better `uv tool install ddgs`. if command -v uvx >/dev/null 2>&1; then exec uvx --quiet --from ddgs python -c "$PROGRAM" "$QUERY" "$MAX" fi echo '{"error":"ddgs is not available. Install it with: uv tool install ddgs"}' >&2 exit 1