Repository: searxng/searxng

Issue:
Support metacpan
<!-- PLEASE FILL THESE FIELDS, IT REALLY HELPS THE MAINTAINERS OF SearXNG -->

**Working URL to the engine**
https://metacpan.org/

**Why do you want to add this engine?**
Would be a nice addition to the "packages" section of the "it" category for users of Perl, as the CPAN is the largest (only?) database of Perl packages there is out there.

**Features of this engine**
Has search terms that can be used to narrow down search results more thoroughly, as described if you press the big question mark button under the search query box on the homepage.

**How can SearXNG fetch the information from this engine?**
Here's the API documentation: https://github.com/metacpan/metacpan-api/blob/master/docs/API-docs.md
Though it's also linked on the front page for easy access!

**Applicable category of this engine**
"it" as mentioned earlier 

**Additional context**
Nothing, just wanted to say thank you for your time!


Discussion:

Resolving patch:
diff --git a/searx/engines/metacpan.py b/searx/engines/metacpan.py
new file mode 100644
--- /dev/null
+++ b/searx/engines/metacpan.py
@@ -0,0 +1,79 @@
+# SPDX-License-Identifier: AGPL-3.0-or-later
+# lint: pylint
+"""metacpan
+"""
+
+from urllib.parse import urlunparse
+from json import dumps
+
+# about
+about = {
+    "website": 'https://metacpan.org/',
+    "wikidata_id": 'Q841507',
+    "official_api_documentation": 'https://github.com/metacpan/metacpan-api/blob/master/docs/API-docs.md',
+    "use_official_api": True,
+    "require_api_key": False,
+    "results": 'JSON',
+}
+
+# engine dependent config
+number_of_results = 20  # Don't put this over 5000
+categories = ["it", "packages"]
+disabled = True
+shortcut = "cpan"
+paging = True
+
+query_data_template = {
+    'query': {
+        'multi_match': {
+            'type': 'most_fields',
+            'fields': ['documentation', 'documentation.*'],
+            'analyzer': 'camelcase',
+        }
+    },
+    'filter': {
+        'bool': {
+            'must': [
+                {'exists': {'field': 'documentation'}},
+                {'term': {'status': 'latest'}},
+                {'term': {'indexed': 1}},
+                {'term': {'authorized': 1}},
+            ]
+        }
+    },
+    "sort": [
+        {"_score": {"order": "desc"}},
+        {"date": {"order": "desc"}},
+    ],
+    '_source': ['documentation', "abstract"],
+    'size': number_of_results,
+}
+search_url = urlunparse(["https", "fastapi.metacpan.org", "/v1/file/_search", "", "", ""])
+
+
+def request(query, params):
+    params["url"] = search_url
+    params["method"] = "POST"
+    query_data = query_data_template
+    query_data["query"]["multi_match"]["query"] = query
+    query_data["from"] = (params["pageno"] - 1) * number_of_results
+    params["data"] = dumps(query_data)
+    return params
+
+
+def response(resp):
+    results = []
+
+    search_results = resp.json()["hits"]["hits"]
+    for result in search_results:
+        fields = result["_source"]
+        module = fields["documentation"]
+        results.append(
+            {
+                "url": "https://metacpan.org/pod/" + module,
+                "title": module,
+                "content": fields.get("abstract", ""),
+            }
+        )
+
+    return results


Test patch: