summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBnyro <bnyro@tutanota.com>2025-09-01 16:33:31 +0200
committerGitHub <noreply@github.com>2025-09-01 16:33:31 +0200
commitb93cc2f9f8ac058152bab236b4b54b8197b942f6 (patch)
treecda2c6822c657481dd69e8ceba5115af57ed73a9
parent501327ddf1d9e3a1380f5f82bbc1242dd25afbb4 (diff)
[feat] engines: add repology.org engine for linux packages (#5103)
Repology_ monitors a huge number of package repositories and other sources comparing packages versions across them and gathering other information. Repology_ shows you in which repositories a given project is packaged, which version is the latest and which needs updating, who maintains the package, and other related information. .. _Repology: https://repology.org/docs/about Co-authored-by: Markus Heiser <markus.heiser@darmarit.de> Format: reST
-rw-r--r--docs/dev/engines/online/repology.rst8
-rw-r--r--searx/engines/repology.py95
-rw-r--r--searx/settings.yml6
3 files changed, 109 insertions, 0 deletions
diff --git a/docs/dev/engines/online/repology.rst b/docs/dev/engines/online/repology.rst
new file mode 100644
index 000000000..485a5bcac
--- /dev/null
+++ b/docs/dev/engines/online/repology.rst
@@ -0,0 +1,8 @@
+.. _repology engine:
+
+========
+Repology
+========
+
+.. automodule:: searx.engines.repology
+ :members:
diff --git a/searx/engines/repology.py b/searx/engines/repology.py
new file mode 100644
index 000000000..022f23190
--- /dev/null
+++ b/searx/engines/repology.py
@@ -0,0 +1,95 @@
+# SPDX-License-Identifier: AGPL-3.0-or-later
+"""Repology_ monitors a huge number of package repositories and other sources
+comparing packages versions across them and gathering other information.
+
+Repology_ shows you in which repositories a given project is packaged, which
+version is the latest and which needs updating, who maintains the package, and
+other related information.
+
+.. _Repology: https://repology.org/docs/about
+
+Configuration
+=============
+
+The engine is inactive by default, meaning it is not available in the service.
+If you want to offer the engine, the ``inactive`` flag must be set to ``false``.
+
+.. code:: yaml
+
+ - name: repology
+ inactive: false
+
+"""
+
+import typing as t
+
+from urllib.parse import urlencode
+from searx.result_types import EngineResults
+
+if t.TYPE_CHECKING:
+ from searx.extended_types import SXNG_Response
+
+about = {
+ 'website': 'https://repology.org',
+ 'wikidata_id': 'Q107409859',
+ 'use_official_api': True,
+ 'official_api_documentation': 'https://repology.org/api/v1',
+ 'require_api_key': False,
+ 'results': 'JSON',
+}
+categories: list[str] = ['packages', 'it']
+base_url: str = 'https://repology.org'
+
+
+def request(query: str, params: dict[str, t.Any]) -> None:
+ args = {
+ 'search': query,
+ }
+ params['url'] = f"{base_url}/api/v1/projects/?{urlencode(args)}"
+
+
+def _get_most_common(items: list[str | None]) -> str | None:
+ counts: dict[str | None, int] = {}
+ for item in items:
+ if item:
+ counts[item] = counts.get(item, 0) + 1
+
+ if len(counts) == 0:
+ return None
+ return max(counts, key=counts.get)
+
+
+def _flatten(xss):
+ return [x for xs in xss for x in xs]
+
+
+def response(resp: 'SXNG_Response') -> EngineResults:
+ res = EngineResults()
+
+ resp_json = resp.json()
+ for pkgname, repositories in resp_json.items():
+
+ # either there's a package with status "newest" or we assume that the
+ # most commonly used version is the latest released (non-alpha) version
+ latest_version = None
+ for repo in repositories:
+ if repo.get("status") == "newest":
+ latest_version = repo["version"]
+ break
+ else:
+ latest_version = _get_most_common([repo.get("version") for repo in repositories])
+
+ res.add(
+ res.types.LegacyResult(
+ template='packages.html',
+ url=f"{base_url}/project/{pkgname}/versions",
+ title=pkgname,
+ content=_get_most_common([pkg.get("summary") for pkg in repositories]),
+ package_name=_get_most_common([pkg.get("visiblename") for pkg in repositories]),
+ version=latest_version,
+ license_name=_get_most_common(_flatten([pkg.get("licenses", []) for pkg in repositories])),
+ tags=list({pkg.get("repo") for pkg in repositories}), # ensure that tags are unique
+ )
+ )
+
+ return res
diff --git a/searx/settings.yml b/searx/settings.yml
index 1957b1d29..94b2edd66 100644
--- a/searx/settings.yml
+++ b/searx/settings.yml
@@ -2525,6 +2525,12 @@ engines:
categories: videos
disabled: true
+ - name: repology
+ engine: repology
+ shortcut: rep
+ disabled: true
+ inactive: true
+
- name: livespace
engine: livespace
shortcut: ls