diff --git a/docs/user/configured_engines.rst b/docs/user/configured_engines.rst index 44cb496b8..a81828e4c 100644 --- a/docs/user/configured_engines.rst +++ b/docs/user/configured_engines.rst @@ -58,8 +58,8 @@ Configured Engines {% for mod in engines %} * - `{{mod.name}} <{{mod.about and mod.about.website}}>`_ - {%- if mod.about and mod.about.language %} - ({{mod.about.language | upper}}) + {%- if mod.language %} + ({{mod.language | upper}}) {%- endif %} - ``!{{mod.shortcut}}`` - {%- if 'searx.engines.' + mod.__name__ in documented_modules %} diff --git a/searx/enginelib/__init__.py b/searx/enginelib/__init__.py index 5e8d738a9..0af69190d 100644 --- a/searx/enginelib/__init__.py +++ b/searx/enginelib/__init__.py @@ -41,7 +41,7 @@ if t.TYPE_CHECKING: from searx.enginelib.traits import EngineTraits from searx.extended_types import SXNG_Response from searx.result_types import EngineResults - from searx.search.processors import OfflineParamTypes, OnlineParamTypes + from searx.search.processors import OfflineParamTypes, OnlineParamTypes, ProcessorType ENGINES_CACHE: ExpireCacheSQLite = ExpireCacheSQLite.build_cache( ExpireCacheCfg( @@ -180,7 +180,7 @@ class EngineCache: return ENGINES_CACHE.secret_hash(name=name) -class EngineAbout(msgspec.Struct): +class EngineAbout(msgspec.Struct, kw_only=True): """Additional fields describing the engine. .. code:: yaml @@ -213,12 +213,11 @@ class EngineAbout(msgspec.Struct): results: str = "" """Data format of the source (online-engines: of the response).""" - language: str = "" - """If the engine supports only one language, this language is specified - here (``en``, ``de``, ``"no"`` or ..); otherwise, the value remains empty. + description: str = "" + """Brief description of the engine and where it gets its data from. - For the YAML configuration: think of the `YAML-Norway problem - `_ + This value should only be set as long as no description of the data source + is available via a :py:obj:`EngineAbout.wikidata_id`. """ @@ -227,6 +226,8 @@ class Engine(abc.ABC): # pylint: disable=too-few-public-methods Further documentation see :ref:`general engine configuration`. + The defaults are taken from :py:obj:`searx.engines.ENGINE_DEFAULT_ARGS`. + .. hint:: This class is currently never initialized and only used for type hinting. @@ -234,49 +235,27 @@ class Engine(abc.ABC): # pylint: disable=too-few-public-methods logger: logging.Logger - # Common options in the engine module + # Common options of the engine module - engine_type: str + engine_type: "ProcessorType" = "online" """Type of the engine (:ref:`searx.search.processors`)""" - paging: bool + paging: bool = False """Engine supports multiple pages.""" max_page: int = 0 """If the engine supports paging, then this is the value for the last page that is still supported. ``0`` means unlimited numbers of pages.""" - time_range_support: bool + time_range_support: bool = False """Engine supports search time range.""" - safesearch: bool + safesearch: bool = False """Engine supports SafeSearch""" - language_support: bool + language_support: bool = False """Engine supports languages (locales) search.""" - language: str - """For an engine, when there is ``language: ...`` in the YAML settings the engine - does support only this one language: - - .. code:: yaml - - - name: google french - engine: google - language: fr - """ - - region: str - """For an engine, when there is ``region: ...`` in the YAML settings the engine - does support only this one region:: - - .. code:: yaml - - - name: google belgium - engine: google - region: fr-BE - """ - fetch_traits: "Callable[[EngineTraits, bool], None]" """Function to to fetch engine's traits from origin.""" @@ -285,9 +264,6 @@ class Engine(abc.ABC): # pylint: disable=too-few-public-methods # settings.yml - categories: list[str] - """Specifies to which :ref:`engine categories` the engine should be added.""" - name: str """Name that will be used across SearXNG to define this engine. In settings, on the result page ..""" @@ -297,6 +273,43 @@ class Engine(abc.ABC): # pylint: disable=too-few-public-methods this search engine (file name from :origin:`searx/engines` without ``.py``).""" + categories: list[str] = ["general"] + """Specifies to which :ref:`engine categories` the engine should be added.""" + + language: str = "" + """If the engine supports only one language, this language is specified here + (``en``, ``de``, ``"no"`` or ..); otherwise, the value remains empty. For + the YAML configuration: think of the `YAML-Norway problem + `_ + + .. code:: yaml + + - name: google norway + engine: google + language: "no" + + Depending on ``language_support``, this value has similar but also slightly + different meanings. + + - When ``language_support`` is **true**, the map of + :py:obj:`traits.EngineTraits.languages` is reduced to the selected + language + + - When ``language_support`` is **false**, then the implementation of the + engine only supports this one ``language`` + """ + + region: str = "" + """For an engine, when there is ``region: ...`` in the YAML settings the engine + does support only this one region:: + + .. code:: yaml + + - name: google belgium + engine: google + region: fr-BE + """ + enable_http: bool """Enable HTTP (by default only HTTPS is enabled).""" @@ -309,6 +322,31 @@ class Engine(abc.ABC): # pylint: disable=too-few-public-methods display_error_messages: bool """Display error messages on the web UI.""" + disabled: bool = False + """To disable by default the engine, but not deleting it. It will allow the + user to manually activate it in the settings.""" + + inactive: bool = False + """Remove the engine from the settings (*disabled & removed*).""" + + about: EngineAbout = EngineAbout() + """Additional fields describing the engine.""" + + using_tor_proxy: bool = False + """Using tor proxy (``true``) or not (``false``) for this engine.""" + + send_accept_language_header: bool = True + """When this option is activated (default), the language (locale) that is + selected by the user is used to build and send a ``Accept-Language`` header + in the request to the origin search engine.""" + + tokens: list[str] = [] + """A list of secret tokens to make this engine *private*, more details see + :ref:`private engines`.""" + + weight: float = 1.0 + """Weighting of the results of this engine (:ref:`weight `).""" + proxies: dict[str, dict[str, str]] """Set proxies for a specific engine (YAML): @@ -319,31 +357,6 @@ class Engine(abc.ABC): # pylint: disable=too-few-public-methods https: socks5://proxy:port """ - disabled: bool - """To disable by default the engine, but not deleting it. It will allow the - user to manually activate it in the settings.""" - - inactive: bool - """Remove the engine from the settings (*disabled & removed*).""" - - about: EngineAbout - """Additional fields describing the engine.""" - - using_tor_proxy: bool - """Using tor proxy (``true``) or not (``false``) for this engine.""" - - send_accept_language_header: bool - """When this option is activated (default), the language (locale) that is - selected by the user is used to build and send a ``Accept-Language`` header - in the request to the origin search engine.""" - - tokens: list[str] - """A list of secret tokens to make this engine *private*, more details see - :ref:`private engines`.""" - - weight: int - """Weighting of the results of this engine (:ref:`weight `).""" - def setup(self, engine_settings: dict[str, t.Any]) -> bool: # pylint: disable=unused-argument """Dynamic setup of the engine settings. diff --git a/searx/enginelib/traits.py b/searx/enginelib/traits.py index 4a051ac05..d4d45ac19 100644 --- a/searx/enginelib/traits.py +++ b/searx/enginelib/traits.py @@ -142,11 +142,11 @@ class EngineTraits: """ if self.data_type == "traits_v1": - self._set_traits_v1(engine) + self._set_traits_v1(engine) # pyright: ignore[reportArgumentType] else: raise TypeError("engine traits of type %s is unknown" % self.data_type) - def _set_traits_v1(self, engine: "Engine | types.ModuleType") -> None: + def _set_traits_v1(self, engine: "Engine") -> None: # For an engine, when there is `language: ...` in the YAML settings the engine # does support only this one language (region):: # @@ -159,22 +159,25 @@ class EngineTraits: _msg = "settings.yml - engine: '%s' / %s: '%s' not supported" - languages = traits.languages - if hasattr(engine, "language"): - if engine.language not in languages: - raise ValueError(_msg % (engine.name, "language", engine.language)) - traits.languages = {engine.language: languages[engine.language]} + if engine.language: + if engine.language_support: + if not len(traits.languages) > 1: + raise ValueError( + f"engine {engine.name}: activated language_support with just one or less languages" + ) + if engine.language not in traits.languages: + raise ValueError(_msg % (engine.name, "language", engine.language)) + traits.languages = {engine.language: traits.languages[engine.language]} - regions = traits.regions - if hasattr(engine, "region"): - if engine.region not in regions: + if engine.region: + if engine.region not in traits.regions: raise ValueError(_msg % (engine.name, "region", engine.region)) - traits.regions = {engine.region: regions[engine.region]} + traits.regions = {engine.region: traits.regions[engine.region]} engine.language_support = bool(traits.languages or traits.regions) # set the copied & modified traits in engine's namespace - engine.traits = traits # pyright: ignore[reportAttributeAccessIssue] + engine.traits = traits class EngineTraitsMap(dict[str, EngineTraits]): diff --git a/searx/engines/360search.py b/searx/engines/360search.py index 900d59082..bf1ba9821 100644 --- a/searx/engines/360search.py +++ b/searx/engines/360search.py @@ -22,8 +22,8 @@ about = { "use_official_api": False, "require_api_key": False, "results": "HTML", - "language": "zh", } +language = "zh" # Engine Configuration categories = ["general"] diff --git a/searx/engines/__builtins__.pyi b/searx/engines/__builtins__.pyi index e16ae48ce..ff3cfda0b 100644 --- a/searx/engines/__builtins__.pyi +++ b/searx/engines/__builtins__.pyi @@ -5,19 +5,19 @@ intended monkey patching of the engine modules. .. attention:: Monkey-patching modules is a practice from the past that shouldn't be - expanded upon. In the long run, there should be an engine class that can be - inherited. However, as long as this class doesn't exist, and as long as all - engine modules aren't converted to an engine class, these builtin types will - still be needed. + expanded upon. In the long run, engines should be instances of + :py:obj:`searx.enginelib.Engine`. However, as long as long as all engine + modules aren't converted to this class, these builtin types will still be + needed. """ import logging from searx.enginelib import traits as _traits logger: logging.Logger -supported_languages: str -language_aliases: str language_support: bool +language: str +region: str traits: _traits.EngineTraits # from searx.engines.ENGINE_DEFAULT_ARGS diff --git a/searx/engines/__init__.py b/searx/engines/__init__.py index e906b780b..b225575e7 100644 --- a/searx/engines/__init__.py +++ b/searx/engines/__init__.py @@ -17,37 +17,44 @@ from os.path import realpath, dirname import types import inspect +import msgspec from searx import logger, settings from searx.utils import load_module -if t.TYPE_CHECKING: - from searx.enginelib import Engine +from searx.enginelib import Engine, EngineAbout logger = logger.getChild('engines') ENGINE_DIR = dirname(realpath(__file__)) # Defaults for the namespace of an engine module, see load_engine() -ENGINE_DEFAULT_ARGS: dict[str, int | str | list[t.Any] | dict[str, t.Any] | bool] = { +ENGINE_DEFAULT_ARGS: dict[str, t.Any] = { # Common options in the engine module "engine_type": "online", "paging": False, + "max_page": 0, "time_range_support": False, "safesearch": False, + "language_support": False, # settings.yml "categories": ["general"], + "language": "", + "region": "", "enable_http": False, "shortcut": "-", "timeout": settings["outgoing"]["request_timeout"], "display_error_messages": True, "disabled": False, "inactive": False, - "about": {}, + "about": EngineAbout(), "using_tor_proxy": False, "send_accept_language_header": True, "tokens": [], - "max_page": 0, + "weight": 1.0, } +"""Default values that are set in an engine of type *module*, please compare +with the class :py:obj:`searx.enginelib.Engine`.""" + # set automatically when an engine does not have any tab category DEFAULT_CATEGORY = 'other' @@ -178,13 +185,27 @@ def set_loggers(engine: "Engine|types.ModuleType", engine_name: str): def update_engine_attributes(engine: "Engine | types.ModuleType", engine_data: dict[str, t.Any]): # set engine attributes from engine_data + + kvargs: dict[str, t.Any] + if isinstance(engine.about, EngineAbout): + kvargs = {**msgspec.to_builtins(engine.about), **engine_data.get("about", {})} + else: + kvargs = {**engine.about, **engine_data.get("about", {})} + + try: + engine.about = EngineAbout(**kvargs) + except TypeError as exc: + raise TypeError( + f"engine {engine_data['name']} ({engine_data['engine']}) - in the about section --> {exc}" + ) from exc + for param_name, param_value in engine_data.items(): + if param_name == "about": + continue if param_name == 'categories': if isinstance(param_value, str): param_value = list(map(str.strip, param_value.split(','))) engine.categories = param_value # type: ignore - elif hasattr(engine, 'about') and param_name == 'about': - engine.about = {**engine.about, **engine_data['about']} # type: ignore else: setattr(engine, param_name, param_value) diff --git a/searx/engines/acfun.py b/searx/engines/acfun.py index c0a9510b3..90922680f 100644 --- a/searx/engines/acfun.py +++ b/searx/engines/acfun.py @@ -16,12 +16,12 @@ about = { "use_official_api": False, "require_api_key": False, "results": "HTML", - "language": "zh", } # Engine Configuration categories = ["videos"] paging = True +language = "zh" # Base URL base_url = "https://www.acfun.cn" diff --git a/searx/engines/ansa.py b/searx/engines/ansa.py index 56cbee31a..21afed900 100644 --- a/searx/engines/ansa.py +++ b/searx/engines/ansa.py @@ -42,8 +42,8 @@ about = { 'use_official_api': False, 'require_api_key': False, 'results': 'HTML', - 'language': 'it', } +language = "it" def request(query, params): diff --git a/searx/engines/azure.py b/searx/engines/azure.py index 4c916bc3b..e00d75872 100644 --- a/searx/engines/azure.py +++ b/searx/engines/azure.py @@ -54,8 +54,8 @@ about = { "use_official_api": True, "require_api_key": True, "results": "JSON", - "language": "en", } +language = "en" CACHE: EngineCache """Persistent (SQLite) key/value cache that deletes its values after ``expire`` diff --git a/searx/engines/baidu.py b/searx/engines/baidu.py index 57d1ed444..4d93100ca 100644 --- a/searx/engines/baidu.py +++ b/searx/engines/baidu.py @@ -23,8 +23,8 @@ about = { "use_official_api": False, "require_api_key": False, "results": "JSON", - "language": "zh", } +language = "zh" paging = True categories = [] diff --git a/searx/engines/bpb.py b/searx/engines/bpb.py index b28fa5895..904f7a44c 100644 --- a/searx/engines/bpb.py +++ b/searx/engines/bpb.py @@ -13,8 +13,8 @@ about = { 'use_official_api': False, 'require_api_key': False, 'results': 'JSON', - 'language': 'de', } +language = "de" paging = True categories = ['general'] diff --git a/searx/engines/chefkoch.py b/searx/engines/chefkoch.py index c569f90f3..99dd5b918 100644 --- a/searx/engines/chefkoch.py +++ b/searx/engines/chefkoch.py @@ -10,8 +10,8 @@ about = { 'use_official_api': False, 'require_api_key': False, 'results': 'JSON', - 'language': 'de', } +language = "de" paging = True categories = [] diff --git a/searx/engines/chinaso.py b/searx/engines/chinaso.py index 620ecc730..a94f4059e 100644 --- a/searx/engines/chinaso.py +++ b/searx/engines/chinaso.py @@ -70,13 +70,13 @@ about = { "use_official_api": False, "require_api_key": False, "results": "JSON", - "language": "zh", } paging = True time_range_support = True results_per_page = 10 categories = [] +language = "zh" ChinasoCategoryType = t.Literal['news', 'videos', 'images'] """ChinaSo supports news, videos, images search. diff --git a/searx/engines/demo_offline.py b/searx/engines/demo_offline.py index 26cd62554..e3fc34f48 100644 --- a/searx/engines/demo_offline.py +++ b/searx/engines/demo_offline.py @@ -24,7 +24,7 @@ import typing as t import json from searx.result_types import EngineResults -from searx.enginelib import EngineCache +from searx.enginelib import EngineCache, EngineAbout if t.TYPE_CHECKING: from searx.search.processors import RequestParams @@ -35,13 +35,11 @@ categories = ["general"] disabled = True timeout = 2.0 -about = { - "wikidata_id": None, - "official_api_documentation": None, - "use_official_api": False, - "require_api_key": False, - "results": "JSON", -} +language = "en" +about = EngineAbout( + results="JSON", + description="Demo offline engine Engine with results in the English language.", +) # if there is a need for globals, use a leading underline _my_offline_engine: str = "" diff --git a/searx/engines/demo_online.py b/searx/engines/demo_online.py index 3dcf3935b..0c74e050b 100644 --- a/searx/engines/demo_online.py +++ b/searx/engines/demo_online.py @@ -25,6 +25,7 @@ import typing as t from urllib.parse import urlencode from searx.result_types import EngineResults +from searx.enginelib import EngineAbout if t.TYPE_CHECKING: from searx.extended_types import SXNG_Response @@ -43,14 +44,14 @@ page_size = 20 search_api = "https://api.artic.edu/api/v1/artworks/search" image_api = "https://www.artic.edu/iiif/2/" -about = { - "website": "https://www.artic.edu", - "wikidata_id": "Q239303", - "official_api_documentation": "http://api.artic.edu/docs/", - "use_official_api": True, - "require_api_key": False, - "results": "JSON", -} +about = EngineAbout( + website="https://www.artic.edu", + wikidata_id="Q239303", + official_api_documentation="http://api.artic.edu/docs/", + use_official_api=True, + require_api_key=False, + results="JSON", +) # if there is a need for globals, use a leading underline diff --git a/searx/engines/destatis.py b/searx/engines/destatis.py index e9ac5deae..3622cd173 100644 --- a/searx/engines/destatis.py +++ b/searx/engines/destatis.py @@ -11,8 +11,8 @@ about = { 'use_official_api': False, 'require_api_key': False, 'results': 'HTML', - 'language': 'de', } +language = "de" categories = [] paging = True diff --git a/searx/engines/duden.py b/searx/engines/duden.py index b422d8339..77664f887 100644 --- a/searx/engines/duden.py +++ b/searx/engines/duden.py @@ -14,8 +14,8 @@ about = { "use_official_api": False, "require_api_key": False, "results": 'HTML', - "language": 'de', } +language = "de" categories = ['dictionaries'] paging = True diff --git a/searx/engines/elasticsearch.py b/searx/engines/elasticsearch.py index c613ae367..382a52dd9 100644 --- a/searx/engines/elasticsearch.py +++ b/searx/engines/elasticsearch.py @@ -55,7 +55,7 @@ about = { 'official_api_documentation': 'https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html', 'use_official_api': True, 'require_api_key': False, - 'format': 'JSON', + "results": "JSON", } base_url = 'http://localhost:9200' diff --git a/searx/engines/geizhals.py b/searx/engines/geizhals.py index 4ada41919..6b8511fb9 100644 --- a/searx/engines/geizhals.py +++ b/searx/engines/geizhals.py @@ -27,8 +27,8 @@ about = { 'official_api_documentation': None, 'require_api_key': False, 'results': 'HTML', - 'language': 'de', } +language = "de" paging = True categories = ['shopping'] diff --git a/searx/engines/il_post.py b/searx/engines/il_post.py index 1215c4dad..862836607 100644 --- a/searx/engines/il_post.py +++ b/searx/engines/il_post.py @@ -34,8 +34,8 @@ about = { "use_official_api": True, "require_api_key": False, "results": "JSON", - "language": "it", } +language = "it" def request(query, params): diff --git a/searx/engines/ina.py b/searx/engines/ina.py index 45f871941..bebd3808e 100644 --- a/searx/engines/ina.py +++ b/searx/engines/ina.py @@ -16,8 +16,8 @@ about = { "use_official_api": False, "require_api_key": False, "results": 'HTML', - "language": 'fr', } +language = "fr" # engine dependent config categories = ['videos'] diff --git a/searx/engines/iqiyi.py b/searx/engines/iqiyi.py index eab954242..b0bb38535 100644 --- a/searx/engines/iqiyi.py +++ b/searx/engines/iqiyi.py @@ -14,9 +14,9 @@ about = { "use_official_api": False, "require_api_key": False, "results": "JSON", - "language": "zh", } +language = "zh" paging = True time_range_support = True categories = ["videos"] diff --git a/searx/engines/jisho.py b/searx/engines/jisho.py index 7f4392bc1..b167d864a 100644 --- a/searx/engines/jisho.py +++ b/searx/engines/jisho.py @@ -13,8 +13,8 @@ about = { "use_official_api": True, "require_api_key": False, "results": 'JSON', - "language": 'ja', } +language = "ja" categories = ['dictionaries'] paging = False @@ -110,8 +110,8 @@ def get_infobox(alt_forms, result_url, definitions): # definitions infobox_content.append( ''' - JMdict - and JMnedict + JMdict + and JMnedict by EDRDG, CC BY-SA 3.0.
    ''' diff --git a/searx/engines/json_engine.py b/searx/engines/json_engine.py index 1a2dcda60..dd9575e47 100644 --- a/searx/engines/json_engine.py +++ b/searx/engines/json_engine.py @@ -79,6 +79,9 @@ from json import loads from urllib.parse import urlencode from searx.utils import to_string, html_to_text from searx.network import raise_for_httperror +from searx.enginelib import EngineAbout + +about = EngineAbout() search_url = None """ diff --git a/searx/engines/mediathekviewweb.py b/searx/engines/mediathekviewweb.py index 8baa20bdb..70afc4057 100644 --- a/searx/engines/mediathekviewweb.py +++ b/searx/engines/mediathekviewweb.py @@ -11,9 +11,9 @@ about = { "use_official_api": True, "require_api_key": False, "results": 'JSON', - "language": "de", } +language = "de" categories = ['videos'] paging = True time_range_support = False diff --git a/searx/engines/moviepilot.py b/searx/engines/moviepilot.py index 532c1e66e..6011405ed 100644 --- a/searx/engines/moviepilot.py +++ b/searx/engines/moviepilot.py @@ -35,8 +35,9 @@ about = { 'use_official_api': False, 'require_api_key': False, 'results': 'JSON', - 'language': 'de', } +language = "de" + paging = True categories = ["movies"] diff --git a/searx/engines/naver.py b/searx/engines/naver.py index c715bc319..ca8d79f7e 100644 --- a/searx/engines/naver.py +++ b/searx/engines/naver.py @@ -26,8 +26,8 @@ about = { "use_official_api": False, "require_api_key": False, "results": "HTML", - "language": "ko", } +language = "ko" categories = [] paging = True diff --git a/searx/engines/niconico.py b/searx/engines/niconico.py index b421a9806..8a943174b 100644 --- a/searx/engines/niconico.py +++ b/searx/engines/niconico.py @@ -13,8 +13,8 @@ about = { "use_official_api": False, "require_api_key": False, "results": "HTML", - "language": "ja", } +language = "ja" categories = ["videos"] paging = True diff --git a/searx/engines/photon.py b/searx/engines/photon.py index 950e82d68..32dea321b 100644 --- a/searx/engines/photon.py +++ b/searx/engines/photon.py @@ -28,7 +28,7 @@ search_string = 'api/?{query}&limit={limit}' result_base_url = 'https://openstreetmap.org/{osm_type}/{osm_id}' # list of supported languages -supported_languages = ['de', 'en', 'fr', 'it'] +photon_supported_languages = ["de", "en", "fr", "it"] # do search-request @@ -37,7 +37,7 @@ def request(query, params): if params['language'] != 'all': language = params['language'].split('_')[0] - if language in supported_languages: + if language in photon_supported_languages: params['url'] = params['url'] + "&lang=" + language # using SearXNG User-Agent diff --git a/searx/engines/presearch.py b/searx/engines/presearch.py index 00a9d3ed8..b54d85b88 100644 --- a/searx/engines/presearch.py +++ b/searx/engines/presearch.py @@ -77,7 +77,7 @@ from searx.utils import gen_useragent, html_to_text, parse_duration_string about = { "website": "https://presearch.io", - "wikidiata_id": "Q7240905", + "wikidata_id": "Q7240905", "official_api_documentation": "https://docs.presearch.io/nodes/api", "use_official_api": False, "require_api_key": False, diff --git a/searx/engines/quark.py b/searx/engines/quark.py index 38d431da9..889f1dbae 100644 --- a/searx/engines/quark.py +++ b/searx/engines/quark.py @@ -16,8 +16,8 @@ about = { "use_official_api": False, "require_api_key": False, "results": "HTML", - "language": "zh", } +language = "zh" # Engine Configuration categories = [] diff --git a/searx/engines/senscritique.py b/searx/engines/senscritique.py index f4dd972ea..ea88c5c9f 100644 --- a/searx/engines/senscritique.py +++ b/searx/engines/senscritique.py @@ -13,8 +13,8 @@ about = { "use_official_api": False, "require_api_key": False, "results": 'JSON', - 'language': 'fr', } +language = "fr" categories = ['movies'] paging = True diff --git a/searx/engines/seznam.py b/searx/engines/seznam.py index 33f363fa2..bc2474821 100644 --- a/searx/engines/seznam.py +++ b/searx/engines/seznam.py @@ -19,8 +19,8 @@ about = { "use_official_api": False, "require_api_key": False, "results": "HTML", - "language": "cz", } +language = "cz" categories = ['general', 'web'] base_url = 'https://search.seznam.cz/' diff --git a/searx/engines/sogou.py b/searx/engines/sogou.py index ea011d970..0eb1affa8 100644 --- a/searx/engines/sogou.py +++ b/searx/engines/sogou.py @@ -16,8 +16,8 @@ about = { "use_official_api": False, "require_api_key": False, "results": "HTML", - "language": "zh", } +language = "zh" # Engine Configuration categories = ["general"] diff --git a/searx/engines/sogou_videos.py b/searx/engines/sogou_videos.py index 9a3565619..7da7a9edb 100644 --- a/searx/engines/sogou_videos.py +++ b/searx/engines/sogou_videos.py @@ -11,8 +11,8 @@ about = { "use_official_api": False, "require_api_key": False, "results": "JSON", - "language": "zh", } +language = "zh" categories = ["videos"] paging = True diff --git a/searx/engines/sogou_wechat.py b/searx/engines/sogou_wechat.py index c9d240ec7..c7e2b877c 100644 --- a/searx/engines/sogou_wechat.py +++ b/searx/engines/sogou_wechat.py @@ -14,8 +14,8 @@ about = { "use_official_api": False, "require_api_key": False, "results": "HTML", - "language": "zh", } +language = "zh" # Engine Configuration categories = ["news"] diff --git a/searx/engines/tagesschau.py b/searx/engines/tagesschau.py index 7669eeb19..12d999593 100644 --- a/searx/engines/tagesschau.py +++ b/searx/engines/tagesschau.py @@ -27,8 +27,9 @@ about = { 'use_official_api': True, 'require_api_key': False, 'results': 'JSON', - 'language': 'de', } +language = "de" + categories = ['general', 'news'] paging = True diff --git a/searx/engines/tonline.py b/searx/engines/tonline.py index cfb1dbb35..328b42d69 100644 --- a/searx/engines/tonline.py +++ b/searx/engines/tonline.py @@ -16,20 +16,17 @@ from lxml import html from searx.utils import eval_xpath_list, eval_xpath, extract_text, get_embeded_stream_url, ElementType from searx.result_types import EngineResults +from searx.enginelib import EngineAbout if t.TYPE_CHECKING: from searx.extended_types import SXNG_Response from searx.search.processors import OnlineParams -about = { - "website": "https://www.t-online.de", - "wikidata_id": "Q590940", - "official_api_documentation": None, - "use_official_api": False, - "require_api_key": False, - "results": "HTML", - "language": "de", -} +about = EngineAbout( + website="https://www.t-online.de", + wikidata_id="Q590940", + results="HTML", +) paging = True time_range_support = True @@ -44,6 +41,8 @@ time_range_map = {"day": "d", "week": "w", "month": "m", "year": "y"} # use "tonline" to only search for results from t-online news articles tonline_channel_map = {"images": "flickr", "videos": "yt"} +language = "de" + def init(_): if tonline_categ not in ("web", "images", "videos", "news"): diff --git a/searx/engines/xpath.py b/searx/engines/xpath.py index 081417513..0f071bca0 100644 --- a/searx/engines/xpath.py +++ b/searx/engines/xpath.py @@ -76,6 +76,9 @@ from lxml import html from searx.utils import extract_text, extract_url, eval_xpath, eval_xpath_list from searx.network import raise_for_httperror from searx.result_types import EngineResults +from searx.enginelib import EngineAbout + +about = EngineAbout() search_url = None """ diff --git a/searx/search/processors/__init__.py b/searx/search/processors/__init__.py index 1c9e0be3c..f7900d284 100644 --- a/searx/search/processors/__init__.py +++ b/searx/search/processors/__init__.py @@ -11,6 +11,7 @@ __all__ = [ "PROCESSORS", "ParamTypes", "RequestParams", + "ProcessorType", ] import typing as t @@ -27,6 +28,14 @@ from .online_url_search import OnlineUrlSearchProcessor, OnlineUrlSearchParams logger = logger.getChild("search.processors") +ProcessorType = t.Literal[ + "offline", + "online", + "online_currency", + "online_dictionary", + "online_url_search", +] + OnlineParamTypes: t.TypeAlias = OnlineParams | OnlineDictParams | OnlineCurrenciesParams | OnlineUrlSearchParams OfflineParamTypes: t.TypeAlias = RequestParams ParamTypes: t.TypeAlias = OfflineParamTypes | OnlineParamTypes diff --git a/searx/settings.yml b/searx/settings.yml index 8d52c3e6e..a509d94d9 100644 --- a/searx/settings.yml +++ b/searx/settings.yml @@ -330,12 +330,12 @@ engines: url_xpath: ./a/@href title_xpath: ./a/h3 content_xpath: ./div + language: "no" about: website: https://abcnyheter.no use_official_api: false require_api_key: false results: HTML - language: "no" - name: acfun engine: acfun @@ -2808,13 +2808,13 @@ engines: shortcut: rel categories: general disabled: true + language: de about: website: https://reloado.com official_api_documentation: use_official_api: false require_api_key: false results: HTML - language: de - name: repology engine: repology @@ -2927,13 +2927,13 @@ engines: content_xpath: //div[@class="synonyms-list-group"] title_xpath: //div[@class="upper-synonyms"]/a no_result_for_http_status: [404] + language: de about: website: https://www.woxikon.de/ wikidata_id: # No Wikidata ID use_official_api: false require_api_key: false results: HTML - language: de - name: tootfinder engine: tootfinder @@ -2988,13 +2988,13 @@ engines: content_xpath: //li/div[@class="searchresult"] categories: general disabled: true + language: fr about: website: https://wikimini.org/ wikidata_id: Q3568032 use_official_api: false require_api_key: false results: HTML - language: fr - name: wttr.in engine: wttr diff --git a/searx/templates/simple/preferences/engines.html b/searx/templates/simple/preferences/engines.html index 977fe9669..c0d5eb32e 100644 --- a/searx/templates/simple/preferences/engines.html +++ b/searx/templates/simple/preferences/engines.html @@ -60,8 +60,8 @@ {%- endif -%} {{- engine_about(search_engine) -}} diff --git a/searx/webapp.py b/searx/webapp.py index 55ef84e8d..85f57266a 100755 --- a/searx/webapp.py +++ b/searx/webapp.py @@ -1075,10 +1075,9 @@ def engine_descriptions(): result[engine] = description # overwrite by about:description (from settings) - for engine_name, engine_mod in engines.items(): - descr = getattr(engine_mod, 'about', {}).get('description', None) - if descr is not None: - result[engine_name] = [descr, "SearXNG config"] + for eng_name, eng_obj in engines.items(): + if eng_obj.about.description: + result[eng_name] = [eng_obj.about.description, "SearXNG config"] return jsonify(result) diff --git a/searx/webutils.py b/searx/webutils.py index 8cf0762e3..9c3e8a0c9 100644 --- a/searx/webutils.py +++ b/searx/webutils.py @@ -323,7 +323,7 @@ def group_engines_in_tab(engines: "Iterable[Engine]") -> List[Tuple[str, "Iterab return (group[0] == NO_SUBGROUPING, group[0].lower()) def engine_sort_key(engine): - return (engine.about.get('language', ''), engine.name) + return (engine.language, engine.name) tabs = list(get_setting('categories_as_tabs').keys()) subgroups = itertools.groupby(sorted(engines, key=get_subgroup), get_subgroup) diff --git a/utils/lib_sxng_test.sh b/utils/lib_sxng_test.sh index 530b4f80d..a9298841b 100755 --- a/utils/lib_sxng_test.sh +++ b/utils/lib_sxng_test.sh @@ -36,7 +36,7 @@ test.pylint() { build_msg TEST "[pylint] ./searx/engines" # shellcheck disable=SC2086 pylint ${PYLINT_OPTIONS} ${PYLINT_VERBOSE} \ - --additional-builtins="traits,supported_languages,language_aliases,logger,categories" \ + --additional-builtins="traits,logger,categories" \ searx/engines build_msg TEST "[pylint] ./searx ./searxng_extra ./tests"