Repository: searxng/searxng

Issue:
New engine: Tagesschau
<!-- PLEASE FILL THESE FIELDS, IT REALLY HELPS THE MAINTAINERS OF SearXNG -->

**Working URL to the engine**
* https://www.tagesschau.de/api2u/

**Features of this engine**
* provides recent news in German

**How can SearXNG fetch the information from this engine?**
* https://www.tagesschau.de/api2u/search?searchText=test
* https://github.com/AndreasFischer1985/tagesschau-api
* the implementation is not the issue, it's rather whether it'd be accepted

**Applicable category of this engine**
* news, general

**Additional context**
There are two concerns/questions from my side regarding adding it:
* According to https://github.com/AndreasFischer1985/tagesschau-api, we're not allowed to run more than 60 api requests per hour (though there's no rate-limiting, so it wouldn't be a problem to fetch more), so it's only some legal stuff about which I'm not sure
* It only provides results in German: I don't know whether engines, that only support a single language other than English are fine to become added


Discussion:
> so it's only some legal stuff about which I'm not sure

From programmers point of view there is no (legal) issue .. depends on the government where the maintainer do host their SearXNG instances.

> It only provides results in German: I don't know whether engines, that only support a single language other than English are fine to become added

Its OK .. not all engines do support all languages on planet earth ;-) 

By example, we have [MediathekViewWeb](https://github.com/searxng/searxng/blob/master/searx/engines/mediathekviewweb.py) .. you can try [`!mvw tagesschau`](https://darmarit.org/searx/search?q=%21mvw+tagesschau)


Okay cool, thanks!
I'll open a PR for it then in the next days :)

PS: Great to see MediatheViewWeb being supported, I actually already have been using it for some years, but really didn't expect it to be available here as well!

Resolving patch:
diff --git a/searx/engines/tagesschau.py b/searx/engines/tagesschau.py
new file mode 100644
--- /dev/null
+++ b/searx/engines/tagesschau.py
@@ -0,0 +1,101 @@
+# SPDX-License-Identifier: AGPL-3.0-or-later
+# lint: pylint
+"""ARD: `Tagesschau API`_
+
+The Tagesschau is a news program of the ARD.  Via the `Tagesschau API`_, current
+news and media reports are available in JSON format.  The `Bundesstelle für Open
+Data`_ offers a `OpenAPI`_ portal at bundDEV_ where APIs are documented an can
+be tested.
+
+This SearXNG engine uses the `/api2u/search`_ API.
+
+.. _/api2u/search: http://tagesschau.api.bund.dev/
+.. _bundDEV: https://bund.dev/apis
+.. _Bundesstelle für Open Data: https://github.com/bundesAPI
+.. _Tagesschau API: https://github.com/AndreasFischer1985/tagesschau-api/blob/main/README_en.md
+.. _OpenAPI: https://swagger.io/specification/
+
+"""
+from typing import TYPE_CHECKING
+
+from datetime import datetime
+from urllib.parse import urlencode
+import re
+
+if TYPE_CHECKING:
+    import logging
+
+    logger: logging.Logger
+
+about = {
+    'website': "https://tagesschau.de",
+    'wikidata_id': "Q703907",
+    'official_api_documentation': None,
+    'use_official_api': True,
+    'require_api_key': False,
+    'results': 'JSON',
+    'language': 'de',
+}
+categories = ['general', 'news']
+paging = True
+
+results_per_page = 10
+base_url = "https://www.tagesschau.de"
+
+
+def request(query, params):
+    args = {
+        'searchText': query,
+        'pageSize': results_per_page,
+        'resultPage': params['pageno'] - 1,
+    }
+
+    params['url'] = f"{base_url}/api2u/search?{urlencode(args)}"
+
+    return params
+
+
+def response(resp):
+    results = []
+
+    json = resp.json()
+
+    for item in json['searchResults']:
+        item_type = item.get('type')
+        if item_type in ('story', 'webview'):
+            results.append(_story(item))
+        elif item_type == 'video':
+            results.append(_video(item))
+        else:
+            logger.error("unknow result type: %s", item_type)
+
+    return results
+
+
+def _story(item):
+    return {
+        'title': item['title'],
+        'thumbnail': item.get('teaserImage', {}).get('imageVariants', {}).get('16x9-256'),
+        'publishedDate': datetime.strptime(item['date'][:19], '%Y-%m-%dT%H:%M:%S'),
+        'content': item['firstSentence'],
+        'url': item['shareURL'],
+    }
+
+
+def _video(item):
+    video_url = item['streams']['h264s']
+    title = item['title']
+
+    if "_vapp.mxf" in title:
+        title = title.replace("_vapp.mxf", "")
+        title = re.sub(r"APP\d+ (FC-)?", "", title, count=1)
+
+    return {
+        'template': 'videos.html',
+        'title': title,
+        'thumbnail': item.get('teaserImage', {}).get('imageVariants', {}).get('16x9-256'),
+        'publishedDate': datetime.strptime(item['date'][:19], '%Y-%m-%dT%H:%M:%S'),
+        'content': item.get('firstSentence', ''),
+        'iframe_src': video_url,
+        'url': video_url,
+    }


Test patch: