Merge pull request #2326 from return42/ungrouped
[mod] clarify the difference of the default category and subgrouping
This commit is contained in:
		
						commit
						393e14965a
					
				| @ -311,7 +311,6 @@ Global Settings | |||||||
| ``results_on_new_tab``: | ``results_on_new_tab``: | ||||||
|   Open result links in a new tab by default. |   Open result links in a new tab by default. | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| .. _settings redis: | .. _settings redis: | ||||||
| 
 | 
 | ||||||
| ``redis:`` | ``redis:`` | ||||||
| @ -457,6 +456,9 @@ Communication with search engines. | |||||||
| ``max_redirects`` : | ``max_redirects`` : | ||||||
|   30 by default. Maximum redirect before it is an error. |   30 by default. Maximum redirect before it is an error. | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | .. _settings categories_as_tabs: | ||||||
|  | 
 | ||||||
| ``categories_as_tabs:`` | ``categories_as_tabs:`` | ||||||
| ----------------------- | ----------------------- | ||||||
| 
 | 
 | ||||||
| @ -477,6 +479,15 @@ Categories not listed here can still be searched with the :ref:`search-syntax`. | |||||||
|     files: |     files: | ||||||
|     social media: |     social media: | ||||||
| 
 | 
 | ||||||
|  | Engines are added to ``categories:`` (compare :ref:`engine categories`), the | ||||||
|  | categories listed in ``categories_as_tabs`` are shown as tabs in the UI.  If | ||||||
|  | there are no active engines in a category, the tab is not displayed (e.g. if a | ||||||
|  | user disables all engines in a category). | ||||||
|  | 
 | ||||||
|  | On the preferences page (``/preferences``) -- under *engines* -- there is an | ||||||
|  | additional tab, called *other*.  In this tab are all engines listed that are not | ||||||
|  | in one of the UI tabs (not included in ``categories_as_tabs``). | ||||||
|  | 
 | ||||||
| .. _settings engine: | .. _settings engine: | ||||||
| 
 | 
 | ||||||
| Engine settings | Engine settings | ||||||
| @ -552,10 +563,21 @@ engine is shown.  Most of the options have a default value or even are optional. | |||||||
|   to build and send a ``Accept-Language`` header in the request to the origin |   to build and send a ``Accept-Language`` header in the request to the origin | ||||||
|   search engine. |   search engine. | ||||||
| 
 | 
 | ||||||
|  | .. _engine categories: | ||||||
|  | 
 | ||||||
| ``categories`` : optional | ``categories`` : optional | ||||||
|   Define in which categories this engine will be active.  Most of the time, it is |   Specifies to which categories the engine should be added.  Engines can be | ||||||
|   defined in the code of the engine, but in a few cases it is useful, like when |   assigned to multiple categories. | ||||||
|   describing multiple search engine using the same code. | 
 | ||||||
|  |   Categories can be shown as tabs (:ref:`settings categories_as_tabs`) in the | ||||||
|  |   UI.  A search in a tab (in the UI) will query all engines that are active in | ||||||
|  |   this tab.  In the preferences page (``/preferences``) -- under *engines* -- | ||||||
|  |   users can select what engine should be active when querying in this tab. | ||||||
|  | 
 | ||||||
|  |   Alternatively, :ref:`\!bang <search-syntax>` can be used to search all engines | ||||||
|  |   in a category, regardless of whether they are active or not, or whether they | ||||||
|  |   are in a tab of the UI or not.  For example, ``!dictionaries`` can be used to | ||||||
|  |   query all search engines in that category (group). | ||||||
| 
 | 
 | ||||||
| ``timeout`` : optional | ``timeout`` : optional | ||||||
|   Timeout of the search with the current search engine.  **Be careful, it will |   Timeout of the search with the current search engine.  **Be careful, it will | ||||||
|  | |||||||
| @ -46,7 +46,7 @@ Engine File | |||||||
|    ======================= =========== ======================================================== |    ======================= =========== ======================================================== | ||||||
|    argument                type        information |    argument                type        information | ||||||
|    ======================= =========== ======================================================== |    ======================= =========== ======================================================== | ||||||
|    categories              list        pages, in which the engine is working |    categories              list        categories, in which the engine is working | ||||||
|    paging                  boolean     support multiple pages |    paging                  boolean     support multiple pages | ||||||
|    time_range_support      boolean     support search time range |    time_range_support      boolean     support search time range | ||||||
|    engine_type             str         - ``online`` :ref:`[ref] <demo online engine>` by |    engine_type             str         - ``online`` :ref:`[ref] <demo online engine>` by | ||||||
|  | |||||||
| @ -81,7 +81,7 @@ class Engine:  # pylint: disable=too-few-public-methods | |||||||
|     # settings.yml |     # settings.yml | ||||||
| 
 | 
 | ||||||
