aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/search-ddgs.sh
blob: 2f818b762273b25dcddc4998ac0eb0be40235809 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#!/usr/bin/env bash
# Searches with ddgs and writes the results as JSON to standard output.
#
#   scripts/search-ddgs.sh "<query>" [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 \"<query>\" [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