From 7eedd44f5f9965cf2fbff14d276f96944b5c6a98 Mon Sep 17 00:00:00 2001 From: Markus Heiser Date: Wed, 10 Sep 2025 16:10:42 +0200 Subject: [PATCH] [mod] typification of SearXNG: add new result type Paper This patch adds a new result type: Paper - Python class: searx/result_types/paper.py - Jinja template: searx/templates/simple/result_templates/paper.html - CSS (less) client/simple/src/less/result_types/paper.less Signed-off-by: Markus Heiser --- .../simple/src/less/result_types/paper.less | 72 +++++++++++++ client/simple/src/less/style.less | 10 +- docs/dev/result_types/main/paper.rst | 7 ++ docs/dev/result_types/main_result.rst | 2 +- searx/result_types/__init__.py | 3 + searx/result_types/_base.py | 6 +- searx/result_types/paper.py | 96 +++++++++++++++++ .../simple/result_templates/paper.html | 102 ++++++++++++++---- searx/utils.py | 36 ++++--- searx/weather.py | 30 +++++- 10 files changed, 318 insertions(+), 46 deletions(-) create mode 100644 client/simple/src/less/result_types/paper.less create mode 100644 docs/dev/result_types/main/paper.rst create mode 100644 searx/result_types/paper.py diff --git a/client/simple/src/less/result_types/paper.less b/client/simple/src/less/result_types/paper.less new file mode 100644 index 000000000..0a83ef224 --- /dev/null +++ b/client/simple/src/less/result_types/paper.less @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +/* + Layout of the Paper result class +*/ + +.result-paper { + .attributes { + display: table; + border-spacing: 0.125rem; + + div { + display: table-row; + + span { + font-size: 0.9rem; + margin-top: 0.25rem; + display: table-cell; + + time { + font-size: 0.9rem; + } + } + + span:first-child { + color: var(--color-base-font); + min-width: 10rem; + } + + span:nth-child(2) { + color: var(--color-result-publishdate-font); + } + } + } + + .content { + margin-top: 0.25rem; + } + + .comments { + font-size: 0.9rem; + margin: 0.25rem 0 0 0; + padding: 0; + word-wrap: break-word; + line-height: 1.24; + font-style: italic; + } +} + +@media screen and (max-width: @phone) { + .result-paper { + .attributes { + display: block; + + div { + display: block; + + span { + display: inline; + } + + span:first-child { + font-weight: bold; + } + + span:nth-child(2) { + .ltr-margin-left(0.5rem); + } + } + } + } +} diff --git a/client/simple/src/less/style.less b/client/simple/src/less/style.less index 3cac7a265..258c45a0e 100644 --- a/client/simple/src/less/style.less +++ b/client/simple/src/less/style.less @@ -309,11 +309,11 @@ article[data-vim-selected].category-social { } } -.result-paper, .result-packages { .attributes { display: table; border-spacing: 0.125rem; + margin-top: 0.3rem; div { display: table-row; @@ -353,12 +353,6 @@ article[data-vim-selected].category-social { } } -.result-packages { - .attributes { - margin-top: 0.3rem; - } -} - .template_group_images { display: flex; flex-wrap: wrap; @@ -1118,7 +1112,6 @@ summary.title { display: none; } - .result-paper, .result-packages { .attributes { display: block; @@ -1164,3 +1157,4 @@ pre code { // import layouts of the Result types @import "result_types/keyvalue.less"; +@import "result_types/paper.less"; diff --git a/docs/dev/result_types/main/paper.rst b/docs/dev/result_types/main/paper.rst new file mode 100644 index 000000000..94d8a81a3 --- /dev/null +++ b/docs/dev/result_types/main/paper.rst @@ -0,0 +1,7 @@ +.. _result_types.paper: + +============= +Paper Results +============= + +.. automodule:: searx.result_types.paper diff --git a/docs/dev/result_types/main_result.rst b/docs/dev/result_types/main_result.rst index f072ea757..f3d09c011 100644 --- a/docs/dev/result_types/main_result.rst +++ b/docs/dev/result_types/main_result.rst @@ -16,6 +16,7 @@ following types have been implemented so far .. main/mainresult main/keyvalue main/code + main/paper The :ref:`LegacyResult ` is used internally for the results that have not yet been typed. The templates can be used as orientation until the @@ -26,7 +27,6 @@ final typing is complete. - :ref:`template videos` - :ref:`template torrent` - :ref:`template map` -- :ref:`template paper` - :ref:`template packages` - :ref:`template files` - :ref:`template products` diff --git a/searx/result_types/__init__.py b/searx/result_types/__init__.py index c8b8eb4f4..a1976c10f 100644 --- a/searx/result_types/__init__.py +++ b/searx/result_types/__init__.py @@ -22,6 +22,7 @@ __all__ = [ "Translations", "WeatherAnswer", "Code", + "Paper", ] import typing as t @@ -31,6 +32,7 @@ from ._base import Result, MainResult, LegacyResult from .answer import AnswerSet, Answer, Translations, WeatherAnswer from .keyvalue import KeyValue from .code import Code +from .paper import Paper class ResultList(list[Result | LegacyResult], abc.ABC): @@ -44,6 +46,7 @@ class ResultList(list[Result | LegacyResult], abc.ABC): Answer = Answer KeyValue = KeyValue Code = Code + Paper = Paper MainResult = MainResult Result = Result Translations = Translations diff --git a/searx/result_types/_base.py b/searx/result_types/_base.py index 1c614651b..b3f2afdeb 100644 --- a/searx/result_types/_base.py +++ b/searx/result_types/_base.py @@ -362,7 +362,11 @@ class MainResult(Result): # pylint: disable=missing-class-docstring """The date on which the object was published.""" pubdate: str = "" - """String representation of :py:obj:`MainResult.publishedDate`""" + """String representation of :py:obj:`MainResult.publishedDate` + + Deprecated: it is still partially used in the templates, but will one day be + completely eliminated. + """ length: time.struct_time | None = None """Playing duration in seconds.""" diff --git a/searx/result_types/paper.py b/searx/result_types/paper.py new file mode 100644 index 000000000..33bb5f99a --- /dev/null +++ b/searx/result_types/paper.py @@ -0,0 +1,96 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Typification of the *paper* results. + +.. _BibTeX field types: https://en.wikipedia.org/wiki/BibTeX#Field_types +.. _BibTeX format: https://www.bibtex.com/g/bibtex-format/ + +Results of this type are rendered in the :origin:`paper.html +` template. + +Related topics: + +- `BibTeX field types`_ +- `BibTeX format`_ + +---- + +.. autoclass:: Paper + :members: + :show-inheritance: + +""" +# pylint: disable=too-few-public-methods, disable=invalid-name + +from __future__ import annotations + +__all__ = ["Paper"] + +import typing as t + +from searx.weather import DateTime +from ._base import MainResult + + +@t.final +class Paper(MainResult, kw_only=True): + """Result type suitable for displaying scientific papers and other + documents.""" + + template: str = "paper.html" + + date_of_publication: DateTime | None = None + """Date the document was published.""" + + content: str = "" + """An abstract or excerpt from the document.""" + + comments: str = "" + """Free text display in italic below the content.""" + + tags: list[str] = [] + """Free tag list.""" + + type: str = "" + """Short description of medium type, e.g. *book*, *pdf* or *html* ...""" + + authors: list[str] | set[str] = [] + """List of authors of the work (authors with a "s" suffix, the "author" is + in the :py:obj:`MainResult.author`).""" + + editor: str = "" + """Editor of the book/paper.""" + + publisher: str = "" + """Name of the publisher.""" + + journal: str = "" + """Name of the journal or magazine the article was published in.""" + + volume: str | int = "" + """Volume number.""" + + pages: str = "" + """Page range where the article is.""" + + number: str = "" + """Number of the report or the issue number for a journal article.""" + + doi: str = "" + """DOI number (like ``10.1038/d41586-018-07848-2``).""" + + issn: list[str] = [] + """List of ISSN numbers like ``1476-4687``""" + + isbn: list[str] = [] + """List of ISBN numbers like ``9780201896831``""" + + pdf_url: str = "" + """URL to the full article, the PDF version""" + + html_url: str = "" + """URL to full article, HTML version""" + + def __post_init__(self): + super().__post_init__() + if self.date_of_publication is None and self.publishedDate is not None: + self.date_of_publication = DateTime(self.publishedDate) diff --git a/searx/templates/simple/result_templates/paper.html b/searx/templates/simple/result_templates/paper.html index 7e94cf174..074ad9081 100644 --- a/searx/templates/simple/result_templates/paper.html +++ b/searx/templates/simple/result_templates/paper.html @@ -1,34 +1,92 @@ {% from 'simple/macros.html' import result_header, result_sub_header, result_sub_footer, result_footer, result_link with context %} -{{ result_header(result, favicons, image_proxify) -}} +{{ result_header(result, favicons, image_proxify) }} +
- {%- if result.publishedDate %}
{{ _("Published date") }}:
{% endif -%} - {%- if result.authors %}
{{ _("Author") }}:{{ result.authors | join(", ") }}
{% endif -%} + {%- if result.date_of_publication %} +
+ {{ _("Published date") }}: + {{ result.date_of_publication.l10n_date("long", "UI") }} +
+ {% endif -%} + {%- if result.authors %} +
+ {{ _("Author") }}: + {{ result.authors | join(", ") }} +
+ {% endif -%} {%- if result.journal -%} -
- {{- _("Journal") }}:{{ result.journal -}} - {%- if result.volume -%} -  {{- result.volume -}} - {%- if result.number -%} - .{{- result.number -}} +
+ {{- _("Journal") }}: + {{ result.journal -}} + {%- if result.volume -%} +  {{- result.volume -}} + {%- if result.number -%}.{{- result.number -}}{%- endif -%} {%- endif -%} - {%- endif -%} - {%- if result.pages -%} -  {{- result.pages -}} - {%- endif -%} + {%- if result.pages -%} {{- result.pages -}}{%- endif -%}
{%- endif %} - {%- if result.editor %}
{{ _("Editor") }}:{{ result.editor }}
{% endif -%} - {%- if result.publisher %}
{{ _("Publisher") }}:{{ result.publisher }}
{% endif -%} - {%- if result.type %}
{{ _("Type") }}:{{ result.type }}
{% endif -%} - {%- if result.tags %}
{{ _("Tags") }}:{{ result.tags | join(", ")}}
{%- endif -%} - {%- if result.doi %}
{{ _("DOI") }}:{{ result_link(doi_resolver + result.doi, result.doi) }}
{% endif -%} - {%- if result.issn %}
{{ _("ISSN") }}:{{ result.issn | join(", ") }}
{% endif -%} - {%- if result.isbn %}
{{ _("ISBN") }}:{{ result.isbn | join(", ") }}
{% endif -%} + {%- if result.editor %} +
+ {{ _("Editor") }}: + {{ result.editor }} +
+ {% endif -%} + {%- if result.publisher %} +
+ {{ _("Publisher") }}: + {{ result.publisher }} +
+ {% endif -%} + {%- if result.type %} +
+ {{ _("Type") }}: + {{ result.type }} +
+ {% endif -%} + {%- if result.tags %} +
+ {{ _("Tags") }}: + {{ result.tags | join(", ")}} +
+ {%- endif -%} + {%- if result.doi %} +
+ {{ _("DOI") }}: + {{ result_link(doi_resolver + result.doi, result.doi) }} +
+ {% endif -%} + {%- if result.issn %} +
+ {{ _("ISSN") }}: + {{ result.issn | join(", ") }} +
+ {% endif -%} + {%- if result.isbn %} +
+ {{ _("ISBN") }}: + {{ result.isbn | join(", ") }} +
+ {% endif -%} + {%- if result.views %} +
+ {{ _('Views') }}: + {{ result.views }} +
+ {% endif -%}
-{%- if result.content -%}

{{- result.content | safe -}}

{%- endif -%} -{%- if result.comments -%}

{{- result.comments -}}

{%- endif -%} +{%- if result.content -%} +

{{- result.content | safe -}}

+{%- endif -%} +{%- if result.comments -%} +

{{- result.comments -}}

+{%- endif -%} + +{%- if result.metadata %} +
{{ result.metadata|safe }}
+{% endif -%} +