diff options
| author | Austin-Olacsi <138650713+Austin-Olacsi@users.noreply.github.com> | 2025-08-09 00:38:11 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-09 08:38:11 +0200 |
| commit | cf5061dc7026e9327044b006b053d84dc6340577 (patch) | |
| tree | 16ab8b9c5404e8bd877a62d4f6527a569eb04326 /searx/engines/marginalia.py | |
| parent | 5e7109cd261dcf3e8634aa011c51a134346cead2 (diff) | |
[feat] engines: add Marginalia (#5087)
To get an API key follow instructions at [1].
[1] https://about.marginalia-search.com/article/api/
Related (historical ordered):
- https://github.com/searxng/searxng/issues/1620
- https://github.com/searxng/searxng/issues/1673
- https://github.com/searxng/searxng/pull/1627
- https://github.com/searxng/searxng/pull/2489
Closes:
- https://github.com/searxng/searxng/issues/3034
Co-authored-by: Markus Heiser <markus.heiser@darmarit.de>
Diffstat (limited to 'searx/engines/marginalia.py')
| -rw-r--r-- | searx/engines/marginalia.py | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/searx/engines/marginalia.py b/searx/engines/marginalia.py new file mode 100644 index 000000000..63f411cf0 --- /dev/null +++ b/searx/engines/marginalia.py @@ -0,0 +1,125 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""`Marginalia Search`_ is an independent open source Internet search engine +operating out of Sweden. It is principally developed and operated by Viktor +Lofgren . + +.. _Marginalia Search: + https://about.marginalia-search.com/ + +Configuration +============= + +The engine has the following required settings: + +- :py:obj:`api_key` + +You can configure a Marginalia engine by: + +.. code:: yaml + + - name: marginalia + engine: marginalia + shortcut: mar + api_key: ... + +Implementations +=============== + +""" +from __future__ import annotations + +import typing as t +from urllib.parse import urlencode, quote_plus +from searx.utils import searxng_useragent +from searx.result_types import EngineResults +from searx.extended_types import SXNG_Response + +about = { + "website": "https://marginalia.nu", + "wikidata_id": None, + "official_api_documentation": "https://about.marginalia-search.com/article/api/", + "use_official_api": True, + "require_api_key": True, + "results": "JSON", +} + +base_url = "https://api.marginalia.nu" +safesearch = True +categories = ["general"] +paging = False +results_per_page = 20 +api_key = None +"""To get an API key, please follow the instructions from `Key and license`_ + +.. _Key and license: + https://about.marginalia-search.com/article/api/ + +""" + + +class ApiSearchResult(t.TypedDict): + """Marginalia's ApiSearchResult_ class definition. + + .. _ApiSearchResult: + https://github.com/MarginaliaSearch/MarginaliaSearch/blob/master/code/services-application/api-service/java/nu/marginalia/api/model/ApiSearchResult.java + """ + + url: str + title: str + description: str + quality: float + format: str + details: str + + +class ApiSearchResults(t.TypedDict): + """Marginalia's ApiSearchResults_ class definition. + + .. _ApiSearchResults: + https://github.com/MarginaliaSearch/MarginaliaSearch/blob/master/code/services-application/api-service/java/nu/marginalia/api/model/ApiSearchResults.java + """ + + license: str + query: str + results: list[ApiSearchResult] + + +def request(query: str, params: dict[str, t.Any]): + + query_params = { + "count": results_per_page, + "nsfw": min(params["safesearch"], 1), + } + + params["url"] = f"{base_url}/{api_key}/search/{quote_plus(query)}?{urlencode(query_params)}" + params["headers"]["User-Agent"] = searxng_useragent() + + +def response(resp: SXNG_Response): + + res = EngineResults() + resp_json: ApiSearchResults = resp.json() # type: ignore + + for item in resp_json.get("results", []): + res.add( + res.types.MainResult( + title=item["title"], + url=item["url"], + content=item.get("description", ""), + ) + ) + + return res + + +def init(engine_settings: dict[str, t.Any]): + + _api_key = engine_settings.get("api_key") + if not _api_key: + logger.error("missing api_key: see https://about.marginalia-search.com/article/api") + return False + + if _api_key == "public": + logger.error("invalid api_key (%s): see https://about.marginalia-search.com/article/api", api_key) + + return True |