mirror of
https://github.com/searxng/searxng.git
synced 2026-06-22 17:48:33 +02:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 72a827ae93 | |||
| 6ca9d3784c | |||
| 63f264220b | |||
| 41fcf0be4b |
@@ -40,7 +40,7 @@ if t.TYPE_CHECKING:
|
|||||||
|
|
||||||
about = {
|
about = {
|
||||||
"website": "https://www.aol.com",
|
"website": "https://www.aol.com",
|
||||||
"wikidata_id": "Q2407",
|
"wikidata_id": "Q27585",
|
||||||
"official_api_documentation": None,
|
"official_api_documentation": None,
|
||||||
"use_official_api": False,
|
"use_official_api": False,
|
||||||
"require_api_key": False,
|
"require_api_key": False,
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
"""Heexy_ is a minimalist search engine that focuses on privacy.
|
||||||
|
|
||||||
|
Although it also supports news and videos, these are not implemented here
|
||||||
|
because they usually return no result to very few irrelevant ones.
|
||||||
|
|
||||||
|
It seems to use Bing internally, as the image thumbnails are loaded from Bing.
|
||||||
|
|
||||||
|
.. _Heexy: https://docs.heexy.org/introduction
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
|
import typing as t
|
||||||
|
|
||||||
|
from searx.exceptions import SearxEngineAccessDeniedException
|
||||||
|
from searx.result_types import EngineResults
|
||||||
|
|
||||||
|
if t.TYPE_CHECKING:
|
||||||
|
from searx.extended_types import SXNG_Response
|
||||||
|
from searx.search.processors import OnlineParams
|
||||||
|
|
||||||
|
about = {
|
||||||
|
"website": "https://heexy.org",
|
||||||
|
"wikidata_id": None,
|
||||||
|
"official_api_documentation": None,
|
||||||
|
"use_official_api": False,
|
||||||
|
"require_api_key": False,
|
||||||
|
"results": "JSON",
|
||||||
|
}
|
||||||
|
|
||||||
|
paging = True
|
||||||
|
safesearch = True
|
||||||
|
|
||||||
|
categories = ["general"]
|
||||||
|
heexy_categ = "web"
|
||||||
|
"""Category to search in. Can be either "web" or "image"."""
|
||||||
|
|
||||||
|
|
||||||
|
base_url = "https://seapi.heexy.org"
|
||||||
|
safe_search_map = {0: "off", 1: "on", 2: "on"}
|
||||||
|
|
||||||
|
|
||||||
|
def init(_):
|
||||||
|
if heexy_categ not in ("web", "image"):
|
||||||
|
raise ValueError("invalid search category: %s" % heexy_categ)
|
||||||
|
|
||||||
|
|
||||||
|
def request(query: str, params: "OnlineParams") -> None:
|
||||||
|
args = {
|
||||||
|
"q": query,
|
||||||
|
"page": params["pageno"],
|
||||||
|
"safe": safe_search_map[params["safesearch"]],
|
||||||
|
}
|
||||||
|
if params["searxng_locale"] != "all":
|
||||||
|
args["lang"] = params["searxng_locale"].split("-")[0]
|
||||||
|
|
||||||
|
params["url"] = f"{base_url}/search/{heexy_categ}?{urlencode(args)}"
|
||||||
|
params["headers"]["Origin"] = base_url
|
||||||
|
|
||||||
|
|
||||||
|
def response(resp: "SXNG_Response"):
|
||||||
|
res = EngineResults()
|
||||||
|
|
||||||
|
json_resp = resp.json()
|
||||||
|
if not json_resp["success"]:
|
||||||
|
raise SearxEngineAccessDeniedException()
|
||||||
|
|
||||||
|
result: dict[str, str]
|
||||||
|
for result in json_resp["results"]:
|
||||||
|
if heexy_categ == "web":
|
||||||
|
res.add(
|
||||||
|
res.types.MainResult(
|
||||||
|
url=result["url"],
|
||||||
|
title=result["title"],
|
||||||
|
content=result["description"],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif heexy_categ == "image":
|
||||||
|
res.add(
|
||||||
|
res.types.Image(
|
||||||
|
title=result["description"],
|
||||||
|
url=result["url"],
|
||||||
|
thumbnail_src=result["image"],
|
||||||
|
img_src=result["rawImage"],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return res
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
"""Seek ninja (general)"""
|
||||||
|
|
||||||
|
from json import loads
|
||||||
|
from hashlib import sha256
|
||||||
|
from urllib.parse import urlencode, quote_plus
|
||||||
|
|
||||||
|
import typing as t
|
||||||
|
|
||||||
|
from searx.extended_types import SXNG_Response
|
||||||
|
from searx.network import get
|
||||||
|
from searx.result_types import EngineResults
|
||||||
|
from searx.utils import extr, html_to_text
|
||||||
|
|
||||||
|
if t.TYPE_CHECKING:
|
||||||
|
from searx.search.processors import OnlineParams
|
||||||
|
|
||||||
|
about = {
|
||||||
|
"website": "https://seek.ninja",
|
||||||
|
"official_api_documentation": None,
|
||||||
|
"use_official_api": False,
|
||||||
|
"require_api_key": False,
|
||||||
|
"results": "JSON",
|
||||||
|
}
|
||||||
|
|
||||||
|
safesearch = True
|
||||||
|
|
||||||
|
base_url = "https://seek.ninja"
|
||||||
|
categories = ["general"]
|
||||||
|
|
||||||
|
safe_search_map = {0: "off", 1: "moderate", 2: "strict"}
|
||||||
|
|
||||||
|
PowChallenge = dict[str, t.Any]
|
||||||
|
|
||||||
|
|
||||||
|
def _get_challenge(query: str) -> PowChallenge:
|
||||||
|
"""Extract the challenge parameters (i.e. nonce, difficulty, ...) from the
|
||||||
|
search website."""
|
||||||
|
|
||||||
|
resp = get(f"{base_url}/s?q={quote_plus(query)}")
|
||||||
|
challenge_raw_json = "{" + extr(resp.text, "pow: {", "},") + "}"
|
||||||
|
return loads(challenge_raw_json)
|
||||||
|
|
||||||
|
|
||||||
|
def _solve_pow(challenge: PowChallenge) -> list[int]:
|
||||||
|
"""Solves a Proof of Work SHA256 challenges. This is a 1:1 port of the
|
||||||
|
site's JS code.
|
||||||
|
|
||||||
|
On a high-level, it tries to ``k`` amount of solutions, where its sha256
|
||||||
|
hash begins with: ``leading`` 0s, i.e.
|
||||||
|
|
||||||
|
.. code: js
|
||||||
|
|
||||||
|
sha256(nonce || solution).startswith("0" * leading)
|
||||||
|
"""
|
||||||
|
nonce = challenge["nonce"]
|
||||||
|
k = int(challenge["k"])
|
||||||
|
indifficulty = float(challenge["indifficulty"])
|
||||||
|
|
||||||
|
leading = int(indifficulty)
|
||||||
|
frac = indifficulty - leading
|
||||||
|
prefix = "".join("0" for _ in range(0, leading))
|
||||||
|
|
||||||
|
maxNib = 15 - int(frac * 16) if frac else 15
|
||||||
|
|
||||||
|
solutions: list[int] = []
|
||||||
|
ans = 0
|
||||||
|
while len(solutions) < k:
|
||||||
|
h = sha256(f"{nonce}{ans}".encode()).hexdigest()
|
||||||
|
if h.startswith(prefix) and (not frac or int(h[leading], base=16) <= maxNib):
|
||||||
|
solutions.append(ans)
|
||||||
|
ans += 1
|
||||||
|
return solutions
|
||||||
|
|
||||||
|
|
||||||
|
def request(query: str, params: 'OnlineParams') -> None:
|
||||||
|
challenge = _get_challenge(query)
|
||||||
|
solution = _solve_pow(challenge)
|
||||||
|
args = {
|
||||||
|
"q": query,
|
||||||
|
"panswers": ",".join(str(s) for s in solution),
|
||||||
|
"pid": challenge["challengeId"],
|
||||||
|
"adult": safe_search_map[params["safesearch"]],
|
||||||
|
}
|
||||||
|
params["url"] = f"{base_url}/search-sse?{urlencode(args)}"
|
||||||
|
|
||||||
|
|
||||||
|
def response(resp: 'SXNG_Response') -> EngineResults:
|
||||||
|
res = EngineResults()
|
||||||
|
# The response is a stream of server-side events,
|
||||||
|
# so it is split into `event: <type>` and `data: {"results": ...}`
|
||||||
|
# see https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/
|
||||||
|
events = resp.text.split("\n\n")
|
||||||
|
for event in events:
|
||||||
|
event_parts = event.split("\n", maxsplit=2)
|
||||||
|
if len(event_parts) != 2:
|
||||||
|
continue
|
||||||
|
|
||||||
|
event_name, data = event_parts
|
||||||
|
if not event_name.endswith("resultsUpdate"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
json_data = loads(data.removeprefix("data: "))
|
||||||
|
for result in json_data["results"]:
|
||||||
|
res.add(
|
||||||
|
res.types.MainResult(
|
||||||
|
url=result["url"],
|
||||||
|
title=result["title"],
|
||||||
|
content=html_to_text(result["blurb"]),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return res
|
||||||
+27
-20
@@ -16,17 +16,18 @@ if t.TYPE_CHECKING:
|
|||||||
from searx.search.processors import OnlineParams
|
from searx.search.processors import OnlineParams
|
||||||
|
|
||||||
about = {
|
about = {
|
||||||
'website': 'https://yep.com/',
|
"website": "https://yep.com/",
|
||||||
'official_api_documentation': 'https://docs.developer.yelp.com',
|
"official_api_documentation": "https://docs.developer.yelp.com",
|
||||||
'use_official_api': False,
|
"use_official_api": False,
|
||||||
'require_api_key': False,
|
"require_api_key": False,
|
||||||
'results': 'JSON',
|
"results": "JSON",
|
||||||
}
|
}
|
||||||
|
|
||||||
base_url = "https://api.yep.com"
|
base_url = "https://api.yep.com"
|
||||||
|
web_base_url = "https://yep.com"
|
||||||
|
|
||||||
safesearch = True
|
safesearch = True
|
||||||
safesearch_map = {0: 'off', 1: 'moderate', 2: 'strict'}
|
safesearch_map = {0: "off", 1: "moderate", 2: "strict"}
|
||||||
|
|
||||||
enable_http2 = False
|
enable_http2 = False
|
||||||
|
|
||||||
@@ -36,34 +37,42 @@ _IMPORT_RE = re.compile(r"import\"(.*?)\";")
|
|||||||
_LANGUAGE_RE = re.compile(r"\{english:\".*?\",code_string:\"(.*?)\",code:\".*?\"\}")
|
_LANGUAGE_RE = re.compile(r"\{english:\".*?\",code_string:\"(.*?)\",code:\".*?\"\}")
|
||||||
|
|
||||||
|
|
||||||
def request(query: str, params: 'OnlineParams') -> None:
|
def request(query: str, params: "OnlineParams") -> None:
|
||||||
args = {'query': query, 'safeSearch': safesearch_map[params['safesearch']], 'limit': results_per_page}
|
args = {"query": query, "safeSearch": safesearch_map[params["safesearch"]], "limit": results_per_page}
|
||||||
|
|
||||||
engine_language: str = traits.get_language(params["searxng_locale"])
|
engine_language: str | None = traits.get_language(params["searxng_locale"])
|
||||||
if engine_language:
|
if engine_language:
|
||||||
args["hl"] = engine_language
|
args["hl"] = engine_language
|
||||||
|
|
||||||
params['url'] = f"{base_url}/search?{urlencode(args)}"
|
params["url"] = f"{base_url}/search?{urlencode(args)}"
|
||||||
params['headers']['Referer'] = 'https://yep.com/'
|
params["headers"].update(
|
||||||
params['headers']['Origin'] = 'https://yep.com'
|
{
|
||||||
|
"Referer": f"{web_base_url}/",
|
||||||
|
"Origin": web_base_url,
|
||||||
|
"Sec-Fetch-Dest": "empty",
|
||||||
|
"Sec-Fetch-Mode": "cors",
|
||||||
|
"Sec-Fetch-Site": "same-site",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def response(resp: 'SXNG_Response') -> EngineResults:
|
def response(resp: "SXNG_Response") -> EngineResults:
|
||||||
res = EngineResults()
|
res = EngineResults()
|
||||||
|
|
||||||
for result in resp.json()[1]['results']:
|
result: dict[str, str]
|
||||||
|
for result in resp.json()[1]["results"]:
|
||||||
res.add(
|
res.add(
|
||||||
res.types.MainResult(
|
res.types.MainResult(
|
||||||
url=result['url'],
|
url=result["url"],
|
||||||
title=result['title'],
|
title=result["title"],
|
||||||
content=html_to_text(result['snippet']),
|
content=html_to_text(result["snippet"]),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
def fetch_traits(engine_traits: 'EngineTraits'):
|
def fetch_traits(engine_traits: "EngineTraits"):
|
||||||
"""Fetch :ref:`languages <yep languages>` and :ref:`regions <yep
|
"""Fetch :ref:`languages <yep languages>` and :ref:`regions <yep
|
||||||
regions>` from Yep.
|
regions>` from Yep.
|
||||||
|
|
||||||
@@ -83,8 +92,6 @@ def fetch_traits(engine_traits: 'EngineTraits'):
|
|||||||
|
|
||||||
from searx.utils import gen_useragent
|
from searx.utils import gen_useragent
|
||||||
|
|
||||||
web_base_url = "https://yep.com"
|
|
||||||
|
|
||||||
headers = {
|
headers = {
|
||||||
"User-Agent": gen_useragent(),
|
"User-Agent": gen_useragent(),
|
||||||
"Referer": f"{web_base_url}/",
|
"Referer": f"{web_base_url}/",
|
||||||
|
|||||||
@@ -1131,6 +1131,22 @@ engines:
|
|||||||
shortcut: hn
|
shortcut: hn
|
||||||
disabled: true
|
disabled: true
|
||||||
|
|
||||||
|
- name: heexy
|
||||||
|
engine: heexy
|
||||||
|
categories: general
|
||||||
|
heexy_categ: web
|
||||||
|
shortcut: he
|
||||||
|
disabled: true
|
||||||
|
inactive: true
|
||||||
|
|
||||||
|
- name: heexy images
|
||||||
|
engine: heexy
|
||||||
|
categories: images
|
||||||
|
heexy_categ: image
|
||||||
|
shortcut: hei
|
||||||
|
disabled: true
|
||||||
|
inactive: true
|
||||||
|
|
||||||
- name: hex
|
- name: hex
|
||||||
engine: hex
|
engine: hex
|
||||||
shortcut: hex
|
shortcut: hex
|
||||||
@@ -1960,6 +1976,14 @@ engines:
|
|||||||
# - ...
|
# - ...
|
||||||
# disabled: true
|
# disabled: true
|
||||||
|
|
||||||
|
- name: seekninja
|
||||||
|
engine: seekninja
|
||||||
|
shortcut: sen
|
||||||
|
# very slow due to its server-side events architecture
|
||||||
|
timeout: 10
|
||||||
|
disabled: true
|
||||||
|
inactive: true
|
||||||
|
|
||||||
- name: semantic scholar
|
- name: semantic scholar
|
||||||
engine: semantic_scholar
|
engine: semantic_scholar
|
||||||
shortcut: se
|
shortcut: se
|
||||||
|
|||||||
Reference in New Issue
Block a user