|     categories: List[str] |     categories: List[str] | ||||||
|     """Tabs, in which the engine is working.""" |     """Specifies to which :ref:`engine categories` the engine should be added.""" | ||||||
| 
 | 
 | ||||||
|     name: str |     name: str | ||||||
|     """Name that will be used across SearXNG to define this engine.  In settings, on |     """Name that will be used across SearXNG to define this engine.  In settings, on | ||||||
|  | |||||||
| @ -45,7 +45,7 @@ ENGINE_DEFAULT_ARGS = { | |||||||
|     "about": {}, |     "about": {}, | ||||||
| } | } | ||||||
| # set automatically when an engine does not have any tab category | # set automatically when an engine does not have any tab category | ||||||
| OTHER_CATEGORY = 'other' | DEFAULT_CATEGORY = 'other' | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # Defaults for the namespace of an engine module, see :py:func:`load_engine` | # Defaults for the namespace of an engine module, see :py:func:`load_engine` | ||||||
| @ -132,7 +132,7 @@ def load_engine(engine_data: dict) -> Optional[Engine]: | |||||||
|     set_loggers(engine, engine_name) |     set_loggers(engine, engine_name) | ||||||
| 
 | 
 | ||||||
|     if not any(cat in settings['categories_as_tabs'] for cat in engine.categories): |     if not any(cat in settings['categories_as_tabs'] for cat in engine.categories): | ||||||
|         engine.categories.append(OTHER_CATEGORY) |         engine.categories.append(DEFAULT_CATEGORY) | ||||||
| 
 | 
 | ||||||
|     return engine |     return engine | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -36,7 +36,7 @@ about = { | |||||||
| send_accept_language_header = True | send_accept_language_header = True | ||||||
| 
 | 
 | ||||||
| # engine dependent config | # engine dependent config | ||||||
| categories = ["others"] | categories = ["weather"] | ||||||
| URL = "https://duckduckgo.com/js/spice/forecast/{query}/{lang}" | URL = "https://duckduckgo.com/js/spice/forecast/{query}/{lang}" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -15,7 +15,7 @@ about = { | |||||||
|     "results": "JSON", |     "results": "JSON", | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| categories = ["others"] | categories = ["weather"] | ||||||
| 
 | 
 | ||||||
| url = "https://wttr.in/{query}?format=j1&lang={lang}" | url = "https://wttr.in/{query}?format=j1&lang={lang}" | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -17,7 +17,7 @@ from searx.enginelib import Engine | |||||||
| from searx.plugins import Plugin | from searx.plugins import Plugin | ||||||
| from searx.locales import LOCALE_NAMES | from searx.locales import LOCALE_NAMES | ||||||
| from searx.webutils import VALID_LANGUAGE_CODE | from searx.webutils import VALID_LANGUAGE_CODE | ||||||
| from searx.engines import OTHER_CATEGORY | from searx.engines import DEFAULT_CATEGORY | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| COOKIE_MAX_AGE = 60 * 60 * 24 * 365 * 5  # 5 years | COOKIE_MAX_AGE = 60 * 60 * 24 * 365 * 5  # 5 years | ||||||
| @ -259,7 +259,7 @@ class EnginesSetting(BooleanChoices): | |||||||
|         choices = {} |         choices = {} | ||||||
|         for engine in engines: |         for engine in engines: | ||||||
|             for category in engine.categories: |             for category in engine.categories: | ||||||
|                 if not category in list(settings['categories_as_tabs'].keys()) + [OTHER_CATEGORY]: |                 if not category in list(settings['categories_as_tabs'].keys()) + [DEFAULT_CATEGORY]: | ||||||
|                     continue |                     continue | ||||||
|                 choices['{}__{}'.format(engine.name, category)] = not engine.disabled |                 choices['{}__{}'.format(engine.name, category)] = not engine.disabled | ||||||
|         super().__init__(default_value, choices) |         super().__init__(default_value, choices) | ||||||
|  | |||||||
| @ -15,8 +15,8 @@ __all__ = [ | |||||||
| 
 | 
 | ||||||
| CONSTANT_NAMES = { | CONSTANT_NAMES = { | ||||||
|     # Constants defined in other modules |     # Constants defined in other modules | ||||||
|     'DEFAULT_GROUP_NAME': webutils.DEFAULT_GROUP_NAME, |     'NO_SUBGROUPING': webutils.NO_SUBGROUPING, | ||||||
|     'OTHER_CATEGORY': engines.OTHER_CATEGORY, |     'DEFAULT_CATEGORY': engines.DEFAULT_CATEGORY, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| CATEGORY_NAMES = { | CATEGORY_NAMES = { | ||||||
|  | |||||||
| @ -298,18 +298,18 @@ | |||||||
|     <p>{{ _('Currently used search engines') }}</p> |     <p>{{ _('Currently used search engines') }}</p> | ||||||
|     {{ tabs_open() }} |     {{ tabs_open() }} | ||||||
|      {% set ns = namespace(checked=true) %} |      {% set ns = namespace(checked=true) %} | ||||||
|      {% for categ in categories_as_tabs + [OTHER_CATEGORY] %} |      {% for categ in categories_as_tabs + [DEFAULT_CATEGORY] %} | ||||||
|      {{ tab_header('enginetab', 'category' + categ, _(categ), ns.checked )}} |      {{ tab_header('enginetab', 'category' + categ, _(categ), ns.checked )}} | ||||||
|      {% set ns.checked = false %} |      {% set ns.checked = false %} | ||||||
|    {% if categ == OTHER_CATEGORY %} |      {% if categ == DEFAULT_CATEGORY %} | ||||||
|       <p>{{_('This tab does not show up for search results, but you can search the engines listed here via bangs.')}}</p> |       <p>{{_('This tab dues not exists in the user interface, but you can search in these engines by its !bangs.')}} <a href="{{ url_for('info', pagename='search-syntax') }}">ⓘ</a></p> | ||||||
|      {% endif %} |      {% endif %} | ||||||
|     <div class="scrollx"> |     <div class="scrollx"> | ||||||
|     <table class="striped table_engines"> |     <table class="striped table_engines"> | ||||||
|       <tr>{{- "" -}} |       <tr>{{- "" -}} | ||||||
|         <th class="engine_checkbox">{{ _("Allow") }}</th>{{- "" -}} |         <th class="engine_checkbox">{{ _("Allow") }}</th>{{- "" -}} | ||||||
|         <th class="name">{{ _("Engine name") }}</th>{{- "" -}} |         <th class="name">{{ _("Engine name") }}</th>{{- "" -}} | ||||||
|         <th class="shortcut">{{ _("Shortcut") }}</th>{{- "" -}} |         <th class="shortcut">{{ _("!bang") }}</th>{{- "" -}} | ||||||
|         <th>{{ _("Supports selected language") }}</th>{{- "" -}} |         <th>{{ _("Supports selected language") }}</th>{{- "" -}} | ||||||
|         <th>{{ _("SafeSearch") }}</th>{{- "" -}} |         <th>{{ _("SafeSearch") }}</th>{{- "" -}} | ||||||
|         <th>{{ _("Time range") }}</th>{{- "" -}} |         <th>{{ _("Time range") }}</th>{{- "" -}} | ||||||
|  | |||||||
| @ -63,7 +63,7 @@ from searx.settings_defaults import OUTPUT_FORMATS | |||||||
| from searx.settings_loader import get_default_settings_path | from searx.settings_loader import get_default_settings_path | ||||||
| from searx.exceptions import SearxParameterException | from searx.exceptions import SearxParameterException | ||||||
| from searx.engines import ( | from searx.engines import ( | ||||||
|     OTHER_CATEGORY, |     DEFAULT_CATEGORY, | ||||||
|     categories, |     categories, | ||||||
|     engines, |     engines, | ||||||
|     engine_shortcuts, |     engine_shortcuts, | ||||||
| @ -435,7 +435,7 @@ def render(template_name: str, **kwargs): | |||||||
|     kwargs['method'] = request.preferences.get_value('method') |     kwargs['method'] = request.preferences.get_value('method') | ||||||
|     kwargs['categories_as_tabs'] = list(settings['categories_as_tabs'].keys()) |     kwargs['categories_as_tabs'] = list(settings['categories_as_tabs'].keys()) | ||||||
|     kwargs['categories'] = _get_enable_categories(categories.keys()) |     kwargs['categories'] = _get_enable_categories(categories.keys()) | ||||||
|     kwargs['OTHER_CATEGORY'] = OTHER_CATEGORY |     kwargs['DEFAULT_CATEGORY'] = DEFAULT_CATEGORY | ||||||
| 
 | 
 | ||||||
|     # i18n |     # i18n | ||||||
|     kwargs['sxng_locales'] = [l for l in sxng_locales if l[0] in settings['search']['languages']] |     kwargs['sxng_locales'] = [l for l in sxng_locales if l[0] in settings['search']['languages']] | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ from codecs import getincrementalencoder | |||||||
| from flask_babel import gettext, format_date | from flask_babel import gettext, format_date | ||||||
| 
 | 
 | ||||||
| from searx import logger, settings | from searx import logger, settings | ||||||
| from searx.engines import OTHER_CATEGORY | from searx.engines import DEFAULT_CATEGORY | ||||||
| 
 | 
 | ||||||
| if TYPE_CHECKING: | if TYPE_CHECKING: | ||||||
|     from searx.enginelib import Engine |     from searx.enginelib import Engine | ||||||
| @ -222,26 +222,24 @@ def is_flask_run_cmdline(): | |||||||
|     return frames[-2].filename.endswith('flask/cli.py') |     return frames[-2].filename.endswith('flask/cli.py') | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| DEFAULT_GROUP_NAME = 'others' | NO_SUBGROUPING = 'without further subgrouping' | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def group_engines_in_tab(engines: Iterable[Engine]) -> List[Tuple[str, Iterable[Engine]]]: | def group_engines_in_tab(engines: Iterable[Engine]) -> List[Tuple[str, Iterable[Engine]]]: | ||||||
|     """Groups an Iterable of engines by their first non tab category""" |     """Groups an Iterable of engines by their first non tab category (first subgroup)""" | ||||||
| 
 | 
 | ||||||
|     def get_group(eng): |     def get_subgroup(eng): | ||||||
|         non_tab_categories = [ |         non_tab_categories = [c for c in eng.categories if c not in tabs + [DEFAULT_CATEGORY]] | ||||||
|             c for c in eng.categories if c not in list(settings['categories_as_tabs'].keys()) + [OTHER_CATEGORY] |         return non_tab_categories[0] if len(non_tab_categories) > 0 else NO_SUBGROUPING | ||||||
|         ] |  | ||||||
|         return non_tab_categories[0] if len(non_tab_categories) > 0 else DEFAULT_GROUP_NAME |  | ||||||
| 
 |  | ||||||
|     groups = itertools.groupby(sorted(engines, key=get_group), get_group) |  | ||||||
| 
 | 
 | ||||||
|     def group_sort_key(group): |     def group_sort_key(group): | ||||||
|         return (group[0] == DEFAULT_GROUP_NAME, group[0].lower()) |         return (group[0] == NO_SUBGROUPING, group[0].lower()) | ||||||
| 
 |  | ||||||
|     sorted_groups = sorted(((name, list(engines)) for name, engines in groups), key=group_sort_key) |  | ||||||
| 
 | 
 | ||||||
|     def engine_sort_key(engine): |     def engine_sort_key(engine): | ||||||
|         return (engine.about.get('language', ''), engine.name) |         return (engine.about.get('language', ''), engine.name) | ||||||
| 
 | 
 | ||||||
|  |     tabs = list(settings['categories_as_tabs'].keys()) | ||||||
|  |     subgroups = itertools.groupby(sorted(engines, key=get_subgroup), get_subgroup) | ||||||
|  |     sorted_groups = sorted(((name, list(engines)) for name, engines in subgroups), key=group_sort_key) | ||||||
|  | 
 | ||||||
|     return [(groupname, sorted(engines, key=engine_sort_key)) for groupname, engines in sorted_groups] |     return [(groupname, sorted(engines, key=engine_sort_key)) for groupname, engines in sorted_groups] | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user